{-# LANGUAGE BangPatterns #-}
module Reanimate.Transform
( identity
, transformPoint
, mkMatrix
, toTransformation
) where
import Data.List (foldl')
import Data.Matrix (Matrix)
import qualified Data.Matrix as M
import Data.Maybe (fromMaybe)
import Graphics.SvgTree (Coord, RPoint, Transformation (..))
import Linear.V2 (V2 (V2))
identity :: Matrix Coord
identity :: Matrix Coord
identity = Int -> Matrix Coord
forall a. Num a => Int -> Matrix a
M.identity Int
3
fromList :: [Coord] -> Matrix Coord
fromList :: [Coord] -> Matrix Coord
fromList [Coord
a,Coord
b,Coord
c,Coord
d,Coord
e,Coord
f] = Int -> Int -> [Coord] -> Matrix Coord
forall a. Int -> Int -> [a] -> Matrix a
M.fromList Int
3 Int
3 [Coord
a,Coord
c,Coord
e,Coord
b,Coord
d,Coord
f,Coord
0,Coord
0,Coord
1]
fromList [Coord]
_ = [Char] -> Matrix Coord
forall a. HasCallStack => [Char] -> a
error [Char]
"Reanimate.Transform.fromList: bad input"
transformPoint :: Matrix Coord -> RPoint -> RPoint
transformPoint :: Matrix Coord -> RPoint -> RPoint
transformPoint Matrix Coord
m (V2 Coord
x Coord
y) = Coord -> Coord -> RPoint
forall a. a -> a -> V2 a
V2 (Coord
aCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
x Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+Coord
cCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
y Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
e) (Coord
bCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
x Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
dCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
y Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+Coord
f)
where
!a :: Coord
a = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
1 Int
1 Matrix Coord
m
!c :: Coord
c = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
1 Int
2 Matrix Coord
m
!e :: Coord
e = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
1 Int
3 Matrix Coord
m
!b :: Coord
b = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
2 Int
1 Matrix Coord
m
!d :: Coord
d = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
2 Int
2 Matrix Coord
m
!f :: Coord
f = Int -> Int -> Matrix Coord -> Coord
forall a. Int -> Int -> Matrix a -> a
M.unsafeGet Int
2 Int
3 Matrix Coord
m
mkMatrix :: Maybe [Transformation] -> Matrix Coord
mkMatrix :: Maybe [Transformation] -> Matrix Coord
mkMatrix Maybe [Transformation]
Nothing = Matrix Coord
identity
mkMatrix (Just [Transformation]
ts) = (Matrix Coord -> Matrix Coord -> Matrix Coord)
-> Matrix Coord -> [Matrix Coord] -> Matrix Coord
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Matrix Coord -> Matrix Coord -> Matrix Coord
forall a. Num a => a -> a -> a
(*) Matrix Coord
identity ((Transformation -> Matrix Coord)
-> [Transformation] -> [Matrix Coord]
forall a b. (a -> b) -> [a] -> [b]
map Transformation -> Matrix Coord
transformationMatrix [Transformation]
ts)
transformationMatrix :: Transformation -> Matrix Coord
transformationMatrix :: Transformation -> Matrix Coord
transformationMatrix Transformation
transformation =
case Transformation
transformation of
TransformMatrix Coord
a Coord
b Coord
c Coord
d Coord
e Coord
f -> [Coord] -> Matrix Coord
fromList [Coord
a,Coord
b,Coord
c,Coord
d,Coord
e,Coord
f]
Translate Coord
x Coord
y -> Coord -> Coord -> Matrix Coord
translate Coord
x Coord
y
Scale Coord
sx Maybe Coord
mbSy -> [Coord] -> Matrix Coord
fromList [Coord
sx,Coord
0,Coord
0,Coord -> Maybe Coord -> Coord
forall a. a -> Maybe a -> a
fromMaybe Coord
sx Maybe Coord
mbSy,Coord
0,Coord
0]
Rotate Coord
a Maybe (Coord, Coord)
Nothing -> Coord -> Matrix Coord
rotate Coord
a
Rotate Coord
a (Just (Coord
x,Coord
y)) -> Coord -> Coord -> Matrix Coord
translate Coord
x Coord
y Matrix Coord -> Matrix Coord -> Matrix Coord
forall a. Num a => a -> a -> a
* Coord -> Matrix Coord
rotate Coord
a Matrix Coord -> Matrix Coord -> Matrix Coord
forall a. Num a => a -> a -> a
* Coord -> Coord -> Matrix Coord
translate (-Coord
x) (-Coord
y)
SkewX Coord
a -> [Coord] -> Matrix Coord
fromList [Coord
1,Coord
0,Coord -> Coord
forall a. Floating a => a -> a
tan (Coord
aCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
forall a. Floating a => a
piCoord -> Coord -> Coord
forall a. Fractional a => a -> a -> a
/Coord
180),Coord
1,Coord
0,Coord
0]
SkewY Coord
a -> [Coord] -> Matrix Coord
fromList [Coord
1,Coord -> Coord
forall a. Floating a => a -> a
tan (Coord
aCoord -> Coord -> Coord
forall a. Num a => a -> a -> a
*Coord
forall a. Floating a => a
piCoord -> Coord -> Coord
forall a. Fractional a => a -> a -> a
/Coord
180),Coord
0,Coord
1,Coord
0,Coord
0]
Transformation
TransformUnknown -> Matrix Coord
identity
where
translate :: Coord -> Coord -> Matrix Coord
translate Coord
x Coord
y = [Coord] -> Matrix Coord
fromList [Coord
1,Coord
0,Coord
0,Coord
1,Coord
x,Coord
y]
rotate :: Coord -> Matrix Coord
rotate Coord
a = [Coord] -> Matrix Coord
fromList [Coord -> Coord
forall a. Floating a => a -> a
cos Coord
r,Coord -> Coord
forall a. Floating a => a -> a
sin Coord
r,-Coord -> Coord
forall a. Floating a => a -> a
sin Coord
r,Coord -> Coord
forall a. Floating a => a -> a
cos Coord
r,Coord
0,Coord
0]
where r :: Coord
r = Coord
a Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
* Coord
forall a. Floating a => a
pi Coord -> Coord -> Coord
forall a. Fractional a => a -> a -> a
/ Coord
180
toTransformation :: Matrix Coord -> Transformation
toTransformation :: Matrix Coord -> Transformation
toTransformation Matrix Coord
m = Coord
-> Coord -> Coord -> Coord -> Coord -> Coord -> Transformation
TransformMatrix Coord
a Coord
b Coord
c Coord
d Coord
e Coord
f
where
[Coord
a,Coord
c,Coord
e,Coord
b,Coord
d,Coord
f,Coord
_,Coord
_,Coord
_] = Matrix Coord -> [Coord]
forall a. Matrix a -> [a]
M.toList Matrix Coord
m