{- ORMOLU_DISABLE -}
-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
-- Copyright 2014 2015 2016, Julia Longtin (julial@turinglace.com)
-- Copyright 2015 2016, Mike MacHenry (mike.machenry@gmail.com)
-- Released under the GNU AGPLV3+, see LICENSE

module Graphics.Implicit.ObjectUtil.GetBox3 (getBox3) where

import Prelude(uncurry, pure, Bool(False), Either (Left, Right), (==), max, (/), (-), (+), fmap, unzip, ($), (<$>), (.), minimum, maximum, min, (>), (*), (<), abs, either, const, otherwise, take, fst, snd)

import Graphics.Implicit.Definitions
    ( Fastℕ,
      fromFastℕ,
      ExtrudeMScale(C2, C1),
      SymbolicObj3(Shared3, Cube, Sphere, Cylinder, Rotate3, Transform3, Extrude, ExtrudeOnEdgeOf, ExtrudeM, RotateExtrude),
      Box3,
      ,
      fromFastℕtoℝ,
      toScaleFn )

import Graphics.Implicit.ObjectUtil.GetBox2 (getBox2, getBox2R)

import Graphics.Implicit.ObjectUtil.GetBoxShared (corners, pointsBox, getBoxShared)

import Linear (V2(V2), V3(V3))
import qualified Linear

-- FIXME: many variables are being ignored here. no rounding for intersect, or difference.. etc.

-- Get a Box3 around the given object.
getBox3 :: SymbolicObj3 -> Box3
-- Primitives
getBox3 :: SymbolicObj3 -> Box3
getBox3 (Shared3 SharedObj SymbolicObj3 V3 ℝ
obj) = forall obj (f :: * -> *) a.
(Object obj f a, VectorStuff (f a), ComponentWiseMultable (f a),
 Fractional a, Metric f) =>
SharedObj obj f a -> (f a, f a)
getBoxShared SharedObj SymbolicObj3 V3 ℝ
obj
getBox3 (Cube V3 ℝ
size) = (forall (f :: * -> *) a. Applicative f => a -> f a
pure 0, V3 ℝ
size)
getBox3 (Sphere r) = (forall (f :: * -> *) a. Applicative f => a -> f a
pure (-r), forall (f :: * -> *) a. Applicative f => a -> f a
pure r)
getBox3 (Cylinder h r1 r2) = (forall a. a -> a -> a -> V3 a
V3 (-r) (-r) 0, forall a. a -> a -> a -> V3 a
V3 r r h ) where r :: ℝ
r = forall a. Ord a => a -> a -> a
max r1 r2
-- (Rounded) CSG
-- Simple transforms
getBox3 (Rotate3 Quaternion ℝ
q SymbolicObj3
symbObj) =
    let box :: Box3
box = SymbolicObj3 -> Box3
getBox3 SymbolicObj3
symbObj
     in forall (f :: * -> *) a.
(Applicative f, Num a, VectorStuff (f a)) =>
[f a] -> (f a, f a)
pointsBox forall a b. (a -> b) -> a -> b
$ forall a.
(Conjugate a, RealFloat a) =>
Quaternion a -> V3 a -> V3 a
Linear.rotate Quaternion ℝ
q forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall vec. VectorStuff vec => (vec, vec) -> [vec]
corners Box3
box
getBox3 (Transform3 M44 ℝ
m SymbolicObj3
symbObj) =
    let box :: Box3
box = SymbolicObj3 -> Box3
getBox3 SymbolicObj3
symbObj
     in forall (f :: * -> *) a.
(Applicative f, Num a, VectorStuff (f a)) =>
[f a] -> (f a, f a)
pointsBox forall a b. (a -> b) -> a -> b
$ forall a. Fractional a => V4 a -> V3 a
Linear.normalizePoint forall b c a. (b -> c) -> (a -> b) -> a -> c
. (M44 ℝ
m forall (m :: * -> *) (r :: * -> *) a.
(Functor m, Foldable r, Additive r, Num a) =>
m (r a) -> r a -> m a
Linear.!*) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => V3 a -> V4 a
Linear.point forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall vec. VectorStuff vec => (vec, vec) -> [vec]
corners Box3
box
-- Misc
-- 2D Based
getBox3 (Extrude SymbolicObj2
symbObj h) = (forall a. a -> a -> a -> V3 a
V3 x1 y1 0, forall a. a -> a -> a -> V3 a
V3 x2 y2 h)
    where
        (V2 x1 y1, V2 x2 y2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj
getBox3 (ExtrudeOnEdgeOf SymbolicObj2
symbObj1 SymbolicObj2
symbObj2) =
    let
        (V2 ax1 ay1, V2 ax2 ay2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj1
        (V2 bx1 by1, V2 bx2 by2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj2
    in
        (forall a. a -> a -> a -> V3 a
V3 (bx1forall a. Num a => a -> a -> a
+ax1) (by1forall a. Num a => a -> a -> a
+ax1) ay1, forall a. a -> a -> a -> V3 a
V3 (bx2forall a. Num a => a -> a -> a
+ax2) (by2forall a. Num a => a -> a -> a
+ax2) ay2)
-- FIXME: magic numbers: 0.2 and 11.
-- FIXME: this may use an approximation, based on sampling functions. generate a warning if the approximation part of this function is used.
-- FIXME: re-implement the expression system, so this can recieve a function, and determine class (constant, linear)... and implement better forms of this function.
getBox3 (ExtrudeM Either ℝ (ℝ -> ℝ)
twist ExtrudeMScale
scale Either ℝ2 (ℝ -> ℝ2)
translate SymbolicObj2
symbObj Either ℝ (ℝ2 -> ℝ)
height) =
    let
        (V2 x1 y1, V2 x2 y2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj
        (dx, dy) = (x2 forall a. Num a => a -> a -> a
- x1, y2 forall a. Num a => a -> a -> a
- y1)

        samples :: Fastℕ
        samples :: Fastℕ
samples = Fastℕ
11
        range :: [Fastℕ]
        range :: [Fastℕ]
range = [Fastℕ
0, Fastℕ
1 .. (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)]
        ([ℝ]
xrange, [ℝ]
yrange) = ( forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((\s -> x1forall a. Num a => a -> a -> a
+sforall a. Num a => a -> a -> a
*dxforall a. Fractional a => a -> a -> a
/Fastℕ -> ℝ
fromFastℕtoℝ (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fastℕ -> ℝ
fromFastℕtoℝ) [Fastℕ]
range, forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((\s -> y1forall a. Num a => a -> a -> a
+sforall a. Num a => a -> a -> a
*dyforall a. Fractional a => a -> a -> a
/Fastℕ -> ℝ
fromFastℕtoℝ (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fastℕ -> ℝ
fromFastℕtoℝ) [Fastℕ]
range)

        hfuzz :: 
        hfuzz :: ℝ
hfuzz = 0.2
        h :: ℝ
h = case Either ℝ (ℝ2 -> ℝ)
height of
              Left hval -> hval
              Right ℝ2 -> ℝ
hfun -> hmax forall a. Num a => a -> a -> a
+ hfuzzforall a. Num a => a -> a -> a
*(hmaxforall a. Num a => a -> a -> a
-hmin)
                where
                    hs :: [ℝ]
hs = [ℝ2 -> ℝ
hfun forall a b. (a -> b) -> a -> b
$ forall a. a -> a -> V2 a
V2 x y | x <- [ℝ]
xrange, y <- [ℝ]
yrange]
                    (hmin, hmax) = (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
hs, forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
hs)
        hrange :: [ℝ]
hrange = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((forall a. Fractional a => a -> a -> a
/ Fastℕ -> ℝ
fromFastℕtoℝ (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (hforall a. Num a => a -> a -> a
*) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fastℕ -> ℝ
fromFastℕtoℝ) [Fastℕ]
range

        (twistXmin, twistYmin, twistXmax, twistYmax) =
          let
            both :: (t -> b) -> (t, t) -> (b, b)
both t -> b
f (t
a, t
b) = (t -> b
f t
a, t -> b
f t
b)
            (V2 scalex' scaley') = case ExtrudeMScale
scale of
              C1 s -> forall a. a -> a -> V2 a
V2 s s
              C2 ℝ2
s -> ℝ2
s
              ExtrudeMScale
s -> forall a. (a, a) -> V2 a
pack forall a b. (a -> b) -> a -> b
$ forall {t} {b}. (t -> b) -> (t, t) -> (b, b)
both forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. V2 a -> (a, a)
unpack forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Num a => a -> a
abs forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExtrudeMScale -> ℝ -> ℝ2
toScaleFn ExtrudeMScale
s forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ℝ]
hrange
            smin :: a -> a -> a
smin a
s a
v = forall a. Ord a => a -> a -> a
min a
v (a
s forall a. Num a => a -> a -> a
* a
v)
            smax :: a -> a -> a
smax a
s a
v = forall a. Ord a => a -> a -> a
max a
v (a
s forall a. Num a => a -> a -> a
* a
v)
            -- FIXME: assumes minimums are negative, and maximums are positive.
            scaleEach :: (ℝ2, ℝ2) -> (ℝ, ℝ, ℝ, ℝ)
scaleEach (V2 d1 d2, V2 d3 d4) = (scalex' forall a. Num a => a -> a -> a
* d1, scaley' forall a. Num a => a -> a -> a
* d2, scalex' forall a. Num a => a -> a -> a
* d3, scaley' forall a. Num a => a -> a -> a
* d4)
          in case Either ℝ (ℝ -> ℝ)
twist of
            Left twval -> if twval forall a. Eq a => a -> a -> Bool
== 0
                          then (forall {a}. (Ord a, Num a) => a -> a -> a
smin scalex' x1, forall {a}. (Ord a, Num a) => a -> a -> a
smin scaley' y1, forall {a}. (Ord a, Num a) => a -> a -> a
smax scalex' x2, forall {a}. (Ord a, Num a) => a -> a -> a
smax scaley' y2)
                          else (ℝ2, ℝ2) -> (ℝ, ℝ, ℝ, ℝ)
scaleEach forall a b. (a -> b) -> a -> b
$ SymbolicObj2 -> ℝ -> (ℝ2, ℝ2)
getBox2R SymbolicObj2
symbObj twval
            Right ℝ -> ℝ
_  -> (ℝ2, ℝ2) -> (ℝ, ℝ, ℝ, ℝ)
scaleEach forall a b. (a -> b) -> a -> b
$ SymbolicObj2 -> ℝ -> (ℝ2, ℝ2)
getBox2R SymbolicObj2
symbObj 360 -- we can't range functions yet, so assume a full circle.

        (tminx, tmaxx, tminy, tmaxy) =
          let
            tvalsx :: ( -> V2 ) -> []
            tvalsx :: (ℝ -> ℝ2) -> [ℝ]
tvalsx ℝ -> ℝ2
tfun = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. V2 a -> (a, a)
unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. ℝ -> ℝ2
tfun) [ℝ]
hrange
            tvalsy :: ( -> V2 ) -> []
            tvalsy :: (ℝ -> ℝ2) -> [ℝ]
tvalsy ℝ -> ℝ2
tfun = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. V2 a -> (a, a)
unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. ℝ -> ℝ2
tfun) [ℝ]
hrange
          in case Either ℝ2 (ℝ -> ℝ2)
translate of
            Left  (V2 tvalx tvaly) -> (tvalx, tvalx, tvaly, tvaly)
            Right ℝ -> ℝ2
tfun -> ( forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum forall a b. (a -> b) -> a -> b
$ (ℝ -> ℝ2) -> [ℝ]
tvalsx ℝ -> ℝ2
tfun
                          , forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall a b. (a -> b) -> a -> b
$ (ℝ -> ℝ2) -> [ℝ]
tvalsx ℝ -> ℝ2
tfun
                          , forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum forall a b. (a -> b) -> a -> b
$ (ℝ -> ℝ2) -> [ℝ]
tvalsy ℝ -> ℝ2
tfun
                          , forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall a b. (a -> b) -> a -> b
$ (ℝ -> ℝ2) -> [ℝ]
tvalsy ℝ -> ℝ2
tfun
                          )
    in
        (forall a. a -> a -> a -> V3 a
V3 (twistXmin forall a. Num a => a -> a -> a
+ tminx) (twistYmin forall a. Num a => a -> a -> a
+ tminy) 0, forall a. a -> a -> a -> V3 a
V3 (twistXmax forall a. Num a => a -> a -> a
+ tmaxx) (twistYmax forall a. Num a => a -> a -> a
+ tmaxy) h)
-- Note: Assumes x2 is always greater than x1.
-- FIXME: Insert the above assumption as an assertion in the type system?
getBox3 (RotateExtrude _ (Left (V2 xshift yshift)) Either ℝ (ℝ -> ℝ)
_ SymbolicObj2
symbObj) =
    let
        (V2 _ y1, V2 x2 y2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj
        r :: ℝ
r = forall a. Ord a => a -> a -> a
max x2 (x2 forall a. Num a => a -> a -> a
+ xshift)
    in
        (forall a. a -> a -> a -> V3 a
V3 (-r) (-r) forall a b. (a -> b) -> a -> b
$ forall a. Ord a => a -> a -> a
min y1 (y1 forall a. Num a => a -> a -> a
+ yshift), forall a. a -> a -> a -> V3 a
V3 r r forall a b. (a -> b) -> a -> b
$ forall a. Ord a => a -> a -> a
max y2 (y2 forall a. Num a => a -> a -> a
+ yshift))
-- FIXME: magic numbers: 0.1, 1.1, and 11.
-- FIXME: this may use an approximation, based on sampling functions. generate a warning if the approximation part of this function is used.
-- FIXME: re-implement the expression system, so this can recieve a function, and determine class (constant, linear)... and implement better forms of this function.
getBox3 (RotateExtrude rot (Right ℝ -> ℝ2
f) Either ℝ (ℝ -> ℝ)
rotate SymbolicObj2
symbObj) =
    let
        samples :: Fastℕ
        samples :: Fastℕ
samples = Fastℕ
11
        xfuzz :: 
        xfuzz :: ℝ
xfuzz = 1.1
        yfuzz :: 
        yfuzz :: ℝ
yfuzz=0.1
        range :: [Fastℕ]
        range :: [Fastℕ]
range = [Fastℕ
0, Fastℕ
1 .. (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)]
        step :: ℝ
step = rotforall a. Fractional a => a -> a -> a
/Fastℕ -> ℝ
fromFastℕtoℝ (Fastℕ
samplesforall a. Num a => a -> a -> a
-Fastℕ
1)
        (V2 x1 y1, V2 x2 y2) = SymbolicObj2 -> (ℝ2, ℝ2)
getBox2 SymbolicObj2
symbObj
        ([ℝ]
xrange, [ℝ]
yrange) = forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. V2 a -> (a, a)
unpack forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take (forall n. FastN n => Fastℕ -> n
fromFastℕ Fastℕ
samples) forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ℝ -> ℝ2
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. (stepforall a. Num a => a -> a -> a
*) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fastℕ -> ℝ
fromFastℕtoℝ) [Fastℕ]
range
        xmax :: ℝ
xmax = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
xrange
        ymax :: ℝ
ymax = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [ℝ]
yrange
        ymin :: ℝ
ymin = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [ℝ]
yrange
        xmax' :: ℝ
xmax' | xmax forall a. Ord a => a -> a -> Bool
> 0 = xmax forall a. Num a => a -> a -> a
* xfuzz
              | xmax forall a. Ord a => a -> a -> Bool
< - x1 = 0
              | Bool
otherwise = xmax
        ymax' :: ℝ
ymax' = ymax forall a. Num a => a -> a -> a
+ yfuzz forall a. Num a => a -> a -> a
* (ymax forall a. Num a => a -> a -> a
- ymin)
        ymin' :: ℝ
ymin' = ymin forall a. Num a => a -> a -> a
- yfuzz forall a. Num a => a -> a -> a
* (ymax forall a. Num a => a -> a -> a
- ymin)
        (r, _, _) = if forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. Eq a => a -> a -> Bool
==0) (forall a b. a -> b -> a
const Bool
False) Either ℝ (ℝ -> ℝ)
rotate
            then let
                s :: ℝ
s = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Num a => a -> a
abs [x2, y1, y2]
            in (s forall a. Num a => a -> a -> a
+ xmax', s forall a. Num a => a -> a -> a
+ ymin', y2 forall a. Num a => a -> a -> a
+ ymax')
            else (x2 forall a. Num a => a -> a -> a
+ xmax', y1 forall a. Num a => a -> a -> a
+ ymin', y2 forall a. Num a => a -> a -> a
+ ymax')
    in
        (forall a. a -> a -> a -> V3 a
V3 (-r) (-r) forall a b. (a -> b) -> a -> b
$ y1 forall a. Num a => a -> a -> a
+ ymin', forall a. a -> a -> a -> V3 a
V3 r  r  forall a b. (a -> b) -> a -> b
$ y2 forall a. Num a => a -> a -> a
+ ymax')

unpack :: V2 a -> (a, a)
unpack :: forall a. V2 a -> (a, a)
unpack (V2 a
a a
b) = (a
a, a
b)

pack :: (a, a) -> V2 a
pack :: forall a. (a, a) -> V2 a
pack = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall a. a -> a -> V2 a
V2