@@ -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