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

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

module Diagrams.ThreeD.Types
       ( -- * 3D Euclidean space
         r3, unr3, mkR3
       , p3, unp3, mkP3
       , r3Iso, p3Iso, project
       , r3SphericalIso, r3CylindricalIso
       , V3 (..), P3,      T3
       , R1 (..), R2 (..), R3 (..)

       ) where

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

import           Diagrams.Angle
import           Diagrams.Core
import           Diagrams.Points
import           Diagrams.TwoD.Types

import           Linear.Metric
import           Linear.V3           as V

------------------------------------------------------------
-- 3D Euclidean space

-- Basic R3 types

type P3 = Point V3
type T3 = Transformation V3

r3Iso :: Iso' (V3 n) (n, n, n)
r3Iso :: forall n. Iso' (V3 n) (n, n, n)
r3Iso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall n. V3 n -> (n, n, n)
unr3 forall n. (n, n, n) -> V3 n
r3

-- | Construct a 3D vector from a triple of components.
r3 :: (n, n, n) -> V3 n
r3 :: forall n. (n, n, n) -> V3 n
r3 (n
x,n
y,n
z) = forall a. a -> a -> a -> V3 a
V3 n
x n
y n
z

-- | Curried version of `r3`.
mkR3 :: n -> n -> n -> V3 n
mkR3 :: forall a. a -> a -> a -> V3 a
mkR3 = forall a. a -> a -> a -> V3 a
V3

-- | Convert a 3D vector back into a triple of components.
unr3 :: V3 n -> (n, n, n)
unr3 :: forall n. V3 n -> (n, n, n)
unr3 (V3 n
x n
y n
z) = (n
x,n
y,n
z)

-- | Construct a 3D point from a triple of coordinates.
p3 :: (n, n, n) -> P3 n
p3 :: forall n. (n, n, n) -> P3 n
p3 = forall (f :: * -> *) a. f a -> Point f a
P forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. (n, n, n) -> V3 n
r3

-- | Convert a 3D point back into a triple of coordinates.
unp3 :: P3 n -> (n, n, n)
unp3 :: forall n. P3 n -> (n, n, n)
unp3 (P (V3 n
x n
y n
z)) = (n
x,n
y,n
z)

p3Iso :: Iso' (P3 n) (n, n, n)
p3Iso :: forall n. Iso' (P3 n) (n, n, n)
p3Iso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall n. P3 n -> (n, n, n)
unp3 forall n. (n, n, n) -> P3 n
p3

-- | Curried version of `r3`.
mkP3 :: n -> n -> n -> P3 n
mkP3 :: forall n. n -> n -> n -> P3 n
mkP3 n
x n
y n
z = forall n. (n, n, n) -> P3 n
p3 (n
x, n
y, n
z)

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

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

r3SphericalIso :: RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso :: forall n. RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso
  (\v :: V3 n
v@(V3 n
x n
y n
z) -> (forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V3 n
v, forall n. RealFloat n => n -> n -> Angle n
atan2A n
y n
x, forall n. Floating n => n -> Angle n
acosA (n
z forall a. Fractional a => a -> a -> a
/ forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V3 n
v)))
  (\(n
r,Angle n
θ,Angle n
φ)   -> forall a. a -> a -> a -> V3 a
V3 (n
r forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
cosA Angle n
θ forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
sinA Angle n
φ) (n
r forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
sinA Angle n
θ forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
sinA Angle n
φ) (n
r forall a. Num a => a -> a -> a
* forall n. Floating n => Angle n -> n
cosA Angle n
φ))

r3CylindricalIso :: RealFloat n => Iso' (V3 n) (n, Angle n, n)
r3CylindricalIso :: forall n. RealFloat n => Iso' (V3 n) (n, Angle n, n)
r3CylindricalIso = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso
  (\(V3 n
x n
y n
z) -> (forall a. Floating a => a -> a
sqrt forall a b. (a -> b) -> a -> b
$ n
xforall a. Num a => a -> a -> a
*n
x forall a. Num a => a -> a -> a
+ n
yforall a. Num a => a -> a -> a
*n
y, forall n. RealFloat n => n -> n -> Angle n
atan2A n
y n
x, n
z))
  (\(n
r,Angle n
θ,n
z)    -> forall a. a -> a -> a -> V3 a
V3 (n
rforall a. Num a => a -> a -> a
*forall n. Floating n => Angle n -> n
cosA Angle n
θ) (n
rforall a. Num a => a -> a -> a
*forall n. Floating n => Angle n -> n
sinA Angle n
θ) n
z)

instance HasR V3 where
  _r :: forall n. RealFloat n => Lens' (V3 n) n
_r = forall n. RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso 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

instance HasTheta V3 where
  _theta :: forall n. RealFloat n => Lens' (V3 n) (Angle n)
_theta = forall n. RealFloat n => Iso' (V3 n) (n, Angle n, n)
r3CylindricalIso 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

instance HasPhi V3 where
  _phi :: forall n. RealFloat n => Lens' (V3 n) (Angle n)
_phi = forall n. RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. Field3 s t a b => Lens s t a b
_3