{-# LANGUAGE TypeFamilies #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.TwoD.Types
-- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Basic types for two-dimensional Euclidean space.
--
-----------------------------------------------------------------------------

module Diagrams.TwoD.Types
       ( -- * 2D Euclidean space
         V2 (..), R1 (..), R2 (..)
       , P2, T2
       , r2, unr2, mkR2, r2Iso
       , p2, mkP2, unp2, p2Iso
       , r2PolarIso
       , HasR (..)
       ) where

import           Control.Lens            (Iso', Lens', iso, _1, _2)

import           Diagrams.Angle
import           Diagrams.Points

import           Diagrams.Core.Transform
import           Diagrams.Core.V
import           Linear.Metric
import           Linear.V2

type P2 = Point V2
type T2 = Transformation V2

type instance V (V2 n) = V2
type instance N (V2 n) = n

-- | Construct a 2D vector from a pair of components.  See also '&'.
r2 :: (n, n) -> V2 n
r2 :: forall n. (n, n) -> V2 n
r2 = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall a. a -> a -> V2 a
V2

-- | Convert a 2D vector back into a pair of components.  See also 'coords'.
unr2 :: V2 n -> (n, n)
unr2 :: forall n. V2 n -> (n, n)
unr2 (V2 n
x n
y) = (n
x, n
y)

-- | Curried form of `r2`.
mkR2 :: n -> n -> V2 n
mkR2 :: forall a. a -> a -> V2 a
mkR2 = forall a. a -> a -> V2 a
V2

r2Iso :: Iso' (V2 n) (n, n)
r2Iso :: forall n. Iso' (V2 n) (n, n)
r2Iso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall n. V2 n -> (n, n)
unr2 forall n. (n, n) -> V2 n
r2

-- | Construct a 2D point from a pair of coordinates.  See also '^&'.
p2 :: (n, n) -> P2 n
p2 :: forall n. (n, n) -> P2 n
p2 = forall (f :: * -> *) a. f a -> Point f a
P forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall a. a -> a -> V2 a
V2

-- | Convert a 2D point back into a pair of coordinates.  See also 'coords'.
unp2 :: P2 n -> (n,n)
unp2 :: forall n. P2 n -> (n, n)
unp2 (P (V2 n
x n
y)) = (n
x,n
y)

-- | Curried form of `p2`.
mkP2 :: n -> n -> P2 n
mkP2 :: forall n. n -> n -> P2 n
mkP2 n
x n
y = forall (f :: * -> *) a. f a -> Point f a
P (forall a. a -> a -> V2 a
V2 n
x n
y)

p2Iso :: Iso' (Point V2 n) (n, n)
p2Iso :: forall n. Iso' (Point V2 n) (n, n)
p2Iso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall n. P2 n -> (n, n)
unp2 forall n. (n, n) -> P2 n
p2

instance Transformable (V2 n) where
  transform :: Transformation (V (V2 n)) (N (V2 n)) -> V2 n -> V2 n
transform = forall (v :: * -> *) n. Transformation v n -> v n -> v n
apply

r2PolarIso :: RealFloat n => Iso' (V2 n) (n, Angle n)
r2PolarIso :: forall n. RealFloat n => Iso' (V2 n) (n, Angle n)
r2PolarIso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\v :: V2 n
v@(V2 n
x n
y) -> (forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V2 n
v, forall n. RealFloat n => n -> n -> Angle n
atan2A n
y n
x))
              (\(n
r,Angle n
θ)      -> forall a. a -> a -> V2 a
V2 (n
r forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
cosA Angle n
θ) (n
r forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
sinA Angle n
θ))
{-# INLINE r2PolarIso #-}

-- | A space which has magnitude '_r' that can be calculated numerically.
class HasR t where
  _r :: RealFloat n => Lens' (t n) n

instance HasR v => HasR (Point v) where
  _r :: forall n. RealFloat n => Lens' (Point v n) n
_r = forall (g :: * -> *) a. Lens' (Point g a) (g a)
lensP forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) n. (HasR t, RealFloat n) => Lens' (t n) n
_r
  {-# INLINE _r #-}

instance HasR V2 where
  _r :: forall n. RealFloat n => Lens' (V2 n) n
_r = forall n. RealFloat n => Iso' (V2 n) (n, Angle n)
r2PolarIso forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. Field1 s t a b => Lens s t a b
_1
  {-# INLINE _r #-}

instance HasTheta V2 where
  _theta :: forall n. RealFloat n => Lens' (V2 n) (Angle n)
_theta = forall n. RealFloat n => Iso' (V2 n) (n, Angle n)
r2PolarIso forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. Field2 s t a b => Lens s t a b
_2
  {-# INLINE _theta #-}