metabrush/src/metabrushes/MetaBrush/Asset/Brushes.hs

132 lines
4.3 KiB
Haskell
Raw Normal View History

2023-01-09 03:27:08 +00:00
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE OverloadedStrings #-}
2023-01-13 22:10:06 +00:00
{-# LANGUAGE ScopedTypeVariables #-}
2020-11-12 17:34:46 +00:00
module MetaBrush.Asset.Brushes where
2023-01-13 22:10:06 +00:00
-- base
import GHC.Exts
( Proxy# )
2022-12-11 01:33:34 +00:00
-- containers
import qualified Data.Sequence as Seq
( fromList )
2021-04-25 23:17:27 +00:00
2020-11-12 17:34:46 +00:00
-- text
import Data.Text
( Text )
2022-12-11 01:33:34 +00:00
-- unordered-containers
import Data.HashMap.Strict
( HashMap )
import qualified Data.HashMap.Strict as HashMap
( fromList, lookup )
-- MetaBrush
2022-12-11 01:33:34 +00:00
import Math.Bezier.Spline
2023-01-08 16:16:14 +00:00
import Math.Linear
import Math.Linear.Dual
2023-01-13 22:10:06 +00:00
( D, type (~>)(..), Differentiable, Diffy(konst), var )
2023-01-08 16:16:14 +00:00
import Math.Module
( Module((^+^), (*^)) )
import MetaBrush.Brush
2023-01-13 22:10:06 +00:00
( Brush(..), SomeBrush(..), WithParams(..) )
2022-12-11 01:33:34 +00:00
import MetaBrush.Records
2023-01-13 22:10:06 +00:00
( Record(MkR) )
--------------------------------------------------------------------------------
2022-12-11 01:33:34 +00:00
lookupBrush :: Text -> Maybe SomeBrush
lookupBrush nm = HashMap.lookup nm brushes
2022-12-11 01:33:34 +00:00
-- | All brushes supported by this application.
brushes :: HashMap Text SomeBrush
brushes = HashMap.fromList
[ ( nm, b )
| b@( SomeBrush ( BrushData { brushName = nm } ) )
<- [ SomeBrush circle, SomeBrush ellipse ]
]
2021-05-13 20:07:49 +00:00
2022-12-11 01:33:34 +00:00
-- | Root of @(Sqrt[2] (4 + 3 κ) - 16) (2 - 3 κ)^2 - 8 (1 - 3 κ) Sqrt[8 - 24 κ + 12 κ^2 + 8 κ^3 + 3 κ^4]@.
--
-- Used to approximate circles and ellipses with Bézier curves.
2023-01-08 16:16:14 +00:00
κ :: Double
κ = 0.5519150244935105707435627227925
2023-01-09 03:27:08 +00:00
type CircleBrushFields = '[ "r" ]
2022-12-11 01:33:34 +00:00
circle :: Brush CircleBrushFields
2023-01-09 03:27:08 +00:00
circle = BrushData "circle" ( WithParams deflts circleBrush )
where
2023-01-08 16:16:14 +00:00
deflts :: Record CircleBrushFields
deflts = MkR ( 1 1 )
2023-01-08 16:16:14 +00:00
type EllipseBrushFields = '[ "a", "b", "phi" ]
2022-12-11 01:33:34 +00:00
ellipse :: Brush EllipseBrushFields
2023-01-09 03:27:08 +00:00
ellipse = BrushData "ellipse" ( WithParams deflts ellipseBrush )
2022-12-11 01:33:34 +00:00
where
2023-01-08 16:16:14 +00:00
deflts :: Record EllipseBrushFields
deflts = MkR ( 3 1 1 0 )
--------------------------------------------------------------------------------
-- Differentiable brushes.
2023-01-13 22:10:06 +00:00
circleSpline :: forall i u v
. Applicative ( D ( I i u ) )
=> ( Double -> Double -> D ( I i u ) ( I i v ) )
-> D ( I i u ) ( Spline 'Closed () ( I i v ) )
2023-01-09 03:27:08 +00:00
circleSpline p = sequenceA $
2023-01-08 16:16:14 +00:00
Spline { splineStart = p 1 0
, splineCurves = ClosedCurves crvs lastCrv }
where
crvs = Seq.fromList
2023-01-13 22:10:06 +00:00
[ Bezier3To ( p 1 κ ) ( p κ 1 ) ( NextPoint (p 0 1) ) ()
, Bezier3To ( p -κ 1 ) ( p -1 κ ) ( NextPoint (p -1 0) ) ()
, Bezier3To ( p -1 -κ ) ( p -κ -1 ) ( NextPoint (p 0 -1) ) ()
2023-01-08 16:16:14 +00:00
]
lastCrv =
2023-01-13 22:10:06 +00:00
Bezier3To ( p κ -1 ) ( p 1 -κ ) BackToStart ()
circleBrush :: forall i
. ( Differentiable i ( Record CircleBrushFields ) )
=> Proxy# i
-> ( forall a. a -> I i a )
-> I i ( Record CircleBrushFields ) ~> Spline 'Closed () ( I i ( 2 ) )
circleBrush _ mkI =
2023-01-09 03:27:08 +00:00
D \ params ->
2023-01-13 22:10:06 +00:00
let r :: D ( I i ( Record CircleBrushFields ) ) ( I i Double )
r = runD ( var ( Fin 1## ) ) params
2023-01-13 22:10:06 +00:00
mkPt :: Double -> Double -> D ( I i ( Record CircleBrushFields ) ) ( I i ( 2 ) )
2023-01-09 03:27:08 +00:00
mkPt ( kon -> x ) ( kon -> y )
= ( x * r ) *^ e_x
2023-01-09 03:27:08 +00:00
^+^ ( y * r ) *^ e_y
2023-01-13 22:10:06 +00:00
in circleSpline @i @( Record CircleBrushFields ) @( 2 ) mkPt
2023-01-09 03:27:08 +00:00
where
2023-01-13 22:10:06 +00:00
e_x, e_y :: D ( I i ( Record CircleBrushFields ) ) ( I i ( 2 ) )
e_x = pure $ mkI $ 2 1 0
e_y = pure $ mkI $ 2 0 1
kon = konst @( I i Double ) @( I i ( Record CircleBrushFields ) ) . mkI
ellipseBrush :: forall i
. ( Differentiable i ( Record EllipseBrushFields ) )
=> Proxy# i
-> ( forall a. a -> I i a )
-> I i ( Record EllipseBrushFields ) ~> Spline 'Closed () ( I i ( 2 ) )
ellipseBrush _ mkI =
2023-01-08 16:16:14 +00:00
D \ params ->
2023-01-13 22:10:06 +00:00
let a, b, phi :: D ( I i ( Record EllipseBrushFields ) ) ( I i Double )
a = runD ( var ( Fin 1## ) ) params
b = runD ( var ( Fin 2## ) ) params
phi = runD ( var ( Fin 3## ) ) params
2023-01-13 22:10:06 +00:00
mkPt :: Double -> Double -> D ( I i ( Record EllipseBrushFields ) ) ( I i ( 2 ) )
2023-01-09 03:27:08 +00:00
mkPt ( kon -> x ) ( kon -> y )
= ( x * a * cos phi - y * b * sin phi ) *^ e_x
2023-01-08 16:16:14 +00:00
^+^ ( y * b * cos phi + x * a * sin phi ) *^ e_y
2023-01-13 22:10:06 +00:00
in circleSpline @i @( Record EllipseBrushFields ) @( 2 ) mkPt
2023-01-08 16:16:14 +00:00
where
2023-01-13 22:10:06 +00:00
e_x, e_y :: D ( I i ( Record EllipseBrushFields ) ) ( I i ( 2 ) )
e_x = pure $ mkI $ 2 1 0
e_y = pure $ mkI $ 2 0 1
2023-01-08 16:16:14 +00:00
2023-01-13 22:10:06 +00:00
kon = konst @( I i Double ) @( I i ( Record EllipseBrushFields ) ) . mkI