diagrams-lib-1.2: src/Diagrams/Angle.hs
{-# 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