{-# language QuasiQuotes #-}

module Data.Metrology.Extra where

import           Control.Applicative
import           Data.Coerce                    ( coerce )
import           Data.Constants.Mechanics.Extra ( )
import qualified Data.Fixed                    as F
                                                ( div'
                                                , divMod'
                                                , mod'
                                                )
import           Data.Metrology
import           Data.Metrology.Unsafe          ( Qu(..) )
import           Data.Units.SI.Parser
import           Linear.Metric
import           Linear.V3
import           Linear.Vector
import           Physics.Orbit.Metrology

mod' :: forall a u l . Real a => Qu u l a -> Qu u l a -> Qu u l a
mod' :: forall a (u :: [Factor (*)]) (l :: LCSU (*)).
Real a =>
Qu u l a -> Qu u l a -> Qu u l a
mod' = coerce :: forall a b. Coercible a b => a -> b
coerce (forall a. Real a => a -> a -> a
F.mod' :: a -> a -> a)

div'
  :: forall a b u v l
   . (Real a, Integral b)
  => Qu u l a
  -> Qu v l a
  -> Qu (Normalize (u @- v)) l b
div' :: forall a b (u :: [Factor (*)]) (v :: [Factor (*)]) (l :: LCSU (*)).
(Real a, Integral b) =>
Qu u l a -> Qu v l a -> Qu (Normalize (u @- v)) l b
div' = coerce :: forall a b. Coercible a b => a -> b
coerce (forall a b. (Real a, Integral b) => a -> a -> b
F.div' :: a -> a -> b)

divMod'
  :: forall a b u l
   . (Real a, Integral b)
  => Qu u l a
  -> Qu u l a
  -> (Qu '[] l b, Qu u l a)
divMod' :: forall a b (u :: [Factor (*)]) (l :: LCSU (*)).
(Real a, Integral b) =>
Qu u l a -> Qu u l a -> (Qu '[] l b, Qu u l a)
divMod' = coerce :: forall a b. Coercible a b => a -> b
coerce (forall a b. (Real a, Integral b) => a -> a -> (b, a)
F.divMod' :: a -> a -> (b, a))

rad :: Fractional a => a -> Angle a
rad :: forall a. Fractional a => a -> Angle a
rad = (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
n -> unit -> Qu dim 'DefaultLCSU n
% [si|rad|])

rdh :: Fractional a => a -> AngleH a
rdh :: forall a. Fractional a => a -> AngleH a
rdh = (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
n -> unit -> Qu dim 'DefaultLCSU n
% RadianHyperbolic
RadianHyperbolic)

qCos :: Floating a => Angle a -> Unitless a
qCos :: forall a. Floating a => Angle a -> Unitless a
qCos Angle a
θ = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall a b. (a -> b) -> a -> b
$ forall a. Floating a => a -> a
cos (Angle a
θ forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si|rad|])

qSin :: Floating a => Angle a -> Unitless a
qSin :: forall a. Floating a => Angle a -> Unitless a
qSin Angle a
θ = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall a b. (a -> b) -> a -> b
$ forall a. Floating a => a -> a
sin (Angle a
θ forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si|rad|])

qTan :: Floating a => Angle a -> Unitless a
qTan :: forall a. Floating a => Angle a -> Unitless a
qTan Angle a
θ = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall a b. (a -> b) -> a -> b
$ forall a. Floating a => a -> a
tan (Angle a
θ forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si|rad|])

qArcTan :: Floating a => Unitless a -> Angle a
qArcTan :: forall a. Floating a => Unitless a -> Angle a
qArcTan = forall a. Fractional a => a -> Angle a
rad forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
atan forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si||])

qArcTan2 :: RealFloat a => Unitless a -> Unitless a -> Angle a
qArcTan2 :: forall a. RealFloat a => Unitless a -> Unitless a -> Angle a
qArcTan2 Unitless a
x Unitless a
y = forall a. Fractional a => a -> Angle a
rad (forall a. RealFloat a => a -> a -> a
atan2 (Unitless a
x forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si||]) (Unitless a
y forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si||]))

qArcCos :: Floating a => Unitless a -> Angle a
qArcCos :: forall a. Floating a => Unitless a -> Angle a
qArcCos = forall a. Fractional a => a -> Angle a
rad forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
acos forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si||])

qRecip
  :: forall u l a . Fractional a => Qu u l a -> Qu (Normalize ('[] @- u)) l a
qRecip :: forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Fractional a =>
Qu u l a -> Qu (Normalize ('[] @- u)) l a
qRecip = coerce :: forall a b. Coercible a b => a -> b
coerce (forall a. Fractional a => a -> a
recip @a)

qTanh :: Floating a => AngleH a -> Unitless a
qTanh :: forall a. Floating a => AngleH a -> Unitless a
qTanh = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
tanh forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# RadianHyperbolic
RadianHyperbolic)

qSinh :: Floating a => AngleH a -> Unitless a
qSinh :: forall a. Floating a => AngleH a -> Unitless a
qSinh = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
sinh forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# RadianHyperbolic
RadianHyperbolic)

qCosh :: Floating a => AngleH a -> Unitless a
qCosh :: forall a. Floating a => AngleH a -> Unitless a
qCosh = forall n (l :: LCSU (*)). n -> Qu '[] l n
quantity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
cosh forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# RadianHyperbolic
RadianHyperbolic)

qArcCosh :: Floating a => Unitless a -> AngleH a
qArcCosh :: forall a. Floating a => Unitless a -> AngleH a
qArcCosh = forall a. Fractional a => a -> AngleH a
rdh forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Floating a => a -> a
acosh forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (dim :: [Factor (*)]) unit n.
(ValidDLU dim 'DefaultLCSU unit, Fractional n) =>
Qu dim 'DefaultLCSU n -> unit -> n
# [si||])

qAbs :: forall a l u . Num a => Qu u l a -> Qu u l a
qAbs :: forall a (l :: LCSU (*)) (u :: [Factor (*)]).
Num a =>
Qu u l a -> Qu u l a
qAbs = coerce :: forall a b. Coercible a b => a -> b
coerce (forall a. Num a => a -> a
abs @a)

qCross
  :: Num n
  => V3 (Qu a l n)
  -> V3 (Qu b l n)
  -> V3 (Qu (Normalize (a @@+ Reorder b a)) l n)
qCross :: forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
V3 (Qu a l n)
-> V3 (Qu b l n) -> V3 (Qu (Normalize (a @@+ Reorder b a)) l n)
qCross (V3 Qu a l n
a Qu a l n
b Qu a l n
c) (V3 Qu b l n
d Qu b l n
e Qu b l n
f) =
  forall a. a -> a -> a -> V3 a
V3 (Qu a l n
b forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
f forall (d1 :: [Factor (*)]) (d2 :: [Factor (*)]) n (l :: LCSU (*)).
(d1 @~ d2, Num n) =>
Qu d1 l n -> Qu d2 l n -> Qu d1 l n
|-| Qu a l n
c forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
e) (Qu a l n
c forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
d forall (d1 :: [Factor (*)]) (d2 :: [Factor (*)]) n (l :: LCSU (*)).
(d1 @~ d2, Num n) =>
Qu d1 l n -> Qu d2 l n -> Qu d1 l n
|-| Qu a l n
a forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
f) (Qu a l n
a forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
e forall (d1 :: [Factor (*)]) (d2 :: [Factor (*)]) n (l :: LCSU (*)).
(d1 @~ d2, Num n) =>
Qu d1 l n -> Qu d2 l n -> Qu d1 l n
|-| Qu a l n
b forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*| Qu b l n
d)

qNorm :: forall u l a . Floating a => V3 (Qu u l a) -> Qu u l a
qNorm :: forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Floating a =>
V3 (Qu u l a) -> Qu u l a
qNorm = coerce :: forall a b. Coercible a b => a -> b
coerce (forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm @V3 @a)

-- qNormalize
--   :: forall u l a . (Floating a, Epsilon a) => V3 (Qu u l a) -> V3 (Qu '[] l a)
-- qNormalize = coerce (normalize @a @V3)
qNormalize
  :: Floating n
  => V3 (Qu b l n)
  -> V3
       ( Qu
           ( Normalize
               (Normalize ('[] @- b) @@+ Reorder b (Normalize ('[] @- b)))
           )
           l
           n
       )
qNormalize :: forall n (b :: [Factor (*)]) (l :: LCSU (*)).
Floating n =>
V3 (Qu b l n)
-> V3
     (Qu
        (Normalize
           (Normalize ('[] @- b) @@+ Reorder b (Normalize ('[] @- b))))
        l
        n)
qNormalize V3 (Qu b l n)
x = (forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Fractional a =>
Qu u l a -> Qu (Normalize ('[] @- u)) l a
qRecip (forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Floating a =>
V3 (Qu u l a) -> Qu u l a
qNorm V3 (Qu b l n)
x) forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*|) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> V3 (Qu b l n)
x

qDot
  :: forall u v l a. Num a
  => V3 (Qu u l a)
  -> V3 (Qu v l a)
  -> Qu (Normalize (u @@+ Reorder v u)) l a
qDot :: forall (u :: [Factor (*)]) (v :: [Factor (*)]) (l :: LCSU (*)) a.
Num a =>
V3 (Qu u l a)
-> V3 (Qu v l a) -> Qu (Normalize (u @@+ Reorder v u)) l a
qDot = coerce :: forall a b. Coercible a b => a -> b
coerce (forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
dot @V3 @a)

qQuadrance
  :: forall u l a
   . Num a
  => V3 (Qu u l a)
  -> Qu (Normalize (u @@+ Reorder u u)) l a
qQuadrance :: forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Num a =>
V3 (Qu u l a) -> Qu (Normalize (u @@+ Reorder u u)) l a
qQuadrance = coerce :: forall a b. Coercible a b => a -> b
coerce (forall (f :: * -> *) a. (Metric f, Num a) => f a -> a
quadrance @V3 @a)

(|^/|) :: (Functor f, Fractional n) =>
            f (Qu b l n)
            -> Qu u l n
            -> f (Qu
                    (Normalize
                       (Normalize ('[] @- u) @@+ Reorder b (Normalize ('[] @- u))))
                    l
                    n)
f (Qu b l n)
x |^/| :: forall (f :: * -> *) n (b :: [Factor (*)]) (l :: LCSU (*))
       (u :: [Factor (*)]).
(Functor f, Fractional n) =>
f (Qu b l n)
-> Qu u l n
-> f (Qu
        (Normalize
           (Normalize ('[] @- u) @@+ Reorder b (Normalize ('[] @- u))))
        l
        n)
|^/| Qu u l n
y = (forall (u :: [Factor (*)]) (l :: LCSU (*)) a.
Fractional a =>
Qu u l a -> Qu (Normalize ('[] @- u)) l a
qRecip Qu u l n
y forall n (a :: [Factor (*)]) (l :: LCSU (*)) (b :: [Factor (*)]).
Num n =>
Qu a l n -> Qu b l n -> Qu (Normalize (a @+ b)) l n
|*|) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f (Qu b l n)
x

(|^-^|)
  :: forall f u l a
   . (Additive f, Applicative f, Num a)
  => f (Qu u l a)
  -> f (Qu u l a)
  -> f (Qu u l a)
|^-^| :: forall (f :: * -> *) (u :: [Factor (*)]) (l :: LCSU (*)) a.
(Additive f, Applicative f, Num a) =>
f (Qu u l a) -> f (Qu u l a) -> f (Qu u l a)
(|^-^|) = forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 forall (d1 :: [Factor (*)]) (d2 :: [Factor (*)]) n (l :: LCSU (*)).
(d1 @~ d2, Num n) =>
Qu d1 l n -> Qu d2 l n -> Qu d1 l n
(|-|)