{-|
Module      : Linear.Geo.ENU
Copyright   : Travis Whitaker 2023
License     : MIT
Maintainer  : pi.boy.travis@gmail.com
Stability   : Provisional
Portability : Portable (Windows, POSIX)

East-North-Up coordinates.

-}

{-# LANGUAGE DataKinds
           , DeriveAnyClass
           , DeriveDataTypeable
           , DeriveGeneric
           , DerivingStrategies
           , MagicHash
           , ScopedTypeVariables
           , TypeFamilies
           #-}

module Linear.Geo.ENU (
    ENU(..)
  , alignOrigin
  , liftAO2
  , liftAO2V
  , rotNormToECEF
  , rotNormToECEFFromENU
  , enuToECEF
  , rotECEFToNorm
  , rotECEFToNormFromENU
  , ecefToENU
  , disp
  , diff
  , lerp
  , dot
  , quadrance
  , norm
  , distance
  , normalize
  , project
  ) where

import Control.DeepSeq (NFData)

import Data.Data (Data)

import GHC.Generics (Generic)

import GHC.Exts

import qualified Linear.Affine  as L
import qualified Linear.Epsilon as L
import qualified Linear.Matrix  as L
import qualified Linear.Metric  as L
import qualified Linear.V2      as L
import qualified Linear.V3      as L
import qualified Linear.Vector  as L

import Linear.Geo.ECEF
import Linear.Geo.Geodetic
import Linear.Geo.PlaneAngle

-- | R3 vector with the origin located at some arbitrary 'ECEF' position vector,
--   first basis pointing east at the origin, second basis vector pointing north
--   at the origin, and third basis vector normal to the plane tangent to the
--   ellipsoid at the origin.
--
--   Each value records both the ENU vector and the ENU origin. Most functions
--   of multiple ENU values will require the points to occupy coordinal frames.
--   Binary operations on ENU values should preserve the coordinate frame of the
--   /left/ value.
--
--   The 'Eq' and 'Ord' instances for this type implement structural equality,
--   i.e. ENU points with different 'enuOrigin' values will never be equal.
--   Floating point errors limit the usefulness of
--   exact-equality-as-coincidence.
--
--   Operations on ENU points use the uncorrected WGS84 geoid model.
data ENU a = ENU {
    forall a. ENU a -> ECEF a
enuOrigin :: ECEF a
  , forall a. ENU a -> V3 a
enuPoint  :: L.V3 a
  } deriving stock ( ENU a -> ENU a -> Bool
forall a. Eq a => ENU a -> ENU a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ENU a -> ENU a -> Bool
$c/= :: forall a. Eq a => ENU a -> ENU a -> Bool
== :: ENU a -> ENU a -> Bool
$c== :: forall a. Eq a => ENU a -> ENU a -> Bool
Eq
                   , ENU a -> ENU a -> Bool
ENU a -> ENU a -> Ordering
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {a}. Ord a => Eq (ENU a)
forall a. Ord a => ENU a -> ENU a -> Bool
forall a. Ord a => ENU a -> ENU a -> Ordering
forall a. Ord a => ENU a -> ENU a -> ENU a
min :: ENU a -> ENU a -> ENU a
$cmin :: forall a. Ord a => ENU a -> ENU a -> ENU a
max :: ENU a -> ENU a -> ENU a
$cmax :: forall a. Ord a => ENU a -> ENU a -> ENU a
>= :: ENU a -> ENU a -> Bool
$c>= :: forall a. Ord a => ENU a -> ENU a -> Bool
> :: ENU a -> ENU a -> Bool
$c> :: forall a. Ord a => ENU a -> ENU a -> Bool
<= :: ENU a -> ENU a -> Bool
$c<= :: forall a. Ord a => ENU a -> ENU a -> Bool
< :: ENU a -> ENU a -> Bool
$c< :: forall a. Ord a => ENU a -> ENU a -> Bool
compare :: ENU a -> ENU a -> Ordering
$ccompare :: forall a. Ord a => ENU a -> ENU a -> Ordering
Ord
                   , Int -> ENU a -> ShowS
forall a. Show a => Int -> ENU a -> ShowS
forall a. Show a => [ENU a] -> ShowS
forall a. Show a => ENU a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ENU a] -> ShowS
$cshowList :: forall a. Show a => [ENU a] -> ShowS
show :: ENU a -> String
$cshow :: forall a. Show a => ENU a -> String
showsPrec :: Int -> ENU a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> ENU a -> ShowS
Show
                   , forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (ENU a) x -> ENU a
forall a x. ENU a -> Rep (ENU a) x
$cto :: forall a x. Rep (ENU a) x -> ENU a
$cfrom :: forall a x. ENU a -> Rep (ENU a) x
Generic
                   , ENU a -> DataType
ENU a -> Constr
forall {a}. Data a => Typeable (ENU a)
forall a. Data a => ENU a -> DataType
forall a. Data a => ENU a -> Constr
forall a. Data a => (forall b. Data b => b -> b) -> ENU a -> ENU a
forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> ENU a -> u
forall a u. Data a => (forall d. Data d => d -> u) -> ENU a -> [u]
forall a r r'.
Data a =>
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
forall a r r'.
Data a =>
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
forall a (m :: * -> *).
(Data a, Monad m) =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
forall a (c :: * -> *).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (ENU a)
forall a (c :: * -> *).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ENU a -> c (ENU a)
forall a (t :: * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (ENU a))
forall a (t :: * -> * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (ENU a))
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (ENU a)
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ENU a -> c (ENU a)
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (ENU a))
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
$cgmapMo :: forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
$cgmapMp :: forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
$cgmapM :: forall a (m :: * -> *).
(Data a, Monad m) =>
(forall d. Data d => d -> m d) -> ENU a -> m (ENU a)
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ENU a -> u
$cgmapQi :: forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> ENU a -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> ENU a -> [u]
$cgmapQ :: forall a u. Data a => (forall d. Data d => d -> u) -> ENU a -> [u]
gmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
$cgmapQr :: forall a r r'.
Data a =>
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
gmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
$cgmapQl :: forall a r r'.
Data a =>
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> ENU a -> r
gmapT :: (forall b. Data b => b -> b) -> ENU a -> ENU a
$cgmapT :: forall a. Data a => (forall b. Data b => b -> b) -> ENU a -> ENU a
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (ENU a))
$cdataCast2 :: forall a (t :: * -> * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (ENU a))
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (ENU a))
$cdataCast1 :: forall a (t :: * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (ENU a))
dataTypeOf :: ENU a -> DataType
$cdataTypeOf :: forall a. Data a => ENU a -> DataType
toConstr :: ENU a -> Constr
$ctoConstr :: forall a. Data a => ENU a -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (ENU a)
$cgunfold :: forall a (c :: * -> *).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (ENU a)
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ENU a -> c (ENU a)
$cgfoldl :: forall a (c :: * -> *).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ENU a -> c (ENU a)
Data
                   , ENU a
forall a. a -> a -> Bounded a
forall a. Bounded a => ENU a
maxBound :: ENU a
$cmaxBound :: forall a. Bounded a => ENU a
minBound :: ENU a
$cminBound :: forall a. Bounded a => ENU a
Bounded
                   )
    deriving anyclass (forall a. NFData a => ENU a -> ()
forall a. (a -> ()) -> NFData a
rnf :: ENU a -> ()
$crnf :: forall a. NFData a => ENU a -> ()
NFData)

instance L.R1 ENU where
    _x :: forall a. Lens' (ENU a) a
_x a -> f a
f (ENU ECEF a
o (L.V3 a
x a
y a
z)) = (\a
x' -> forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o (forall a. a -> a -> a -> V3 a
L.V3 a
x' a
y a
z)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f a
f a
x

instance L.R2 ENU where
    _y :: forall a. Lens' (ENU a) a
_y  a -> f a
f (ENU ECEF a
o (L.V3 a
x a
y a
z)) = (\a
y' -> forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o (forall a. a -> a -> a -> V3 a
L.V3 a
x a
y' a
z)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f a
f a
y
    _xy :: forall a. Lens' (ENU a) (V2 a)
_xy V2 a -> f (V2 a)
f (ENU ECEF a
o (L.V3 a
x a
y a
z)) = (\(L.V2 a
x' a
y') -> forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o (forall a. a -> a -> a -> V3 a
L.V3 a
x' a
y' a
z))
                             forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> V2 a -> f (V2 a)
f (forall a. a -> a -> V2 a
L.V2 a
x a
y)

instance L.R3 ENU where
    _z :: forall a. Lens' (ENU a) a
_z   a -> f a
f (ENU ECEF a
o (L.V3 a
x a
y a
z)) = (\a
z' -> forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o (forall a. a -> a -> a -> V3 a
L.V3 a
x a
y a
z')) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f a
f a
z
    _xyz :: forall a. Lens' (ENU a) (V3 a)
_xyz V3 a -> f (V3 a)
f (ENU ECEF a
o V3 a
v)            = forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> V3 a -> f (V3 a)
f V3 a
v

-- | Align the second argument with the coordinate system of the first.
alignOrigin :: RealFloat a => ENU a -> ENU a -> ENU a
alignOrigin :: forall a. RealFloat a => ENU a -> ENU a -> ENU a
alignOrigin (ENU ECEF a
xo V3 a
_) y :: ENU a
y@(ENU ECEF a
yo V3 a
_)
    | Int# -> Bool
isTrue# (forall a. a -> a -> Int#
reallyUnsafePtrEquality# ECEF a
xo ECEF a
yo) = ENU a
y
    | ECEF a
xo forall a. Eq a => a -> a -> Bool
== ECEF a
yo  = ENU a
y
    | Bool
otherwise = forall a. RealFloat a => ECEF a -> ECEF a -> ENU a
ecefToENU ECEF a
xo (forall a. RealFloat a => ENU a -> ECEF a
enuToECEF ENU a
y)

-- | Lift a function on vectors to a function on origin-aligned ENU points.
liftAO2 :: RealFloat a => (L.V3 a -> L.V3 a -> b) -> ENU a -> ENU a -> b
liftAO2 :: forall a b.
RealFloat a =>
(V3 a -> V3 a -> b) -> ENU a -> ENU a -> b
liftAO2 V3 a -> V3 a -> b
f x :: ENU a
x@(ENU ECEF a
_ V3 a
xp) ENU a
y = let (ENU ECEF a
_ V3 a
y'p) = forall a. RealFloat a => ENU a -> ENU a -> ENU a
alignOrigin ENU a
x ENU a
y
                           in V3 a -> V3 a -> b
f V3 a
xp V3 a
y'p

-- | Lift a binary operation on vectors to a binary operation on origin-aligned
--   ENU points.
liftAO2V :: RealFloat a
         => (L.V3 a -> L.V3 a -> L.V3 a)
         -> ENU a
         -> ENU a
         -> ENU a
liftAO2V :: forall a.
RealFloat a =>
(V3 a -> V3 a -> V3 a) -> ENU a -> ENU a -> ENU a
liftAO2V V3 a -> V3 a -> V3 a
f x :: ENU a
x@(ENU ECEF a
xo V3 a
xp) ENU a
y = let (ENU ECEF a
_ V3 a
y'p) = forall a. RealFloat a => ENU a -> ENU a -> ENU a
alignOrigin ENU a
x ENU a
y
                             in forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
xo (V3 a -> V3 a -> V3 a
f V3 a
xp V3 a
y'p)

-- | Rotation matrix that rotates the ENU coordinate frame at the provided
--   latitude and longitude to the ECEF coordinate frame.
rotNormToECEF :: Floating a
              => Radians a -- ^ lat
              -> Radians a -- ^ lon
              -> L.M33 a
rotNormToECEF :: forall a. Floating a => Radians a -> Radians a -> M33 a
rotNormToECEF (Radians a
po) (Radians a
lo) =
    forall a. a -> a -> a -> V3 a
L.V3 (forall a. a -> a -> a -> V3 a
L.V3 (-(forall a. Floating a => a -> a
sin a
lo)) ((-(forall a. Floating a => a -> a
cos a
lo)) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
sin a
po))  ((forall a. Floating a => a -> a
cos a
lo) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
cos a
po)))
         (forall a. a -> a -> a -> V3 a
L.V3 (forall a. Floating a => a -> a
cos a
lo)    ((- (forall a. Floating a => a -> a
sin a
lo)) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
sin a
po)) ((forall a. Floating a => a -> a
sin a
lo) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
cos a
po)))
         (forall a. a -> a -> a -> V3 a
L.V3 a
0           (forall a. Floating a => a -> a
cos a
po)                  (forall a. Floating a => a -> a
sin a
po)             )

-- | Do 'rotNormToECEF', but get the lat and lon from some 'ENU's origin.
rotNormToECEFFromENU :: RealFloat a => ENU a -> L.M33 a
rotNormToECEFFromENU :: forall a. RealFloat a => ENU a -> M33 a
rotNormToECEFFromENU (ENU ECEF a
o V3 a
_) =
    let (Geo Radians a
po Radians a
lo a
_) = forall a. RealFloat a => ECEF a -> Geo a
ecefToGeo ECEF a
o
    in forall a. Floating a => Radians a -> Radians a -> M33 a
rotNormToECEF Radians a
po Radians a
lo

-- | Convert an 'ENU' to an 'ECEF' by adding the rotated position vector to the
--   origin.
enuToECEF :: RealFloat a => ENU a -> ECEF a
enuToECEF :: forall a. RealFloat a => ENU a -> ECEF a
enuToECEF enu :: ENU a
enu@(ENU ECEF a
o V3 a
x) =
    let rot :: M33 a
rot = forall a. RealFloat a => ENU a -> M33 a
rotNormToECEFFromENU ENU a
enu
    in ECEF a
o forall (p :: * -> *) a. (Affine p, Num a) => p a -> Diff p a -> p a
L..+^ (M33 a
rot forall (m :: * -> *) (r :: * -> *) a.
(Functor m, Foldable r, Additive r, Num a) =>
m (r a) -> r a -> m a
L.!* V3 a
x)

-- | Rotation matrix that rotates the ECEF coordinate frame to the ENU
--   coordinate frame at the provided latitude and longitude.
rotECEFToNorm :: Floating a
              => Radians a -- ^ lat
              -> Radians a -- ^ lon
              -> L.M33 a
rotECEFToNorm :: forall a. Floating a => Radians a -> Radians a -> M33 a
rotECEFToNorm (Radians a
po) (Radians a
lo) =
    forall a. a -> a -> a -> V3 a
L.V3 (forall a. a -> a -> a -> V3 a
L.V3 (-(forall a. Floating a => a -> a
sin a
lo))              (forall a. Floating a => a -> a
cos a
lo)                 a
0       )
         (forall a. a -> a -> a -> V3 a
L.V3 ((-(forall a. Floating a => a -> a
cos a
lo)) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
sin a
po)) ((-(forall a. Floating a => a -> a
sin a
lo)) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
sin a
po)) (forall a. Floating a => a -> a
cos a
po))
         (forall a. a -> a -> a -> V3 a
L.V3 ((forall a. Floating a => a -> a
cos a
lo) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
cos a
po))    ((forall a. Floating a => a -> a
sin a
lo) forall a. Num a => a -> a -> a
* (forall a. Floating a => a -> a
cos a
po))    (forall a. Floating a => a -> a
sin a
po))

-- | Do 'rotECEFToNorm', but get the lat and lon from some 'ENU's origin.
rotECEFToNormFromENU :: RealFloat a => ENU a -> L.M33 a
rotECEFToNormFromENU :: forall a. RealFloat a => ENU a -> M33 a
rotECEFToNormFromENU (ENU ECEF a
o V3 a
_) =
    let (Geo Radians a
po Radians a
lo a
_) = forall a. RealFloat a => ECEF a -> Geo a
ecefToGeo ECEF a
o
    in forall a. Floating a => Radians a -> Radians a -> M33 a
rotECEFToNorm Radians a
po Radians a
lo

-- | Pack an 'ECEF' origin and point into an 'ENU'. 
ecefToENU :: RealFloat a
          => ECEF a -- ^ Origin
          -> ECEF a -- ^ Point
          -> ENU a
ecefToENU :: forall a. RealFloat a => ECEF a -> ECEF a -> ENU a
ecefToENU o :: ECEF a
o@(ECEF V3 a
vo) (ECEF V3 a
vp) =
    let (Geo Radians a
po Radians a
lo a
_) = forall a. RealFloat a => ECEF a -> Geo a
ecefToGeo ECEF a
o
        rot :: M33 a
rot = forall a. Floating a => Radians a -> Radians a -> M33 a
rotECEFToNorm Radians a
po Radians a
lo
        x :: V3 a
x = M33 a
rot forall (m :: * -> *) (r :: * -> *) a.
(Functor m, Foldable r, Additive r, Num a) =>
m (r a) -> r a -> m a
L.!* (V3 a
vp forall a. Num a => a -> a -> a
- V3 a
vo)
    in forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o V3 a
x

-- | Affine addition. Apply a displacement vector.
disp :: Num a => ENU a -> L.V3 a -> ENU a
disp :: forall a. Num a => ENU a -> V3 a -> ENU a
disp (ENU ECEF a
o V3 a
p) V3 a
v = (forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
o (V3 a
p forall a. Num a => a -> a -> a
+ V3 a
v))

-- | Affine subtraction. Get the vector from the first to the second ENU point.
diff :: RealFloat a => ENU a -> ENU a -> L.V3 a
diff :: forall a. RealFloat a => ENU a -> ENU a -> V3 a
diff ENU a
x ENU a
y = forall a. ENU a -> V3 a
enuPoint forall a b. (a -> b) -> a -> b
$ forall a.
RealFloat a =>
(V3 a -> V3 a -> V3 a) -> ENU a -> ENU a -> ENU a
liftAO2V forall (p :: * -> *) a. (Affine p, Num a) => p a -> p a -> Diff p a
(L..-.) ENU a
x ENU a
y

-- | Linearly interpolate between two points.
lerp :: RealFloat a => a -> ENU a -> ENU a -> ENU a
lerp :: forall a. RealFloat a => a -> ENU a -> ENU a -> ENU a
lerp a
f = forall a.
RealFloat a =>
(V3 a -> V3 a -> V3 a) -> ENU a -> ENU a -> ENU a
liftAO2V (forall (f :: * -> *) a.
(Additive f, Num a) =>
a -> f a -> f a -> f a
L.lerp a
f)

-- | Lifted dot.
dot :: RealFloat a => ENU a -> ENU a -> a
dot :: forall a. RealFloat a => ENU a -> ENU a -> a
dot = forall a b.
RealFloat a =>
(V3 a -> V3 a -> b) -> ENU a -> ENU a -> b
liftAO2 forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
L.dot

-- | Lifted quadrance.
quadrance :: Num a => ENU a -> a
quadrance :: forall a. Num a => ENU a -> a
quadrance = forall (f :: * -> *) a. (Metric f, Num a) => f a -> a
L.quadrance forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ENU a -> V3 a
enuPoint

-- | Lifted norm.
norm :: Floating a => ENU a -> a
norm :: forall a. Floating a => ENU a -> a
norm = forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
L.norm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ENU a -> V3 a
enuPoint

-- | Lifted distance.
distance :: RealFloat a => ENU a -> ENU a -> a
distance :: forall a. RealFloat a => ENU a -> ENU a -> a
distance = forall a b.
RealFloat a =>
(V3 a -> V3 a -> b) -> ENU a -> ENU a -> b
liftAO2 forall (f :: * -> *) a. (Metric f, Floating a) => f a -> f a -> a
L.distance

-- | Lifted normalize.
normalize :: (Floating a, L.Epsilon a) => ENU a -> ENU a
normalize :: forall a. (Floating a, Epsilon a) => ENU a -> ENU a
normalize (ENU ECEF a
xo V3 a
xp) = forall a. ECEF a -> V3 a -> ENU a
ENU ECEF a
xo (forall a (f :: * -> *).
(Floating a, Metric f, Epsilon a) =>
f a -> f a
L.normalize V3 a
xp)

-- | Lifted project.
project :: RealFloat a => ENU a -> ENU a -> ENU a
project :: forall a. RealFloat a => ENU a -> ENU a -> ENU a
project = forall a.
RealFloat a =>
(V3 a -> V3 a -> V3 a) -> ENU a -> ENU a -> ENU a
liftAO2V forall (v :: * -> *) a.
(Metric v, Fractional a) =>
v a -> v a -> v a
L.project