{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies     #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.TwoD.Size
-- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Utilities for working with sizes of two-dimensional objects.
--
-----------------------------------------------------------------------------
module Diagrams.TwoD.Size
       (
         -- ** Computing sizes
         width, height
       , extentX, extentY

         -- ** Specifying sizes
       , mkSizeSpec2D
       , mkWidth
       , mkHeight
       , dims2D

       ) where

import           Diagrams.Core
import           Diagrams.Core.Envelope
import           Diagrams.Size
import           Diagrams.TwoD.Types
import           Diagrams.TwoD.Vector

------------------------------------------------------------
-- Computing diagram sizes
------------------------------------------------------------

-- | Compute the width of an enveloped object.
--
--   Note this is just @diameter unitX@.
width :: (InSpace V2 n a, Enveloped a) => a -> n
width :: forall n a. (InSpace V2 n a, Enveloped a) => a -> n
width = forall a (v :: * -> *) n.
(V a ~ v, N a ~ n, Enveloped a) =>
v n -> a -> n
diameter forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

-- | Compute the height of an enveloped object.
height :: (InSpace V2 n a, Enveloped a) => a -> n
height :: forall n a. (InSpace V2 n a, Enveloped a) => a -> n
height = forall a (v :: * -> *) n.
(V a ~ v, N a ~ n, Enveloped a) =>
v n -> a -> n
diameter forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | Compute the absolute x-coordinate range of an enveloped object in
--   the form @(lo,hi)@. Return @Nothing@ for objects with an empty
--   envelope.
--
--   Note this is just @extent unitX@.
extentX :: (InSpace v n a, R1 v, Enveloped a) => a -> Maybe (n, n)
extentX :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Enveloped a) =>
a -> Maybe (n, n)
extentX = forall a (v :: * -> *) n.
(V a ~ v, N a ~ n, Enveloped a) =>
v n -> a -> Maybe (n, n)
extent forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

-- | Compute the absolute y-coordinate range of an enveloped object in
--   the form @(lo,hi)@. Return @Nothing@ for objects with an empty
--   envelope.
extentY :: (InSpace v n a, R2 v, Enveloped a) => a -> Maybe (n, n)
extentY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Enveloped a) =>
a -> Maybe (n, n)
extentY = forall a (v :: * -> *) n.
(V a ~ v, N a ~ n, Enveloped a) =>
v n -> a -> Maybe (n, n)
extent forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | Make a 'SizeSpec' from possibly-specified width and height.
mkSizeSpec2D :: Num n => Maybe n -> Maybe n -> SizeSpec V2 n
mkSizeSpec2D :: forall n. Num n => Maybe n -> Maybe n -> SizeSpec V2 n
mkSizeSpec2D Maybe n
x Maybe n
y = forall (v :: * -> *) n.
(Functor v, Num n) =>
v (Maybe n) -> SizeSpec v n
mkSizeSpec (forall a. a -> a -> V2 a
V2 Maybe n
x Maybe n
y)

-- | Make a 'SizeSpec' from a width and height.
dims2D :: n -> n -> SizeSpec V2 n
dims2D :: forall n. n -> n -> SizeSpec V2 n
dims2D n
x n
y = forall (v :: * -> *) n. v n -> SizeSpec v n
dims (forall a. a -> a -> V2 a
V2 n
x n
y)

-- | Make a 'SizeSpec' with only width defined.
mkWidth :: Num n => n -> SizeSpec V2 n
mkWidth :: forall n. Num n => n -> SizeSpec V2 n
mkWidth n
w = forall (v :: * -> *) n. v n -> SizeSpec v n
dims (forall a. a -> a -> V2 a
V2 n
w n
0)

-- | Make a 'SizeSpec' with only height defined.
mkHeight :: Num n => n -> SizeSpec V2 n
mkHeight :: forall n. Num n => n -> SizeSpec V2 n
mkHeight n
h = forall (v :: * -> *) n. v n -> SizeSpec v n
dims (forall a. a -> a -> V2 a
V2 n
0 n
h)