module Graphics.Rasterific.Transformations
( Transformation( .. )
, applyTransformation
, applyVectorTransformation
, translate
, scale
, rotate
, rotateCenter
, skewX
, skewY
, toNewXBase
, inverseTransformation
) where
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid( Monoid( .. ) )
#endif
import Data.Monoid( (<>) )
import Graphics.Rasterific.Types
import Graphics.Rasterific.Linear( V2( .. ), (^+^), normalize )
data Transformation = Transformation
{ _transformA :: !Float
, _transformC :: !Float
, _transformE :: !Float
, _transformB :: !Float
, _transformD :: !Float
, _transformF :: !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 Monoid Transformation where
mappend = transformCombine
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