    {-# 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 (x :: n
    x,y :: n
    y,z :: 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 x :: n
    x y :: n
    y z :: 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 x :: n
    x y :: n
    y z :: 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 x :: n
    x y :: n
    y z :: 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 x :: n
    x y :: n
    y z :: 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)))
      (\(r :: 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 x :: n
    x y :: n
    y z :: 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))
      (\(r :: n
    r,θ :: Angle n
    θ,z :: 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