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