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

module Graphics.Implicit.ObjectUtil.GetImplicit3 (getImplicit3) where

import Prelude (id, (||), (/=), either, round, fromInteger, Either(Left, Right), abs, (-), (/), (*), sqrt, (+), atan2, max, cos, minimum, ($), sin, pi, (.), Bool(True, False), ceiling, floor, pure, (==), otherwise)

import Graphics.Implicit.Definitions
    ( objectRounding, ObjectContext, , SymbolicObj3(Cube, Sphere, Cylinder, Rotate3, Transform3, Extrude, ExtrudeM, ExtrudeOnEdgeOf, RotateExtrude, Shared3), Obj3, ℝ2, , fromℕtoℝ, toScaleFn )

import Graphics.Implicit.MathUtil ( rmax, rmaximum )

import qualified Data.Either as Either (either)

-- Use getImplicit for handling extrusion of 2D shapes to 3D.
import Graphics.Implicit.ObjectUtil.GetImplicitShared (getImplicitShared)
import Linear (V2(V2), V3(V3))
import qualified Linear

import {-# SOURCE #-} Graphics.Implicit.Primitives (getImplicit)

default ()

-- Get a function that describes the surface of the object.
getImplicit3 :: ObjectContext -> SymbolicObj3 -> Obj3
-- Primitives
getImplicit3 :: ObjectContext -> SymbolicObj3 -> Obj3
getImplicit3 ObjectContext
ctx (Cube (V3 dx dy dz)) =
    \(V3 x y z) -> ℝ -> [ℝ] -> ℝ
rmaximum (ObjectContext -> ℝ
objectRounding ObjectContext
ctx) [forall a. Num a => a -> a
abs (xforall a. Num a => a -> a -> a
-dxforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- dxforall a. Fractional a => a -> a -> a
/2, forall a. Num a => a -> a
abs (yforall a. Num a => a -> a -> a
-dyforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- dyforall a. Fractional a => a -> a -> a
/2, forall a. Num a => a -> a
abs (zforall a. Num a => a -> a -> a
-dzforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- dzforall a. Fractional a => a -> a -> a
/2]
getImplicit3 ObjectContext
_ (Sphere r) =
    \(V3 x y z) -> forall a. Floating a => a -> a
sqrt (xforall a. Num a => a -> a -> a
*x forall a. Num a => a -> a -> a
+ yforall a. Num a => a -> a -> a
*y forall a. Num a => a -> a -> a
+ zforall a. Num a => a -> a -> a
*z) forall a. Num a => a -> a -> a
- r
getImplicit3 ObjectContext
_ (Cylinder h r1 r2) = \(V3 x y z) ->
    let
        d :: ℝ
d = forall a. Floating a => a -> a
sqrt (xforall a. Num a => a -> a -> a
*x forall a. Num a => a -> a -> a
+ yforall a. Num a => a -> a -> a
*y) forall a. Num a => a -> a -> a
- ((r2forall a. Num a => a -> a -> a
-r1)forall a. Fractional a => a -> a -> a
/hforall a. Num a => a -> a -> a
*zforall a. Num a => a -> a -> a
+r1)
        θ :: ℝ
θ = forall a. RealFloat a => a -> a -> a
atan2 (r2forall a. Num a => a -> a -> a
-r1) h
    in
        forall a. Ord a => a -> a -> a
max (d forall a. Num a => a -> a -> a
* forall a. Floating a => a -> a
cos θ) (forall a. Num a => a -> a
abs (zforall a. Num a => a -> a -> a
-hforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- (hforall a. Fractional a => a -> a -> a
/2))
-- Simple transforms
getImplicit3 ObjectContext
ctx (Rotate3 Quaternion ℝ
q SymbolicObj3
symbObj) =
    ObjectContext -> SymbolicObj3 -> Obj3
getImplicit3 ObjectContext
ctx SymbolicObj3
symbObj forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a.
(Conjugate a, RealFloat a) =>
Quaternion a -> V3 a -> V3 a
Linear.rotate (forall a. Conjugate a => a -> a
Linear.conjugate Quaternion ℝ
q)
getImplicit3 ObjectContext
ctx (Transform3 M44 ℝ
m SymbolicObj3
symbObj) =
    ObjectContext -> SymbolicObj3 -> Obj3
getImplicit3 ObjectContext
ctx SymbolicObj3
symbObj forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Fractional a => V4 a -> V3 a
Linear.normalizePoint forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Fractional a => M44 a -> M44 a
Linear.inv44 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
-- 2D Based
getImplicit3 ObjectContext
ctx (Extrude SymbolicObj2
symbObj h) =
    let
        obj :: V2 ℝ -> ℝ
obj = forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symbObj
    in
        \(V3 x y z) -> ℝ -> ℝ -> ℝ -> ℝ
rmax (ObjectContext -> ℝ
objectRounding ObjectContext
ctx) (V2 ℝ -> ℝ
obj (forall a. a -> a -> V2 a
V2 x y)) (forall a. Num a => a -> a
abs (z forall a. Num a => a -> a -> a
- hforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- hforall a. Fractional a => a -> a -> a
/2)
getImplicit3 ObjectContext
ctx (ExtrudeM Either ℝ (ℝ -> ℝ)
twist ExtrudeMScale
scale Either (V2 ℝ) (ℝ -> V2 ℝ)
translate SymbolicObj2
symbObj Either ℝ (V2 ℝ -> ℝ)
height) =
    let
        r :: ℝ
r = ObjectContext -> ℝ
objectRounding ObjectContext
ctx
        obj :: V2 ℝ -> ℝ
obj = forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symbObj
        height' :: V2 ℝ -> ℝ
height' (V2 x y) = case Either ℝ (V2 ℝ -> ℝ)
height of
            Left n -> n
            Right V2 ℝ -> ℝ
f -> V2 ℝ -> ℝ
f (forall a. a -> a -> V2 a
V2 x y)
        -- FIXME: twist functions should have access to height, if height is allowed to vary.
        twistVal :: Either  ( -> ) ->  ->  -> 
        twistVal :: Either ℝ (ℝ -> ℝ) -> ℝ -> ℝ -> ℝ
twistVal Either ℝ (ℝ -> ℝ)
twist' z h =
          case Either ℝ (ℝ -> ℝ)
twist' of
                   Left twval  -> if twval forall a. Eq a => a -> a -> Bool
== 0
                                  then 0
                                  else twval forall a. Num a => a -> a -> a
* (z forall a. Fractional a => a -> a -> a
/ h)
                   Right ℝ -> ℝ
twfun -> ℝ -> ℝ
twfun z
        translatePos :: Either ℝ2 ( -> ℝ2) ->  -> ℝ2 -> ℝ2
        translatePos :: Either (V2 ℝ) (ℝ -> V2 ℝ) -> ℝ -> V2 ℝ -> V2 ℝ
translatePos Either (V2 ℝ) (ℝ -> V2 ℝ)
trans z (V2 x y) = forall a. a -> a -> V2 a
V2 (x forall a. Num a => a -> a -> a
- xTrans) (y forall a. Num a => a -> a -> a
- yTrans)
          where
            (V2 xTrans yTrans) = case Either (V2 ℝ) (ℝ -> V2 ℝ)
trans of
                                 Left  V2 ℝ
tval -> V2 ℝ
tval
                                 Right ℝ -> V2 ℝ
tfun -> ℝ -> V2 ℝ
tfun z
        scaleVec ::  -> ℝ2 -> ℝ2
        scaleVec :: ℝ -> V2 ℝ -> V2 ℝ
scaleVec z (V2 x y) = let (V2 sx sy) = ExtrudeMScale -> ℝ -> V2 ℝ
toScaleFn ExtrudeMScale
scale z
                               in forall a. a -> a -> V2 a
V2 (x forall a. Fractional a => a -> a -> a
/ sx) (y forall a. Fractional a => a -> a -> a
/ sy)
        rotateVec ::  -> ℝ2 -> ℝ2
        rotateVec :: ℝ -> V2 ℝ -> V2 ℝ
rotateVec θ (V2 x y)
          | θ forall a. Eq a => a -> a -> Bool
== 0    = forall a. a -> a -> V2 a
V2 x y
          | Bool
otherwise = forall a. a -> a -> V2 a
V2 (xforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos θ forall a. Num a => a -> a -> a
+ yforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin θ) (yforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
cos θ forall a. Num a => a -> a -> a
- xforall a. Num a => a -> a -> a
*forall a. Floating a => a -> a
sin θ)
        k :: 
        k :: ℝ
k = forall a. Floating a => a
piforall a. Fractional a => a -> a -> a
/180
    in
        \(V3 x y z) ->
          let
            h :: ℝ
h = V2 ℝ -> ℝ
height' forall a b. (a -> b) -> a -> b
$ forall a. a -> a -> V2 a
V2 x y
            res :: ℝ
res = ℝ -> ℝ -> ℝ -> ℝ
rmax r
                (V2 ℝ -> ℝ
obj
                 forall b c a. (b -> c) -> (a -> b) -> a -> c
. ℝ -> V2 ℝ -> V2 ℝ
rotateVec (-kforall a. Num a => a -> a -> a
*Either ℝ (ℝ -> ℝ) -> ℝ -> ℝ -> ℝ
twistVal Either ℝ (ℝ -> ℝ)
twist z h)
                 forall b c a. (b -> c) -> (a -> b) -> a -> c
. ℝ -> V2 ℝ -> V2 ℝ
scaleVec z
                 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either (V2 ℝ) (ℝ -> V2 ℝ) -> ℝ -> V2 ℝ -> V2 ℝ
translatePos Either (V2 ℝ) (ℝ -> V2 ℝ)
translate z
                 forall a b. (a -> b) -> a -> b
$ forall a. a -> a -> V2 a
V2 x y )
                (forall a. Num a => a -> a
abs (z forall a. Num a => a -> a -> a
- hforall a. Fractional a => a -> a -> a
/2) forall a. Num a => a -> a -> a
- hforall a. Fractional a => a -> a -> a
/2)
          in
            res
getImplicit3 ObjectContext
_ (ExtrudeOnEdgeOf SymbolicObj2
symbObj1 SymbolicObj2
symbObj2) =
    let
        obj1 :: V2 ℝ -> ℝ
obj1 = forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symbObj1
        obj2 :: V2 ℝ -> ℝ
obj2 = forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symbObj2
    in
        \(V3 x y z) -> V2 ℝ -> ℝ
obj1 forall a b. (a -> b) -> a -> b
$ forall a. a -> a -> V2 a
V2 (V2 ℝ -> ℝ
obj2 (forall a. a -> a -> V2 a
V2 x y)) z
getImplicit3 ObjectContext
ctx (RotateExtrude totalRotation Either (V2 ℝ) (ℝ -> V2 ℝ)
translate Either ℝ (ℝ -> ℝ)
rotate SymbolicObj2
symbObj) =
    let
        tau :: 
        tau :: ℝ
tau = 2 forall a. Num a => a -> a -> a
* forall a. Floating a => a
pi
        obj :: V2 ℝ -> ℝ
obj = forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symbObj

        is360m ::  -> Bool
        is360m :: ℝ -> Bool
is360m n = tau forall a. Num a => a -> a -> a
* forall a. Num a => Integer -> a
fromInteger (forall a b. (RealFrac a, Integral b) => a -> b
round forall a b. (a -> b) -> a -> b
$ n forall a. Fractional a => a -> a -> a
/ tau) forall a. Eq a => a -> a -> Bool
/= n
        capped :: Bool
capped
             = ℝ -> Bool
is360m totalRotation
            Bool -> Bool -> Bool
|| forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ( forall a. Eq a => a -> a -> Bool
/= forall (f :: * -> *) a. Applicative f => a -> f a
pure 0) (\ℝ -> V2 ℝ
f -> ℝ -> V2 ℝ
f 0 forall a. Eq a => a -> a -> Bool
/= ℝ -> V2 ℝ
f totalRotation) Either (V2 ℝ) (ℝ -> V2 ℝ)
translate
            Bool -> Bool -> Bool
|| forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ℝ -> Bool
is360m (\ℝ -> ℝ
f -> ℝ -> Bool
is360m (ℝ -> ℝ
f 0 forall a. Num a => a -> a -> a
- ℝ -> ℝ
f totalRotation)) Either ℝ (ℝ -> ℝ)
rotate
        round' :: ℝ
round' = ObjectContext -> ℝ
objectRounding ObjectContext
ctx
        translate' ::  -> ℝ2
        translate' :: ℝ -> V2 ℝ
translate' = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Either.either
                (\(V2 a b) θ -> forall a. a -> a -> V2 a
V2 (aforall a. Num a => a -> a -> a
*θforall a. Fractional a => a -> a -> a
/totalRotation) (bforall a. Num a => a -> a -> a
*θforall a. Fractional a => a -> a -> a
/totalRotation))
                forall a. a -> a
id
                Either (V2 ℝ) (ℝ -> V2 ℝ)
translate
        rotate' ::  -> 
        rotate' :: ℝ -> ℝ
rotate' = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Either.either
                (\t θ -> tforall a. Num a => a -> a -> a
*θforall a. Fractional a => a -> a -> a
/totalRotation )
                forall a. a -> a
id
                Either ℝ (ℝ -> ℝ)
rotate
        twists :: Bool
twists = case Either ℝ (ℝ -> ℝ)
rotate of
                   Left 0  -> Bool
True
                   Either ℝ (ℝ -> ℝ)
_       -> Bool
False
    in
        \(V3 x y z) -> forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum forall a b. (a -> b) -> a -> b
$ do
            let
                r :: ℝ
r = forall a. Floating a => a -> a
sqrt forall a b. (a -> b) -> a -> b
$ xforall a. Num a => a -> a -> a
*x forall a. Num a => a -> a -> a
+ yforall a. Num a => a -> a -> a
*y
                θ :: ℝ
θ = forall a. RealFloat a => a -> a -> a
atan2 y x
                ns :: []
                ns :: [ℕ]
ns =
                    if Bool
capped
                    then -- we will cap a different way, but want leeway to keep the function cont
                        [-1 .. forall a b. (RealFrac a, Integral b) => a -> b
ceiling forall a b. (a -> b) -> a -> b
$ (totalRotation forall a. Fractional a => a -> a -> a
/ tau) forall a. Num a => a -> a -> a
+ 1]
                    else
                        [0 .. forall a b. (RealFrac a, Integral b) => a -> b
floor forall a b. (a -> b) -> a -> b
$ (totalRotation forall a. Num a => a -> a -> a
- θ) forall a. Fractional a => a -> a -> a
/ tau]
            n <- [ℕ]
ns
            let
                θvirt :: ℝ
θvirt = ℕ -> ℝ
fromℕtoℝ n forall a. Num a => a -> a -> a
* tau forall a. Num a => a -> a -> a
+ θ
                (V2 rshift zshift) = ℝ -> V2 ℝ
translate' θvirt
                twist :: ℝ
twist = ℝ -> ℝ
rotate' θvirt
                rz_pos :: V2 ℝ
rz_pos = if Bool
twists
                        then let
                            (c,s) = (forall a. Floating a => a -> a
cos twist, forall a. Floating a => a -> a
sin twist)
                            (r',z') = (rforall a. Num a => a -> a -> a
-rshift, zforall a. Num a => a -> a -> a
-zshift)
                        in
                            forall a. a -> a -> V2 a
V2 (cforall a. Num a => a -> a -> a
*r' forall a. Num a => a -> a -> a
- sforall a. Num a => a -> a -> a
*z') (cforall a. Num a => a -> a -> a
*z' forall a. Num a => a -> a -> a
+ sforall a. Num a => a -> a -> a
*r')
                        else forall a. a -> a -> V2 a
V2 (r forall a. Num a => a -> a -> a
- rshift) (z forall a. Num a => a -> a -> a
- zshift)
            forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
              if Bool
capped
              then ℝ -> ℝ -> ℝ -> ℝ
rmax round'
                    (forall a. Num a => a -> a
abs (θvirt forall a. Num a => a -> a -> a
- (totalRotation forall a. Fractional a => a -> a -> a
/ 2)) forall a. Num a => a -> a -> a
- (totalRotation forall a. Fractional a => a -> a -> a
/ 2))
                    (V2 ℝ -> ℝ
obj V2 ℝ
rz_pos)
              else V2 ℝ -> ℝ
obj V2 ℝ
rz_pos
getImplicit3 ObjectContext
ctx (Shared3 SharedObj SymbolicObj3 V3 ℝ
obj) = forall obj (f :: * -> *).
(Object obj f ℝ, VectorStuff (f ℝ), ComponentWiseMultable (f ℝ),
 Metric f) =>
ObjectContext -> SharedObj obj f ℝ -> f ℝ -> ℝ
getImplicitShared ObjectContext
ctx SharedObj SymbolicObj3 V3 ℝ
obj