@@ -392,6 +392,144 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
392
392
MT (vts,fcs)
393
393
end
394
394
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
+
395
533
# Linearly interpolate the position where an isosurface cuts
396
534
# an edge between two vertices, each with their own scalar value
397
535
function 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_
415
553
function (:: Type{MT} )(df:: SignedDistanceField , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
416
554
marching_cubes (df, method. iso, MT, method. eps)
417
555
end
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