module Graphics.Rasterific.Transformations
( Transformation( .. )
, applyTransformation
, applyVectorTransformation
, translate
, scale
, rotate
, rotateCenter
, skewX
, skewY
, toNewXBase
, inverseTransformation
) where
import Data.Semigroup( Semigroup( .. ) )
import Graphics.Rasterific.Types
import Graphics.Rasterific.Linear( V2( .. ), normalize )
data Transformation = Transformation
{ _transformA :: {-# UNPACK #-} !Float
, _transformC :: {-# UNPACK #-} !Float
, _transformE :: {-# UNPACK #-} !Float
, _transformB :: {-# UNPACK #-} !Float
, _transformD :: {-# UNPACK #-} !Float
, _transformF :: {-# UNPACK #-} !Float
}
deriving (Eq, Show)
transformCombine :: Transformation -> Transformation -> Transformation
transformCombine (Transformation a c e
b d f)
(Transformation a' c' e'
b' d' f') =
Transformation (a * a' + c * b' )
(a * c' + c * d' )
(a * e' + c * f' + e )
(b * a' + d * b' )
(b * c' + d * d' )
(b * e' + d * f' + f )
instance Semigroup Transformation where
(<>) = transformCombine
instance Monoid Transformation where
mappend = (<>)
mempty = Transformation 1 0 0
0 1 0
applyTransformation :: Transformation -> Point -> Point
applyTransformation (Transformation a c e
b d f) (V2 x y) =
V2 (a * x + y * c + e) (b * x + d * y + f)
applyVectorTransformation :: Transformation -> Vector -> Vector
applyVectorTransformation
(Transformation a c _e
b d _f) (V2 x y) =
V2 (a * x + y * c) (b * x + d * y)
rotate :: Float
-> Transformation
rotate angle = Transformation ca (-sa) 0
sa ca 0
where ca = cos angle
sa = sin angle
rotateCenter :: Float
-> Point
-> Transformation
rotateCenter angle p =
translate p <> rotate angle <> translate (negate p)
scale :: Float -> Float -> Transformation
scale scaleX scaleY =
Transformation scaleX 0 0
0 scaleY 0
translate :: Vector -> Transformation
translate (V2 x y) =
Transformation 1 0 x
0 1 y
skewX :: Float -> Transformation
skewX v =
Transformation 1 t 0
0 1 0
where t = tan v
skewY :: Float -> Transformation
skewY v =
Transformation 1 0 0
t 1 0
where t = tan v
toNewXBase :: Vector -> Transformation
toNewXBase vec =
Transformation dx (-dy) 0
dy dx 0
where V2 dx dy = normalize vec
transformationDeterminant :: Transformation -> Float
transformationDeterminant (Transformation a c _e
b d _f) = a * d - c * b
inverseTransformation :: Transformation -> Maybe Transformation
inverseTransformation trans
| transformationDeterminant trans == 0 = Nothing
inverseTransformation (Transformation a c e
b d f) =
Just $ Transformation a' c' e' b' d' f'
where det = a * d - b * c
a' = d / det
c' = (- c) / det
e' = (c * f - e * d) / det
b' = (- b) / det
d' = a / det
f' = (e * b - a * f) / det