cairo-core-1.16.3: src/Graphics/Cairo/Utilities/Matrix.hs
{-# LANGUAGE FlexibleInstances #-}
{-|
Description : λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html //div[@class="refnamediv"]/table/tr/td/p/text()
λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-cairo-matrix-t.description
-}
module Graphics.Cairo.Utilities.Matrix where
import Graphics.Cairo.Types
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-init
matrixInit :: a -> a -> a -> a -> a -> a -> Matrix a
matrixInit = Matrix
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-init-identity
matrixInitIdentity :: Matrix Double
matrixInitIdentity = Matrix 1 0 0 1 0 0
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-init-translate
matrixInitTranslate :: X0 -> Y0 -> Matrix Double
matrixInitTranslate = Matrix 1 0 0 1
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-init-scale
matrixInitScale :: XX -> YY -> Matrix Double
matrixInitScale sx sy = Matrix sx 0 0 sy 0 0
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-init-rotate
matrixInitRotate :: Radius -> Matrix Double
matrixInitRotate radians = Matrix c s (-s) c 0 0
where s = sin radians
c = cos radians
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-translate
matrixTranslate :: X0 -> Y0 -> Matrix Double -> Matrix Double
matrixTranslate tx ty m = m * matrixInitTranslate tx ty
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-scale
matrixScale :: XX -> YY -> Matrix Double -> Matrix Double
matrixScale sx sy m = m * matrixInitScale sx sy
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-rotate
matrixRotate :: Radius -> Matrix Double -> Matrix Double
matrixRotate radians m = m * matrixInitRotate radians
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-invert
matrixInvert :: Matrix Double -> Maybe (Matrix Double)
matrixInvert (Matrix 0 0 0 _ _ _) = Nothing
matrixInvert (Matrix _ 0 0 0 _ _) = Nothing
matrixInvert (Matrix xx 0 0 yy x0 y0) =
let (xx', x0') = if xx /= 1
then (recip xx, -x0 * recip xx)
else (xx, -x0)
(yy', y0') = if yy /= 1
then (recip yy, -y0 * recip yy)
else (yy, -y0)
in Just $ Matrix xx' 0 0 yy' x0' y0'
matrixInvert matrix
| determinant matrix == 0 = Nothing
| otherwise = Just $ scalarMultiply (adjoint matrix) (recip $ determinant matrix)
where
determinant (Matrix xx' yx' xy' yy' _ _) = xx' * yy' - yx' * xy'
adjoint (Matrix xx' yx' xy' yy' x0' y0') = Matrix yy' (-yx') (-xy') xx' (xy' * y0' - yy' * x0') (yx' * x0' - xx' * y0')
scalarMultiply matrix' scalar = fmap (scalar *) matrix'
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-multiply
matrixMultiply :: Matrix Double -> Matrix Double -> Matrix Double
matrixMultiply = (*)
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-transform-distance
matrixTransformDistance :: Matrix Double -> (X, Y) -> (X, Y)
matrixTransformDistance (Matrix xx yx xy yy _ _) (x, y) =
(xx * x + xy * y, yx * x + yy * y)
-- λ https://www.cairographics.org/manual/cairo-cairo-matrix-t.html#cairo-matrix-transform-point
matrixTransformPoint :: Matrix Double -> (X, Y) -> (X, Y)
matrixTransformPoint matrix@(Matrix _ _ _ _ x0 y0) pd =
let (x, y) = matrixTransformDistance matrix pd
in (x + x0, y + y0)