never executed always true always false
1 {-# LANGUAGE BangPatterns #-}
2 {-|
3 2D transformation matrices capable of translating, scaling,
4 rotating, and skewing.
5 -}
6 module Reanimate.Transform
7 ( identity
8 , transformPoint
9 , mkMatrix
10 , toTransformation
11 ) where
12
13 -- XXX: Use Linear.Matrix instead of Data.Matrix to drop the 'matrix' dependency.
14 import Data.List
15 import Data.Matrix (Matrix)
16 import qualified Data.Matrix as M
17 import Data.Maybe
18 import Graphics.SvgTree
19 import Linear.V2
20
21 type TMatrix = Matrix Coord
22
23 -- | Identity matrix.
24 --
25 -- @transformPoints identity x = x@
26 identity :: TMatrix
27 identity = M.identity 3
28
29 fromList :: [Coord] -> TMatrix
30 fromList [a,b,c,d,e,f] = M.fromList 3 3 [a,c,e,b,d,f,0,0,1]
31 fromList _ = error "Reanimate.Transform.fromList: bad input"
32
33 -- | Apply a transformation matrix to a 2D point.
34 transformPoint :: TMatrix -> RPoint -> RPoint
35 transformPoint m (V2 x y) = V2 (a*x +c*y + e) (b*x + d*y +f)
36 where
37 !a = M.unsafeGet 1 1 m
38 !c = M.unsafeGet 1 2 m
39 !e = M.unsafeGet 1 3 m
40 !b = M.unsafeGet 2 1 m
41 !d = M.unsafeGet 2 2 m
42 !f = M.unsafeGet 2 3 m
43 -- (a:c:e:b:d:f:_) = M.toList m
44
45 -- | Convert multiple SVG transformations into a single transformation matrix.
46 mkMatrix :: Maybe [Transformation] -> TMatrix
47 mkMatrix Nothing = identity
48 mkMatrix (Just ts) = foldl' (*) identity (map transformationMatrix ts)
49
50 -- | Convert an SVG transformation into a transformation matrix.
51 transformationMatrix :: Transformation -> TMatrix
52 transformationMatrix transformation =
53 case transformation of
54 TransformMatrix a b c d e f -> fromList [a,b,c,d,e,f]
55 Translate x y -> translate x y
56 Scale sx mbSy -> fromList [sx,0,0,fromMaybe sx mbSy,0,0]
57 Rotate a Nothing -> rotate a
58 Rotate a (Just (x,y)) -> translate x y * rotate a * translate (-x) (-y)
59 SkewX a -> fromList [1,0,tan (a*pi/180),1,0,0]
60 SkewY a -> fromList [1,tan (a*pi/180),0,1,0,0]
61 TransformUnknown -> identity
62 where
63 translate x y = fromList [1,0,0,1,x,y]
64 rotate a = fromList [cos r,sin r,-sin r,cos r,0,0]
65 where r = a * pi / 180
66
67 -- | Convert a transformation matrix back into an SVG transformation.
68 toTransformation :: TMatrix -> Transformation
69 toTransformation m = TransformMatrix a b c d e f
70 where
71 [a,c,e,b,d,f,_,_,_] = M.toList m