@@ -205,6 +205,175 @@ function surface_nets(data::Vector{T}, dims,eps,scale,origin) where {T}
205
205
vertices, faces # faces are quads, indexed to vertices
206
206
end
207
207
208
+ """
209
+ Generate a mesh using naive surface nets.
210
+ This takes the center of mass of the voxel as the vertex for each cube.
211
+ """
212
+ function surface_nets (f:: Function , dims:: NTuple{3,Int} ,eps,scale,origin)
213
+
214
+ # TODO
215
+ T = Float64
216
+
217
+ vertices = Point{3 ,T}[]
218
+ faces = Face{4 ,Int}[]
219
+
220
+ sizehint! (vertices,ceil (Int,maximum (dims)^ 2 / 2 ))
221
+ sizehint! (faces,ceil (Int,maximum (dims)^ 2 / 2 ))
222
+
223
+ n = 0
224
+ x = [0 ,0 ,0 ]
225
+ R = Array {Int} ([1 , (dims[1 ]+ 1 ), (dims[1 ]+ 1 )* (dims[2 ]+ 1 )])
226
+ buf_no = 1
227
+
228
+ buffer = fill (zero (Int),R[3 ]* 2 )
229
+
230
+ v = Vector {T} ([0.0 ,0.0 ,0.0 ])
231
+
232
+ # March over the voxel grid
233
+ x[3 ] = 0
234
+ @inbounds while x[3 ]< dims[3 ]- 1
235
+
236
+ # m is the pointer into the buffer we are going to use.
237
+ # This is slightly obtuse because javascript does not have good support for packed data structures, so we must use typed arrays :(
238
+ # The contents of the buffer will be the indices of the vertices on the previous x/y slice of the volume
239
+ m = 1 + (dims[1 ]+ 1 ) * (1 + buf_no * (dims[2 ]+ 1 ))
240
+
241
+ x[2 ]= 0
242
+ @inbounds while x[2 ]< dims[2 ]- 1
243
+
244
+ x[1 ]= 0
245
+ @inbounds while x[1 ] < dims[1 ]- 1
246
+
247
+ # Read in 8 field values around this vertex and store them in an array
248
+ points = (Point {3,Float64} (x[1 ],x[2 ],x[3 ]).* scale + origin,
249
+ Point {3,Float64} (x[1 ]+ 1 ,x[2 ],x[3 ]).* scale + origin,
250
+ Point {3,Float64} (x[1 ],x[2 ]+ 1 ,x[3 ]).* scale + origin,
251
+ Point {3,Float64} (x[1 ]+ 1 ,x[2 ]+ 1 ,x[3 ]).* scale + origin,
252
+ Point {3,Float64} (x[1 ],x[2 ],x[3 ]+ 1 ).* scale + origin,
253
+ Point {3,Float64} (x[1 ]+ 1 ,x[2 ],x[3 ]+ 1 ).* scale + origin,
254
+ Point {3,Float64} (x[1 ],x[2 ]+ 1 ,x[3 ]+ 1 ).* scale + origin,
255
+ Point {3,Float64} (x[1 ]+ 1 ,x[2 ]+ 1 ,x[3 ]+ 1 ).* scale + origin)
256
+
257
+ @inbounds grid = map (f, points)
258
+
259
+ # Also calculate 8-bit mask, like in marching cubes, so we can speed up sign checks later
260
+ mask = 0x00
261
+ signbit (grid[1 ]) && (mask |= 0x01 )
262
+ signbit (grid[2 ]) && (mask |= 0x02 )
263
+ signbit (grid[3 ]) && (mask |= 0x04 )
264
+ signbit (grid[4 ]) && (mask |= 0x08 )
265
+ signbit (grid[5 ]) && (mask |= 0x10 )
266
+ signbit (grid[6 ]) && (mask |= 0x20 )
267
+ signbit (grid[7 ]) && (mask |= 0x40 )
268
+ signbit (grid[8 ]) && (mask |= 0x80 )
269
+
270
+ # Check for early termination if cell does not intersect boundary
271
+ if mask == 0x00 || mask == 0xff
272
+ x[1 ] += 1
273
+ n += 1
274
+ m += 1
275
+ continue
276
+ end
277
+
278
+ # Sum up edge intersections
279
+ edge_mask = sn_edge_table[mask+ 1 ]
280
+ v[1 ] = 0.0
281
+ v[2 ] = 0.0
282
+ v[3 ] = 0.0
283
+ e_count = 0
284
+
285
+ # For every edge of the cube...
286
+ @inbounds for i= 0 : 11
287
+
288
+ # Use edge mask to check if it is crossed
289
+ if (edge_mask & (1 << i)) == 0
290
+ continue
291
+ end
292
+
293
+ # If it did, increment number of edge crossings
294
+ e_count += 1
295
+
296
+ # Now find the point of intersection
297
+ e0 = cube_edges[(i<< 1 )+ 1 ] # Unpack vertices
298
+ e1 = cube_edges[(i<< 1 )+ 2 ]
299
+ g0 = grid[e0+ 1 ] # Unpack grid values
300
+ g1 = grid[e1+ 1 ]
301
+ t = g0 - g1 # Compute point of intersection
302
+ if abs (t) > eps
303
+ t = g0 / t
304
+ else
305
+ continue
306
+ end
307
+
308
+ # Interpolate vertices and add up intersections (this can be done without multiplying)
309
+ k = 1
310
+ for j = 1 : 3
311
+ a = e0 & k
312
+ b = e1 & k
313
+ (a != 0 ) && (v[j] += 1.0 )
314
+ if a != b
315
+ v[j] += (a != 0 ? - t : t)
316
+ end
317
+ k<<= 1
318
+ end
319
+ end # edge check
320
+
321
+ # Now we just average the edge intersections and add them to coordinate
322
+ s = 1.0 / e_count
323
+ for i= 1 : 3
324
+ @inbounds v[i] = (x[i] + s * v[i])# * scale[i] + origin[i]
325
+ end
326
+
327
+ # Add vertex to buffer, store pointer to vertex index in buffer
328
+ buffer[m+ 1 ] = length (vertices)
329
+ push! (vertices, Point {3,T} (v[1 ],v[2 ],v[3 ]))
330
+
331
+ # Now we need to add faces together, to do this we just loop over 3 basis components
332
+ for i= 0 : 2
333
+ # The first three entries of the edge_mask count the crossings along the edge
334
+ if (edge_mask & (1 << i)) == 0
335
+ continue
336
+ end
337
+
338
+ # i = axes we are point along. iu, iv = orthogonal axes
339
+ iu = (i+ 1 )% 3
340
+ iv = (i+ 2 )% 3
341
+
342
+ # If we are on a boundary, skip it
343
+ if (x[iu+ 1 ] == 0 || x[iv+ 1 ] == 0 )
344
+ continue
345
+ end
346
+
347
+ # Otherwise, look up adjacent edges in buffer
348
+ du = R[iu+ 1 ]
349
+ dv = R[iv+ 1 ]
350
+
351
+ # Remember to flip orientation depending on the sign of the corner.
352
+ if (mask & 0x01 ) != 0x00
353
+ push! (faces,Face {4,Int} (buffer[m+ 1 ]+ 1 , buffer[m- du+ 1 ]+ 1 , buffer[m- du- dv+ 1 ]+ 1 , buffer[m- dv+ 1 ]+ 1 ));
354
+ else
355
+ push! (faces,Face {4,Int} (buffer[m+ 1 ]+ 1 , buffer[m- dv+ 1 ]+ 1 , buffer[m- du- dv+ 1 ]+ 1 , buffer[m- du+ 1 ]+ 1 ));
356
+ end
357
+ end
358
+ x[1 ] += 1
359
+ n += 1
360
+ m += 1
361
+ end
362
+ x[2 ] += 1
363
+ n += 1
364
+ m += 2
365
+ end
366
+ x[3 ] += 1
367
+ n+= dims[1 ]
368
+ buf_no = xor (buf_no,1 )
369
+ R[3 ]= - R[3 ]
370
+ end
371
+ # All done! Return the result
372
+
373
+ vertices, faces # faces are quads, indexed to vertices
374
+ end
375
+
376
+
208
377
struct NaiveSurfaceNets{T} <: AbstractMeshingAlgorithm
209
378
iso:: T
210
379
eps:: T
@@ -235,3 +404,18 @@ function (::Type{MT})(sdf::SignedDistanceField, method::NaiveSurfaceNets) where
235
404
orig)
236
405
MT (vts, fcs):: MT
237
406
end
407
+
408
+ function (:: Type{MT} )(f:: Function , bounds:: HyperRectangle , size:: NTuple{3,Int} , method:: NaiveSurfaceNets ) where {MT <: AbstractMesh }
409
+ orig = origin (bounds)
410
+ w = widths (bounds)
411
+ scale = w ./ Point (size .- 1 ) # subtract 1 because an SDF with N points per side has N-1 cells
412
+
413
+ # TODO ISO val
414
+
415
+ vts, fcs = surface_nets (f,
416
+ size,
417
+ method. eps,
418
+ scale,
419
+ orig)
420
+ MT (vts, fcs):: MT
421
+ end
0 commit comments