```{- |
Bounding boxes of various numbers of dimensions, plus a class for generically handling them.
-}

{-# LANGUAGE TypeFamilies #-}

module Data.BoundingBox
(
-- * Class
BoundingBox (..),

-- * Types

-- ** 1 dimension
R.Range (), B1.BBox1 (),

-- ** 2 dimensions
B2.BBox2 (),

-- ** 3 dimensions
B3.BBox3 (),

-- ** 4 dimensions
B4.BBox4 ()
)
where

import Data.Vector
import qualified Data.BoundingBox.Range as R
import qualified Data.BoundingBox.B1    as B1
import qualified Data.BoundingBox.B2    as B2
import qualified Data.BoundingBox.B3    as B3
import qualified Data.BoundingBox.B4    as B4

-- | Class for dealing with bounding boxes.
class BoundingBox b where
-- | The type of vectors that this bounding box deals with.
type Point b :: *

-- | Given two corner points, construct a bounding box containing them both. (You can use any two points, given in any order, provided that they are from /opposite/ corners.)
bounds :: Point b -> Point b -> b

-- | Return a point containing the minimum values for all coordinates.
min_bound :: b -> Point b

-- | Return a point containing the maximum values for all coordinates.
max_bound :: b -> Point b

-- | Test whether a given point lies within a given bounding box.
within_bounds :: Point b -> b -> Bool

-- | Take the union of two bounding boxes. The result is a new bounding box that contains every point that the original pair of boxes contained, and probably some extra space as well.
union :: b -> b -> b

-- | Take the intersection of two bounding boxes. If the boxes do not overlap, return 'Nothing'. Otherwise return a bounding box containing only the points common to both original bounding boxes.
isect :: b -> b -> Maybe b

instance BoundingBox R.Range where
type Point R.Range = Scalar
bounds        = R.bounds
min_bound     = R.min_bound
max_bound     = R.max_bound
within_bounds = R.within_bounds
union         = R.union
isect         = R.isect

instance BoundingBox B1.BBox1 where
type Point B1.BBox1 = Vector1
bounds        = B1.bounds
min_bound     = B1.min_bound
max_bound     = B1.max_bound
within_bounds = B1.within_bounds
union         = B1.union
isect         = B1.isect

instance BoundingBox B2.BBox2 where
type Point B2.BBox2 = Vector2
bounds        = B2.bounds
min_bound     = B2.min_bound
max_bound     = B2.max_bound
within_bounds = B2.within_bounds
union         = B2.union
isect         = B2.isect

instance BoundingBox B3.BBox3 where
type Point B3.BBox3 = Vector3
bounds        = B3.bounds
min_bound     = B3.min_bound
max_bound     = B3.max_bound
within_bounds = B3.within_bounds
union         = B3.union
isect         = B3.isect

instance BoundingBox B4.BBox4 where
type Point B4.BBox4 = Vector4
bounds        = B4.bounds
min_bound     = B4.min_bound
max_bound     = B4.max_bound
within_bounds = B4.within_bounds
union         = B4.union
isect         = B4.isect
```