@@ -305,21 +305,6 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
305305 vertlist = Vector {Point{3,Float64}} (undef, 12 )
306306 @inbounds for xi = 1 : nx- 1 , yi = 1 : ny- 1 , zi = 1 : nz- 1
307307
308- # Determine the index into the edge table which
309- # tells us which vertices are inside of the surface
310- cubeindex = sdf[xi,yi,zi] < iso ? 1 : 0
311- sdf[xi+ 1 ,yi,zi] < iso && (cubeindex |= 2 )
312- sdf[xi+ 1 ,yi+ 1 ,zi] < iso && (cubeindex |= 4 )
313- sdf[xi,yi+ 1 ,zi] < iso && (cubeindex |= 8 )
314- sdf[xi,yi,zi+ 1 ] < iso && (cubeindex |= 16 )
315- sdf[xi+ 1 ,yi,zi+ 1 ] < iso && (cubeindex |= 32 )
316- sdf[xi+ 1 ,yi+ 1 ,zi+ 1 ] < iso && (cubeindex |= 64 )
317- sdf[xi,yi+ 1 ,zi+ 1 ] < iso && (cubeindex |= 128 )
318- cubeindex += 1
319-
320- # Cube is entirely in/out of the surface
321- edge_table[cubeindex] == 0 && continue
322-
323308 points = (Point {3,Float64} (xi- 1 ,yi- 1 ,zi- 1 ) .* s .+ orig,
324309 Point {3,Float64} (xi,yi- 1 ,zi- 1 ) .* s .+ orig,
325310 Point {3,Float64} (xi,yi,zi- 1 ) .* s .+ orig,
@@ -328,57 +313,123 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
328313 Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig,
329314 Point {3,Float64} (xi,yi,zi) .* s .+ orig,
330315 Point {3,Float64} (xi- 1 ,yi,zi) .* s .+ orig)
316+ iso_vals = (sdf[xi,yi,zi],
317+ sdf[xi+ 1 ,yi,zi],
318+ sdf[xi+ 1 ,yi+ 1 ,zi],
319+ sdf[xi,yi+ 1 ,zi],
320+ sdf[xi,yi,zi+ 1 ],
321+ sdf[xi+ 1 ,yi,zi+ 1 ],
322+ sdf[xi+ 1 ,yi+ 1 ,zi+ 1 ],
323+ sdf[xi,yi+ 1 ,zi+ 1 ])
324+
325+ # Determine the index into the edge table which
326+ # tells us which vertices are inside of the surface
327+ cubeindex = iso_vals[1 ] < iso ? 1 : 0
328+ iso_vals[2 ] < iso && (cubeindex |= 2 )
329+ iso_vals[3 ] < iso && (cubeindex |= 4 )
330+ iso_vals[4 ] < iso && (cubeindex |= 8 )
331+ iso_vals[5 ] < iso && (cubeindex |= 16 )
332+ iso_vals[6 ] < iso && (cubeindex |= 32 )
333+ iso_vals[7 ] < iso && (cubeindex |= 64 )
334+ iso_vals[8 ] < iso && (cubeindex |= 128 )
335+ cubeindex += 1
336+
337+ # Cube is entirely in/out of the surface
338+ edge_table[cubeindex] == 0 && continue
331339
332340 # Find the vertices where the surface intersects the cube
333- if (edge_table[cubeindex] & 1 != 0 )
334- vertlist[1 ] =
335- vertex_interp (iso,points[1 ],points[2 ],sdf[xi,yi,zi],sdf[xi+ 1 ,yi,zi], eps)
336- end
337- if (edge_table[cubeindex] & 2 != 0 )
338- vertlist[2 ] =
339- vertex_interp (iso,points[2 ],points[3 ],sdf[xi+ 1 ,yi,zi],sdf[xi+ 1 ,yi+ 1 ,zi], eps)
340- end
341- if (edge_table[cubeindex] & 4 != 0 )
342- vertlist[3 ] =
343- vertex_interp (iso,points[3 ],points[4 ],sdf[xi+ 1 ,yi+ 1 ,zi],sdf[xi,yi+ 1 ,zi], eps)
344- end
345- if (edge_table[cubeindex] & 8 != 0 )
346- vertlist[4 ] =
347- vertex_interp (iso,points[4 ],points[1 ],sdf[xi,yi+ 1 ,zi],sdf[xi,yi,zi], eps)
348- end
349- if (edge_table[cubeindex] & 16 != 0 )
350- vertlist[5 ] =
351- vertex_interp (iso,points[5 ],points[6 ],sdf[xi,yi,zi+ 1 ],sdf[xi+ 1 ,yi,zi+ 1 ], eps)
352- end
353- if (edge_table[cubeindex] & 32 != 0 )
354- vertlist[6 ] =
355- vertex_interp (iso,points[6 ],points[7 ],sdf[xi+ 1 ,yi,zi+ 1 ],sdf[xi+ 1 ,yi+ 1 ,zi+ 1 ], eps)
356- end
357- if (edge_table[cubeindex] & 64 != 0 )
358- vertlist[7 ] =
359- vertex_interp (iso,points[7 ],points[8 ],sdf[xi+ 1 ,yi+ 1 ,zi+ 1 ],sdf[xi,yi+ 1 ,zi+ 1 ], eps)
360- end
361- if (edge_table[cubeindex] & 128 != 0 )
362- vertlist[8 ] =
363- vertex_interp (iso,points[8 ],points[5 ],sdf[xi,yi+ 1 ,zi+ 1 ],sdf[xi,yi,zi+ 1 ], eps)
364- end
365- if (edge_table[cubeindex] & 256 != 0 )
366- vertlist[9 ] =
367- vertex_interp (iso,points[1 ],points[5 ],sdf[xi,yi,zi],sdf[xi,yi,zi+ 1 ], eps)
368- end
369- if (edge_table[cubeindex] & 512 != 0 )
370- vertlist[10 ] =
371- vertex_interp (iso,points[2 ],points[6 ],sdf[xi+ 1 ,yi,zi],sdf[xi+ 1 ,yi,zi+ 1 ], eps)
372- end
373- if (edge_table[cubeindex] & 1024 != 0 )
374- vertlist[11 ] =
375- vertex_interp (iso,points[3 ],points[7 ],sdf[xi+ 1 ,yi+ 1 ,zi],sdf[xi+ 1 ,yi+ 1 ,zi+ 1 ], eps)
341+ find_vertices_interp! (vertlist, points, iso_vals, cubeindex, iso, eps)
342+
343+ # Create the triangle
344+ for i = 1 : 3 : 13
345+ tri_table[cubeindex][i] == - 1 && break
346+ push! (vts, vertlist[tri_table[cubeindex][i ]])
347+ push! (vts, vertlist[tri_table[cubeindex][i+ 1 ]])
348+ push! (vts, vertlist[tri_table[cubeindex][i+ 2 ]])
349+ fct = length (vts)
350+ push! (fcs, Face {3,Int} (fct, fct- 1 , fct- 2 ))
376351 end
377- if (edge_table[cubeindex] & 2048 != 0 )
378- vertlist[12 ] =
379- vertex_interp (iso,points[4 ],points[8 ],sdf[xi,yi+ 1 ,zi],sdf[xi,yi+ 1 ,zi+ 1 ], eps)
352+ end
353+ MT (vts,fcs)
354+ end
355+
356+
357+ function marching_cubes (f:: Function ,
358+ bounds:: HyperRectangle ,
359+ samples:: NTuple{3,Int} = (256 ,256 ,256 ),
360+ iso= 0.0 ,
361+ MT:: Type{M} = SimpleMesh{Point{3 ,Float64},Face{3 ,Int}},
362+ eps= 0.00001 ) where {ST,FT,M<: AbstractMesh }
363+ nx, ny, nz = samples[1 ], samples[2 ], samples[3 ]
364+ w = widths (bounds)
365+ orig = origin (bounds)
366+
367+ # we subtract one from the length along each axis because
368+ # an NxNxN SDF has N-1 cells on each axis
369+ s = Point {3,Float64} (w[1 ]/ (nx- 1 ), w[2 ]/ (ny- 1 ), w[3 ]/ (nz- 1 ))
370+
371+ # arrays for vertices and faces
372+ vts = Point{3 ,Float64}[]
373+ fcs = Face{3 ,Int}[]
374+ mt = max (nx,ny,nz)
375+ sizehint! (vts, mt* mt* 6 )
376+ sizehint! (fcs, mt* mt* 2 )
377+ vertlist = Vector {Point{3,Float64}} (undef, 12 )
378+ iso_vals = Vector {Float64} (undef,8 )
379+ points = Vector {Point{3,Float64}} (undef,8 )
380+ @inbounds for xi = 1 : nx- 1 , yi = 1 : ny- 1 , zi = 1 : nz- 1
381+
382+ if zi == 1
383+ points[1 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi- 1 ) .* s .+ orig
384+ points[2 ] = Point {3,Float64} (xi,yi- 1 ,zi- 1 ) .* s .+ orig
385+ points[3 ] = Point {3,Float64} (xi,yi,zi- 1 ) .* s .+ orig
386+ points[4 ] = Point {3,Float64} (xi- 1 ,yi,zi- 1 ) .* s .+ orig
387+ points[5 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi) .* s .+ orig
388+ points[6 ] = Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig
389+ points[7 ] = Point {3,Float64} (xi,yi,zi) .* s .+ orig
390+ points[8 ] = Point {3,Float64} (xi- 1 ,yi,zi) .* s .+ orig
391+ for i = 1 : 8
392+ iso_vals[i] = f (points[i])
393+ end
394+ else
395+ points[1 ] = points[5 ]
396+ points[2 ] = points[6 ]
397+ points[3 ] = points[7 ]
398+ points[4 ] = points[8 ]
399+ points[5 ] = Point {3,Float64} (xi- 1 ,yi- 1 ,zi) .* s .+ orig
400+ points[6 ] = Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig
401+ points[7 ] = Point {3,Float64} (xi,yi,zi) .* s .+ orig
402+ points[8 ] = Point {3,Float64} (xi- 1 ,yi,zi) .* s .+ orig
403+ iso_vals[1 ] = iso_vals[5 ]
404+ iso_vals[2 ] = iso_vals[6 ]
405+ iso_vals[3 ] = iso_vals[7 ]
406+ iso_vals[4 ] = iso_vals[8 ]
407+ iso_vals[5 ] = f (points[5 ])
408+ iso_vals[6 ] = f (points[6 ])
409+ iso_vals[7 ] = f (points[7 ])
410+ iso_vals[8 ] = f (points[8 ])
380411 end
381412
413+ # Determine the index into the edge table which
414+ # tells us which vertices are inside of the surface
415+ cubeindex = iso_vals[1 ] < iso ? 1 : 0
416+ iso_vals[2 ] < iso && (cubeindex |= 2 )
417+ iso_vals[3 ] < iso && (cubeindex |= 4 )
418+ iso_vals[4 ] < iso && (cubeindex |= 8 )
419+ iso_vals[5 ] < iso && (cubeindex |= 16 )
420+ iso_vals[6 ] < iso && (cubeindex |= 32 )
421+ iso_vals[7 ] < iso && (cubeindex |= 64 )
422+ iso_vals[8 ] < iso && (cubeindex |= 128 )
423+ cubeindex += 1
424+
425+ # Cube is entirely in/out of the surface
426+ edge_table[cubeindex] == 0 && continue
427+
428+ # Find the vertices where the surface intersects the cube
429+ # TODO this can use the underlying function to find the zero.
430+ # The underlying space is non-linear so there will be error otherwise
431+ find_vertices_interp! (vertlist, points, iso_vals, cubeindex, iso, eps)
432+
382433 # Create the triangle
383434 for i = 1 : 3 : 13
384435 tri_table[cubeindex][i] == - 1 && break
@@ -392,6 +443,57 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
392443 MT (vts,fcs)
393444end
394445
446+ @inline function find_vertices_interp! (vertlist, points, iso_vals, cubeindex, iso, eps)
447+ if (edge_table[cubeindex] & 1 != 0 )
448+ vertlist[1 ] =
449+ vertex_interp (iso,points[1 ],points[2 ],iso_vals[1 ],iso_vals[2 ], eps)
450+ end
451+ if (edge_table[cubeindex] & 2 != 0 )
452+ vertlist[2 ] =
453+ vertex_interp (iso,points[2 ],points[3 ],iso_vals[2 ],iso_vals[3 ], eps)
454+ end
455+ if (edge_table[cubeindex] & 4 != 0 )
456+ vertlist[3 ] =
457+ vertex_interp (iso,points[3 ],points[4 ],iso_vals[3 ],iso_vals[4 ], eps)
458+ end
459+ if (edge_table[cubeindex] & 8 != 0 )
460+ vertlist[4 ] =
461+ vertex_interp (iso,points[4 ],points[1 ],iso_vals[4 ],iso_vals[1 ], eps)
462+ end
463+ if (edge_table[cubeindex] & 16 != 0 )
464+ vertlist[5 ] =
465+ vertex_interp (iso,points[5 ],points[6 ],iso_vals[5 ],iso_vals[6 ], eps)
466+ end
467+ if (edge_table[cubeindex] & 32 != 0 )
468+ vertlist[6 ] =
469+ vertex_interp (iso,points[6 ],points[7 ],iso_vals[6 ],iso_vals[7 ], eps)
470+ end
471+ if (edge_table[cubeindex] & 64 != 0 )
472+ vertlist[7 ] =
473+ vertex_interp (iso,points[7 ],points[8 ],iso_vals[7 ],iso_vals[8 ], eps)
474+ end
475+ if (edge_table[cubeindex] & 128 != 0 )
476+ vertlist[8 ] =
477+ vertex_interp (iso,points[8 ],points[5 ],iso_vals[8 ],iso_vals[5 ], eps)
478+ end
479+ if (edge_table[cubeindex] & 256 != 0 )
480+ vertlist[9 ] =
481+ vertex_interp (iso,points[1 ],points[5 ],iso_vals[1 ],iso_vals[5 ], eps)
482+ end
483+ if (edge_table[cubeindex] & 512 != 0 )
484+ vertlist[10 ] =
485+ vertex_interp (iso,points[2 ],points[6 ],iso_vals[2 ],iso_vals[6 ], eps)
486+ end
487+ if (edge_table[cubeindex] & 1024 != 0 )
488+ vertlist[11 ] =
489+ vertex_interp (iso,points[3 ],points[7 ],iso_vals[3 ],iso_vals[7 ], eps)
490+ end
491+ if (edge_table[cubeindex] & 2048 != 0 )
492+ vertlist[12 ] =
493+ vertex_interp (iso,points[4 ],points[8 ],iso_vals[4 ],iso_vals[8 ], eps)
494+ end
495+ end
496+
395497# Linearly interpolate the position where an isosurface cuts
396498# an edge between two vertices, each with their own scalar value
397499function vertex_interp (iso, p1, p2, valp1, valp2, eps = 0.00001 )
@@ -415,3 +517,11 @@ MarchingCubes(iso::T1=0.0, eps::T2=1e-3) where {T1, T2} = MarchingCubes{promote_
415517function (:: Type{MT} )(df:: SignedDistanceField , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
416518 marching_cubes (df, method. iso, MT, method. eps)
417519end
520+
521+ function (:: Type{MT} )(f:: Function , h:: HyperRectangle , size:: NTuple{3,Int} , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
522+ marching_cubes (f, h, size, method. iso, MT, method. eps)
523+ end
524+
525+ function (:: Type{MT} )(f:: Function , h:: HyperRectangle , method:: MarchingCubes ; size:: NTuple{3,Int} = (128 ,128 ,128 )):: MT where {MT <: AbstractMesh }
526+ marching_cubes (f, h, size, method. iso, MT, method. eps)
527+ end
0 commit comments