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

-- Allow us to use the tearser parallel list comprehension syntax, to avoid having to call zip in the complicated comprehensions below.
{-# LANGUAGE ParallelListComp #-}

-- export getContour and getMesh, which returns the edge of a 2D object, or the surface of a 3D object, respectively.
module Graphics.Implicit.Export.Render (getMesh, getContour) where

import Prelude(error, (-), ceiling, ($), (+), (*), max, div, tail, fmap, reverse, (.), foldMap, min, Int, (<>), (<$>), traverse)

import Graphics.Implicit.Definitions (, , Fastℕ, ℝ2, ℝ3, TriangleMesh, Obj2, SymbolicObj2, Obj3, SymbolicObj3, Polyline(getSegments), (⋯/), fromℕtoℝ, fromℕ, ℝ3' (ℝ3'))

import Graphics.Implicit.Export.Symbolic.Rebound2 (rebound2)

import Graphics.Implicit.Export.Symbolic.Rebound3 (rebound3)

import Graphics.Implicit.ObjectUtil (getBox2, getBox3)

import Data.Foldable(fold)
import Linear ( V3(V3), V2(V2) )

-- Here's the plan for rendering a cube (the 2D case is trivial):

-- (1) We calculate midpoints using interpolate.
--     This guarentees that our mesh will line up everywhere.
--     (Contrast with calculating them in getSegs)
import Graphics.Implicit.Export.Render.Interpolate (interpolate)

-- (2) We calculate the segments separating the inside and outside of our
--     object on the sides of the cube.
--     getSegs internally uses refine from RefineSegs to subdivide the segs
--     to better match the boundary.
import Graphics.Implicit.Export.Render.GetSegs (getSegs)

-- (3) We put the segments from all sides of the cube together
--     and extract closed loops.
import Graphics.Implicit.Export.Render.GetLoops (getLoops)

-- (4) We tesselate the loops, using a mixture of triangles and squares
import Graphics.Implicit.Export.Render.TesselateLoops (tesselateLoop)

-- (5) We try to merge squares, then turn everything into triangles.
import Graphics.Implicit.Export.Render.HandleSquares (mergedSquareTris)

-- Success: This is our mesh.

-- Each step on the Z axis is done in parallel using Control.Parallel.Strategies
import Control.Parallel.Strategies (using, rdeepseq, parBuffer)

-- The actual code is just a bunch of ugly argument passing.
-- Utility functions can be found at the end.

-- For efficiency, we need to avoid looking things up in other lists
-- (since they're 3D, it's an O(n³) operation...). So we need to make
-- our algorithms "flow" along the data structure instead of accessing
-- within it. To do this we use the ParallelListComp GHC extention.

-- We also compute lots of things in advance and pass them in as arguments,
-- to reduce redundant computations.

-- All in all, this is kind of ugly. But it is necessary.

-- Note: As far as the actual results of the rendering algorithm, nothing in
--       this file really matters. All the actual decisions about how to build
--       the mesh are abstracted into the imported files.

-- For the 2D case, we need one last thing, cleanLoopsFromSegs:
import Graphics.Implicit.Export.Render.HandlePolylines (cleanLoopsFromSegs)
import Data.Maybe (fromMaybe)
import Graphics.Implicit.Primitives (getImplicit)
import Control.Lens (_Wrapped, view, over, _Just)

-- Set the default types for the numbers in this file.
default (, Fastℕ, )

getMesh :: ℝ3 -> SymbolicObj3 -> TriangleMesh
getMesh :: ℝ3 -> SymbolicObj3 -> TriangleMesh
getMesh res :: ℝ3
res@(V3 xres yres zres) SymbolicObj3
symObj =
    let
        -- Grow bounds a little to avoid sampling at exact bounds
        (Obj3
obj, (p1 :: ℝ3
p1@(V3 x1 y1 z1), ℝ3
p2)) = (Obj3, Box3) -> (Obj3, Box3)
rebound3 (forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj3
symObj, SymbolicObj3 -> Box3
getBox3 SymbolicObj3
symObj)

        -- How much space are we rendering?
        d :: ℝ3
d = ℝ3
p2 forall a. Num a => a -> a -> a
- ℝ3
p1

        -- How many steps will we take on each axis?
        nx, ny, nz :: 
        steps :: V3 ℕ
steps@(V3 nx ny nz) = forall a b. (RealFrac a, Integral b) => a -> b
ceiling forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ( ℝ3
d forall a. ComponentWiseMultable a => a -> a -> a
⋯/ ℝ3
res)

        -- How big are the steps?
        (V3 rx ry rz) = ℝ3
d forall a. ComponentWiseMultable a => a -> a -> a
⋯/ (ℕ -> ℝ
fromℕtoℝ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> V3 ℕ
steps)

        -- The planes we're rendering along.
        pYZ :: [ℝ]
pYZ = [ x1 forall a. Num a => a -> a -> a
+ rxforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ n | n <- [0.. nx] ]
        pXZ :: [ℝ]
pXZ = [ y1 forall a. Num a => a -> a -> a
+ ryforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ n | n <- [0.. ny] ]
        pXY :: [ℝ]
pXY = [ z1 forall a. Num a => a -> a -> a
+ rzforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ n | n <- [0.. nz] ]

        -- performance tuning.
        -- FIXME: magic number.
        forcesteps :: Int
        forcesteps :: Int
forcesteps = Int
32

        -- Evaluate obj to avoid waste in mids, segs, later.
        objV :: [[[ℝ]]]
objV = ℕ -> ℕ -> ℕ -> [[[ℝ]]]
par3DList nx ny nz

        -- Sample our object(s) at every point in the 3D space given.
        par3DList ::  ->  ->  -> [[[]]]
        par3DList :: ℕ -> ℕ -> ℕ -> [[[ℝ]]]
par3DList lenx leny lenz =
            [[[ ℕ -> ℕ -> ℕ -> ℝ
sample mx my mz
            | mx <- [0..lenx] ] | my <- [0..leny] ] | mz <- [0..lenz] ]
              forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ (lenxforall a. Num a => a -> a -> a
+lenyforall a. Num a => a -> a -> a
+lenz)) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- sample our object(s) at the given point.
        sample ::  ->  ->  -> 
        sample :: ℕ -> ℕ -> ℕ -> ℝ
sample mx my mz = Obj3
obj forall a b. (a -> b) -> a -> b
$
              forall a. a -> a -> a -> V3 a
V3
                (x1 forall a. Num a => a -> a -> a
+ rxforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ mx)
                (y1 forall a. Num a => a -> a -> a
+ ryforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ my)
                (z1 forall a. Num a => a -> a -> a
+ rzforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ mz)

        -- (1) Calculate mid points on X, Y, and Z axis in 3D space.
        midsZ :: [[[ℝ]]]
midsZ = [[[
                 ℝ2 -> ℝ2 -> (ℝ -> ℝ) -> ℝ -> ℝ
interpolate (forall a. a -> a -> V2 a
V2 z0 objX0Y0Z0) (forall a. a -> a -> V2 a
V2 z1' objX0Y0Z1) (Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appABC Obj3
obj x0 y0) zres
                 | x0 <- [ℝ]
pYZ |                   objX0Y0Z0 <- [ℝ]
objY0Z0 | objX0Y0Z1 <- [ℝ]
objY0Z1
                ]| y0 <- [ℝ]
pXZ |                   [ℝ]
objY0Z0   <- [[ℝ]]
objZ0   | [ℝ]
objY0Z1   <- [[ℝ]]
objZ1
                ]| z0 <- [ℝ]
pXY | z1' <- forall a. [a] -> [a]
tail [ℝ]
pXY | [[ℝ]]
objZ0     <- [[[ℝ]]]
objV    | [[ℝ]]
objZ1     <- forall a. [a] -> [a]
tail [[[ℝ]]]
objV
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ nz) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        midsY :: [[[ℝ]]]
midsY = [[[
                 ℝ2 -> ℝ2 -> (ℝ -> ℝ) -> ℝ -> ℝ
interpolate (forall a. a -> a -> V2 a
V2 y0 objX0Y0Z0) (forall a. a -> a -> V2 a
V2 y1' objX0Y1Z0) (Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appACB Obj3
obj x0 z0) yres
                 | x0 <- [ℝ]
pYZ |                   objX0Y0Z0 <- [ℝ]
objY0Z0 | objX0Y1Z0 <- [ℝ]
objY1Z0
                ]| y0 <- [ℝ]
pXZ | y1' <- forall a. [a] -> [a]
tail [ℝ]
pXZ | [ℝ]
objY0Z0   <- [[ℝ]]
objZ0   | [ℝ]
objY1Z0   <- forall a. [a] -> [a]
tail [[ℝ]]
objZ0
                ]| z0 <- [ℝ]
pXY |                   [[ℝ]]
objZ0     <- [[[ℝ]]]
objV
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ ny) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        midsX :: [[[ℝ]]]
midsX = [[[
                 ℝ2 -> ℝ2 -> (ℝ -> ℝ) -> ℝ -> ℝ
interpolate (forall a. a -> a -> V2 a
V2 x0 objX0Y0Z0) (forall a. a -> a -> V2 a
V2 x1' objX1Y0Z0) (Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appBCA Obj3
obj y0 z0) xres
                 | x0 <- [ℝ]
pYZ | x1' <- forall a. [a] -> [a]
tail [ℝ]
pYZ | objX0Y0Z0 <- [ℝ]
objY0Z0 | objX1Y0Z0 <- forall a. [a] -> [a]
tail [ℝ]
objY0Z0
                ]| y0 <- [ℝ]
pXZ |                   [ℝ]
objY0Z0   <- [[ℝ]]
objZ0
                ]| z0 <- [ℝ]
pXY |                   [[ℝ]]
objZ0     <- [[[ℝ]]]
objV
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ nx) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- (2) Calculate segments for each side
        segsZ :: [[[[[ℝ3]]]]]
segsZ = [[[
            ℝ -> Polyline -> [ℝ3]
injZ z0 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ℝ2 -> ℝ2 -> Obj2 -> (ℝ, ℝ, ℝ, ℝ) -> (ℝ, ℝ, ℝ, ℝ) -> [Polyline]
getSegs (forall a. a -> a -> V2 a
V2 x0 y0) (forall a. a -> a -> V2 a
V2 x1' y1') (Obj3
obj Obj3 -> ℝ -> Obj2
**$ z0) (objX0Y0Z0, objX1Y0Z0, objX0Y1Z0, objX1Y1Z0) (midA0, midA1, midB0, midB1)
             | x0<-[ℝ]
pYZ | x1'<-forall a. [a] -> [a]
tail [ℝ]
pYZ |midB0<-[ℝ]
mX''  | midB1<-[ℝ]
mX'T     | midA0<-[ℝ]
mY''  | midA1<-forall a. [a] -> [a]
tail [ℝ]
mY''  | objX0Y0Z0<-[ℝ]
objY0Z0 | objX1Y0Z0<- forall a. [a] -> [a]
tail [ℝ]
objY0Z0 | objX0Y1Z0<-[ℝ]
objY1Z0    | objX1Y1Z0<-forall a. [a] -> [a]
tail [ℝ]
objY1Z0
            ]| y0<-[ℝ]
pXZ | y1'<-forall a. [a] -> [a]
tail [ℝ]
pXZ |[ℝ]
mX'' <-[[ℝ]]
mX'   | [ℝ]
mX'T <-forall a. [a] -> [a]
tail [[ℝ]]
mX' | [ℝ]
mY'' <-[[ℝ]]
mY'                       | [ℝ]
objY0Z0  <-[[ℝ]]
objZ0                              | [ℝ]
objY1Z0  <-forall a. [a] -> [a]
tail [[ℝ]]
objZ0
            ]| z0<-[ℝ]
pXY                 |[[ℝ]]
mX'  <-[[[ℝ]]]
midsX |                   [[ℝ]]
mY'  <-[[[ℝ]]]
midsY                     | [[ℝ]]
objZ0    <-[[[ℝ]]]
objV
            ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ nz) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        segsY :: [[[[[ℝ3]]]]]
segsY = [[[
            ℝ -> Polyline -> [ℝ3]
injY y0 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ℝ2 -> ℝ2 -> Obj2 -> (ℝ, ℝ, ℝ, ℝ) -> (ℝ, ℝ, ℝ, ℝ) -> [Polyline]
getSegs (forall a. a -> a -> V2 a
V2 x0 z0) (forall a. a -> a -> V2 a
V2 x1' z1') (Obj3
obj Obj3 -> ℝ -> Obj2
*$* y0) (objX0Y0Z0, objX1Y0Z0, objX0Y0Z1, objX1Y0Z1) (midA0, midA1, midB0, midB1)
             | x0<-[ℝ]
pYZ | x1'<-forall a. [a] -> [a]
tail [ℝ]
pYZ | midB0<-[ℝ]
mB''  | midB1<-[ℝ]
mBT'       | midA0<-[ℝ]
mA''  | midA1<-forall a. [a] -> [a]
tail [ℝ]
mA'' | objX0Y0Z0<-[ℝ]
objY0Z0 | objX1Y0Z0<-forall a. [a] -> [a]
tail [ℝ]
objY0Z0 | objX0Y0Z1<-[ℝ]
objY0Z1 | objX1Y0Z1<-forall a. [a] -> [a]
tail [ℝ]
objY0Z1
            ]| y0<-[ℝ]
pXZ |                 [ℝ]
mB'' <-[[ℝ]]
mB'   | [ℝ]
mBT' <-[[ℝ]]
mBT        | [ℝ]
mA'' <-[[ℝ]]
mA'                      | [ℝ]
objY0Z0  <-[[ℝ]]
objZ0                             | [ℝ]
objY0Z1  <-[[ℝ]]
objZ1
            ]| z0<-[ℝ]
pXY | z1'<-forall a. [a] -> [a]
tail [ℝ]
pXY | [[ℝ]]
mB'  <-[[[ℝ]]]
midsX | [[ℝ]]
mBT  <-forall a. [a] -> [a]
tail [[[ℝ]]]
midsX | [[ℝ]]
mA'  <-[[[ℝ]]]
midsZ                    | [[ℝ]]
objZ0    <-[[[ℝ]]]
objV                              | [[ℝ]]
objZ1    <-forall a. [a] -> [a]
tail [[[ℝ]]]
objV
            ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ ny) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        segsX :: [[[[[ℝ3]]]]]
segsX = [[[
            ℝ -> Polyline -> [ℝ3]
injX x0 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ℝ2 -> ℝ2 -> Obj2 -> (ℝ, ℝ, ℝ, ℝ) -> (ℝ, ℝ, ℝ, ℝ) -> [Polyline]
getSegs (forall a. a -> a -> V2 a
V2 y0 z0) (forall a. a -> a -> V2 a
V2 y1' z1') (Obj3
obj Obj3 -> ℝ -> Obj2
$** x0) (objX0Y0Z0, objX0Y1Z0, objX0Y0Z1, objX0Y1Z1) (midA0, midA1, midB0, midB1)
             | x0<-[ℝ]
pYZ |                 midB0<-[ℝ]
mB''  | midB1<-[ℝ]
mBT'       | midA0<-[ℝ]
mA''  | midA1<-[ℝ]
mA'T     | objX0Y0Z0<-[ℝ]
objY0Z0 | objX0Y1Z0<-[ℝ]
objY1Z0    | objX0Y0Z1<-[ℝ]
objY0Z1    | objX0Y1Z1<-     [ℝ]
objY1Z1
            ]| y0<-[ℝ]
pXZ | y1'<-forall a. [a] -> [a]
tail [ℝ]
pXZ | [ℝ]
mB'' <-[[ℝ]]
mB'   | [ℝ]
mBT' <-[[ℝ]]
mBT        | [ℝ]
mA'' <-[[ℝ]]
mA'   | [ℝ]
mA'T <-forall a. [a] -> [a]
tail [[ℝ]]
mA' | [ℝ]
objY0Z0  <-[[ℝ]]
objZ0   | [ℝ]
objY1Z0  <-forall a. [a] -> [a]
tail [[ℝ]]
objZ0 | [ℝ]
objY0Z1  <-[[ℝ]]
objZ1      | [ℝ]
objY1Z1  <-forall a. [a] -> [a]
tail [[ℝ]]
objZ1
            ]| z0<-[ℝ]
pXY | z1'<-forall a. [a] -> [a]
tail [ℝ]
pXY | [[ℝ]]
mB'  <-[[[ℝ]]]
midsY | [[ℝ]]
mBT  <-forall a. [a] -> [a]
tail [[[ℝ]]]
midsY | [[ℝ]]
mA'  <-[[[ℝ]]]
midsZ                   | [[ℝ]]
objZ0    <- [[[ℝ]]]
objV                           | [[ℝ]]
objZ1    <- forall a. [a] -> [a]
tail [[[ℝ]]]
objV
            ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ nx) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- (3) & (4) : get and tesselate loops
        -- FIXME: hack.
        minres :: ℝ
minres = xres forall a. Ord a => a -> a -> a
`min` yres forall a. Ord a => a -> a -> a
`min` zres
        sqTris :: [[[[TriSquare]]]]
sqTris = [[[
            forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (ℝ -> Obj3 -> [[ℝ3]] -> [TriSquare]
tesselateLoop minres Obj3
obj) forall a b. (a -> b) -> a -> b
$
              forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => [Char] -> a
error [Char]
"unclosed loop in paths given") forall a b. (a -> b) -> a -> b
$
              -- Shove the ℝ3s into ℝ3's to get the NaN checks, then
              -- unwrap everything. This should mostly compile away
              -- given that it is lensy and passing a newtype instance
              -- around. `getLoops` is the function actually doing the
              -- work we care about
              forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over (forall a b. Prism (Maybe a) (Maybe b) a b
_Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse) (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall s t. Rewrapping s t => Iso s t (Unwrapped s) (Unwrapped t)
_Wrapped) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Eq a => [[a]] -> Maybe [[[a]]]
getLoops forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over (forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse) ℝ3 -> ℝ3'
ℝ3' forall a b. (a -> b) -> a -> b
$
                        [[ℝ3]]
segX''' forall a. Semigroup a => a -> a -> a
<>
                   [[ℝ3]] -> [[ℝ3]]
mapR [[ℝ3]]
segX''T forall a. Semigroup a => a -> a -> a
<>
                   [[ℝ3]] -> [[ℝ3]]
mapR [[ℝ3]]
segY''' forall a. Semigroup a => a -> a -> a
<>
                        [[ℝ3]]
segY'T' forall a. Semigroup a => a -> a -> a
<>
                        [[ℝ3]]
segZ''' forall a. Semigroup a => a -> a -> a
<>
                   [[ℝ3]] -> [[ℝ3]]
mapR [[ℝ3]]
segZT''
             | [[ℝ3]]
segZ'''<- [[[ℝ3]]]
segZ''| [[ℝ3]]
segZT''<- [[[ℝ3]]]
segZT'
             | [[ℝ3]]
segY'''<- [[[ℝ3]]]
segY''| [[ℝ3]]
segY'T'<- [[[ℝ3]]]
segY'T
             | [[ℝ3]]
segX'''<- [[[ℝ3]]]
segX''| [[ℝ3]]
segX''T<- forall a. [a] -> [a]
tail [[[ℝ3]]]
segX''

            ]| [[[ℝ3]]]
segZ'' <- [[[[ℝ3]]]]
segZ' | [[[ℝ3]]]
segZT' <- [[[[ℝ3]]]]
segZT
             | [[[ℝ3]]]
segY'' <- [[[[ℝ3]]]]
segY' | [[[ℝ3]]]
segY'T <- forall a. [a] -> [a]
tail [[[[ℝ3]]]]
segY'
             | [[[ℝ3]]]
segX'' <- [[[[ℝ3]]]]
segX'

            ]| [[[[ℝ3]]]]
segZ'  <- [[[[[ℝ3]]]]]
segsZ | [[[[ℝ3]]]]
segZT  <- forall a. [a] -> [a]
tail [[[[[ℝ3]]]]]
segsZ
             | [[[[ℝ3]]]]
segY'  <- [[[[[ℝ3]]]]]
segsY
             | [[[[ℝ3]]]]
segX'  <- [[[[[ℝ3]]]]]
segsX
            ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ forall a b. (a -> b) -> a -> b
$ nxforall a. Num a => a -> a -> a
+nyforall a. Num a => a -> a -> a
+nz) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

    in
      -- (5) merge squares, etc
      [TriSquare] -> TriangleMesh
mergedSquareTris forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold [[[[TriSquare]]]]
sqTris

-- | getContour gets a polyline describing the edge of a 2D object.
getContour :: ℝ2 -> SymbolicObj2 -> [Polyline]
getContour :: ℝ2 -> SymbolicObj2 -> [Polyline]
getContour res :: ℝ2
res@(V2 xres yres) SymbolicObj2
symObj =
    let
        -- Grow bounds a little to avoid sampling at exact bounds
        (Obj2
obj, (p1 :: ℝ2
p1@(V2 x1 y1), ℝ2
p2)) = (Obj2, Box2) -> (Obj2, Box2)
rebound2 (forall obj (f :: * -> *) a. Object obj f a => obj -> f a -> a
getImplicit SymbolicObj2
symObj, SymbolicObj2 -> Box2
getBox2 SymbolicObj2
symObj)

        -- The size of the region we're being asked to search.
        d :: ℝ2
d = ℝ2
p2 forall a. Num a => a -> a -> a
- ℝ2
p1

        -- How many steps will we take on each axis?
        nx, ny :: 
        steps :: V2 ℕ
steps@(V2 nx ny) = forall a b. (RealFrac a, Integral b) => a -> b
ceiling forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ℝ2
d forall a. ComponentWiseMultable a => a -> a -> a
⋯/ ℝ2
res)

        -- How big are the steps?
        (V2 rx ry) = ℝ2
d forall a. ComponentWiseMultable a => a -> a -> a
⋯/ (ℕ -> ℝ
fromℕtoℝ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> V2 ℕ
steps)

        -- The lines we are rendering along.
        pX :: [ℝ]
pX = [ x1 forall a. Num a => a -> a -> a
+ rxforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ p | p <- [0.. nx] ]
        pY :: [ℝ]
pY = [ y1 forall a. Num a => a -> a -> a
+ ryforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ p | p <- [0.. ny] ]

        -- Performance tuning.
        -- FIXME: magic number.
        forcesteps :: Int
        forcesteps :: Int
forcesteps = Int
32

        -- Evaluate obj to avoid waste in mids, segs, later.
        objV :: [[ℝ]]
objV = ℕ -> ℕ -> [[ℝ]]
par2DList nx ny

        -- Sample our object(s) at every point in the 2D plane given.
        par2DList ::  ->  -> [[]]
        par2DList :: ℕ -> ℕ -> [[ℝ]]
par2DList lenx leny =
            [[ ℕ -> ℕ -> ℝ
sample mx my
                  | mx <- [0..lenx]
                ] | my <- [0..leny]
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ forall a b. (a -> b) -> a -> b
$ lenxforall a. Num a => a -> a -> a
+leny) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- sample our object(s) at the given point.
        sample ::  ->  -> 
        sample :: ℕ -> ℕ -> ℝ
sample mx my = Obj2
obj forall a b. (a -> b) -> a -> b
$
          forall a. a -> a -> V2 a
V2
                (x1 forall a. Num a => a -> a -> a
+ rxforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ mx)
                (y1 forall a. Num a => a -> a -> a
+ ryforall a. Num a => a -> a -> a
*ℕ -> ℝ
fromℕtoℝ my)

        -- Calculate mid points on X axis in 2D space.
        midsX :: [[ℝ]]
midsX = [[
                 ℝ2 -> ℝ2 -> (ℝ -> ℝ) -> ℝ -> ℝ
interpolate (forall a. a -> a -> V2 a
V2 x0 objX0Y0) (forall a. a -> a -> V2 a
V2 x1' objX1Y0) (Obj2
obj Obj2 -> ℝ -> ℝ -> ℝ
*$ y0) xres
                 | x0 <- [ℝ]
pX | x1' <- forall a. [a] -> [a]
tail [ℝ]
pX | objX0Y0 <- [ℝ]
objY0 | objX1Y0 <- forall a. [a] -> [a]
tail [ℝ]
objY0
                ]| y0 <- [ℝ]
pY |                   [ℝ]
objY0   <- [[ℝ]]
objV
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ nx) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- Calculate mid points on Y axis in 2D space.
        midsY :: [[ℝ]]
midsY = [[
                 ℝ2 -> ℝ2 -> (ℝ -> ℝ) -> ℝ -> ℝ
interpolate (forall a. a -> a -> V2 a
V2 y0 objX0Y0) (forall a. a -> a -> V2 a
V2 y1' objX0Y1) (Obj2
obj Obj2 -> ℝ -> ℝ -> ℝ
$* x0) yres
                 | x0 <- [ℝ]
pX |                  objX0Y0 <- [ℝ]
objY0   | objX0Y1 <- [ℝ]
objY1
                ]| y0 <- [ℝ]
pY | y1' <- forall a. [a] -> [a]
tail [ℝ]
pY | [ℝ]
objY0   <- [[ℝ]]
objV    | [ℝ]
objY1   <- forall a. [a] -> [a]
tail [[ℝ]]
objV
                ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ ny) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq

        -- Calculate segments for each side
        segs :: [[[Polyline]]]
segs = [[
            ℝ2 -> ℝ2 -> Obj2 -> (ℝ, ℝ, ℝ, ℝ) -> (ℝ, ℝ, ℝ, ℝ) -> [Polyline]
getSegs (forall a. a -> a -> V2 a
V2 x0 y0) (forall a. a -> a -> V2 a
V2 x1' y1') Obj2
obj (objX0Y0, objX1Y0, objX0Y1, objX1Y1) (midA0, midA1, midB0, midB1)
             | x0<-[ℝ]
pX | x1'<-forall a. [a] -> [a]
tail [ℝ]
pX |midB0<-[ℝ]
mX''  | midB1<-[ℝ]
mX'T       | midA0<-[ℝ]
mY''  | midA1<-forall a. [a] -> [a]
tail [ℝ]
mY'' | objX0Y0<-[ℝ]
objY0 | objX1Y0<-forall a. [a] -> [a]
tail [ℝ]
objY0 | objX0Y1<-[ℝ]
objY1 | objX1Y1<-forall a. [a] -> [a]
tail [ℝ]
objY1
            ]| y0<-[ℝ]
pY | y1'<-forall a. [a] -> [a]
tail [ℝ]
pY |[ℝ]
mX'' <-[[ℝ]]
midsX | [ℝ]
mX'T <-forall a. [a] -> [a]
tail [[ℝ]]
midsX | [ℝ]
mY'' <-[[ℝ]]
midsY                    | [ℝ]
objY0 <- [[ℝ]]
objV                        | [ℝ]
objY1 <- forall a. [a] -> [a]
tail [[ℝ]]
objV
            ] forall a. a -> Strategy a -> a
`using` forall a. Int -> Strategy a -> Strategy [a]
parBuffer (forall a. Ord a => a -> a -> a
max Int
1 forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> a -> a
div (forall n. N n => ℕ -> n
fromℕ forall a b. (a -> b) -> a -> b
$ nxforall a. Num a => a -> a -> a
+ny) Int
forcesteps) forall a. NFData a => Strategy a
rdeepseq
    in
      -- Merge squares
      [Polyline] -> [Polyline]
cleanLoopsFromSegs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold [[[Polyline]]]
segs

-- utility functions

injX ::  -> Polyline -> [ℝ3]
injX :: ℝ -> Polyline -> [ℝ3]
injX val Polyline
polyline = ℝ -> ℝ2 -> ℝ3
prepend val forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Polyline -> [ℝ2]
getSegments Polyline
polyline
  where
    prepend ::  -> ℝ2 -> ℝ3
    prepend :: ℝ -> ℝ2 -> ℝ3
prepend a (V2 b c) = forall a. a -> a -> a -> V3 a
V3 a b c

injY ::  -> Polyline -> [ℝ3]
injY :: ℝ -> Polyline -> [ℝ3]
injY val Polyline
polyline = ℝ -> ℝ2 -> ℝ3
insert val  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Polyline -> [ℝ2]
getSegments Polyline
polyline
  where
    insert ::  -> ℝ2 -> ℝ3
    insert :: ℝ -> ℝ2 -> ℝ3
insert b (V2 a c) = forall a. a -> a -> a -> V3 a
V3 a b c

injZ ::  -> Polyline -> [ℝ3]
injZ :: ℝ -> Polyline -> [ℝ3]
injZ val Polyline
polyline = ℝ -> ℝ2 -> ℝ3
postfix val forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Polyline -> [ℝ2]
getSegments Polyline
polyline
  where
    postfix ::  -> ℝ2 -> ℝ3
    postfix :: ℝ -> ℝ2 -> ℝ3
postfix c (V2 a b) = forall a. a -> a -> a -> V3 a
V3 a b c

($**) :: Obj3 ->  -> ℝ2 -> 
Obj3
f $** :: Obj3 -> ℝ -> Obj2
$** a = \(V2 b c) -> Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)
infixr 0 $**

(*$*) :: Obj3 ->  -> ℝ2 -> 
Obj3
f *$* :: Obj3 -> ℝ -> Obj2
*$* b = \(V2 a c) -> Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)
infixr 0 *$*

(**$) :: Obj3 ->  -> ℝ2 -> 
Obj3
f **$ :: Obj3 -> ℝ -> Obj2
**$ c = \(V2 a b) -> Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)
infixr 0 **$

($*) :: Obj2 ->  ->  -> 
Obj2
f $* :: Obj2 -> ℝ -> ℝ -> ℝ
$* a = Obj2
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> a -> V2 a
V2 a
infixr 0 $*

(*$) :: Obj2 ->  ->  -> 
Obj2
f *$ :: Obj2 -> ℝ -> ℝ -> ℝ
*$ b = \a -> Obj2
f (forall a. a -> a -> V2 a
V2 a b)
infixr 0 *$

appABC :: Obj3 ->  ->  ->  -> 
appABC :: Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appABC Obj3
f a b c = Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)
appBCA :: Obj3 ->  ->  ->  -> 
appBCA :: Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appBCA Obj3
f b c a = Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)
appACB :: Obj3 ->  ->  ->  -> 
appACB :: Obj3 -> ℝ -> ℝ -> ℝ -> ℝ
appACB Obj3
f a c b = Obj3
f (forall a. a -> a -> a -> V3 a
V3 a b c)

mapR :: [[ℝ3]] -> [[ℝ3]]
mapR :: [[ℝ3]] -> [[ℝ3]]
mapR = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. [a] -> [a]
reverse