{- |
  This module provides the 'BBox1' type (mainly for completeness).
-}

module Data.BoundingBox.B1 where

import Data.Vector.Class
import Data.Vector.V1
import Data.BoundingBox.Range as R

-- | The 'BBox1' type is basically a 'Range', but all the operations over it work with 'Vector1' (which is really 'Scalar'). While it's called a bounding /box/, a 1-dimensional box is in truth a simple line interval, just like 'Range'.
newtype BBox1 = BBox1 {range :: Range} deriving (Eq, Show)

-- | Given two vectors, construct a bounding box (swapping the endpoints if necessary).
bounds :: Vector1 -> Vector1 -> BBox1
bounds (Vector1 xa) (Vector1 xb) = BBox1 $ R.bounds xa xb

-- | Test whether a 'Vector1' lies within a 'BBox1'.
within_bounds :: Vector1 -> BBox1 -> Bool
within_bounds (Vector1 x) (BBox1 r) = x `R.within_bounds` r

-- | Return the minimum endpoint for a 'BBox1'.
min_bound :: BBox1 -> Vector1
min_bound = Vector1 . R.min_bound . range

-- | Return the maximum endpoint for a 'BBox1'.
max_bound :: BBox1 -> Vector1
max_bound = Vector1 . R.max_bound . range

-- | Take the union of two 'BBox1' values. The result is a new 'BBox1' that contains all the points the original boxes contained, plus any extra space between them.
union :: BBox1 -> BBox1 -> BBox1
union (BBox1 r0) (BBox1 r1) = BBox1 (r0 `R.union` r1)

-- | Take the intersection of two 'BBox1' values. If the boxes do not overlap, return 'Nothing'. Otherwise return a 'BBox1' containing only the points common to both argument boxes.
isect :: BBox1 -> BBox1 -> Maybe BBox1
isect (BBox1 r0) (BBox1 r1) = do
  r <- (r0 `R.isect` r1)
  return (BBox1 r)