{-# 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 :: p (n, n, n) (f (n, n, n)) -> p (V3 n) (f (V3 n))
r3Iso = (V3 n -> (n, n, n))
-> ((n, n, n) -> V3 n) -> Iso (V3 n) (V3 n) (n, n, n) (n, n, n)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso V3 n -> (n, n, n)
forall n. V3 n -> (n, n, n)
unr3 (n, n, n) -> V3 n
forall n. (n, n, n) -> V3 n
r3

-- | Construct a 3D vector from a triple of components.
r3 :: (n, n, n) -> V3 n
r3 :: (n, n, n) -> V3 n
r3 (n
x,n
y,n
z) = n -> n -> n -> V3 n
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 :: n -> n -> n -> V3 n
mkR3 = n -> n -> n -> V3 n
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 :: 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 :: (n, n, n) -> P3 n
p3 = V3 n -> P3 n
forall (f :: * -> *) a. f a -> Point f a
P (V3 n -> P3 n) -> ((n, n, n) -> V3 n) -> (n, n, n) -> P3 n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n, n, n) -> V3 n
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 :: 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 :: p (n, n, n) (f (n, n, n)) -> p (P3 n) (f (P3 n))
p3Iso = (P3 n -> (n, n, n))
-> ((n, n, n) -> P3 n) -> Iso (P3 n) (P3 n) (n, n, n) (n, n, n)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso P3 n -> (n, n, n)
forall n. P3 n -> (n, n, n)
unp3 (n, n, n) -> P3 n
forall n. (n, n, n) -> P3 n
p3

-- | Curried version of `r3`.
mkP3 :: n -> n -> n -> P3 n
mkP3 :: n -> n -> n -> P3 n
mkP3 n
x n
y n
z = (n, n, n) -> P3 n
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 = Transformation (V (V3 n)) (N (V3 n)) -> V3 n -> V3 n
forall (v :: * -> *) n. Transformation v n -> v n -> v n
apply

r3SphericalIso :: RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso :: Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso = (V3 n -> (n, Angle n, Angle n))
-> ((n, Angle n, Angle n) -> V3 n)
-> Iso' (V3 n) (n, Angle n, Angle n)
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) -> (V3 n -> n
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V3 n
v, n -> n -> Angle n
forall n. RealFloat n => n -> n -> Angle n
atan2A n
y n
x, n -> Angle n
forall n. Floating n => n -> Angle n
acosA (n
z n -> n -> n
forall a. Fractional a => a -> a -> a
/ V3 n -> n
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm V3 n
v)))
  (\(n
r,Angle n
θ,Angle n
φ)   -> n -> n -> n -> V3 n
forall a. a -> a -> a -> V3 a
V3 (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 -> n -> n
forall a. Num a => a -> a -> a
* Angle n -> n
forall n. Floating n => Angle n -> n
sinA 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
θ n -> n -> n
forall a. Num a => a -> a -> a
* Angle n -> n
forall n. Floating n => Angle n -> n
sinA Angle n
φ) (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
φ))

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

instance HasR V3 where
  _r :: Lens' (V3 n) n
_r = ((n, Angle n, Angle n) -> f (n, Angle n, Angle n))
-> V3 n -> f (V3 n)
forall n. RealFloat n => Iso' (V3 n) (n, Angle n, Angle n)
r3SphericalIso (((n, Angle n, Angle n) -> f (n, Angle n, Angle n))
 -> V3 n -> f (V3 n))
-> ((n -> f n) -> (n, Angle n, Angle n) -> f (n, Angle n, Angle n))
-> (n -> f n)
-> V3 n
-> f (V3 n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> f n) -> (n, Angle n, Angle n) -> f (n, Angle n, Angle n)
forall s t a b. Field1 s t a b => Lens s t a b
_1

instance HasTheta V3 where
  _theta :: Lens' (V3 n) (Angle n)
_theta = ((n, Angle n, n) -> f (n, Angle n, n)) -> V3 n -> f (V3 n)
forall n. RealFloat n => Iso' (V3 n) (n, Angle n, n)
r3CylindricalIso (((n, Angle n, n) -> f (n, Angle n, n)) -> V3 n -> f (V3 n))
-> ((Angle n -> f (Angle n))
    -> (n, Angle n, n) -> f (n, Angle n, n))
-> (Angle n -> f (Angle n))
-> V3 n
-> f (V3 n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Angle n -> f (Angle n)) -> (n, Angle n, n) -> f (n, Angle n, n)
forall s t a b. Field2 s t a b => Lens s t a b
_2

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