{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Angle -- Copyright : (c) 2013 diagrams-lib team (see LICENSE) -- License : BSD-style (see LICENSE) -- Maintainer : diagrams-discuss@googlegroups.com -- -- Type for representing angles, independent of vector-space -- ----------------------------------------------------------------------------- module Diagrams.Angle ( Angle , rad, turn, deg , fullTurn, fullCircle, angleRatio , sinA, cosA, tanA, asinA, acosA, atanA , (@@) , angleBetween , HasTheta(..) ) where import Control.Lens (Iso', Lens', iso, review, (^.)) -- , review , (^.), _1, _2, Lens', lens) import Data.VectorSpace -- | Angles can be expressed in a variety of units. Internally, -- they are represented in radians. newtype Angle = Radians Double deriving (Read, Show, Eq, Ord, Enum, AdditiveGroup) instance VectorSpace Angle where type Scalar Angle = Double s *^ Radians t = Radians (s*t) -- | The radian measure of an @Angle@ @a@ can be accessed as @a -- ^. rad@. A new @Angle@ can be defined in radians as @pi \@\@ rad@. rad :: Iso' Angle Double rad = iso (\(Radians r) -> r) Radians -- | The measure of an @Angle@ @a@ in full circles can be accessed as -- @a ^. turn@. A new @Angle@ of one-half circle can be defined in as -- @1/2 \@\@ turn@. turn :: Iso' Angle Double turn = iso (\(Radians r) -> r/2/pi) (Radians . (*(2*pi))) -- | The degree measure of an @Angle@ @a@ can be accessed as @a -- ^. deg@. A new @Angle@ can be defined in degrees as @180 \@\@ -- deg@. deg :: Iso' Angle Double deg = iso (\(Radians r) -> r/2/pi*360) (Radians . (*(2*pi/360))) -- | An angle representing one full turn. fullTurn :: Angle fullTurn = 1 @@ turn -- | Deprecated synonym for 'fullTurn', retained for backwards compatibility. fullCircle :: Angle fullCircle = fullTurn -- | Calculate ratio between two angles. angleRatio :: Angle -> Angle -> Double angleRatio a b = (a^.rad) / (b^.rad) -- | The sine of the given @Angle@. sinA :: Angle -> Double sinA (Radians r) = sin r -- | The cosine of the given @Angle@. cosA :: Angle -> Double cosA (Radians r) = cos r -- | The tangent function of the given @Angle@. tanA :: Angle -> Double tanA (Radians r) = tan r -- | The @Angle@ with the given sine. asinA :: Double -> Angle asinA = Radians . asin -- | The @Angle@ with the given cosine. acosA :: Double -> Angle acosA = Radians . acos -- | The @Angle@ with the given tangent. atanA :: Double -> Angle atanA = Radians . atan -- | @30 \@\@ deg@ is an @Angle@ of the given measure and units. -- -- More generally, @\@\@@ reverses the @Iso\'@ on its right, and -- applies the @Iso\'@ to the value on the left. @Angle@s are the -- motivating example where this order improves readability. (@@) :: b -> Iso' a b -> a -- The signature above is slightly specialized, in favor of readability a @@ i = review i a infixl 5 @@ -- | compute the positive angle between the two vectors in their common plane angleBetween :: (InnerSpace v, Scalar v ~ Double) => v -> v -> Angle angleBetween v1 v2 = acos (normalized v1 <.> normalized v2) @@ rad ------------------------------------------------------------ -- Polar Coordinates -- | The class of types with at least one angle coordinate, called _theta. class HasTheta t where _theta :: Lens' t Angle