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 :: Solid -> Maybe (V3 Double, V3 Double)
axisAlignedBoundingBox Solid
s =  
    if Solid -> Double
volume Solid
s Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
0
        then Maybe (V3 Double, V3 Double)
forall a. Maybe a
Nothing 
        else (V3 Double, V3 Double) -> Maybe (V3 Double, V3 Double)
forall a. a -> Maybe a
Just ((V3 Double, V3 Double) -> Maybe (V3 Double, V3 Double))
-> (Acquire (V3 Double, V3 Double) -> (V3 Double, V3 Double))
-> Acquire (V3 Double, V3 Double)
-> Maybe (V3 Double, V3 Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Acquire (V3 Double, V3 Double) -> (V3 Double, V3 Double)
forall a. Acquire a -> a
unsafeFromAcquire (Acquire (V3 Double, V3 Double) -> Maybe (V3 Double, V3 Double))
-> Acquire (V3 Double, V3 Double) -> Maybe (V3 Double, V3 Double)
forall a b. (a -> b) -> a -> b
$ do
            Ptr Shape
solid <- Solid -> Acquire (Ptr Shape)
acquireSolid Solid
s
            Ptr Box
theBox <- Acquire (Ptr Box)
Bnd.Box.new
            IO () -> Acquire ()
forall a. IO a -> Acquire a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Acquire ()) -> IO () -> Acquire ()
forall a b. (a -> b) -> a -> b
$ Ptr Shape -> Ptr Box -> Bool -> Bool -> IO ()
BRepBndLib.addOptimal Ptr Shape
solid Ptr Box
theBox Bool
True Bool
False
            V3 Double
p1 <- IO (V3 Double) -> Acquire (V3 Double)
forall a. IO a -> Acquire a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (V3 Double) -> Acquire (V3 Double))
-> (Ptr Pnt -> IO (V3 Double)) -> Ptr Pnt -> Acquire (V3 Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Pnt -> IO (V3 Double)
gpPntToV3 (Ptr Pnt -> Acquire (V3 Double))
-> Acquire (Ptr Pnt) -> Acquire (V3 Double)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr Box -> Acquire (Ptr Pnt)
Bnd.Box.cornerMin Ptr Box
theBox
            V3 Double
p2 <- IO (V3 Double) -> Acquire (V3 Double)
forall a. IO a -> Acquire a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (V3 Double) -> Acquire (V3 Double))
-> (Ptr Pnt -> IO (V3 Double)) -> Ptr Pnt -> Acquire (V3 Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr Pnt -> IO (V3 Double)
gpPntToV3 (Ptr Pnt -> Acquire (V3 Double))
-> Acquire (Ptr Pnt) -> Acquire (V3 Double)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr Box -> Acquire (Ptr Pnt)
Bnd.Box.cornerMax Ptr Box
theBox
            (V3 Double, V3 Double) -> Acquire (V3 Double, V3 Double)
forall a. a -> Acquire a
forall (m :: * -> *) a. Monad m => a -> m a
return (V3 Double
p1, V3 Double
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 :: (V3 Double, V3 Double) -> Solid
aabbToSolid (V3 Double
lo, V3 Double
hi) = V3 Double -> Solid -> Solid
forall a. Transformable a => V3 Double -> a -> a
translate V3 Double
lo (Solid -> Solid) -> Solid -> Solid
forall a b. (a -> b) -> a -> b
$ V3 Double -> Solid
box (V3 Double
hi V3 Double -> V3 Double -> V3 Double
forall a. Num a => V3 a -> V3 a -> V3 a
forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^-^ V3 Double
lo)