brillo-1.13.3: Brillo/Data/ViewPort.hs
module Brillo.Data.ViewPort (
ViewPort (..),
viewPortInit,
applyViewPortToPicture,
invertViewPort,
)
where
import Brillo.Data.Picture
import Brillo.Data.Point.Arithmetic qualified as Pt
{-| The 'ViewPort' represents the global transformation applied to the displayed picture.
When the user pans, zooms, or rotates the display then this changes the 'ViewPort'.
-}
data ViewPort
= ViewPort
{ viewPortTranslate :: !(Float, Float)
-- ^ Global translation.
, viewPortRotate :: !Float
-- ^ Global rotation (in degrees).
, viewPortScale :: !Float
-- ^ Global scaling (of both x and y coordinates).
}
-- | The initial state of the viewport.
viewPortInit :: ViewPort
viewPortInit =
ViewPort
{ viewPortTranslate = (0, 0)
, viewPortRotate = 0
, viewPortScale = 1
}
-- | Translates, rotates, and scales an image according to the 'ViewPort'.
applyViewPortToPicture :: ViewPort -> Picture -> Picture
applyViewPortToPicture
ViewPort
{ viewPortScale = vscale
, viewPortTranslate = (transX, transY)
, viewPortRotate = vrotate
} =
Scale vscale vscale . Rotate vrotate . Translate transX transY
{-| Takes a point using screen coordinates, and uses the `ViewPort` to convert
it to Picture coordinates. This is the inverse of `applyViewPortToPicture`
for points.
-}
invertViewPort :: ViewPort -> Point -> Point
invertViewPort
ViewPort
{ viewPortScale = vscale
, viewPortTranslate = vtrans
, viewPortRotate = vrotate
}
pos =
rotateV (degToRad vrotate) (mulSV (1 / vscale) pos) Pt.- vtrans
-- | Convert degrees to radians
degToRad :: Float -> Float
degToRad d = d * pi / 180
{-# INLINE degToRad #-}
-- | Multiply a vector by a scalar.
mulSV :: Float -> Vector -> Vector
mulSV s (x, y) =
(s * x, s * y)
{-# INLINE mulSV #-}
-- | Rotate a vector by an angle (in radians). +ve angle is counter-clockwise.
rotateV :: Float -> Vector -> Vector
rotateV r (x, y) =
( x * cos r - y * sin r
, x * sin r + y * cos r
)
{-# INLINE rotateV #-}