module Graphics.Implicit.Export.MarchingSquaresFill (getContourMesh) where
import Prelude(Bool(True, False), ($), (-), (+), (/), (*), (<=), ceiling, max, div, floor)
import Graphics.Implicit.Definitions (ℕ, ℝ, ℝ2, both, Polytri(Polytri), Obj2, (⋯/), (⋯*), fromℕtoℝ, fromℕ)
import Data.VectorSpace ((^-^),(^+^))
import Data.List(genericIndex)
import Data.Foldable (fold)
import Control.Parallel.Strategies (using, rdeepseq, parBuffer, parList)
getContourMesh :: ℝ2 -> ℝ2 -> ℝ2 -> Obj2 -> [Polytri]
getContourMesh p1 p2 res obj =
let
d = p2 ^-^ p1
nx :: ℕ
ny :: ℕ
n@(nx,ny) = ceiling `both` (d ⋯/ res)
gridPos :: (ℕ,ℕ) -> (ℕ,ℕ) -> ℝ2
gridPos n' m = p1 ^+^ d ⋯* ((fromℕtoℝ `both` m) ⋯/ (fromℕtoℝ `both` n'))
toGrid :: ℝ2 -> (ℕ,ℕ)
toGrid f = floor `both` ((fromℕtoℝ `both` n) ⋯* (f ^-^ p1) ⋯/ d)
valsOnGrid :: [[ℝ]]
valsOnGrid = [[ obj $ gridPos n (mx, my) | mx <- [0..nx-1] ] | my <- [0..ny-1] ] `using` parList rdeepseq
preEvaledObj p = valsOnGrid `genericIndex` my `genericIndex` mx where (mx,my) = toGrid p
trisOnGrid :: [[[Polytri]]]
trisOnGrid = [[getSquareTriangles (gridPos n (mx,my)) (gridPos n (mx+1,my+1)) preEvaledObj
| mx <- [0..nx-1] ] | my <- [0..ny-1] ] `using` parBuffer (max 1 $ fromℕ $ div ny 32) rdeepseq
triangles = fold $ fold trisOnGrid
in
triangles
getSquareTriangles :: ℝ2 -> ℝ2 -> Obj2 -> [Polytri]
getSquareTriangles (x1, y1) (x2, y2) obj =
let
(x,y) = (x1, y1)
x1y1 = obj (x1, y1)
x2y1 = obj (x2, y1)
x1y2 = obj (x1, y2)
x2y2 = obj (x2, y2)
c = obj ((x1+x2)/2, (y1+y2)/2)
dx = x2 - x1
dy = y2 - y1
intx1 = (x, y + dy*x1y1/(x1y1-x1y2))
intx2 = (x + dx, y + dy*x2y1/(x2y1-x2y2))
inty1 = (x + dx*x1y1/(x1y1-x2y1), y )
inty2 = (x + dx*x1y2/(x1y2-x2y2), y + dy)
square :: ℝ2 -> ℝ2 -> ℝ2 -> ℝ2 -> [Polytri]
square aa bb cc dd = [Polytri (aa,bb,cc), Polytri (aa,cc,dd)]
in case (x1y1 <= 0, x2y1 <= 0, x2y2 <= 0, x1y2 <= 0, c <= 0) of
(False, False, False, False, _) -> []
( True, True, True, True, _) -> square (x1,y1) (x2,y1) (x2,y2) (x1,y2)
( True, True, False, False, _) -> square (x1,y1) (x2,y1) intx2 intx1
(False, True, True, False, _) -> square inty1 (x2,y1) (x2,y2) inty2
(False, False, True, True, _) -> square intx1 intx2 (x2,y2) (x1,y2)
( True, False, False, True, _) -> square (x1,y1) inty1 inty2 (x1,y2)
(False, False, False, True, _) -> [Polytri ( intx1 , inty2 , (x1,y2))]
(False, False, True, False, _) -> [Polytri ( intx2 , (x2,y2), inty2 )]
(False, True, False, False, _) -> [Polytri ( inty1 , (x2,y1), intx1 )]
( True, False, False, False, _) -> [Polytri ((x1,y1), inty1 , intx1 )]
(False, True, True, True, _) -> [Polytri ( intx1 , (x2,y2), (x1,y2)), Polytri ( inty1 , (x2,y2), intx1 ), Polytri ( inty1 , (x2,y1), (x2,y2))]
( True, False, True, True, _) -> [Polytri ((x1,y1), inty1 , (x1,y2)), Polytri ( inty1 , intx2 , (x1,y2)), Polytri ( intx2 , (x2,y2), (x1,y2))]
( True, True, False, True, _) -> [Polytri ((x1,y1), inty2 , (x1,y2)), Polytri ((x1,y1), intx2 , inty2 ), Polytri ((x1,y1), (x2,y1), intx2 )]
( True, True, True, False, _) -> [Polytri ((x1,y1), (x2,y1), intx1 ), Polytri ( intx1 , (x2,y1), inty2 ), Polytri ((x2,y1), (x2,y2), inty2 )]
(False, True, False, True, False) -> [Polytri ( inty1 , (x1,y2), intx1 ), Polytri ((x2,y1), inty2 , intx2 )]
(False, True, False, True, True) -> [Polytri ( inty1 , (x1,y2), intx1 ), Polytri ((x2,y1), inty2 , intx2 ), Polytri ( inty1 , (x2,y1), (x1,y2)), Polytri ((x2,y1), inty2, (x1,y2))]
( True, False, True, False, False) -> [Polytri ((x1,y1), inty1 , intx2 ), Polytri ( intx1 , (x2,y2), inty2 )]
( True, False, True, False, True) -> [Polytri ((x1,y1), inty1 , intx2 ), Polytri ( intx1 , (x2,y2), inty2 ), Polytri ((x1,y1), intx2 , (x2,y2)), Polytri ((x1,y1), (x2,y2), intx1)]