module RSAGL.Math.Angle
(Angle,
BoundAngle(..),
fromDegrees,
fromRadians,
fromRotations,
fromTimeOfDayHMS,
fromArcMinutes,
fromArcSeconds,
sine,
arcSine,
cosine,
arcCosine,
tangent,
arcTangent,
cartesianToPolar,
polarToCartesian,
toRadians,
toRadians_,
toDegrees,
toDegrees_,
toRotations,
toRotations_,
scaleAngle,
supplementaryAngle,
zero_angle,
angularIncrements,
angleAdd,
angleSubtract,
angleNegate,
absoluteAngle,
unboundAngle)
where
import RSAGL.Math.FMod
import RSAGL.Math.AbstractVector
import RSAGL.Math.Types
newtype Angle = Radians RSdouble deriving (Read,Show)
newtype BoundAngle = BoundAngle Angle deriving (Read,Show)
zero_angle :: Angle
zero_angle = Radians 0
instance Eq Angle where
(==) a b = case (toRadians_ a,toRadians_ b) of
(x,y) | abs x == pi && abs y == pi -> True
(x,y) | x == y -> True
_ -> False
instance Ord Angle where
compare x y = case () of
_ | x == y -> EQ
_ -> compare (toRadians_ x) (toRadians_ y)
instance AbstractZero Angle where
zero = zero_angle
instance AbstractZero BoundAngle where
zero = BoundAngle zero_angle
instance AbstractAdd Angle Angle where
add = angleAdd
instance AbstractAdd BoundAngle Angle where
add (BoundAngle a) x = BoundAngle $ boundAngle $ a `add` x
instance AbstractSubtract Angle Angle where
sub = angleSubtract
instance AbstractSubtract BoundAngle Angle where
sub (BoundAngle a) (BoundAngle b) = boundAngle $ a `sub` b
instance AbstractScale Angle where
scalarMultiply = scaleAngle
instance AbstractVector Angle
instance AbstractMagnitude Angle where
magnitude = toRotations_ . absoluteAngle
angularIncrements :: Integer -> [Angle]
angularIncrements subdivisions = map (fromRadians . (2*pi*) . (/ fromInteger subdivisions) . fromInteger) [0 .. subdivisions 1]
fromRadians :: RSdouble -> Angle
fromRadians = Radians
fromDegrees :: RSdouble -> Angle
fromDegrees = Radians . ((*) (pi/180))
fromRotations :: RSdouble -> Angle
fromRotations = Radians . ((*) (2*pi))
fromTimeOfDayHMS :: RSdouble -> RSdouble -> RSdouble -> Angle
fromTimeOfDayHMS h m s = fromRotations (((s/60+m)/60+h)/24)
fromArcMinutes :: RSdouble -> Angle
fromArcMinutes = fromDegrees . (/60)
fromArcSeconds :: RSdouble -> Angle
fromArcSeconds = fromArcMinutes . (/60)
toDegrees :: Angle -> RSdouble
toDegrees x = let x' = toRadians x
in x' * 180 / pi
toDegrees_ :: Angle -> RSdouble
toDegrees_ (Radians x) = x * 180 / pi
toRadians :: Angle -> RSdouble
toRadians x = let (Radians x') = boundAngle x
in x'
toRadians_ :: Angle -> RSdouble
toRadians_ (Radians x) = x
toRotations :: Angle -> RSdouble
toRotations x= let x' = toRadians x
in x' / pi / 2
toRotations_ :: Angle -> RSdouble
toRotations_ (Radians x) = x / pi / 2
scaleAngle :: RSdouble -> Angle -> Angle
scaleAngle x = Radians . (*x) . toRadians_
supplementaryAngle :: Angle -> Angle
supplementaryAngle (Radians x) = Radians $ pi x
angleAdd :: Angle -> Angle -> Angle
angleAdd (Radians x) (Radians y) = Radians $ x + y
angleSubtract :: Angle -> Angle -> Angle
angleSubtract (Radians x) (Radians y) = Radians $ x y
angleNegate :: Angle -> Angle
angleNegate (Radians x) = Radians $ negate x
absoluteAngle :: Angle -> Angle
absoluteAngle (Radians x) = Radians $ abs x
sine :: Angle -> RSdouble
sine (Radians x) = sin x
arcSine :: RSdouble -> Angle
arcSine = fromRadians . asin
cosine :: Angle -> RSdouble
cosine (Radians x) = cos x
arcCosine :: RSdouble -> Angle
arcCosine = fromRadians . acos
tangent :: Angle -> RSdouble
tangent (Radians x) = tan x
arcTangent :: RSdouble -> Angle
arcTangent = fromRadians . atan
cartesianToPolar :: (RSdouble,RSdouble) -> (Angle,RSdouble)
cartesianToPolar (u,v) = (fromRadians $ atan2 v u,sqrt $ u*u + v*v)
polarToCartesian :: (Angle,RSdouble) -> (RSdouble,RSdouble)
polarToCartesian (a,d) = (cosine a*d,sine a*d)
boundAngle :: Angle -> Angle
boundAngle (Radians x) = Radians $ if bounded > pi then bounded 2*pi else bounded
where bounded = x `fmod` (2*pi)
unboundAngle :: BoundAngle -> Angle
unboundAngle (BoundAngle a) = a