module Waterfall.BoundingBox.AxisAligned ( axisAlignedBoundingBox , aabbToSolid ) where import Waterfall.Internal.Solid(Solid, acquireSolid) import Waterfall.Internal.Finalizers (unsafeFromAcquire) import Waterfall.Internal.FromOpenCascade (gpPntToV3) import Waterfall.Solids (box, volume) import Waterfall.Transforms (translate) import Linear (V3 (..), (^-^)) import qualified OpenCascade.Bnd.Box as Bnd.Box import qualified OpenCascade.BRepBndLib as BRepBndLib import Control.Monad.IO.Class (liftIO) -- | Return the smallest Axis Aligned Bounding Box (AABB) that contains the Solid. -- -- If computable, the AABB is returned in the form '(lo, hi)', -- where 'lo' is the vertex of the box with the lowest individual values, -- and 'hi' is the vertex with the highest values. axisAlignedBoundingBox :: Solid -> Maybe (V3 Double, V3 Double) axisAlignedBoundingBox s = if volume s <= 0 then Nothing else Just . unsafeFromAcquire $ do solid <- acquireSolid s theBox <- Bnd.Box.new liftIO $ BRepBndLib.addOptimal solid theBox True False p1 <- liftIO . gpPntToV3 =<< Bnd.Box.cornerMin theBox p2 <- liftIO . gpPntToV3 =<< Bnd.Box.cornerMax theBox return (p1, p2) -- | A cuboid, specified by two diagonal vertices. -- -- This can be used to make a solid from the output of `axisAlignedBoundingBox` aabbToSolid :: (V3 Double, V3 Double) -- ^ if this argument input is `(lo, hi)`, one vertex of the cuboid is placed at `lo`, the oposite vertex is at `hi` -> Solid aabbToSolid (lo, hi) = translate lo $ box (hi ^-^ lo)