{- |
  This module provides the 'BBox3' type for 3-dimensional bounding boxes (\"bounding volumes\").
-}

module Data.BoundingBox.B3 where

import Data.Vector.Class
import Data.Vector.V3
import qualified Data.BoundingBox.Range as R

-- | A 'BBox3' is a 3D bounding box (aligned to the coordinate axies).
data BBox3 = BBox3 {BBox3 -> Scalar
minX, BBox3 -> Scalar
minY, BBox3 -> Scalar
minZ, BBox3 -> Scalar
maxX, BBox3 -> Scalar
maxY, BBox3 -> Scalar
maxZ :: {-# UNPACK #-} !Scalar} deriving (BBox3 -> BBox3 -> Bool
(BBox3 -> BBox3 -> Bool) -> (BBox3 -> BBox3 -> Bool) -> Eq BBox3
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BBox3 -> BBox3 -> Bool
== :: BBox3 -> BBox3 -> Bool
$c/= :: BBox3 -> BBox3 -> Bool
/= :: BBox3 -> BBox3 -> Bool
Eq, Int -> BBox3 -> ShowS
[BBox3] -> ShowS
BBox3 -> String
(Int -> BBox3 -> ShowS)
-> (BBox3 -> String) -> ([BBox3] -> ShowS) -> Show BBox3
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BBox3 -> ShowS
showsPrec :: Int -> BBox3 -> ShowS
$cshow :: BBox3 -> String
show :: BBox3 -> String
$cshowList :: [BBox3] -> ShowS
showList :: [BBox3] -> ShowS
Show)

-- | Return the X-range that this bounding box covers.
rangeX :: BBox3 -> R.Range
rangeX :: BBox3 -> Range
rangeX BBox3
b = Scalar -> Scalar -> Range
R.Range (BBox3 -> Scalar
minX BBox3
b) (BBox3 -> Scalar
maxX BBox3
b)

-- | Return the Y-range that this bounding box covers.
rangeY :: BBox3 -> R.Range
rangeY :: BBox3 -> Range
rangeY BBox3
b = Scalar -> Scalar -> Range
R.Range (BBox3 -> Scalar
minY BBox3
b) (BBox3 -> Scalar
maxY BBox3
b)

-- | Return the Z-range that this bounding box covers.
rangeZ :: BBox3 -> R.Range
rangeZ :: BBox3 -> Range
rangeZ BBox3
b = Scalar -> Scalar -> Range
R.Range (BBox3 -> Scalar
minZ BBox3
b) (BBox3 -> Scalar
maxZ BBox3
b)

-- | Given ranges for each coordinate axis, construct a bounding box.
rangeXYZ :: R.Range -> R.Range -> R.Range -> BBox3
rangeXYZ :: Range -> Range -> Range -> BBox3
rangeXYZ (R.Range Scalar
x0 Scalar
x1) (R.Range Scalar
y0 Scalar
y1) (R.Range Scalar
z0 Scalar
z1) = Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> BBox3
BBox3 Scalar
x0 Scalar
y0 Scalar
z0 Scalar
x1 Scalar
y1 Scalar
z1

-- | Given a pair of corner points, construct a bounding box. (The points must be from opposite corners, but it doesn't matter /which/ corners nor which order they are given in.)
bound_corners :: Vector3 -> Vector3 -> BBox3
bound_corners :: Vector3 -> Vector3 -> BBox3
bound_corners (Vector3 Scalar
xa Scalar
ya Scalar
za) (Vector3 Scalar
xb Scalar
yb Scalar
zb) = Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> BBox3
BBox3 (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
xa Scalar
xb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
ya Scalar
yb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
za Scalar
zb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
xa Scalar
xb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
ya Scalar
yb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
za Scalar
zb)

-- | Find the bounds of a list of points. (Throws an exception if the list is empty.)
bound_points :: [Vector3] -> BBox3
bound_points :: [Vector3] -> BBox3
bound_points [Vector3]
ps =
  let
    xs :: [Scalar]
xs = (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3x [Vector3]
ps
    ys :: [Scalar]
ys = (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3y [Vector3]
ps
    zs :: [Scalar]
zs = (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3z [Vector3]
ps
  in Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> BBox3
BBox3 ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Scalar]
xs) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Scalar]
ys) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Scalar]
zs) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Scalar]
xs) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Scalar]
ys) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Scalar]
zs)

-- | Test whether a given 3D vector is inside this bounding box.
within_bounds :: Vector3 -> BBox3 -> Bool
within_bounds :: Vector3 -> BBox3 -> Bool
within_bounds (Vector3 Scalar
x Scalar
y Scalar
z) BBox3
b =
  Scalar
x Scalar -> Range -> Bool
`R.within_bounds` (BBox3 -> Range
rangeX BBox3
b) Bool -> Bool -> Bool
&&
  Scalar
y Scalar -> Range -> Bool
`R.within_bounds` (BBox3 -> Range
rangeY BBox3
b) Bool -> Bool -> Bool
&&
  Scalar
z Scalar -> Range -> Bool
`R.within_bounds` (BBox3 -> Range
rangeZ BBox3
b)

-- | Return the minimum values for all coordinates.
min_point :: BBox3 -> Vector3
min_point :: BBox3 -> Vector3
min_point (BBox3 Scalar
x0 Scalar
y0 Scalar
z0 Scalar
x1 Scalar
y1 Scalar
z1) = Scalar -> Scalar -> Scalar -> Vector3
Vector3 Scalar
x0 Scalar
y0 Scalar
z0

-- | Return the maximum values for all coordinates.
max_point :: BBox3 -> Vector3
max_point :: BBox3 -> Vector3
max_point (BBox3 Scalar
x0 Scalar
y0 Scalar
z0 Scalar
x1 Scalar
y1 Scalar
z1) = Scalar -> Scalar -> Scalar -> Vector3
Vector3 Scalar
x1 Scalar
y1 Scalar
z1

-- | Take the union of two bounding boxes. The result is a new bounding box that contains all the points the original boxes contained, plus any extra space between them.
union :: BBox3 -> BBox3 -> BBox3
union :: BBox3 -> BBox3 -> BBox3
union BBox3
b0 BBox3
b1 =
  let
    rx :: Range
rx = (BBox3 -> Range
rangeX BBox3
b0) Range -> Range -> Range
`R.union` (BBox3 -> Range
rangeX BBox3
b1)
    ry :: Range
ry = (BBox3 -> Range
rangeY BBox3
b0) Range -> Range -> Range
`R.union` (BBox3 -> Range
rangeY BBox3
b1)
    rz :: Range
rz = (BBox3 -> Range
rangeZ BBox3
b0) Range -> Range -> Range
`R.union` (BBox3 -> Range
rangeZ BBox3
b1)
  in Range -> Range -> Range -> BBox3
rangeXYZ Range
rx Range
ry Range
rz

-- | Take the intersection of two bounding boxes. If the boxes do not overlap, return 'Nothing'. Otherwise return a new bounding box containing only the points common to both argument boxes.
isect :: BBox3 -> BBox3 -> Maybe BBox3
isect :: BBox3 -> BBox3 -> Maybe BBox3
isect BBox3
b0 BBox3
b1 = do
  Range
rx <- (BBox3 -> Range
rangeX BBox3
b0) Range -> Range -> Maybe Range
`R.isect` (BBox3 -> Range
rangeX BBox3
b1)
  Range
ry <- (BBox3 -> Range
rangeY BBox3
b0) Range -> Range -> Maybe Range
`R.isect` (BBox3 -> Range
rangeY BBox3
b1)
  Range
rz <- (BBox3 -> Range
rangeZ BBox3
b0) Range -> Range -> Maybe Range
`R.isect` (BBox3 -> Range
rangeZ BBox3
b1)
  BBox3 -> Maybe BBox3
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (Range -> Range -> Range -> BBox3
rangeXYZ Range
rx Range
ry Range
rz)

-- | Efficiently compute the union of a list of bounding boxes.
unions :: [BBox3] -> BBox3
unions :: [BBox3] -> BBox3
unions [BBox3]
bs =
  let
    minP :: [Vector3]
minP = (BBox3 -> Vector3) -> [BBox3] -> [Vector3]
forall a b. (a -> b) -> [a] -> [b]
map BBox3 -> Vector3
min_point [BBox3]
bs
    maxP :: [Vector3]
maxP = (BBox3 -> Vector3) -> [BBox3] -> [Vector3]
forall a b. (a -> b) -> [a] -> [b]
map BBox3 -> Vector3
max_point [BBox3]
bs
  in
    Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> Scalar -> BBox3
BBox3
      ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3x [Vector3]
minP) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3y [Vector3]
minP) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3z [Vector3]
minP)
      ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3x [Vector3]
maxP) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3y [Vector3]
maxP) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Vector3 -> Scalar) -> [Vector3] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Vector3 -> Scalar
v3z [Vector3]
maxP)