{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Math.Bezier.Quadratic ( Bezier(..) , bezier, bezier' ) where -- base import GHC.Generics ( Generic ) -- acts import Data.Act ( Act ( (•) ) , Torsor ( (-->) ) ) -- MetaBrush import Math.Module ( Module (..) , lerp ) -------------------------------------------------------------------------------- -- | Points defining a quadratic Bézier curve. -- -- @ p0 @ and @ p2 @ are endpoints, whereas @ p1 @ is a control point. data Bezier p = Bezier { p0 :: !p , p1 :: !p , p2 :: !p } deriving stock ( Show, Generic, Functor, Foldable, Traversable ) instance Module r p => Module r ( Bezier p ) where ( Bezier p0 p1 p2 ) ^+^ ( Bezier q0 q1 q2 ) = Bezier ( p0 ^+^ q0 ) ( p1 ^+^ q1 ) ( p2 ^+^ q2 ) r *^ bz = fmap ( r *^ ) bz -- | Quadratic Bézier curve. bezier :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> p bezier ( Bezier { .. } ) t = lerp @v t ( lerp @v t p0 p1 ) ( lerp @v t p1 p2 ) -- | Derivative of quadratic Bézier curve. bezier' :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> v bezier' ( Bezier { .. } ) t = 2 *^ lerp @v t ( p0 --> p1 ) ( p1 --> p2 )