2023-01-09 03:27:08 +00:00
|
|
|
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2023-01-13 22:10:06 +00:00
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2020-08-29 17:41:07 +00:00
|
|
|
|
|
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 )
|
2020-08-29 17:41:07 +00:00
|
|
|
|
|
|
|
|
|
-- 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((^+^), (*^)) )
|
2020-11-14 22:32:23 +00:00
|
|
|
|
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) )
|
2020-08-29 17:41:07 +00:00
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2022-12-11 01:33:34 +00:00
|
|
|
|
lookupBrush :: Text -> Maybe SomeBrush
|
|
|
|
|
lookupBrush nm = HashMap.lookup nm brushes
|
2020-08-29 17:41:07 +00:00
|
|
|
|
|
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
|
2021-05-25 11:45:21 +00:00
|
|
|
|
|
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 )
|
2020-08-29 17:41:07 +00:00
|
|
|
|
where
|
2023-01-08 16:16:14 +00:00
|
|
|
|
deflts :: Record CircleBrushFields
|
|
|
|
|
deflts = MkR ( ℝ1 1 )
|
2020-08-29 17:41:07 +00:00
|
|
|
|
|
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 )
|
2023-01-09 19:54:19 +00:00
|
|
|
|
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 )
|
2023-01-09 19:54:19 +00:00
|
|
|
|
= ( 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 )
|
2023-01-09 19:54:19 +00:00
|
|
|
|
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 )
|
2023-01-09 19:54:19 +00:00
|
|
|
|
= ( 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
|