module Graphics.Rasterific.QuadraticFormula( QuadraticFormula( .. )
                                           , discriminant
                                           , formulaRoots
                                           ) where

-- | Represent an equation `a * x^2 + b * x + c = 0`

data QuadraticFormula a = QuadraticFormula
    { QuadraticFormula a -> a
_coeffA :: !a -- ^ Coefficient for the square part (x^2)

    , QuadraticFormula a -> a
_coeffB :: !a -- ^ Coefficient the linear part (x)

    , QuadraticFormula a -> a
_coeffC :: !a -- ^ Constant

    }

instance Functor QuadraticFormula where
    {-# INLINE fmap #-}
    fmap :: (a -> b) -> QuadraticFormula a -> QuadraticFormula b
fmap a -> b
f (QuadraticFormula a
a a
b a
c) =
        b -> b -> b -> QuadraticFormula b
forall a. a -> a -> a -> QuadraticFormula a
QuadraticFormula (a -> b
f a
a) (a -> b
f a
b) (a -> b
f a
c)

instance Applicative QuadraticFormula where
  pure :: a -> QuadraticFormula a
pure a
a = a -> a -> a -> QuadraticFormula a
forall a. a -> a -> a -> QuadraticFormula a
QuadraticFormula a
a a
a a
a
  {-# INLINE pure #-}

  QuadraticFormula a -> b
a a -> b
b a -> b
c <*> :: QuadraticFormula (a -> b)
-> QuadraticFormula a -> QuadraticFormula b
<*> QuadraticFormula a
d a
e a
f =
      b -> b -> b -> QuadraticFormula b
forall a. a -> a -> a -> QuadraticFormula a
QuadraticFormula (a -> b
a a
d) (a -> b
b a
e) (a -> b
c a
f)
  {-# INLINE (<*>) #-}

-- | Discriminant equation, if the result is:

--

--  * Below 0, then the formula doesn't have any solution

--

--  * Equal to 0, then the formula has an unique root.

--

--  * Above 0, the formula has two solutions

--

discriminant :: Num a => QuadraticFormula a -> a
discriminant :: QuadraticFormula a -> a
discriminant (QuadraticFormula a
a a
b a
c) = a
b a -> a -> a
forall a. Num a => a -> a -> a
* a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
4 a -> a -> a
forall a. Num a => a -> a -> a
* a
a a -> a -> a
forall a. Num a => a -> a -> a
*a
c

-- | Extract all the roots of the formula ie. where the

-- unknown gives a result of 0

formulaRoots :: (Ord a, Floating a) => QuadraticFormula a -> [a]
formulaRoots :: QuadraticFormula a -> [a]
formulaRoots formula :: QuadraticFormula a
formula@(QuadraticFormula a
a a
b a
_)
  | a
disc a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = []
  | a
disc a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = [a
positiveResult]
  | Bool
otherwise = [a
positiveResult, a
negativeResult]
  where
    disc :: a
disc = QuadraticFormula a -> a
forall a. Num a => QuadraticFormula a -> a
discriminant QuadraticFormula a
formula
    squarePart :: a
squarePart = a -> a
forall a. Floating a => a -> a
sqrt a
disc
    positiveResult :: a
positiveResult = (a -> a
forall a. Num a => a -> a
negate a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
squarePart) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
a)
    negativeResult :: a
negativeResult = (a -> a
forall a. Num a => a -> a
negate a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
squarePart) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
a)