{-|
Module: Data.Astro.Utils
Description: Utility functions
Copyright: Alexander Ignatyev, 2016

Utility functions.
-}


module Data.Astro.Utils
(
  fromFixed
  , trunc
  , fraction
  , reduceToZeroRange
  , toRadians
  , fromRadians
  , roundToN
  , tropicalYearLen
)

where

import Data.Fixed(Fixed(MkFixed), HasResolution(resolution))

-- | Convert From Fixed to Fractional

fromFixed :: (Fractional a, HasResolution b) => Fixed b -> a
fromFixed :: Fixed b -> a
fromFixed fv :: Fixed b
fv@(MkFixed Integer
v) = (Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
v) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> a) -> Integer -> a
forall a b. (a -> b) -> a -> b
$ Fixed b -> Integer
forall k (a :: k) (p :: k -> *). HasResolution a => p a -> Integer
resolution Fixed b
fv)


-- | return the integral part of a number

-- almost the same as truncate but result type is Real

trunc :: RealFrac a => a -> a
trunc :: a -> a
trunc = Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> a) -> (a -> Integer) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
truncate


-- | Almost the same the properFraction function but result type

fraction :: (RealFrac a, Num b) => a -> (b, a)
fraction :: a -> (b, a)
fraction a
v = let (Integer
i, a
f) = (a -> (Integer, a)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction a
v)
             in (Integer -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
i, a
f)


-- | Reduce to range from 0 to n

reduceToZeroRange :: RealFrac a => a -> a -> a
reduceToZeroRange :: a -> a -> a
reduceToZeroRange a
r a
n =
  let b :: a
b = a
n a -> a -> a
forall a. Num a => a -> a -> a
- (a -> a
forall a. RealFrac a => a -> a
trunc (a
n a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
r)) a -> a -> a
forall a. Num a => a -> a -> a
* a
r
  in if a
b a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 then a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
r else a
b


-- | Convert from degrees to radians

toRadians :: Floating a => a -> a
toRadians :: a -> a
toRadians a
deg = a
dega -> a -> a
forall a. Num a => a -> a -> a
*a
forall a. Floating a => a
pia -> a -> a
forall a. Fractional a => a -> a -> a
/a
180


-- | Convert from radians to degrees

fromRadians :: Floating a => a -> a
fromRadians :: a -> a
fromRadians a
rad = a
rada -> a -> a
forall a. Num a => a -> a -> a
*a
180a -> a -> a
forall a. Fractional a => a -> a -> a
/a
forall a. Floating a => a
pi


-- | Round to a specified number of digits

roundToN :: RealFrac a => Int -> a -> a
roundToN :: Int -> a -> a
roundToN Int
n a
f = (Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a) -> Integer -> a
forall a b. (a -> b) -> a -> b
$ a -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (a -> Integer) -> a -> Integer
forall a b. (a -> b) -> a -> b
$ a
f a -> a -> a
forall a. Num a => a -> a -> a
* a
factor) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
factor
  where factor :: a
factor = a
10.0a -> Int -> a
forall a b. (Fractional a, Integral b) => a -> b -> a
^^Int
n


-- | Length of a tropical year in days

tropicalYearLen :: Double
tropicalYearLen :: Double
tropicalYearLen = Double
365.242191