{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies    #-}
{-# LANGUAGE TypeOperators   #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.ThreeD.Align
-- Copyright   :  (c) 2013 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Alignment combinators specialized for three dimensions.  See
-- "Diagrams.Align" for more general alignment combinators.
--
-- The basic idea is that alignment is achieved by moving diagrams'
-- local origins relative to their envelopes or traces (or some other
-- sort of boundary).  For example, to align several diagrams along
-- their tops, we first move their local origins to the upper edge of
-- their boundary (using e.g. @map 'alignZMax'@), and then put them
-- together with their local origins along a line (using e.g. 'cat'
-- from "Diagrams.Combinators").
--
-----------------------------------------------------------------------------

module Diagrams.ThreeD.Align
    ( -- * Absolute alignment
      -- ** Align by envelope
      alignXMin, alignXMax, alignYMin, alignYMax, alignZMin, alignZMax

      -- ** Align by trace
    , snugXMin, snugXMax, snugYMin, snugYMax, snugZMin, snugZMax

      -- * Relative alignment
    , alignX, snugX, alignY, snugY, alignZ, snugZ

      -- * Centering
    , centerX, centerY, centerZ
    , centerXY, centerXZ, centerYZ, centerXYZ
    , snugCenterX, snugCenterY, snugCenterZ
    , snugCenterXY, snugCenterXZ, snugCenterYZ, snugCenterXYZ

    ) where

import           Diagrams.Core

import           Diagrams.Align
import           Diagrams.ThreeD.Types
import           Diagrams.ThreeD.Vector
import           Diagrams.TwoD.Align

-- | Translate the diagram along unitX so that all points have
--   positive x-values.
alignXMin :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignXMin :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignXMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unit_X

snugXMin :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugXMin :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugXMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unit_X

-- | Translate the diagram along unitX so that all points have
-- negative x-values.
alignXMax :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignXMax :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignXMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

snugXMax :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugXMax :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugXMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX


-- | Translate the diagram along unitY so that all points have
--   positive y-values.
alignYMin :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignYMin :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignYMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unit_Y

snugYMin :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugYMin :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugYMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unit_Y

-- | Translate the diagram along unitY so that all points have
-- negative y-values.
alignYMax :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignYMax :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignYMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

snugYMax :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugYMax :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugYMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY


-- | Translate the diagram along unitZ so that all points have
--   positive z-values.
alignZMin :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignZMin :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignZMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unit_Z

snugZMin :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugZMin :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugZMin = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unit_Z

-- | Translate the diagram along unitZ so that all points have
-- negative z-values.
alignZMax :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
alignZMax :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignZMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ

snugZMax :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugZMax :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugZMax = v n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ

-- | Like 'alignX', but moving the local origin in the Z direction, with an
--   argument of @1@ corresponding to the top edge and @(-1)@ corresponding
--   to the bottom edge.
alignZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a
alignZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
n -> a -> a
alignZ = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ

-- | See the documentation for 'alignZ'.
snugZ :: (V a ~ v, N a ~ n, Alignable a, Traced a, HasOrigin a,
          R3 v, Fractional n) => n -> a -> a
snugZ :: forall a (v :: * -> *) n.
(V a ~ v, N a ~ n, Alignable a, Traced a, HasOrigin a, R3 v,
 Fractional n) =>
n -> a -> a
snugZ = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ


-- | Center the local origin along the Z-axis.
centerZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerZ = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ n
0

snugCenterZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugCenterZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterZ = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R3 v, Additive v, Num n) => v n
unitZ n
0

-- | Center along both the X- and Z-axes.
centerXZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerXZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerXZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerZ

snugCenterXZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugCenterXZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterXZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterZ


-- | Center along both the Y- and Z-axes.
centerYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerYZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerYZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerZ (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerY

snugCenterYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugCenterYZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterYZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterZ (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterY

-- | Center an object in three dimensions.
centerXYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerXYZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerXYZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerY (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerZ

snugCenterXYZ :: (InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a, Traced a) => a -> a
snugCenterXYZ :: forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterXYZ = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterY (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R3 v, Fractional n, Alignable a, HasOrigin a,
 Traced a) =>
a -> a
snugCenterZ