module Data.Angle where
import Data.Fixed
newtype Angle a = Radians { angleValueRadians :: a } deriving (Eq, Show)
angleFromDegrees :: (Integral d, Floating r) => d -> Angle r
angleFromDegrees x = Radians $ (realToFrac x) * pi/180
angleFromTurns :: (Real t, Floating r) => t -> Angle r
angleFromTurns x = Radians $ (realToFrac x) * pi*2
angleFromRadians :: (Floating r) => r -> Angle r
angleFromRadians = Radians
angleValueDegrees :: (Floating r, RealFrac r, Integral d) => Angle r -> d
angleValueDegrees (Radians x) = round $ x / pi * 180.0
angleValueTurns :: (Floating r) => Angle r -> r
angleValueTurns (Radians x) = x / (pi*2)
instance Functor Angle where
fmap f (Radians x) = Radians (f x)
instance Applicative Angle where
pure = Radians
Radians f <*> r = fmap f r
addAngle :: (Floating a) => Angle a -> Angle a -> Angle a
addAngle r1 r2 = (+) <$> r1 <*> r2
normAngle :: (Floating a, Real a) => Angle a -> Angle a
normAngle (Radians r) = Radians $ mod' r (pi*2)
addAngleNorm :: (Floating a, Real a) => Angle a -> Angle a -> Angle a
addAngleNorm a b = normAngle $ addAngle a b
distAngle :: (Floating a, Real a) => Angle a -> Angle a -> Angle a
distAngle (Radians r1) (Radians r2) = Radians $ if (a' < b') then a' else b'
where
a' = mod' (r1r2) (pi*2)
b' = mod' (r2r1) (pi*2)
flipAngle :: (Floating a) => Angle a -> Angle a
flipAngle = fmap negate
flipAngleNorm :: (Floating a, Real a) => Angle a -> Angle a
flipAngleNorm = normAngle . flipAngle
addAngleDegrees :: (Floating r, Integral d) => Angle r -> d -> Angle r
addAngleDegrees ang deg = addAngle ang $ angleFromDegrees deg
addAngleRadians :: (Floating r) => Angle r -> r -> Angle r
addAngleRadians (Radians r1) r2 = Radians $ r1 + r2
addAngleTurns :: (Floating r, Real t) => Angle r -> t -> Angle r
addAngleTurns ang turn = addAngle ang $ angleFromTurns turn
sinAngle :: (Floating a) => Angle a -> a
sinAngle = sin . angleValueRadians
cosAngle :: (Floating a) => Angle a -> a
cosAngle = cos . angleValueRadians
tanAngle :: (Floating a) => Angle a -> a
tanAngle = tan . angleValueRadians
cotAngle :: (Floating a) => Angle a -> a
cotAngle = recip . tan . angleValueRadians
asinAngle :: (Floating a) => a -> Angle a
asinAngle = Radians . asin
acosAngle :: (Floating a) => a -> Angle a
acosAngle = Radians . acos
atanAngle :: (Floating a) => a -> Angle a
atanAngle = Radians . atan
acotAngle :: (Floating a) => a -> Angle a
acotAngle x = Radians $ (pi/2) (atan x)
atan2Angle :: (Floating a, RealFloat a) => a -> a -> Angle a
atan2Angle y x = Radians $ atan2 y x