{-# 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 :: (n, n) -> V2 n
r2 = (n -> n -> V2 n) -> (n, n) -> V2 n
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry n -> n -> V2 n
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 :: V2 n -> (n, n)
unr2 (V2 n
x n
y) = (n
x, n
y)

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

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

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

p2Iso :: Iso' (Point V2 n) (n, n)
p2Iso :: p (n, n) (f (n, n)) -> p (Point V2 n) (f (Point V2 n))
p2Iso = (Point V2 n -> (n, n))
-> ((n, n) -> Point V2 n)
-> Iso (Point V2 n) (Point V2 n) (n, n) (n, n)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Point V2 n -> (n, n)
forall n. P2 n -> (n, n)
unp2 (n, n) -> Point V2 n
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 = Transformation (V (V2 n)) (N (V2 n)) -> V2 n -> V2 n
forall (v :: * -> *) n. Transformation v n -> v n -> v n
apply

r2PolarIso :: RealFloat n => Iso' (V2 n) (n, Angle n)
r2PolarIso :: Iso' (V2 n) (n, Angle n)
r2PolarIso = (V2 n -> (n, Angle n))
-> ((n, Angle n) -> V2 n) -> Iso' (V2 n) (n, Angle n)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\v :: V2 n
v@(V2 n
x n
y) -> (V2 n -> n
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V2 n
v, n -> n -> Angle n
forall n. RealFloat n => n -> n -> Angle n
atan2A n
y n
x))
              (\(n
r,Angle n
θ)      -> n -> n -> V2 n
forall a. a -> a -> V2 a
V2 (n
r n -> n -> n
forall a. Num a => a -> a -> a
* Angle n -> n
forall n. Floating n => Angle n -> n
cosA Angle n
θ) (n
r n -> n -> n
forall a. Num a => a -> a -> a
* Angle n -> n
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 :: Lens' (Point v n) n
_r = (v n -> f (v n)) -> Point v n -> f (Point v n)
forall (g :: * -> *) a. Lens' (Point g a) (g a)
lensP ((v n -> f (v n)) -> Point v n -> f (Point v n))
-> ((n -> f n) -> v n -> f (v n))
-> (n -> f n)
-> Point v n
-> f (Point v n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> f n) -> v n -> f (v n)
forall (t :: * -> *) n. (HasR t, RealFloat n) => Lens' (t n) n
_r
  {-# INLINE _r #-}

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

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