metabrush/src/metabrushes/MetaBrush/Brush.hs

168 lines
5.1 KiB
Haskell
Raw Normal View History

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module MetaBrush.Brush
2023-01-13 22:10:06 +00:00
( WithParams(..)
, Brush(..), SomeBrush(..), BrushFunction
2023-01-08 16:16:14 +00:00
, PointFields, provePointFields, duplicates
)
where
-- base
2023-01-08 16:16:14 +00:00
import Data.Kind
( Type, Constraint )
import Data.List
( nub )
import Data.Typeable
( Typeable )
import GHC.Exts
2023-01-08 16:16:14 +00:00
( Proxy#, proxy# )
import GHC.TypeLits
( Symbol, someSymbolVal
, SomeSymbol(..)
)
-- deepseq
import Control.DeepSeq
2022-12-11 01:33:34 +00:00
( NFData(..) )
-- hashable
import Data.Hashable
( Hashable(..) )
-- text
import Data.Text
( Text )
import qualified Data.Text as Text
( unpack )
-- MetaBrush
2023-01-20 15:34:04 +00:00
import Math.Algebra.Dual
( C )
import Math.Bezier.Spline
2023-01-13 22:10:06 +00:00
( SplineType(Closed), Spline )
2023-01-20 15:34:04 +00:00
import Math.Differentiable
( DiffInterp, ExtentOrder )
import Math.Interval
( type I, Extent(Point, Interval) )
import Math.Linear
import MetaBrush.Records
2023-01-13 22:10:06 +00:00
( KnownSymbols, Length, Record )
2023-01-08 16:16:14 +00:00
import MetaBrush.Serialisable
( Serialisable )
--------------------------------------------------------------------------------
2023-01-13 22:10:06 +00:00
-- | A differentiable function from a given record type,
-- with provided default values that can be overridden.
2023-01-20 15:34:04 +00:00
type WithParams :: Type -> ( Type -> Type ) -> Type
2023-01-13 22:10:06 +00:00
data WithParams params f =
WithParams
2023-01-20 15:34:04 +00:00
{ defaultParams :: params
, withParams
:: forall i
. ( DiffInterp i params )
=> Proxy# i
-> ( forall a. a -> I i a )
-> C ( ExtentOrder i ) ( I i params ) ( f ( I i ( 2 ) ) )
2023-01-13 22:10:06 +00:00
}
--------------------------------------------------------------------------------
2022-12-11 01:33:34 +00:00
-- | A brush function: a function from a record of parameters to a closed spline.
2023-01-08 16:16:14 +00:00
type BrushFunction :: [ Symbol ] -> Type
2023-01-20 15:34:04 +00:00
type BrushFunction brushFields =
WithParams ( Record brushFields ) ( Spline Closed () )
2023-01-08 16:16:14 +00:00
type Brush :: [ Symbol ] -> Type
data Brush brushFields where
BrushData
:: forall brushFields
2023-01-13 22:10:06 +00:00
. ( KnownSymbols brushFields, Typeable brushFields
2023-01-20 15:34:04 +00:00
, Representable Double ( ( Length brushFields ) )
, DiffInterp Point ( ( Length brushFields ) )
, DiffInterp Interval ( ( Length brushFields ) )
2023-01-13 22:10:06 +00:00
)
2023-01-08 16:16:14 +00:00
=> { brushName :: !Text
, brushFunction :: BrushFunction brushFields
}
-> Brush brushFields
data SomeBrush where
SomeBrush
2023-01-08 16:16:14 +00:00
:: { someBrush :: !( Brush brushFields ) }
-> SomeBrush
instance Show ( Brush brushFields ) where
2022-12-11 01:33:34 +00:00
show ( BrushData { brushName } ) =
"BrushData\n\
\ { brushName = " <> Text.unpack brushName <> "\n\
\ }"
2022-12-11 01:33:34 +00:00
instance NFData ( Brush brushFields ) where
2022-12-11 01:33:34 +00:00
rnf ( BrushData { brushName } )
= rnf brushName
instance Eq ( Brush brushFields ) where
2022-12-11 01:33:34 +00:00
BrushData name1 _ == BrushData name2 _ = name1 == name2
instance Ord ( Brush brushFields ) where
2022-12-11 01:33:34 +00:00
compare ( BrushData name1 _ ) ( BrushData name2 _ ) = compare name1 name2
instance Hashable ( Brush brushFields ) where
2022-12-11 01:33:34 +00:00
hashWithSalt salt ( BrushData { brushName } ) =
hashWithSalt salt brushName
2023-01-08 16:16:14 +00:00
type PointFields :: [ Symbol ] -> Constraint
class ( KnownSymbols pointFields, Typeable pointFields
, Serialisable ( Record pointFields )
, Show ( Record pointFields )
, NFData ( Record pointFields )
2023-01-20 15:34:04 +00:00
, Representable Double ( ( Length pointFields ) )
, DiffInterp Point ( ( Length pointFields ) )
, DiffInterp Interval ( ( Length pointFields ) )
)
2023-01-08 16:16:14 +00:00
=> PointFields pointFields where { }
instance ( KnownSymbols pointFields, Typeable pointFields
, Serialisable ( Record pointFields )
, Show ( Record pointFields )
, NFData ( Record pointFields )
2023-01-20 15:34:04 +00:00
, Representable Double ( ( Length pointFields ) )
, DiffInterp Point ( ( Length pointFields ) )
, DiffInterp Interval ( ( Length pointFields ) )
2023-01-08 16:16:14 +00:00
)
=> PointFields pointFields where { }
-- | Assumes the input has no duplicates (doesn't check.)
2023-01-20 15:34:04 +00:00
provePointFields :: [ Text ]
-> ( forall pointFields. PointFields pointFields => Proxy# pointFields -> r )
-> r
2023-01-08 16:16:14 +00:00
provePointFields fieldNames k =
case fieldNames of
[]
-> k ( proxy# @'[] )
[ f1 ]
| SomeSymbol @f1 _ <- someSymbolVal ( Text.unpack f1 )
-> k ( proxy# @'[ f1 ] )
[ f1, f2 ]
| SomeSymbol @f1 _ <- someSymbolVal ( Text.unpack f1 )
, SomeSymbol @f2 _ <- someSymbolVal ( Text.unpack f2 )
-> k ( proxy# @'[ f1, f2 ] )
[ f1, f2, f3 ]
| SomeSymbol @f1 _ <- someSymbolVal ( Text.unpack f1 )
, SomeSymbol @f2 _ <- someSymbolVal ( Text.unpack f2 )
, SomeSymbol @f3 _ <- someSymbolVal ( Text.unpack f3 )
-> k ( proxy# @'[ f1, f2, f3 ] )
_ -> error $ "I haven't defined " ++ show ( length fieldNames )
{-# INLINE provePointFields #-}
duplicates :: [ Text ] -> [ Text ]
duplicates = nub . duplicatesAcc [] []
where
duplicatesAcc :: [ Text ] -> [ Text ] -> [ Text ] -> [ Text ]
duplicatesAcc _ dups [] = dups
duplicatesAcc seen dups ( k : kvs )
| k `elem` seen
= duplicatesAcc seen ( k : dups ) kvs
| otherwise
= duplicatesAcc ( k : seen ) dups kvs