@@ -392,6 +392,144 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
392392 MT (vts,fcs)
393393end
394394
395+
396+ function marching_cubes (f:: Function ,
397+ bounds:: HyperRectangle ,
398+ samples:: NTuple{3,Int} = (256 ,256 ,256 ),
399+ iso= 0.0 ,
400+ MT:: Type{M} = SimpleMesh{Point{3 ,Float64},Face{3 ,Int}},
401+ eps= 0.00001 ) where {ST,FT,M<: AbstractMesh }
402+ nx, ny, nz = samples[1 ], samples[2 ], samples[3 ]
403+ w = widths (bounds)
404+ orig = origin (bounds)
405+
406+ # we subtract one from the length along each axis because
407+ # an NxNxN SDF has N-1 cells on each axis
408+ s = Point {3,Float64} (w[1 ]/ (nx- 1 ), w[2 ]/ (ny- 1 ), w[3 ]/ (nz- 1 ))
409+
410+ # arrays for vertices and faces
411+ vts = Point{3 ,Float64}[]
412+ fcs = Face{3 ,Int}[]
413+ mt = max (nx,ny,nz)
414+ sizehint! (vts, mt* mt* 6 )
415+ sizehint! (fcs, mt* mt* 2 )
416+ vertlist = Vector {Point{3,Float64}} (undef, 12 )
417+ iso_vals = Vector {Float64} (undef,8 )
418+ points = Vector {Point{3,Float64}} (undef,8 )
419+ @inbounds for xi = 1 : nx- 1 , yi = 1 : ny- 1 , zi = 1 : nz- 1
420+
421+
422+ if zi == 1
423+ points[1 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi- 1 ) .* s .+ orig
424+ points[2 ] = Point {3,Float64} (xi,yi- 1 ,zi- 1 ) .* s .+ orig
425+ points[3 ] = Point {3,Float64} (xi,yi,zi- 1 ) .* s .+ orig
426+ points[4 ] = Point {3,Float64} (xi- 1 ,yi,zi- 1 ) .* s .+ orig
427+ points[5 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi) .* s .+ orig
428+ points[6 ] = Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig
429+ points[7 ] = Point {3,Float64} (xi,yi,zi) .* s .+ orig
430+ points[8 ] = Point {3,Float64} (xi- 1 ,yi,zi) .* s .+ orig
431+ for i = 1 : 8
432+ iso_vals[i] = f (points[i])
433+ end
434+ else
435+ points[1 ] = points[5 ]
436+ points[2 ] = points[6 ]
437+ points[3 ] = points[7 ]
438+ points[4 ] = points[8 ]
439+ points[5 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi) .* s .+ orig
440+ points[6 ] = Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig
441+ points[7 ] = Point {3,Float64} (xi,yi,zi) .* s .+ orig
442+ points[8 ] = Point {3,Float64} (xi- 1 ,yi,zi) .* s .+ orig
443+ iso_vals[1 ] = iso_vals[5 ]
444+ iso_vals[2 ] = iso_vals[6 ]
445+ iso_vals[3 ] = iso_vals[7 ]
446+ iso_vals[4 ] = iso_vals[8 ]
447+ iso_vals[5 ] = f (points[5 ])
448+ iso_vals[6 ] = f (points[6 ])
449+ iso_vals[7 ] = f (points[7 ])
450+ iso_vals[8 ] = f (points[8 ])
451+ end
452+
453+ # Determine the index into the edge table which
454+ # tells us which vertices are inside of the surface
455+ cubeindex = iso_vals[1 ] < iso ? 1 : 0
456+ iso_vals[2 ] < iso && (cubeindex |= 2 )
457+ iso_vals[3 ] < iso && (cubeindex |= 4 )
458+ iso_vals[4 ] < iso && (cubeindex |= 8 )
459+ iso_vals[5 ] < iso && (cubeindex |= 16 )
460+ iso_vals[6 ] < iso && (cubeindex |= 32 )
461+ iso_vals[7 ] < iso && (cubeindex |= 64 )
462+ iso_vals[8 ] < iso && (cubeindex |= 128 )
463+ cubeindex += 1
464+
465+ # Cube is entirely in/out of the surface
466+ edge_table[cubeindex] == 0 && continue
467+
468+ # Find the vertices where the surface intersects the cube
469+ # TODO this can use the underlying function to find the zero.
470+ # The underlying space is non-linear so there will be error otherwise
471+ if (edge_table[cubeindex] & 1 != 0 )
472+ vertlist[1 ] =
473+ vertex_interp (iso,points[1 ],points[2 ],iso_vals[1 ],iso_vals[2 ], eps)
474+ end
475+ if (edge_table[cubeindex] & 2 != 0 )
476+ vertlist[2 ] =
477+ vertex_interp (iso,points[2 ],points[3 ],iso_vals[2 ],iso_vals[3 ], eps)
478+ end
479+ if (edge_table[cubeindex] & 4 != 0 )
480+ vertlist[3 ] =
481+ vertex_interp (iso,points[3 ],points[4 ],iso_vals[3 ],iso_vals[4 ], eps)
482+ end
483+ if (edge_table[cubeindex] & 8 != 0 )
484+ vertlist[4 ] =
485+ vertex_interp (iso,points[4 ],points[1 ],iso_vals[4 ],iso_vals[1 ], eps)
486+ end
487+ if (edge_table[cubeindex] & 16 != 0 )
488+ vertlist[5 ] =
489+ vertex_interp (iso,points[5 ],points[6 ],iso_vals[5 ],iso_vals[6 ], eps)
490+ end
491+ if (edge_table[cubeindex] & 32 != 0 )
492+ vertlist[6 ] =
493+ vertex_interp (iso,points[6 ],points[7 ],iso_vals[6 ],iso_vals[7 ], eps)
494+ end
495+ if (edge_table[cubeindex] & 64 != 0 )
496+ vertlist[7 ] =
497+ vertex_interp (iso,points[7 ],points[8 ],iso_vals[7 ],iso_vals[8 ], eps)
498+ end
499+ if (edge_table[cubeindex] & 128 != 0 )
500+ vertlist[8 ] =
501+ vertex_interp (iso,points[8 ],points[5 ],iso_vals[8 ],iso_vals[5 ], eps)
502+ end
503+ if (edge_table[cubeindex] & 256 != 0 )
504+ vertlist[9 ] =
505+ vertex_interp (iso,points[1 ],points[5 ],iso_vals[1 ],iso_vals[5 ], eps)
506+ end
507+ if (edge_table[cubeindex] & 512 != 0 )
508+ vertlist[10 ] =
509+ vertex_interp (iso,points[2 ],points[6 ],iso_vals[2 ],iso_vals[6 ], eps)
510+ end
511+ if (edge_table[cubeindex] & 1024 != 0 )
512+ vertlist[11 ] =
513+ vertex_interp (iso,points[3 ],points[7 ],iso_vals[3 ],iso_vals[7 ], eps)
514+ end
515+ if (edge_table[cubeindex] & 2048 != 0 )
516+ vertlist[12 ] =
517+ vertex_interp (iso,points[4 ],points[8 ],iso_vals[4 ],iso_vals[8 ], eps)
518+ end
519+
520+ # Create the triangle
521+ for i = 1 : 3 : 13
522+ tri_table[cubeindex][i] == - 1 && break
523+ push! (vts, vertlist[tri_table[cubeindex][i ]])
524+ push! (vts, vertlist[tri_table[cubeindex][i+ 1 ]])
525+ push! (vts, vertlist[tri_table[cubeindex][i+ 2 ]])
526+ fct = length (vts)
527+ push! (fcs, Face {3,Int} (fct, fct- 1 , fct- 2 ))
528+ end
529+ end
530+ MT (vts,fcs)
531+ end
532+
395533# Linearly interpolate the position where an isosurface cuts
396534# an edge between two vertices, each with their own scalar value
397535function vertex_interp (iso, p1, p2, valp1, valp2, eps = 0.00001 )
@@ -415,3 +553,7 @@ MarchingCubes(iso::T1=0.0, eps::T2=1e-3) where {T1, T2} = MarchingCubes{promote_
415553function (:: Type{MT} )(df:: SignedDistanceField , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
416554 marching_cubes (df, method. iso, MT, method. eps)
417555end
556+
557+ function (:: Type{MT} )(f:: Function , h:: HyperRectangle , size:: NTuple{3,Int} , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
558+ marching_cubes (f, h, size, method. iso, MT, method. eps)
559+ end
0 commit comments