Update stylish preferences.

This commit is contained in:
David Himmelstrup 2020-08-27 13:42:59 +08:00
commit aa4656d77d
12 changed files with 132 additions and 34 deletions

View file

@ -81,7 +81,7 @@ steps:
# > init, last, length) # > init, last, length)
# #
# Default: true # Default: true
pad_module_names: false pad_module_names: true
# Long list align style takes effect when import is too long. This is # Long list align style takes effect when import is too long. This is
# determined by 'columns' setting. # determined by 'columns' setting.

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

View file

@ -0,0 +1,18 @@
#!/usr/bin/env stack
-- stack runghc --package reanimate
{-# LANGUAGE OverloadedStrings #-}
module Main(main) where
import Reanimate
import Reanimate.Builtin.Documentation
import Reanimate.Morph.Common
import Reanimate.Morph.Linear
import Reanimate.Morph.Rotational
import Graphics.SvgTree
main :: IO ()
main = reanimate $ docEnv $ playThenReverseA $ pauseAround 0.5 0.5 $ mkAnimation 3 $ \t ->
withStrokeLineJoin JoinRound $
let src = scale 8 $ center $ latex "X"
dst = scale 8 $ center $ latex "H"
in morph linear{morphTrajectory=rotationalTrajectory (0.5,0.5)} src dst t

View file

@ -27,16 +27,19 @@ traceBuffer :: IORef [Animation]
traceBuffer = unsafePerformIO (newIORef []) traceBuffer = unsafePerformIO (newIORef [])
{-# NOINLINE traceSVG #-} {-# NOINLINE traceSVG #-}
-- | Add SVG image to trace stack.
traceSVG :: SVG -> a -> a traceSVG :: SVG -> a -> a
traceSVG = traceA . staticFrame (recip 60) traceSVG = traceA . staticFrame (recip 60)
{-# NOINLINE traceA #-} {-# NOINLINE traceA #-}
-- | Add animation to trace stack.
traceA :: Animation -> a -> a traceA :: Animation -> a -> a
traceA a v = unsafePerformIO $ do traceA a v = unsafePerformIO $ do
modifyIORef' traceBuffer (a :) modifyIORef' traceBuffer (a :)
evaluate v evaluate v
{-# NOINLINE playTraces #-} {-# NOINLINE playTraces #-}
-- | Evaluate argument and play back the trace stack.
playTraces :: a -> Animation playTraces :: a -> Animation
playTraces v = unsafePerformIO $ do playTraces v = unsafePerformIO $ do
_ <- evaluate v _ <- evaluate v

View file

@ -47,6 +47,7 @@ import System.IO.Unsafe ( unsafePerformIO )
latex :: T.Text -> Tree latex :: T.Text -> Tree
latex = latexWithHeaders [] latex = latexWithHeaders []
-- | Invoke latex with extra script headers.
latexWithHeaders :: [T.Text] -> T.Text -> Tree latexWithHeaders :: [T.Text] -> T.Text -> Tree
latexWithHeaders = someTexWithHeaders "latex" "dvi" [] latexWithHeaders = someTexWithHeaders "latex" "dvi" []
@ -58,6 +59,7 @@ someTexWithHeaders exec dvi args headers tex =
where where
script = mkTexScript exec args headers tex script = mkTexScript exec args headers tex
-- | Invoke latex and separate results.
latexChunks :: [T.Text] -> [Tree] latexChunks :: [T.Text] -> [Tree]
latexChunks chunks | pNoExternals = map mkText chunks latexChunks chunks | pNoExternals = map mkText chunks
latexChunks chunks = worker (svgGlyphs $ latex $ T.concat chunks) chunks latexChunks chunks = worker (svgGlyphs $ latex $ T.concat chunks) chunks
@ -74,6 +76,7 @@ latexChunks chunks = worker (svgGlyphs $ latex $ T.concat chunks)
xelatex :: Text -> Tree xelatex :: Text -> Tree
xelatex = xelatexWithHeaders [] xelatex = xelatexWithHeaders []
-- | Invoke xelatex with extra script headers.
xelatexWithHeaders :: [T.Text] -> T.Text -> Tree xelatexWithHeaders :: [T.Text] -> T.Text -> Tree
xelatexWithHeaders = someTexWithHeaders "xelatex" "xdv" ["-no-pdf"] xelatexWithHeaders = someTexWithHeaders "xelatex" "xdv" ["-no-pdf"]
@ -89,6 +92,7 @@ xelatexWithHeaders = someTexWithHeaders "xelatex" "xdv" ["-no-pdf"]
ctex :: T.Text -> Tree ctex :: T.Text -> Tree
ctex = ctexWithHeaders [] ctex = ctexWithHeaders []
-- | Invoke xelatex with extra script headers + ctex headers.
ctexWithHeaders :: [T.Text] -> T.Text -> Tree ctexWithHeaders :: [T.Text] -> T.Text -> Tree
ctexWithHeaders headers = xelatexWithHeaders ("\\usepackage[UTF8]{ctex}" : headers) ctexWithHeaders headers = xelatexWithHeaders ("\\usepackage[UTF8]{ctex}" : headers)

View file

@ -1,6 +1,23 @@
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-|
Copyright : Written by David Himmelstrup
License : Unlicense
Maintainer : lemmih@gmail.com
Stability : experimental
Portability : POSIX
With animations defined as SVG images over time, it is unfortunately
quite easy to write inefficient code where expensive expressions are
re-evaluated for every frame even if nothing has changed. This get
around this issue, this module defines a global key-value table that
can store expensive expressions such that they are evaluated only once.
There is currently no way to clear values from the table and it is your
own responsibility to not consume all available memory.
-}
module Reanimate.Memo module Reanimate.Memo
( Key(..) ( Key(..)
, memo , memo
@ -57,15 +74,20 @@ cacheMapInsert (k:ks) v (CacheMap sub vals) =
fn = Just . cacheMapInsert ks v . fromMaybe emptyCacheMap fn = Just . cacheMapInsert ks v . fromMaybe emptyCacheMap
{-# NOINLINE cacheMap #-} {-# NOINLINE cacheMap #-}
-- FIXME: There should be a way to clear the cache.
cacheMap :: IORef CacheMap cacheMap :: IORef CacheMap
cacheMap = unsafePerformIO (newIORef emptyCacheMap) cacheMap = unsafePerformIO (newIORef emptyCacheMap)
-- | Keys can either by any boxed object with identity (to be compared with
-- StableNames) or a primitive type with an Eq instance.
data Key = forall a. Key !a | forall a. (Typeable a, Eq a, Ord a) => KeyPrim !a data Key = forall a. Key !a | forall a. (Typeable a, Eq a, Ord a) => KeyPrim !a
fromKey :: Key -> IO DynamicName fromKey :: Key -> IO DynamicName
fromKey (Key val) = DynamicName <$> makeStableName val fromKey (Key val) = DynamicName <$> makeStableName val
fromKey (KeyPrim val) = pure (DynamicKey val) fromKey (KeyPrim val) = pure (DynamicKey val)
-- | Cache expensive value in global store. You must guarantee that the
-- key uniquely determines the value.
memo :: Typeable a => [Key] -> a -> a memo :: Typeable a => [Key] -> a -> a
memo !k v = unsafePerformIO $ do memo !k v = unsafePerformIO $ do
keys <- mapM fromKey k keys <- mapM fromKey k

View file

@ -6,7 +6,8 @@ Stability : experimental
Portability : POSIX Portability : POSIX
-} -}
module Reanimate.Morph.Rotational module Reanimate.Morph.Rotational
( rotationalTrajectory ( Origin
, rotationalTrajectory
, polygonOrigin , polygonOrigin
) where ) where
@ -19,8 +20,22 @@ import Reanimate.Ease
import Reanimate.Morph.Common import Reanimate.Morph.Common
import Reanimate.Math.Polygon import Reanimate.Math.Polygon
-- | Rotational origin relative to polygon center.
-- (0.5, 0.5) is center of polygon. Top right is (1,1) and
-- bottom left is (0,0)
type Origin = (Double, Double) type Origin = (Double, Double)
-- | Interpolation by rotating around an origin point.
--
-- Example:
--
-- > playThenReverseA $ pauseAround 0.5 0.5 $ mkAnimation 3 $ \t ->
-- > withStrokeLineJoin JoinRound $
-- > let src = scale 8 $ center $ latex "X"
-- > dst = scale 8 $ center $ latex "H"
-- > in morph linear{morphTrajectory=rotationalTrajectory (0.5,0.5)} src dst t
--
-- <<docs/gifs/doc_rotationalTrajectory.gif>>
rotationalTrajectory :: Origin -> Trajectory rotationalTrajectory :: Origin -> Trajectory
rotationalTrajectory origin (src,dst) = rotationalTrajectory origin (src,dst) =
\t -> \t ->
@ -41,6 +56,7 @@ rotationalTrajectory origin (src,dst) =
originAngle o = lineAngle (o + V2 1 0) o originAngle o = lineAngle (o + V2 1 0) o
-- | Compute the absolute position of rotational origin point in polygon.
polygonOrigin :: Polygon -> Origin -> V2 Double polygonOrigin :: Polygon -> Origin -> V2 Double
polygonOrigin poly (originX, originY) = polygonOrigin poly (originX, originY) =
case pBoundingBox poly of case pBoundingBox poly of

View file

@ -5,6 +5,10 @@ License : Unlicense
Maintainer : lemmih@gmail.com Maintainer : lemmih@gmail.com
Stability : experimental Stability : experimental
Portability : POSIX Portability : POSIX
Internal tools for rastering SVGs and rendering videos. You are unlikely
to ever directly use the functions in this module.
-} -}
module Reanimate.Render module Reanimate.Render
( render ( render
@ -54,6 +58,7 @@ idempotentFile path action = do
where where
lockFile = path <.> "lock" lockFile = path <.> "lock"
-- | Generate SVGs at 60fps and put them in a folder.
renderSvgs :: FilePath -> Int -> Bool -> Animation -> IO () renderSvgs :: FilePath -> Int -> Bool -> Animation -> IO ()
renderSvgs folder offset _prettyPrint ani = do renderSvgs folder offset _prettyPrint ani = do
print frameCount print frameCount
@ -77,6 +82,8 @@ renderSvgs folder offset _prettyPrint ani = do
hPutStrLn stderr msg hPutStrLn stderr msg
exitWith (ExitFailure 1) exitWith (ExitFailure 1)
-- | Select a single frame that doesn't already exist in the output
-- folder and render it. If all frames have been rendered, print "Done".
renderOneFrame :: FilePath -> Int -> Bool -> Int -> Animation -> IO () renderOneFrame :: FilePath -> Int -> Bool -> Int -> Animation -> IO ()
renderOneFrame folder offset _prettyPrint rate ani = renderOneFrame folder offset _prettyPrint rate ani =
worker (frameOrder rate frameCount) worker (frameOrder rate frameCount)
@ -99,6 +106,9 @@ renderOneFrame folder offset _prettyPrint rate ani =
frameCount = round (duration ani * fromIntegral rate) :: Int frameCount = round (duration ani * fromIntegral rate) :: Int
-- XXX: Merge with 'renderSvgs' -- XXX: Merge with 'renderSvgs'
-- | Render 10 frames and print them to stdout. Used for testing.
--
-- XXX: Not related to the snippets in the playground.
renderSnippets :: Animation -> IO () renderSnippets :: Animation -> IO ()
renderSnippets ani = forM_ [0 .. frameCount - 1] $ \nth -> do renderSnippets ani = forM_ [0 .. frameCount - 1] $ \nth -> do
let now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth let now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth
@ -120,6 +130,7 @@ filterFrameList seen nthFrame nFrames = filter (not . isSeen)
[0, nthFrame .. nFrames - 1] [0, nthFrame .. nFrames - 1]
where isSeen x = any (\y -> x `mod` y == 0) seen where isSeen x = any (\y -> x `mod` y == 0) seen
-- | Video formats supported by reanimate.
data Format = RenderMp4 | RenderGif | RenderWebm data Format = RenderMp4 | RenderGif | RenderWebm
deriving (Show) deriving (Show)
@ -150,6 +161,7 @@ mp4Arguments fps progress template target =
-- gifArguments :: FPS -> FilePath -> FilePath -> FilePath -> [String] -- gifArguments :: FPS -> FilePath -> FilePath -> FilePath -> [String]
-- gifArguments fps progress template target = -- gifArguments fps progress template target =
-- | Render animation to a video file with given parameters.
render render
:: Animation :: Animation
-> FilePath -> FilePath
@ -334,6 +346,8 @@ rasterTemplate RasterNone = "render-%05d.svg"
rasterTemplate RasterAuto = "render-%05d.svg" rasterTemplate RasterAuto = "render-%05d.svg"
rasterTemplate _ = "render-%05d.png" rasterTemplate _ = "render-%05d.png"
-- | Resolve RasterNone and RasterAuto. If no valid raster can
-- be found, exit with an error message.
requireRaster :: Raster -> IO Raster requireRaster :: Raster -> IO Raster
requireRaster raster = do requireRaster raster = do
raster' <- selectRaster (if raster == RasterNone then RasterAuto else raster) raster' <- selectRaster (if raster == RasterNone then RasterAuto else raster)
@ -346,6 +360,8 @@ requireRaster raster = do
exitWith (ExitFailure 1) exitWith (ExitFailure 1)
_ -> pure raster' _ -> pure raster'
-- | Resolve RasterNone and RasterAuto. If no valid raster can
-- be found, return RasterNone.
selectRaster :: Raster -> IO Raster selectRaster :: Raster -> IO Raster
selectRaster RasterAuto = do selectRaster RasterAuto = do
rsvg <- hasRSvg rsvg <- hasRSvg
@ -358,6 +374,8 @@ selectRaster RasterAuto = do
| otherwise -> pure RasterNone | otherwise -> pure RasterNone
selectRaster r = pure r selectRaster r = pure r
-- | Convert SVG file to a PNG file with selected raster engine. If
-- raster engine is RasterAuto or RasterNone, do nothing.
applyRaster :: Raster -> FilePath -> IO () applyRaster :: Raster -> FilePath -> IO ()
applyRaster RasterNone _ = return () applyRaster RasterNone _ = return ()
applyRaster RasterAuto _ = return () applyRaster RasterAuto _ = return ()

View file

@ -11,18 +11,18 @@ module Reanimate.Svg.BoundingBox
, svgWidth , svgWidth
) where ) where
import Control.Arrow ((***)) import Control.Arrow ((***))
import Control.Lens ((^.)) import Control.Lens ((^.))
import Data.List import Data.List
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Graphics.SvgTree hiding (height, line, path, use, import qualified Data.Vector.Unboxed as V
width) import qualified Geom2D.CubicBezier.Linear as Bezier
import Linear.V2 hiding (angle) import Graphics.SvgTree hiding (height, line, path, use, width)
import Linear.V2 hiding (angle)
import Linear.Vector import Linear.Vector
import Reanimate.Constants import Reanimate.Constants
import Reanimate.Svg.LineCommand import Reanimate.Svg.LineCommand
import qualified Reanimate.Transform as Transform import qualified Reanimate.Transform as Transform
-- import qualified Geom2D.CubicBezier as Bezier
-- | Return bounding box of SVG tree. -- | Return bounding box of SVG tree.
-- The four numbers returned are (minimal X-coordinate, minimal Y-coordinate, width, height) -- The four numbers returned are (minimal X-coordinate, minimal Y-coordinate, width, height)
@ -67,7 +67,8 @@ linePoints = worker zero
LineBezier [p] -> LineBezier [p] ->
p : worker p xs p : worker p xs
LineBezier ctrl -> -- approximation LineBezier ctrl -> -- approximation
[ last (partialBezierPoints (from:ctrl) 0 (recip chunks*i)) | i <- [0..chunks]] ++ let bezier = Bezier.AnyBezier (V.fromList (from:ctrl))
in [ Bezier.evalBezier bezier (recip chunks*i) | i <- [0..chunks]] ++
worker (last ctrl) xs worker (last ctrl) xs
LineEnd p -> p : worker p xs LineEnd p -> p : worker p xs
chunks = 10 chunks = 10
@ -106,7 +107,7 @@ svgBoundingPoints t = map (Transform.transformPoint m) $
pointToRPoint p = pointToRPoint p =
case mapTuple (toUserUnit defaultDPI) p of case mapTuple (toUserUnit defaultDPI) p of
(Num x, Num y) -> V2 x y (Num x, Num y) -> V2 x y
_ -> error "Reanimate.Svg.svgBoundingPoints: Unrecognized number format." _ -> error "Reanimate.Svg.svgBoundingPoints: Unrecognized number format."
circleBoundingPoints circ = circleBoundingPoints circ =
let (xnum, ynum) = circ ^. circleCenter let (xnum, ynum) = circ ^. circleCenter

View file

@ -1,18 +1,33 @@
module Reanimate.Svg.LineCommand where {-|
Copyright : Written by David Himmelstrup
License : Unlicense
Maintainer : lemmih@gmail.com
Stability : experimental
Portability : POSIX
-}
module Reanimate.Svg.LineCommand
( LineCommand(..)
, lineLength
, toLineCommands
, lineToPath
, lineToPoints
, partialSvg
) where
import Control.Lens ((%~), (&), (.~)) import Control.Lens ((%~), (&), (.~))
import Control.Monad.Fix import Control.Monad.Fix
import Control.Monad.State import Control.Monad.State
import Data.Functor import Data.Functor
import qualified Data.Vector.Unboxed as V import qualified Data.Vector.Unboxed as V
import qualified Geom2D.CubicBezier.Linear as Bezier import qualified Geom2D.CubicBezier.Linear as Bezier
import Graphics.SvgTree hiding (height, line, path, use, width) import Graphics.SvgTree hiding (height, line, path, use, width)
import Linear.Metric import Linear.Metric
import Linear.V2 hiding (angle) import Linear.V2 hiding (angle)
import Linear.Vector import Linear.Vector
type CmdM a = State RPoint a type CmdM a = State RPoint a
-- | Simplified version of a PathCommand where all points are absolute.
data LineCommand data LineCommand
= LineMove RPoint = LineMove RPoint
-- | LineDraw RPoint -- | LineDraw RPoint
@ -20,6 +35,7 @@ data LineCommand
| LineEnd RPoint | LineEnd RPoint
deriving (Show) deriving (Show)
-- | Convert from line commands to path commands.
lineToPath :: [LineCommand] -> [PathCommand] lineToPath :: [LineCommand] -> [PathCommand]
lineToPath = map worker lineToPath = map worker
where where
@ -31,6 +47,7 @@ lineToPath = map worker
worker LineBezier{} = error "Reanimate.Svg.lineToPath: invalid bezier curve" worker LineBezier{} = error "Reanimate.Svg.lineToPath: invalid bezier curve"
worker LineEnd{} = EndPath worker LineEnd{} = EndPath
-- | Using @n@ control points, approximate the path of the curves.
lineToPoints :: Int -> [LineCommand] -> [RPoint] lineToPoints :: Int -> [LineCommand] -> [RPoint]
lineToPoints nPoints cmds = lineToPoints nPoints cmds =
map lineEnd lineSegments map lineEnd lineSegments
@ -58,10 +75,11 @@ adjustLineLength :: Double -> RPoint -> LineCommand -> LineCommand
adjustLineLength alpha from cmd = adjustLineLength alpha from cmd =
case cmd of case cmd of
LineBezier points -> LineBezier $ drop 1 $ partialBezierPoints (from:points) 0 alpha LineBezier points -> LineBezier $ drop 1 $ partialBezierPoints (from:points) 0 alpha
LineMove p -> LineMove p LineMove p -> LineMove p
-- LineDraw t -> LineDraw (lerp alpha t from) -- LineDraw t -> LineDraw (lerp alpha t from)
LineEnd p -> LineBezier [lerp alpha p from] LineEnd p -> LineBezier [lerp alpha p from]
-- | Estimated length of all segments in a line.
lineLength :: LineCommand -> CmdM Double lineLength :: LineCommand -> CmdM Double
lineLength cmd = lineLength cmd =
case cmd of case cmd of
@ -80,11 +98,12 @@ lineLength cmd =
rpointsToBezier :: [RPoint] -> Bezier.CubicBezier Double rpointsToBezier :: [RPoint] -> Bezier.CubicBezier Double
rpointsToBezier lst = rpointsToBezier lst =
case lst of case lst of
[a,b] -> Bezier.CubicBezier a a b b [a,b] -> Bezier.CubicBezier a a b b
[a,b,c] -> Bezier.quadToCubic (Bezier.QuadBezier a b c) [a,b,c] -> Bezier.quadToCubic (Bezier.QuadBezier a b c)
[a,b,c,d] -> Bezier.CubicBezier a b c d [a,b,c,d] -> Bezier.CubicBezier a b c d
_ -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst _ -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst
-- | Convert from path commands to line commands.
toLineCommands :: [PathCommand] -> [LineCommand] toLineCommands :: [PathCommand] -> [LineCommand]
toLineCommands ps = evalState (worker zero Nothing ps) zero toLineCommands ps = evalState (worker zero Nothing ps) zero
where where
@ -239,9 +258,6 @@ partialBezierPoints ps a b =
Bezier.AnyBezier os = Bezier.bezierSubsegment c1 a b Bezier.AnyBezier os = Bezier.bezierSubsegment c1 a b
in V.toList os in V.toList os
interpolatePathCommands :: Double -> [PathCommand] -> [PathCommand]
interpolatePathCommands alpha = lineToPath . partialLine alpha . toLineCommands
{- | Create an image showing portion of a path. {- | Create an image showing portion of a path.
Note that this only affects paths (see 'Reanimate.Svg.Constructors.mkPath'). Note that this only affects paths (see 'Reanimate.Svg.Constructors.mkPath').
You can also use this with other SVG shapes if you convert them to path first (see 'Reanimate.Svg.pathify'). You can also use this with other SVG shapes if you convert them to path first (see 'Reanimate.Svg.pathify').

View file

@ -18,20 +18,18 @@ import Data.Maybe
import Graphics.SvgTree import Graphics.SvgTree
import Linear.V2 import Linear.V2
type TMatrix = Matrix Coord
-- | Identity matrix. -- | Identity matrix.
-- --
-- @transformPoints identity x = x@ -- @transformPoints identity x = x@
identity :: TMatrix identity :: Matrix Coord
identity = M.identity 3 identity = M.identity 3
fromList :: [Coord] -> TMatrix fromList :: [Coord] -> Matrix Coord
fromList [a,b,c,d,e,f] = M.fromList 3 3 [a,c,e,b,d,f,0,0,1] fromList [a,b,c,d,e,f] = M.fromList 3 3 [a,c,e,b,d,f,0,0,1]
fromList _ = error "Reanimate.Transform.fromList: bad input" fromList _ = error "Reanimate.Transform.fromList: bad input"
-- | Apply a transformation matrix to a 2D point. -- | Apply a transformation matrix to a 2D point.
transformPoint :: TMatrix -> RPoint -> RPoint transformPoint :: Matrix Coord -> RPoint -> RPoint
transformPoint m (V2 x y) = V2 (a*x +c*y + e) (b*x + d*y +f) transformPoint m (V2 x y) = V2 (a*x +c*y + e) (b*x + d*y +f)
where where
!a = M.unsafeGet 1 1 m !a = M.unsafeGet 1 1 m
@ -43,12 +41,12 @@ transformPoint m (V2 x y) = V2 (a*x +c*y + e) (b*x + d*y +f)
-- (a:c:e:b:d:f:_) = M.toList m -- (a:c:e:b:d:f:_) = M.toList m
-- | Convert multiple SVG transformations into a single transformation matrix. -- | Convert multiple SVG transformations into a single transformation matrix.
mkMatrix :: Maybe [Transformation] -> TMatrix mkMatrix :: Maybe [Transformation] -> Matrix Coord
mkMatrix Nothing = identity mkMatrix Nothing = identity
mkMatrix (Just ts) = foldl' (*) identity (map transformationMatrix ts) mkMatrix (Just ts) = foldl' (*) identity (map transformationMatrix ts)
-- | Convert an SVG transformation into a transformation matrix. -- | Convert an SVG transformation into a transformation matrix.
transformationMatrix :: Transformation -> TMatrix transformationMatrix :: Transformation -> Matrix Coord
transformationMatrix transformation = transformationMatrix transformation =
case transformation of case transformation of
TransformMatrix a b c d e f -> fromList [a,b,c,d,e,f] TransformMatrix a b c d e f -> fromList [a,b,c,d,e,f]
@ -65,7 +63,7 @@ transformationMatrix transformation =
where r = a * pi / 180 where r = a * pi / 180
-- | Convert a transformation matrix back into an SVG transformation. -- | Convert a transformation matrix back into an SVG transformation.
toTransformation :: TMatrix -> Transformation toTransformation :: Matrix Coord -> Transformation
toTransformation m = TransformMatrix a b c d e f toTransformation m = TransformMatrix a b c d e f
where where
[a,c,e,b,d,f,_,_,_] = M.toList m [a,c,e,b,d,f,_,_,_] = M.toList m

View file

@ -10,6 +10,7 @@
module Reanimate.Voice module Reanimate.Voice
( Transcript(..) ( Transcript(..)
, TWord(..) , TWord(..)
, Phone(..)
, findWord -- :: Transcript -> [Text] -> Text -> TWord , findWord -- :: Transcript -> [Text] -> Text -> TWord
, findWords -- :: Transcript -> [Text] -> Text -> [TWord] , findWords -- :: Transcript -> [Text] -> Text -> [TWord]
, loadTranscript -- :: FilePath -> Transcript , loadTranscript -- :: FilePath -> Transcript
@ -90,6 +91,7 @@ instance FromJSON TWord where
<*> o <*> o
.: "word" .: "word"
-- | Phoneme type
data Phone = Phone data Phone = Phone
{ phoneDuration :: Double { phoneDuration :: Double
, phoneType :: Text , phoneType :: Text