module Graphics.Implicit.Export.SymbolicObj3 (symbolicGetMesh) where
import Graphics.Implicit.Definitions
import Graphics.Implicit.Export.Definitions
import Graphics.Implicit.Export.Render (getMesh)
import Graphics.Implicit.Primitives
import Graphics.Implicit.ObjectUtil
import Graphics.Implicit.MathUtil
import Graphics.Implicit.Export.SymbolicObj2
import qualified Data.Maybe as Maybe
import Graphics.Implicit.Export.Symbolic.Rebound2
import Graphics.Implicit.Export.Symbolic.Rebound3
import Graphics.Implicit.Export.Util (normTriangle)
import Data.VectorSpace
instance DiscreteAproxable SymbolicObj3 TriangleMesh where
discreteAprox res obj = symbolicGetMesh res obj
instance DiscreteAproxable SymbolicObj3 NormedTriangleMesh where
discreteAprox res obj = map (normTriangle res (getImplicit3 obj)) $ symbolicGetMesh res obj
symbolicGetMesh :: ℝ -> SymbolicObj3 -> [(ℝ3, ℝ3, ℝ3)]
symbolicGetMesh res (Translate3 v obj) =
map (\(a,b,c) -> (a ^+^ v, b ^+^ v, c ^+^ v) ) (symbolicGetMesh res obj)
symbolicGetMesh res (Scale3 s obj) =
let
mesh :: [(ℝ3, ℝ3, ℝ3)]
mesh = symbolicGetMesh res obj
scaleTriangle :: (ℝ3, ℝ3, ℝ3) -> (ℝ3, ℝ3, ℝ3)
scaleTriangle (a,b,c) = (s ⋯* a, s ⋯* b, s ⋯* c)
in map scaleTriangle mesh
symbolicGetMesh _ (Rect3R 0 (x1,y1,z1) (x2,y2,z2)) =
let
square a b c d = [(a,b,c),(d,a,c)]
rsquare a b c d = [(c,b,a),(c,a,d)]
in
rsquare (x1,y1,z1) (x2,y1,z1) (x2,y2,z1) (x1,y2,z1)
++ square (x1,y1,z2) (x2,y1,z2) (x2,y2,z2) (x1,y2,z2)
++ square (x1,y1,z1) (x2,y1,z1) (x2,y1,z2) (x1,y1,z2)
++ rsquare (x1,y2,z1) (x2,y2,z1) (x2,y2,z2) (x1,y2,z2)
++ square (x1,y1,z1) (x1,y1,z2) (x1,y2,z2) (x1,y2,z1)
++ rsquare (x2,y1,z1) (x2,y1,z2) (x2,y2,z2) (x2,y2,z1)
symbolicGetMesh res (Sphere r) = half1 ++ half2
where
square a b c d = [(a,b,c),(d,a,c)]
rsquare a b c d = [(c,b,a),(c,a,d)]
m = max 3 (fromIntegral $ ceiling $ 1.5*r/res)
n = 2*m
spherical θ φ = (r*cos(θ), r*sin(θ)*cos(φ), r*sin(θ)*sin(φ))
f n' m' = spherical (2*pi*n'/n) (pi*m'/m)
half1 = concat [ square (f m1 m2) (f (m1+1) m2) (f (m1+1) (m2+1)) (f m1 (m2+1))
| m1 <- [0.. m1], m2 <- [0.. m1] ]
half2 = concat [ rsquare (f m1 m2) (f (m1+1) m2) (f (m1+1) (m2+1)) (f m1 (m2+1))
| m1 <- [m.. n1], m2 <- [0.. m1] ]
symbolicGetMesh res (ExtrudeR r obj2 h) =
let
obj2mag :: ℝ2 -> ℝ
obj2mag = getImplicit2 obj2
dh x y = sqrt (r^2 ( max 0 $ min r $ r+obj2mag (x,y))^2)
segify (a:b:xs) = (a,b):(segify $ b:xs)
segify _ = []
flipTri (a,b,c) = (a,c,b)
segToSide (x1,y1) (x2,y2) =
[((x1,y1,rdh x1 y1), (x2,y2,rdh x2 y2), (x2,y2,hr+dh x2 y2)),
((x1,y1,rdh x1 y1), (x2,y2,hr+dh x2 y2), (x1,y1,hr+dh x1 y1)) ]
segs = concat $ map segify $ symbolicGetOrientedContour res obj2
side_tris = concat $ map (\(a,b) -> segToSide a b) segs
fill_tris = symbolicGetContourMesh res obj2
bottom_tris = map flipTri $ [((a1,a2,rdh a1 a2), (b1,b2,r dh b1 b2), (c1,c2,r dh c1 c2))
| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
top_tris = [((a1,a2,hr+dh a1 a2), (b1,b2,hr+dh b1 b2), (c1,c2,hr+dh c1 c2))
| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
in
side_tris ++ bottom_tris ++ top_tris
symbolicGetMesh res (ExtrudeRM r@0 twist scale translate obj2 h@(Left _)) =
let
obj2mag :: Obj2
obj2mag = getImplicit2 obj2
twist' = Maybe.fromMaybe (const 0) twist
scale' = Maybe.fromMaybe (const 1) scale
translate' = Maybe.fromMaybe (const (0,0)) translate
h' = case h of
Left n -> const n
Right f -> f
dh x y = sqrt (r^2 ( max 0 $ min r $ r+obj2mag (x,y))^2)
segify (a:b:xs) = (a,b):(segify $ b:xs)
segify _ = []
flipTri (a,b,c) = (a,c,b)
n = max 4 $ fromIntegral $ ceiling $ h' (0,0)/res
segToSide m (x1,y1) (x2,y2) =
let
mainH1 = h' (x1, y1) 2*r + 2*dh x1 y1
mainH2 = h' (x2, y2) 2*r + 2*dh x2 y2
la1 = rdh x1 y1 + mainH1*m/n
lb1 = rdh x1 y1 + mainH1*(m+1)/n
la2 = rdh x2 y2 + mainH2*m/n
lb2 = rdh x2 y2 + mainH2*(m+1)/n
in
[((x1,y1,la1), (x2,y2,la2), (x2,y2,lb2)),
((x1,y1,la1), (x2,y2,lb2), (x1,y1,lb1)) ]
segs = concat $ map segify $ symbolicGetOrientedContour res obj2
side_tris = map flipTri $ concat $
[concat $ map (\(a,b) -> segToSide m a b) segs | m <- [0.. n1] ]
fill_tris = symbolicGetContourMesh res obj2
bottom_tris = [((a1,a2,rdh a1 a2), (b1,b2,r dh b1 b2), (c1,c2,r dh c1 c2))
| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
top_tris = map flipTri $ [((a1,a2,h' (a1,a2) r+dh a1 a2), (b1,b2,h' (b1,b2) r+dh b1 b2), (c1,c2,h' (c1,c2)r+dh c1 c2))
| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
k = 2*pi/360
fx :: ℝ3 -> ℝ
fx (x,y,z) = let (tx,ty) = translate' z in
scale' z *((x+tx)*cos(k*twist' z) + (y+ty)*sin(k*twist' z))
fy :: ℝ3 -> ℝ
fy (x,y,z) =let (tx,ty) = translate' z in
scale' z *((x+tx)*sin(k*twist' z) (y+ty)*cos(k*twist' z))
transformTriangle :: (ℝ3,ℝ3,ℝ3) -> (ℝ3,ℝ3,ℝ3)
transformTriangle (a@(_,_,z1), b@(_,_,z2), c@(_,_,z3)) =
((fx a, fy a, z1), (fx b, fy b, z2), (fx c, fy c, z3))
in
map transformTriangle (side_tris ++ bottom_tris ++ top_tris)
symbolicGetMesh res inputObj@(UnionR3 r objs) =
let
boxes = map getBox3 objs
boxedObjs = zip boxes objs
sepFree ((box,obj):others) =
if length (filter (box3sWithin r box) boxes) > 1
then (\(a,b) -> (obj:a,b)) $ sepFree others
else (\(a,b) -> (a,obj:b)) $ sepFree others
sepFree [] = ([],[])
(dependants, independents) = sepFree boxedObjs
in if null independents
then case rebound3 (getImplicit3 inputObj, getBox3 inputObj) of
(obj, (a,b)) -> getMesh a b res obj
else if null dependants
then concat $ map (symbolicGetMesh res) independents
else concat $
map (symbolicGetMesh res) independents
++ [symbolicGetMesh res (UnionR3 r dependants)]
symbolicGetMesh res obj =
case rebound3 (getImplicit3 obj, getBox3 obj) of
(obj, (a,b)) -> getMesh a b res obj