Data-Angle-0.9: src/Data/Angle.hs
module Data.Angle where
import Data.Fixed -- mod'
newtype Angle a = Radians { angleValueRadians :: a } deriving (Eq, Show)
-- Creating Angle from a value
-- | Create an Angle with the given degrees
angleFromDegrees :: (Integral d, Floating r) => d -> Angle r
angleFromDegrees x = Radians $ (realToFrac x) * pi/180
-- | Create an Angle with the given turns
angleFromTurns :: (Real t, Floating r) => t -> Angle r
angleFromTurns x = Radians $ (realToFrac x) * pi*2
-- | Create an Angle with the given turns
angleFromRadians :: (Floating r) => r -> Angle r
angleFromRadians = Radians
-- Get the value from angle
-- | Get degrees from an angle
angleValueDegrees :: (Floating r, RealFrac r, Integral d) => Angle r -> d
angleValueDegrees (Radians x) = round $ x / pi * 180.0
-- | Get turns from an angle
angleValueTurns :: (Floating r) => Angle r -> r
angleValueTurns (Radians x) = x / (pi*2)
-- Functor and Applicative instance
instance Functor Angle where
fmap f (Radians x) = Radians (f x)
instance Applicative Angle where
pure = Radians
Radians f <*> r = fmap f r
-- Basic functions
-- | Adding two angles
addAngle :: (Floating a) => Angle a -> Angle a -> Angle a
addAngle r1 r2 = (+) <$> r1 <*> r2
-- | Normalize Angle: transforming back to (0-2pi)
normAngle :: (Floating a, Real a) => Angle a -> Angle a
normAngle (Radians r) = Radians $ mod' r (pi*2)
-- | Add two angles and normalize the result
addAngleNorm :: (Floating a, Real a) => Angle a -> Angle a -> Angle a
addAngleNorm a b = normAngle $ addAngle a b
-- | Distance between two angles
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' (r1-r2) (pi*2)
b' = mod' (r2-r1) (pi*2)
-- | Flip angle
flipAngle :: (Floating a) => Angle a -> Angle a
flipAngle = fmap negate
-- | Flip angle and normalize the result
flipAngleNorm :: (Floating a, Real a) => Angle a -> Angle a
flipAngleNorm = normAngle . flipAngle
-- | Add degrees to angle
addAngleDegrees :: (Floating r, Integral d) => Angle r -> d -> Angle r
addAngleDegrees ang deg = addAngle ang $ angleFromDegrees deg
-- | Add radians to angle
addAngleRadians :: (Floating r) => Angle r -> r -> Angle r
addAngleRadians (Radians r1) r2 = Radians $ r1 + r2
-- | Add turns to angle
addAngleTurns :: (Floating r, Real t) => Angle r -> t -> Angle r
addAngleTurns ang turn = addAngle ang $ angleFromTurns turn
-- Trigonometric functions
-- | Sine of the angle
sinAngle :: (Floating a) => Angle a -> a
sinAngle = sin . angleValueRadians
-- | Cosine of the angle
cosAngle :: (Floating a) => Angle a -> a
cosAngle = cos . angleValueRadians
-- | Tangent of the angle
tanAngle :: (Floating a) => Angle a -> a
tanAngle = tan . angleValueRadians
-- | Cotangent of the angle
cotAngle :: (Floating a) => Angle a -> a
cotAngle = recip . tan . angleValueRadians
-- Inverse trigonometric functions
-- | Create angle from inverse sine
asinAngle :: (Floating a) => a -> Angle a
asinAngle = Radians . asin
-- | Create angle from inverse cosine
acosAngle :: (Floating a) => a -> Angle a
acosAngle = Radians . acos
-- | Create angle from inverse tangent
atanAngle :: (Floating a) => a -> Angle a
atanAngle = Radians . atan
-- | Create angle from inverse cotangent
acotAngle :: (Floating a) => a -> Angle a
acotAngle x = Radians $ (pi/2) - (atan x)
-- | Create angle from atan2
atan2Angle :: (Floating a, RealFloat a) => a -> a -> Angle a
atan2Angle y x = Radians $ atan2 y x