@@ -305,21 +305,6 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
305
305
vertlist = Vector {Point{3,Float64}} (undef, 12 )
306
306
@inbounds for xi = 1 : nx- 1 , yi = 1 : ny- 1 , zi = 1 : nz- 1
307
307
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
-
323
308
points = (Point {3,Float64} (xi- 1 ,yi- 1 ,zi- 1 ) .* s .+ orig,
324
309
Point {3,Float64} (xi,yi- 1 ,zi- 1 ) .* s .+ orig,
325
310
Point {3,Float64} (xi,yi,zi- 1 ) .* s .+ orig,
@@ -328,57 +313,123 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
328
313
Point {3,Float64} (xi,yi- 1 ,zi) .* s .+ orig,
329
314
Point {3,Float64} (xi,yi,zi) .* s .+ orig,
330
315
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
331
339
332
340
# 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 ))
376
351
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 ])
380
411
end
381
412
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
+
382
433
# Create the triangle
383
434
for i = 1 : 3 : 13
384
435
tri_table[cubeindex][i] == - 1 && break
@@ -392,6 +443,57 @@ function marching_cubes(sdf::SignedDistanceField{3,ST,FT},
392
443
MT (vts,fcs)
393
444
end
394
445
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
+
395
497
# Linearly interpolate the position where an isosurface cuts
396
498
# an edge between two vertices, each with their own scalar value
397
499
function 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_
415
517
function (:: Type{MT} )(df:: SignedDistanceField , method:: MarchingCubes ):: MT where {MT <: AbstractMesh }
416
518
marching_cubes (df, method. iso, MT, method. eps)
417
519
end
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