10 #ifndef OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED 11 #define OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED 19 #include <tbb/blocked_range.h> 20 #include <tbb/parallel_for.h> 21 #include <tbb/parallel_reduce.h> 22 #include <tbb/task_arena.h> 28 #include <type_traits> 52 template<
typename Gr
idType>
56 std::vector<Vec3s>& points,
57 std::vector<Vec4I>& quads,
58 double isovalue = 0.0);
73 template<
typename Gr
idType>
77 std::vector<Vec3s>& points,
78 std::vector<Vec3I>& triangles,
79 std::vector<Vec4I>& quads,
80 double isovalue = 0.0,
81 double adaptivity = 0.0,
82 bool relaxDisorientedTriangles =
true);
98 inline PolygonPool(
const size_t numQuads,
const size_t numTriangles);
102 inline void resetQuads(
size_t size);
103 inline void clearQuads();
105 inline void resetTriangles(
size_t size);
106 inline void clearTriangles();
111 const size_t&
numQuads()
const {
return mNumQuads; }
126 const char&
quadFlags(
size_t n)
const {
return mQuadFlags[n]; }
135 inline bool trimQuads(
const size_t n,
bool reallocate =
false);
136 inline bool trimTrinagles(
const size_t n,
bool reallocate =
false);
142 size_t mNumQuads, mNumTriangles;
143 std::unique_ptr<openvdb::Vec4I[]> mQuads;
144 std::unique_ptr<openvdb::Vec3I[]> mTriangles;
145 std::unique_ptr<char[]> mQuadFlags, mTriangleFlags;
167 VolumeToMesh(
double isovalue = 0,
double adaptivity = 0,
bool relaxDisorientedTriangles =
true);
183 const std::vector<uint8_t>&
pointFlags()
const {
return mPointFlags; }
192 template<
typename InputGr
idType>
193 void operator()(
const InputGridType&);
246 size_t mPointListSize, mSeamPointListSize, mPolygonPoolListSize;
247 double mIsovalue, mPrimAdaptivity, mSecAdaptivity;
254 bool mInvertSurfaceMask, mRelaxDisorientedTriangles;
256 std::unique_ptr<uint32_t[]> mQuantizedSeamPoints;
257 std::vector<uint8_t> mPointFlags;
271 const std::vector<Vec3d>& points,
272 const std::vector<Vec3d>& normals)
278 if (points.empty())
return avgPos;
280 for (
size_t n = 0, N = points.size(); n < N; ++n) {
284 avgPos /= double(points.size());
288 double m00=0,m01=0,m02=0,
295 for (
size_t n = 0, N = points.size(); n < N; ++n) {
297 const Vec3d& n_ref = normals[n];
300 m00 += n_ref[0] * n_ref[0];
301 m11 += n_ref[1] * n_ref[1];
302 m22 += n_ref[2] * n_ref[2];
304 m01 += n_ref[0] * n_ref[1];
305 m02 += n_ref[0] * n_ref[2];
306 m12 += n_ref[1] * n_ref[2];
309 rhs += n_ref * n_ref.
dot(points[n] - avgPos);
334 Mat3d D = Mat3d::identity();
337 double tolerance =
std::max(std::abs(eigenValues[0]), std::abs(eigenValues[1]));
338 tolerance =
std::max(tolerance, std::abs(eigenValues[2]));
342 for (
int i = 0; i < 3; ++i ) {
343 if (std::abs(eigenValues[i]) < tolerance) {
347 D[i][i] = 1.0 / eigenValues[i];
354 return avgPos + pseudoInv * rhs;
369 namespace volume_to_mesh_internal {
371 template<
typename ValueType>
374 FillArray(ValueType* array,
const ValueType& v) : mArray(array), mValue(v) { }
376 void operator()(
const tbb::blocked_range<size_t>& range)
const {
377 const ValueType v = mValue;
378 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
383 ValueType *
const mArray;
384 const ValueType mValue;
388 template<
typename ValueType>
390 fillArray(ValueType* array,
const ValueType& val,
const size_t length)
392 const auto grainSize = std::max<size_t>(
393 length / tbb::this_task_arena::max_concurrency(), 1024);
394 const tbb::blocked_range<size_t> range(0, length, grainSize);
395 tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
400 enum { SIGNS = 0xFF, EDGES = 0xE00, INSIDE = 0x100,
401 XEDGE = 0x200, YEDGE = 0x400, ZEDGE = 0x800, SEAM = 0x1000};
405 const bool sAdaptable[256] = {
406 1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,
407 1,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,0,1,
408 1,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
409 1,0,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,1,
410 1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,
411 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,1,
412 1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,
413 1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1};
417 const unsigned char sAmbiguousFace[256] = {
418 0,0,0,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,1,0,0,5,1,0,4,0,0,0,4,0,0,0,
419 0,1,0,0,2,0,0,0,0,1,5,0,2,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0,0,0,0,0,
420 0,0,2,2,0,5,0,0,3,3,0,0,0,0,0,0,6,6,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
421 0,1,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
422 0,4,0,4,3,0,3,0,0,0,5,0,0,0,0,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,
423 6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
424 0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
425 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
431 const unsigned char sEdgeGroupTable[256][13] = {
432 {0,0,0,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},
433 {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},{1,1,1,1,1,0,0,0,0,1,0,1,0},
434 {1,1,0,1,0,0,0,0,0,0,1,1,0},{1,0,0,1,1,0,0,0,0,1,1,1,0},{1,0,0,1,1,0,0,0,0,0,0,0,1},
435 {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,1,1,1,1,0,0,0,0,0,1,0,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},
436 {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},
437 {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,0,0,0,0,1,0,0,1,1,0,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},
438 {1,1,1,0,0,1,0,0,1,1,1,0,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},
439 {1,1,1,1,1,1,0,0,1,0,0,1,0},{1,1,0,1,0,1,0,0,1,1,1,1,0},{1,0,0,1,1,1,0,0,1,0,1,1,0},
440 {1,0,0,1,1,1,0,0,1,1,0,0,1},{1,1,0,1,0,1,0,0,1,0,0,0,1},{2,2,1,1,2,1,0,0,1,2,1,0,1},
441 {1,0,1,1,0,1,0,0,1,0,1,0,1},{1,0,1,0,1,1,0,0,1,1,0,1,1},{1,1,1,0,0,1,0,0,1,0,0,1,1},
442 {2,1,0,0,1,2,0,0,2,1,2,2,2},{1,0,0,0,0,1,0,0,1,0,1,1,1},{1,0,0,0,0,1,1,0,0,0,1,0,0},
443 {1,1,0,0,1,1,1,0,0,1,1,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},
444 {1,0,1,1,0,1,1,0,0,0,1,1,0},{2,2,2,1,1,1,1,0,0,1,2,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},
445 {1,0,0,1,1,1,1,0,0,1,0,1,0},{2,0,0,2,2,1,1,0,0,0,1,0,2},{1,1,0,1,0,1,1,0,0,1,1,0,1},
446 {1,1,1,1,1,1,1,0,0,0,0,0,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},{1,0,1,0,1,1,1,0,0,0,1,1,1},
447 {2,1,1,0,0,2,2,0,0,2,1,2,2},{1,1,0,0,1,1,1,0,0,0,0,1,1},{1,0,0,0,0,1,1,0,0,1,0,1,1},
448 {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},
449 {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,0,1,1,0,0,1,0,1,1,1,1,0},{2,1,1,2,2,0,2,0,2,0,1,2,0},
450 {1,1,0,1,0,0,1,0,1,1,0,1,0},{1,0,0,1,1,0,1,0,1,0,0,1,0},{1,0,0,1,1,0,1,0,1,1,1,0,1},
451 {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,1,2,2,1,0,2,0,2,1,0,0,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},
452 {2,0,2,0,2,0,1,0,1,2,2,1,1},{2,2,2,0,0,0,1,0,1,0,2,1,1},{2,2,0,0,2,0,1,0,1,2,0,1,1},
453 {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,0,0,0,0,0,1,1,0,0,0,1,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},
454 {1,1,1,0,0,0,1,1,0,0,1,1,0},{1,0,1,0,1,0,1,1,0,1,1,1,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},
455 {1,1,1,1,1,0,1,1,0,1,0,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},{1,0,0,1,1,0,1,1,0,1,1,0,0},
456 {1,0,0,1,1,0,1,1,0,0,0,1,1},{1,1,0,1,0,0,1,1,0,1,0,1,1},{2,1,2,2,1,0,1,1,0,0,1,2,1},
457 {2,0,1,1,0,0,2,2,0,2,2,1,2},{1,0,1,0,1,0,1,1,0,0,0,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},
458 {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,0,0,0,0,0,1,1,0,1,1,0,1},{1,0,0,0,0,1,1,1,1,1,0,1,0},
459 {1,1,0,0,1,1,1,1,1,0,0,1,0},{2,1,1,0,0,2,2,1,1,1,2,1,0},{2,0,2,0,2,1,1,2,2,0,1,2,0},
460 {1,0,1,1,0,1,1,1,1,1,0,0,0},{2,2,2,1,1,2,2,1,1,0,0,0,0},{2,2,0,2,0,1,1,2,2,2,1,0,0},
461 {2,0,0,1,1,2,2,1,1,0,2,0,0},{2,0,0,1,1,1,1,2,2,1,0,1,2},{2,2,0,2,0,2,2,1,1,0,0,2,1},
462 {4,3,2,2,3,4,4,1,1,3,4,2,1},{3,0,2,2,0,1,1,3,3,0,1,2,3},{2,0,2,0,2,2,2,1,1,2,0,0,1},
463 {2,1,1,0,0,1,1,2,2,0,0,0,2},{3,1,0,0,1,2,2,3,3,1,2,0,3},{2,0,0,0,0,1,1,2,2,0,1,0,2},
464 {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,1,0,0,1,1,0,1,0,1,1,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},
465 {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},{2,1,1,2,2,2,0,2,0,2,1,0,0},
466 {1,1,0,1,0,1,0,1,0,0,0,0,0},{1,0,0,1,1,1,0,1,0,1,0,0,0},{1,0,0,1,1,1,0,1,0,0,1,1,1},
467 {2,2,0,2,0,1,0,1,0,1,2,2,1},{2,2,1,1,2,2,0,2,0,0,0,1,2},{2,0,2,2,0,1,0,1,0,1,0,2,1},
468 {1,0,1,0,1,1,0,1,0,0,1,0,1},{2,2,2,0,0,1,0,1,0,1,2,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},
469 {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,0,0,0,0,0,0,1,1,1,1,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},
470 {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},
471 {2,2,2,1,1,0,0,1,1,0,2,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},{1,0,0,1,1,0,0,1,1,0,0,0,0},
472 {2,0,0,2,2,0,0,1,1,2,2,2,1},{2,1,0,1,0,0,0,2,2,0,1,1,2},{3,2,1,1,2,0,0,3,3,2,0,1,3},
473 {2,0,1,1,0,0,0,2,2,0,0,1,2},{2,0,1,0,1,0,0,2,2,1,1,0,2},{2,1,1,0,0,0,0,2,2,0,1,0,2},
474 {2,1,0,0,1,0,0,2,2,1,0,0,2},{1,0,0,0,0,0,0,1,1,0,0,0,1},{1,0,0,0,0,0,0,1,1,0,0,0,1},
475 {1,1,0,0,1,0,0,1,1,1,0,0,1},{2,1,1,0,0,0,0,2,2,0,1,0,2},{1,0,1,0,1,0,0,1,1,1,1,0,1},
476 {1,0,1,1,0,0,0,1,1,0,0,1,1},{2,1,1,2,2,0,0,1,1,1,0,1,2},{1,1,0,1,0,0,0,1,1,0,1,1,1},
477 {2,0,0,1,1,0,0,2,2,2,2,2,1},{1,0,0,1,1,0,0,1,1,0,0,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},
478 {1,1,1,1,1,0,0,1,1,0,1,0,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},
479 {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},{1,0,0,0,0,0,0,1,1,1,1,1,0},
480 {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},{1,1,1,0,0,1,0,1,0,1,1,0,1},
481 {1,0,1,0,1,1,0,1,0,0,1,0,1},{1,0,1,1,0,1,0,1,0,1,0,1,1},{2,2,2,1,1,2,0,2,0,0,0,2,1},
482 {2,1,0,1,0,2,0,2,0,1,2,2,1},{2,0,0,2,2,1,0,1,0,0,1,1,2},{1,0,0,1,1,1,0,1,0,1,0,0,0},
483 {1,1,0,1,0,1,0,1,0,0,0,0,0},{2,1,2,2,1,2,0,2,0,1,2,0,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},
484 {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},{2,2,0,0,2,1,0,1,0,2,1,1,0},
485 {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,0,0,0,0,1,1,1,1,0,1,0,1},{2,1,0,0,1,2,1,1,2,2,1,0,1},
486 {1,1,1,0,0,1,1,1,1,0,0,0,1},{2,0,2,0,2,1,2,2,1,1,0,0,2},{2,0,1,1,0,1,2,2,1,0,1,2,1},
487 {4,1,1,3,3,2,4,4,2,2,1,4,3},{2,2,0,2,0,2,1,1,2,0,0,1,2},{3,0,0,1,1,2,3,3,2,2,0,3,1},
488 {1,0,0,1,1,1,1,1,1,0,1,0,0},{2,2,0,2,0,1,2,2,1,1,2,0,0},{2,2,1,1,2,2,1,1,2,0,0,0,0},
489 {2,0,1,1,0,2,1,1,2,2,0,0,0},{2,0,2,0,2,2,1,1,2,0,2,1,0},{3,1,1,0,0,3,2,2,3,3,1,2,0},
490 {2,1,0,0,1,1,2,2,1,0,0,2,0},{2,0,0,0,0,2,1,1,2,2,0,1,0},{1,0,0,0,0,0,1,1,0,1,1,0,1},
491 {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},{1,0,1,0,1,0,1,1,0,0,0,0,1},
492 {2,0,2,2,0,0,1,1,0,2,2,1,2},{3,1,1,2,2,0,3,3,0,0,1,3,2},{2,1,0,1,0,0,2,2,0,1,0,2,1},
493 {2,0,0,1,1,0,2,2,0,0,0,2,1},{1,0,0,1,1,0,1,1,0,1,1,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},
494 {2,2,1,1,2,0,1,1,0,2,0,0,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},{2,0,1,0,1,0,2,2,0,1,1,2,0},
495 {2,1,1,0,0,0,2,2,0,0,1,2,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},{1,0,0,0,0,0,1,1,0,0,0,1,0},
496 {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,1,0,0,1,0,1,0,1,1,0,1,1},{1,1,1,0,0,0,1,0,1,0,1,1,1},
497 {2,0,2,0,2,0,1,0,1,1,1,2,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},{2,2,2,1,1,0,2,0,2,2,0,0,1},
498 {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,0,0,2,2,0,1,0,1,1,1,0,2},{1,0,0,1,1,0,1,0,1,0,0,1,0},
499 {1,1,0,1,0,0,1,0,1,1,0,1,0},{2,2,1,1,2,0,2,0,2,0,2,1,0},{2,0,2,2,0,0,1,0,1,1,1,2,0},
500 {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},
501 {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,0,0,0,0,1,1,0,0,1,0,1,1},{1,1,0,0,1,1,1,0,0,0,0,1,1},
502 {2,2,2,0,0,1,1,0,0,2,1,2,2},{2,0,1,0,1,2,2,0,0,0,2,1,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},
503 {2,1,1,2,2,1,1,0,0,0,0,0,2},{2,1,0,1,0,2,2,0,0,1,2,0,1},{2,0,0,2,2,1,1,0,0,0,1,0,2},
504 {1,0,0,1,1,1,1,0,0,1,0,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},{3,1,2,2,1,3,3,0,0,1,3,2,0},
505 {2,0,1,1,0,2,2,0,0,0,2,1,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},
506 {2,2,0,0,2,1,1,0,0,2,1,0,0},{1,0,0,0,0,1,1,0,0,0,1,0,0},{1,0,0,0,0,1,0,0,1,0,1,1,1},
507 {2,2,0,0,2,1,0,0,1,1,2,2,2},{1,1,1,0,0,1,0,0,1,0,0,1,1},{2,0,1,0,1,2,0,0,2,2,0,1,1},
508 {1,0,1,1,0,1,0,0,1,0,1,0,1},{3,1,1,3,3,2,0,0,2,2,1,0,3},{1,1,0,1,0,1,0,0,1,0,0,0,1},
509 {2,0,0,2,2,1,0,0,1,1,0,0,2},{1,0,0,1,1,1,0,0,1,0,1,1,0},{2,1,0,1,0,2,0,0,2,2,1,1,0},
510 {2,1,2,2,1,1,0,0,1,0,0,2,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},
511 {2,1,1,0,0,2,0,0,2,2,1,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},{1,0,0,0,0,1,0,0,1,1,0,0,0},
512 {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},
513 {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},{2,1,1,2,2,0,0,0,0,0,1,0,2},
514 {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,0,0,1,1,0,0,0,0,0,0,0,1},{1,0,0,1,1,0,0,0,0,1,1,1,0},
515 {1,1,0,1,0,0,0,0,0,0,1,1,0},{2,1,2,2,1,0,0,0,0,1,0,2,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},
516 {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},
517 {0,0,0,0,0,0,0,0,0,0,0,0,0}};
524 const Vec3d& p0,
const Vec3d& p1,
525 const Vec3d& p2,
const Vec3d& p3,
526 double epsilon = 0.001)
529 Vec3d normal = (p2-p0).cross(p1-p3);
531 const Vec3d centroid = (p0 + p1 + p2 + p3);
532 const double d = centroid.
dot(normal) * 0.25;
536 double absDist = std::abs(p0.dot(normal) - d);
537 if (absDist > epsilon)
return false;
539 absDist = std::abs(p1.dot(normal) - d);
540 if (absDist > epsilon)
return false;
542 absDist = std::abs(p2.dot(normal) - d);
543 if (absDist > epsilon)
return false;
545 absDist = std::abs(p3.dot(normal) - d);
546 if (absDist > epsilon)
return false;
559 MASK_FIRST_10_BITS = 0x000003FF,
560 MASK_DIRTY_BIT = 0x80000000,
561 MASK_INVALID_BIT = 0x40000000
565 packPoint(
const Vec3d& v)
570 assert(!(v.x() > 1.0) && !(v.y() > 1.0) && !(v.z() > 1.0));
571 assert(!(v.x() < 0.0) && !(v.y() < 0.0) && !(v.z() < 0.0));
573 data |= (uint32_t(v.x() * 1023.0) & MASK_FIRST_10_BITS) << 20;
574 data |= (uint32_t(v.y() * 1023.0) & MASK_FIRST_10_BITS) << 10;
575 data |= (uint32_t(v.z() * 1023.0) & MASK_FIRST_10_BITS);
581 unpackPoint(uint32_t data)
584 v.
z() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
586 v.y() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
588 v.x() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
598 inline bool isBoolValue() {
return false; }
601 inline bool isBoolValue<bool>() {
return true; }
606 inline bool isInsideValue(T
value, T isovalue) {
return value < isovalue; }
609 inline bool isInsideValue<bool>(
bool value,
bool ) {
return value; }
612 template<
typename AccessorT>
614 getCellVertexValues(
const AccessorT& accessor, Coord ijk,
617 values[0] = accessor.getValue(ijk);
619 values[1] = accessor.getValue(ijk);
621 values[2] = accessor.getValue(ijk);
623 values[3] = accessor.getValue(ijk);
625 values[4] = accessor.getValue(ijk);
627 values[5] = accessor.getValue(ijk);
629 values[6] = accessor.getValue(ijk);
631 values[7] = accessor.getValue(ijk);
635 template<
typename LeafT>
637 getCellVertexValues(
const LeafT& leaf,
const Index offset,
640 values[0] = leaf.getValue(offset);
641 values[3] = leaf.getValue(offset + 1);
642 values[4] = leaf.getValue(offset + LeafT::DIM);
643 values[7] = leaf.getValue(offset + LeafT::DIM + 1);
644 values[1] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM));
645 values[2] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1);
646 values[5] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM);
647 values[6] = leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1);
651 template<
typename ValueType>
656 signs |= isInsideValue(values[0], iso) ? 1u : 0u;
657 signs |= isInsideValue(values[1], iso) ? 2u : 0u;
658 signs |= isInsideValue(values[2], iso) ? 4u : 0u;
659 signs |= isInsideValue(values[3], iso) ? 8u : 0u;
660 signs |= isInsideValue(values[4], iso) ? 16u : 0u;
661 signs |= isInsideValue(values[5], iso) ? 32u : 0u;
662 signs |= isInsideValue(values[6], iso) ? 64u : 0u;
663 signs |= isInsideValue(values[7], iso) ? 128u : 0u;
664 return uint8_t(signs);
670 template<
typename AccessorT>
672 evalCellSigns(
const AccessorT& accessor,
const Coord& ijk,
typename AccessorT::ValueType iso)
676 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 1u;
678 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 2u;
680 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 4u;
682 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 8u;
683 coord[1] += 1; coord[2] = ijk[2];
684 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 16u;
686 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 32u;
688 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 64u;
690 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 128u;
691 return uint8_t(signs);
697 template<
typename LeafT>
699 evalCellSigns(
const LeafT& leaf,
const Index offset,
typename LeafT::ValueType iso)
704 if (isInsideValue(leaf.getValue(offset), iso)) signs |= 1u;
707 if (isInsideValue(leaf.getValue(offset + 1), iso)) signs |= 8u;
710 if (isInsideValue(leaf.getValue(offset + LeafT::DIM), iso)) signs |= 16u;
713 if (isInsideValue(leaf.getValue(offset + LeafT::DIM + 1), iso)) signs |= 128u;
716 if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) ), iso)) signs |= 2u;
719 if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1), iso)) signs |= 4u;
722 if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM), iso)) signs |= 32u;
725 if (isInsideValue(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1), iso)) signs |= 64u;
727 return uint8_t(signs);
733 template<
class AccessorT>
735 correctCellSigns(uint8_t& signs, uint8_t face,
736 const AccessorT& acc, Coord ijk,
typename AccessorT::ValueType iso)
741 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 3) signs = uint8_t(~signs);
745 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 4) signs = uint8_t(~signs);
749 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 1) signs = uint8_t(~signs);
753 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 2) signs = uint8_t(~signs);
757 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 6) signs = uint8_t(~signs);
761 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 5) signs = uint8_t(~signs);
769 template<
class AccessorT>
771 isNonManifold(
const AccessorT& accessor,
const Coord& ijk,
772 typename AccessorT::ValueType isovalue,
const int dim)
778 p[0] = isInsideValue(accessor.getValue(coord), isovalue);
780 p[1] = isInsideValue(accessor.getValue(coord), isovalue);
782 p[2] = isInsideValue(accessor.getValue(coord), isovalue);
784 p[3] = isInsideValue(accessor.getValue(coord), isovalue);
785 coord[1] += dim; coord[2] = ijk[2];
786 p[4] = isInsideValue(accessor.getValue(coord), isovalue);
788 p[5] = isInsideValue(accessor.getValue(coord), isovalue);
790 p[6] = isInsideValue(accessor.getValue(coord), isovalue);
792 p[7] = isInsideValue(accessor.getValue(coord), isovalue);
796 if (p[0]) signs |= 1u;
797 if (p[1]) signs |= 2u;
798 if (p[2]) signs |= 4u;
799 if (p[3]) signs |= 8u;
800 if (p[4]) signs |= 16u;
801 if (p[5]) signs |= 32u;
802 if (p[6]) signs |= 64u;
803 if (p[7]) signs |= 128u;
804 if (!sAdaptable[signs])
return true;
809 int i = ijk[0], ip = ijk[0] + hDim, ipp = ijk[0] + dim;
810 int j = ijk[1], jp = ijk[1] + hDim, jpp = ijk[1] + dim;
811 int k = ijk[2], kp = ijk[2] + hDim, kpp = ijk[2] + dim;
814 coord.reset(ip, j, k);
815 m = isInsideValue(accessor.getValue(coord), isovalue);
816 if (p[0] != m && p[1] != m)
return true;
819 coord.reset(ipp, j, kp);
820 m = isInsideValue(accessor.getValue(coord), isovalue);
821 if (p[1] != m && p[2] != m)
return true;
824 coord.reset(ip, j, kpp);
825 m = isInsideValue(accessor.getValue(coord), isovalue);
826 if (p[2] != m && p[3] != m)
return true;
829 coord.reset(i, j, kp);
830 m = isInsideValue(accessor.getValue(coord), isovalue);
831 if (p[0] != m && p[3] != m)
return true;
834 coord.reset(ip, jpp, k);
835 m = isInsideValue(accessor.getValue(coord), isovalue);
836 if (p[4] != m && p[5] != m)
return true;
839 coord.reset(ipp, jpp, kp);
840 m = isInsideValue(accessor.getValue(coord), isovalue);
841 if (p[5] != m && p[6] != m)
return true;
844 coord.reset(ip, jpp, kpp);
845 m = isInsideValue(accessor.getValue(coord), isovalue);
846 if (p[6] != m && p[7] != m)
return true;
849 coord.reset(i, jpp, kp);
850 m = isInsideValue(accessor.getValue(coord), isovalue);
851 if (p[7] != m && p[4] != m)
return true;
854 coord.reset(i, jp, k);
855 m = isInsideValue(accessor.getValue(coord), isovalue);
856 if (p[0] != m && p[4] != m)
return true;
859 coord.reset(ipp, jp, k);
860 m = isInsideValue(accessor.getValue(coord), isovalue);
861 if (p[1] != m && p[5] != m)
return true;
864 coord.reset(ipp, jp, kpp);
865 m = isInsideValue(accessor.getValue(coord), isovalue);
866 if (p[2] != m && p[6] != m)
return true;
870 coord.reset(i, jp, kpp);
871 m = isInsideValue(accessor.getValue(coord), isovalue);
872 if (p[3] != m && p[7] != m)
return true;
878 coord.reset(ip, jp, k);
879 m = isInsideValue(accessor.getValue(coord), isovalue);
880 if (p[0] != m && p[1] != m && p[4] != m && p[5] != m)
return true;
883 coord.reset(ipp, jp, kp);
884 m = isInsideValue(accessor.getValue(coord), isovalue);
885 if (p[1] != m && p[2] != m && p[5] != m && p[6] != m)
return true;
888 coord.reset(ip, jp, kpp);
889 m = isInsideValue(accessor.getValue(coord), isovalue);
890 if (p[2] != m && p[3] != m && p[6] != m && p[7] != m)
return true;
893 coord.reset(i, jp, kp);
894 m = isInsideValue(accessor.getValue(coord), isovalue);
895 if (p[0] != m && p[3] != m && p[4] != m && p[7] != m)
return true;
898 coord.reset(ip, j, kp);
899 m = isInsideValue(accessor.getValue(coord), isovalue);
900 if (p[0] != m && p[1] != m && p[2] != m && p[3] != m)
return true;
903 coord.reset(ip, jpp, kp);
904 m = isInsideValue(accessor.getValue(coord), isovalue);
905 if (p[4] != m && p[5] != m && p[6] != m && p[7] != m)
return true;
908 coord.reset(ip, jp, kp);
909 m = isInsideValue(accessor.getValue(coord), isovalue);
910 if (p[0] != m && p[1] != m && p[2] != m && p[3] != m &&
911 p[4] != m && p[5] != m && p[6] != m && p[7] != m)
return true;
920 template <
class LeafType>
922 mergeVoxels(LeafType& leaf,
const Coord& start,
int dim,
int regionId)
924 Coord ijk, end = start;
929 for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
930 for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
931 for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
932 leaf.setValueOnly(ijk, regionId);
941 template <
class LeafType>
943 isMergable(LeafType& leaf,
const Coord& start,
int dim,
944 typename LeafType::ValueType::value_type adaptivity)
946 if (adaptivity < 1e-6)
return false;
948 using VecT =
typename LeafType::ValueType;
949 Coord ijk, end = start;
954 std::vector<VecT> norms;
955 for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
956 for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
957 for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
959 if(!leaf.isValueOn(ijk))
continue;
960 norms.push_back(leaf.getValue(ijk));
965 size_t N = norms.size();
966 for (
size_t ni = 0; ni < N; ++ni) {
967 VecT n_i = norms[ni];
968 for (
size_t nj = 0; nj < N; ++nj) {
969 VecT n_j = norms[nj];
970 if ((1.0 - n_i.dot(n_j)) > adaptivity)
return false;
981 inline double evalZeroCrossing(
double v0,
double v1,
double iso) {
return (iso - v0) / (v1 - v0); }
985 template<
typename LeafT>
987 collectCornerValues(
const LeafT& leaf,
const Index offset, std::vector<double>& values)
989 values[0] = double(leaf.getValue(offset));
990 values[3] = double(leaf.getValue(offset + 1));
991 values[4] = double(leaf.getValue(offset + LeafT::DIM));
992 values[7] = double(leaf.getValue(offset + LeafT::DIM + 1));
993 values[1] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM)));
994 values[2] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1));
995 values[5] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM));
996 values[6] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1));
1001 template<
typename AccessorT>
1003 collectCornerValues(
const AccessorT& acc,
const Coord& ijk, std::vector<double>& values)
1006 values[0] = double(acc.getValue(coord));
1009 values[1] = double(acc.getValue(coord));
1012 values[2] = double(acc.getValue(coord));
1015 values[3] = double(acc.getValue(coord));
1017 coord[1] += 1; coord[2] = ijk[2];
1018 values[4] = double(acc.getValue(coord));
1021 values[5] = double(acc.getValue(coord));
1024 values[6] = double(acc.getValue(coord));
1027 values[7] = double(acc.getValue(coord));
1033 computePoint(
const std::vector<double>& values,
unsigned char signs,
1034 unsigned char edgeGroup,
double iso)
1036 Vec3d avg(0.0, 0.0, 0.0);
1039 if (sEdgeGroupTable[signs][1] == edgeGroup) {
1040 avg[0] += evalZeroCrossing(values[0], values[1], iso);
1044 if (sEdgeGroupTable[signs][2] == edgeGroup) {
1046 avg[2] += evalZeroCrossing(values[1], values[2], iso);
1050 if (sEdgeGroupTable[signs][3] == edgeGroup) {
1051 avg[0] += evalZeroCrossing(values[3], values[2], iso);
1056 if (sEdgeGroupTable[signs][4] == edgeGroup) {
1057 avg[2] += evalZeroCrossing(values[0], values[3], iso);
1061 if (sEdgeGroupTable[signs][5] == edgeGroup) {
1062 avg[0] += evalZeroCrossing(values[4], values[5], iso);
1067 if (sEdgeGroupTable[signs][6] == edgeGroup) {
1070 avg[2] += evalZeroCrossing(values[5], values[6], iso);
1074 if (sEdgeGroupTable[signs][7] == edgeGroup) {
1075 avg[0] += evalZeroCrossing(values[7], values[6], iso);
1081 if (sEdgeGroupTable[signs][8] == edgeGroup) {
1083 avg[2] += evalZeroCrossing(values[4], values[7], iso);
1087 if (sEdgeGroupTable[signs][9] == edgeGroup) {
1088 avg[1] += evalZeroCrossing(values[0], values[4], iso);
1092 if (sEdgeGroupTable[signs][10] == edgeGroup) {
1094 avg[1] += evalZeroCrossing(values[1], values[5], iso);
1098 if (sEdgeGroupTable[signs][11] == edgeGroup) {
1100 avg[1] += evalZeroCrossing(values[2], values[6], iso);
1105 if (sEdgeGroupTable[signs][12] == edgeGroup) {
1106 avg[1] += evalZeroCrossing(values[3], values[7], iso);
1112 double w = 1.0 / double(samples);
1125 computeMaskedPoint(Vec3d& avg,
const std::vector<double>& values,
unsigned char signs,
1126 unsigned char signsMask,
unsigned char edgeGroup,
double iso)
1128 avg = Vec3d(0.0, 0.0, 0.0);
1131 if (sEdgeGroupTable[signs][1] == edgeGroup
1132 && sEdgeGroupTable[signsMask][1] == 0) {
1133 avg[0] += evalZeroCrossing(values[0], values[1], iso);
1137 if (sEdgeGroupTable[signs][2] == edgeGroup
1138 && sEdgeGroupTable[signsMask][2] == 0) {
1140 avg[2] += evalZeroCrossing(values[1], values[2], iso);
1144 if (sEdgeGroupTable[signs][3] == edgeGroup
1145 && sEdgeGroupTable[signsMask][3] == 0) {
1146 avg[0] += evalZeroCrossing(values[3], values[2], iso);
1151 if (sEdgeGroupTable[signs][4] == edgeGroup
1152 && sEdgeGroupTable[signsMask][4] == 0) {
1153 avg[2] += evalZeroCrossing(values[0], values[3], iso);
1157 if (sEdgeGroupTable[signs][5] == edgeGroup
1158 && sEdgeGroupTable[signsMask][5] == 0) {
1159 avg[0] += evalZeroCrossing(values[4], values[5], iso);
1164 if (sEdgeGroupTable[signs][6] == edgeGroup
1165 && sEdgeGroupTable[signsMask][6] == 0) {
1168 avg[2] += evalZeroCrossing(values[5], values[6], iso);
1172 if (sEdgeGroupTable[signs][7] == edgeGroup
1173 && sEdgeGroupTable[signsMask][7] == 0) {
1174 avg[0] += evalZeroCrossing(values[7], values[6], iso);
1180 if (sEdgeGroupTable[signs][8] == edgeGroup
1181 && sEdgeGroupTable[signsMask][8] == 0) {
1183 avg[2] += evalZeroCrossing(values[4], values[7], iso);
1187 if (sEdgeGroupTable[signs][9] == edgeGroup
1188 && sEdgeGroupTable[signsMask][9] == 0) {
1189 avg[1] += evalZeroCrossing(values[0], values[4], iso);
1193 if (sEdgeGroupTable[signs][10] == edgeGroup
1194 && sEdgeGroupTable[signsMask][10] == 0) {
1196 avg[1] += evalZeroCrossing(values[1], values[5], iso);
1200 if (sEdgeGroupTable[signs][11] == edgeGroup
1201 && sEdgeGroupTable[signsMask][11] == 0) {
1203 avg[1] += evalZeroCrossing(values[2], values[6], iso);
1208 if (sEdgeGroupTable[signs][12] == edgeGroup
1209 && sEdgeGroupTable[signsMask][12] == 0) {
1210 avg[1] += evalZeroCrossing(values[3], values[7], iso);
1216 double w = 1.0 / double(samples);
1229 computeWeightedPoint(
const Vec3d& p,
const std::vector<double>& values,
1230 unsigned char signs,
unsigned char edgeGroup,
double iso)
1232 std::vector<Vec3d> samples;
1235 std::vector<double> weights;
1238 Vec3d avg(0.0, 0.0, 0.0);
1240 if (sEdgeGroupTable[signs][1] == edgeGroup) {
1241 avg[0] = evalZeroCrossing(values[0], values[1], iso);
1245 samples.push_back(avg);
1246 weights.push_back((avg-p).lengthSqr());
1249 if (sEdgeGroupTable[signs][2] == edgeGroup) {
1252 avg[2] = evalZeroCrossing(values[1], values[2], iso);
1254 samples.push_back(avg);
1255 weights.push_back((avg-p).lengthSqr());
1258 if (sEdgeGroupTable[signs][3] == edgeGroup) {
1259 avg[0] = evalZeroCrossing(values[3], values[2], iso);
1263 samples.push_back(avg);
1264 weights.push_back((avg-p).lengthSqr());
1267 if (sEdgeGroupTable[signs][4] == edgeGroup) {
1270 avg[2] = evalZeroCrossing(values[0], values[3], iso);
1272 samples.push_back(avg);
1273 weights.push_back((avg-p).lengthSqr());
1276 if (sEdgeGroupTable[signs][5] == edgeGroup) {
1277 avg[0] = evalZeroCrossing(values[4], values[5], iso);
1281 samples.push_back(avg);
1282 weights.push_back((avg-p).lengthSqr());
1285 if (sEdgeGroupTable[signs][6] == edgeGroup) {
1288 avg[2] = evalZeroCrossing(values[5], values[6], iso);
1290 samples.push_back(avg);
1291 weights.push_back((avg-p).lengthSqr());
1294 if (sEdgeGroupTable[signs][7] == edgeGroup) {
1295 avg[0] = evalZeroCrossing(values[7], values[6], iso);
1299 samples.push_back(avg);
1300 weights.push_back((avg-p).lengthSqr());
1303 if (sEdgeGroupTable[signs][8] == edgeGroup) {
1306 avg[2] = evalZeroCrossing(values[4], values[7], iso);
1308 samples.push_back(avg);
1309 weights.push_back((avg-p).lengthSqr());
1312 if (sEdgeGroupTable[signs][9] == edgeGroup) {
1314 avg[1] = evalZeroCrossing(values[0], values[4], iso);
1317 samples.push_back(avg);
1318 weights.push_back((avg-p).lengthSqr());
1321 if (sEdgeGroupTable[signs][10] == edgeGroup) {
1323 avg[1] = evalZeroCrossing(values[1], values[5], iso);
1326 samples.push_back(avg);
1327 weights.push_back((avg-p).lengthSqr());
1330 if (sEdgeGroupTable[signs][11] == edgeGroup) {
1332 avg[1] = evalZeroCrossing(values[2], values[6], iso);
1335 samples.push_back(avg);
1336 weights.push_back((avg-p).lengthSqr());
1339 if (sEdgeGroupTable[signs][12] == edgeGroup) {
1341 avg[1] = evalZeroCrossing(values[3], values[7], iso);
1344 samples.push_back(avg);
1345 weights.push_back((avg-p).lengthSqr());
1352 for (
size_t i = 0, I = weights.size(); i < I; ++i) {
1353 minWeight =
std::min(minWeight, weights[i]);
1354 maxWeight =
std::max(maxWeight, weights[i]);
1357 const double offset = maxWeight + minWeight * 0.1;
1358 for (
size_t i = 0, I = weights.size(); i < I; ++i) {
1359 weights[i] = offset - weights[i];
1363 double weightSum = 0.0;
1364 for (
size_t i = 0, I = weights.size(); i < I; ++i) {
1365 weightSum += weights[i];
1372 if (samples.size() > 1) {
1373 for (
size_t i = 0, I = samples.size(); i < I; ++i) {
1374 avg += samples[i] * (weights[i] / weightSum);
1377 avg = samples.front();
1387 computeCellPoints(std::vector<Vec3d>& points,
1388 const std::vector<double>& values,
unsigned char signs,
double iso)
1390 for (
size_t n = 1, N = sEdgeGroupTable[signs][0] + 1; n < N; ++n) {
1391 points.push_back(computePoint(values, signs, uint8_t(n), iso));
1400 matchEdgeGroup(
unsigned char groupId,
unsigned char lhsSigns,
unsigned char rhsSigns)
1403 for (
size_t i = 1; i <= 12; ++i) {
1404 if (sEdgeGroupTable[lhsSigns][i] == groupId && sEdgeGroupTable[rhsSigns][i] != 0) {
1405 id = sEdgeGroupTable[rhsSigns][i];
1418 computeCellPoints(std::vector<Vec3d>& points, std::vector<bool>& weightedPointMask,
1419 const std::vector<double>& lhsValues,
const std::vector<double>& rhsValues,
1420 unsigned char lhsSigns,
unsigned char rhsSigns,
1421 double iso,
size_t pointIdx,
const uint32_t * seamPointArray)
1423 for (
size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) {
1425 int id = matchEdgeGroup(uint8_t(n), lhsSigns, rhsSigns);
1429 const unsigned char e = uint8_t(
id);
1430 const uint32_t& quantizedPoint = seamPointArray[pointIdx + (
id - 1)];
1432 if ((quantizedPoint & MASK_DIRTY_BIT) && !(quantizedPoint & MASK_INVALID_BIT)) {
1433 Vec3d p = unpackPoint(quantizedPoint);
1434 points.push_back(computeWeightedPoint(p, rhsValues, rhsSigns, e, iso));
1435 weightedPointMask.push_back(
true);
1437 points.push_back(computePoint(rhsValues, rhsSigns, e, iso));
1438 weightedPointMask.push_back(
false);
1442 points.push_back(computePoint(lhsValues, lhsSigns, uint8_t(n), iso));
1443 weightedPointMask.push_back(
false);
1449 template <
typename InputTreeType>
1450 struct ComputePoints
1452 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1453 using InputValueType =
typename InputLeafNodeType::ValueType;
1455 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
1456 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
1458 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
1459 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
1461 ComputePoints(
Vec3s * pointArray,
1462 const InputTreeType& inputTree,
1463 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1464 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1465 const std::unique_ptr<
Index32[]>& leafNodeOffsets,
1469 void setRefData(
const InputTreeType& refInputTree,
1470 const Index32TreeType& refPointIndexTree,
1471 const Int16TreeType& refSignFlagsTree,
1472 const uint32_t * quantizedSeamLinePoints,
1473 uint8_t * seamLinePointsFlags);
1475 void operator()(
const tbb::blocked_range<size_t>&)
const;
1478 Vec3s *
const mPoints;
1479 InputTreeType
const *
const mInputTree;
1480 Index32LeafNodeType *
const *
const mPointIndexNodes;
1481 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
1482 Index32 const *
const mNodeOffsets;
1484 double const mIsovalue;
1486 InputTreeType
const * mRefInputTree;
1487 Index32TreeType
const * mRefPointIndexTree;
1488 Int16TreeType
const * mRefSignFlagsTree;
1489 uint32_t
const * mQuantizedSeamLinePoints;
1490 uint8_t * mSeamLinePointsFlags;
1494 template <
typename InputTreeType>
1495 ComputePoints<InputTreeType>::ComputePoints(
1497 const InputTreeType& inputTree,
1498 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1499 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1500 const std::unique_ptr<
Index32[]>& leafNodeOffsets,
1503 : mPoints(pointArray)
1504 , mInputTree(&inputTree)
1505 , mPointIndexNodes(pointIndexLeafNodes.data())
1506 , mSignFlagsNodes(signFlagsLeafNodes.data())
1507 , mNodeOffsets(leafNodeOffsets.get())
1510 , mRefInputTree(
nullptr)
1511 , mRefPointIndexTree(
nullptr)
1512 , mRefSignFlagsTree(
nullptr)
1513 , mQuantizedSeamLinePoints(
nullptr)
1514 , mSeamLinePointsFlags(
nullptr)
1518 template <
typename InputTreeType>
1520 ComputePoints<InputTreeType>::setRefData(
1521 const InputTreeType& refInputTree,
1522 const Index32TreeType& refPointIndexTree,
1523 const Int16TreeType& refSignFlagsTree,
1524 const uint32_t * quantizedSeamLinePoints,
1525 uint8_t * seamLinePointsFlags)
1527 mRefInputTree = &refInputTree;
1528 mRefPointIndexTree = &refPointIndexTree;
1529 mRefSignFlagsTree = &refSignFlagsTree;
1530 mQuantizedSeamLinePoints = quantizedSeamLinePoints;
1531 mSeamLinePointsFlags = seamLinePointsFlags;
1534 template <
typename InputTreeType>
1536 ComputePoints<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
const 1542 using IndexType =
typename Index32TreeType::ValueType;
1544 using IndexArray = std::vector<Index>;
1545 using IndexArrayMap = std::map<IndexType, IndexArray>;
1547 InputTreeAccessor inputAcc(*mInputTree);
1551 std::vector<Vec3d> points(4);
1552 std::vector<bool> weightedPointMask(4);
1553 std::vector<double> values(8), refValues(8);
1554 const double iso = mIsovalue;
1558 std::unique_ptr<InputTreeAccessor> refInputAcc;
1559 std::unique_ptr<Index32TreeAccessor> refPointIndexAcc;
1560 std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
1562 const bool hasReferenceData = mRefInputTree && mRefPointIndexTree && mRefSignFlagsTree;
1564 if (hasReferenceData) {
1565 refInputAcc.reset(
new InputTreeAccessor(*mRefInputTree));
1566 refPointIndexAcc.reset(
new Index32TreeAccessor(*mRefPointIndexTree));
1567 refSignFlagsAcc.reset(
new Int16TreeAccessor(*mRefSignFlagsTree));
1570 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1572 Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
1573 const Coord& origin = pointIndexNode.origin();
1575 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1576 const InputLeafNodeType * inputNode = inputAcc.probeConstLeaf(origin);
1579 const InputLeafNodeType * refInputNode =
nullptr;
1580 const Index32LeafNodeType * refPointIndexNode =
nullptr;
1581 const Int16LeafNodeType * refSignFlagsNode =
nullptr;
1583 if (hasReferenceData) {
1584 refInputNode = refInputAcc->probeConstLeaf(origin);
1585 refPointIndexNode = refPointIndexAcc->probeConstLeaf(origin);
1586 refSignFlagsNode = refSignFlagsAcc->probeConstLeaf(origin);
1589 IndexType pointOffset = IndexType(mNodeOffsets[n]);
1590 IndexArrayMap regions;
1592 for (
auto it = pointIndexNode.beginValueOn(); it; ++it) {
1593 const Index offset = it.pos();
1595 const IndexType
id = it.getValue();
1598 regions[id].push_back(offset);
1603 pointIndexNode.setValueOnly(offset, pointOffset);
1605 const Int16 flags = signFlagsNode.getValue(offset);
1606 uint8_t signs = uint8_t(SIGNS & flags);
1607 uint8_t refSigns = 0;
1609 if ((flags & SEAM) && refPointIndexNode && refSignFlagsNode) {
1610 if (refSignFlagsNode->isValueOn(offset)) {
1611 refSigns = uint8_t(SIGNS & refSignFlagsNode->getValue(offset));
1615 ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1617 const bool inclusiveCell = inputNode &&
1618 ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1619 ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1620 ijk[2] < int(Index32LeafNodeType::DIM - 1);
1624 if (inclusiveCell) collectCornerValues(*inputNode, offset, values);
1625 else collectCornerValues(inputAcc, ijk, values);
1628 weightedPointMask.clear();
1630 if (refSigns == 0) {
1632 computeCellPoints(points, values, signs, iso);
1635 if (inclusiveCell && refInputNode) {
1636 collectCornerValues(*refInputNode, offset, refValues);
1638 collectCornerValues(*refInputAcc, ijk, refValues);
1640 computeCellPoints(points, weightedPointMask, values, refValues, signs, refSigns,
1641 iso, refPointIndexNode->getValue(offset), mQuantizedSeamLinePoints);
1644 xyz[0] = double(ijk[0]);
1645 xyz[1] = double(ijk[1]);
1646 xyz[2] = double(ijk[2]);
1648 for (
size_t i = 0, I = points.size(); i < I; ++i) {
1650 Vec3d& point = points[i];
1653 if (!std::isfinite(point[0]) ||
1654 !std::isfinite(point[1]) ||
1655 !std::isfinite(point[2]))
1658 "VolumeToMesh encountered NaNs or infs in the input VDB!" 1659 " Hint: Check the input and consider using the \"Diagnostics\" tool " 1660 "to detect and resolve the NaNs.");
1664 point = mTransform.indexToWorld(point);
1666 Vec3s& pos = mPoints[pointOffset];
1667 pos[0] = float(point[0]);
1668 pos[1] = float(point[1]);
1669 pos[2] = float(point[2]);
1671 if (mSeamLinePointsFlags && !weightedPointMask.empty() && weightedPointMask[i]) {
1672 mSeamLinePointsFlags[pointOffset] = uint8_t(1);
1680 for (
typename IndexArrayMap::iterator it = regions.begin(); it != regions.end(); ++it) {
1682 Vec3d avg(0.0), point(0.0);
1685 const IndexArray& voxels = it->second;
1686 for (
size_t i = 0, I = voxels.size(); i < I; ++i) {
1688 const Index offset = voxels[i];
1689 ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1691 const bool inclusiveCell = inputNode &&
1692 ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1693 ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1694 ijk[2] < int(Index32LeafNodeType::DIM - 1);
1698 pointIndexNode.setValueOnly(offset, pointOffset);
1700 uint8_t signs = uint8_t(SIGNS & signFlagsNode.getValue(offset));
1702 if (inclusiveCell) collectCornerValues(*inputNode, offset, values);
1703 else collectCornerValues(inputAcc, ijk, values);
1706 computeCellPoints(points, values, signs, iso);
1708 avg[0] += double(ijk[0]) + points[0][0];
1709 avg[1] += double(ijk[1]) + points[0][1];
1710 avg[2] += double(ijk[2]) + points[0][2];
1716 double w = 1.0 / double(count);
1722 avg = mTransform.indexToWorld(avg);
1724 Vec3s& pos = mPoints[pointOffset];
1725 pos[0] = float(avg[0]);
1726 pos[1] = float(avg[1]);
1727 pos[2] = float(avg[2]);
1738 template <
typename InputTreeType>
1739 struct SeamLineWeights
1741 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1742 using InputValueType =
typename InputLeafNodeType::ValueType;
1744 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
1745 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
1747 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
1748 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
1750 SeamLineWeights(
const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1751 const InputTreeType& inputTree,
1752 const Index32TreeType& refPointIndexTree,
1753 const Int16TreeType& refSignFlagsTree,
1754 uint32_t * quantizedPoints,
1756 : mSignFlagsNodes(signFlagsLeafNodes.data())
1757 , mInputTree(&inputTree)
1758 , mRefPointIndexTree(&refPointIndexTree)
1759 , mRefSignFlagsTree(&refSignFlagsTree)
1760 , mQuantizedPoints(quantizedPoints)
1765 void operator()(
const tbb::blocked_range<size_t>& range)
const 1771 std::vector<double> values(8);
1772 const double iso = double(mIsovalue);
1776 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1778 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1779 const Coord& origin = signFlagsNode.origin();
1781 const Int16LeafNodeType * refSignNode = signFlagsTreeAcc.
probeConstLeaf(origin);
1782 if (!refSignNode)
continue;
1784 const Index32LeafNodeType* refPointIndexNode =
1786 if (!refPointIndexNode)
continue;
1788 const InputLeafNodeType * inputNode = inputTreeAcc.
probeConstLeaf(origin);
1790 for (
typename Int16LeafNodeType::ValueOnCIter it = signFlagsNode.cbeginValueOn();
1793 const Index offset = it.pos();
1795 ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1797 const bool inclusiveCell = inputNode &&
1798 ijk[0] < int(Index32LeafNodeType::DIM - 1) &&
1799 ijk[1] < int(Index32LeafNodeType::DIM - 1) &&
1800 ijk[2] < int(Index32LeafNodeType::DIM - 1);
1804 if ((it.getValue() & SEAM) && refSignNode->isValueOn(offset)) {
1806 uint8_t lhsSigns = uint8_t(SIGNS & it.getValue());
1807 uint8_t rhsSigns = uint8_t(SIGNS & refSignNode->getValue(offset));
1810 if (inclusiveCell) {
1811 collectCornerValues(*inputNode, offset, values);
1813 collectCornerValues(inputTreeAcc, ijk, values);
1817 for (
unsigned i = 1, I = sEdgeGroupTable[lhsSigns][0] + 1; i < I; ++i) {
1819 int id = matchEdgeGroup(uint8_t(i), lhsSigns, rhsSigns);
1823 uint32_t& data = mQuantizedPoints[
1824 refPointIndexNode->getValue(offset) + (
id - 1)];
1826 if (!(data & MASK_DIRTY_BIT)) {
1828 int smaples = computeMaskedPoint(
1829 pos, values, lhsSigns, rhsSigns, uint8_t(i), iso);
1831 if (smaples > 0) data = packPoint(pos);
1832 else data = MASK_INVALID_BIT;
1834 data |= MASK_DIRTY_BIT;
1846 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
1847 InputTreeType
const *
const mInputTree;
1848 Index32TreeType
const *
const mRefPointIndexTree;
1849 Int16TreeType
const *
const mRefSignFlagsTree;
1850 uint32_t *
const mQuantizedPoints;
1851 InputValueType
const mIsovalue;
1855 template <
typename TreeType>
1856 struct SetSeamLineFlags
1858 using LeafNodeType =
typename TreeType::LeafNodeType;
1860 SetSeamLineFlags(
const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1861 const TreeType& refSignFlagsTree)
1862 : mSignFlagsNodes(signFlagsLeafNodes.data())
1863 , mRefSignFlagsTree(&refSignFlagsTree)
1867 void operator()(
const tbb::blocked_range<size_t>& range)
const 1871 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1873 LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1874 const Coord& origin = signFlagsNode.origin();
1876 const LeafNodeType * refSignNode = refSignFlagsTreeAcc.
probeConstLeaf(origin);
1877 if (!refSignNode)
continue;
1879 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
1880 const Index offset = it.pos();
1882 uint8_t rhsSigns = uint8_t(refSignNode->getValue(offset) & SIGNS);
1884 if (sEdgeGroupTable[rhsSigns][0] > 0) {
1886 const typename LeafNodeType::ValueType value = it.getValue();
1887 uint8_t lhsSigns = uint8_t(value & SIGNS);
1889 if (rhsSigns != lhsSigns) {
1890 signFlagsNode.setValueOnly(offset, value | SEAM);
1900 LeafNodeType *
const *
const mSignFlagsNodes;
1901 TreeType
const *
const mRefSignFlagsTree;
1905 template <
typename BoolTreeType,
typename SignDataType>
1906 struct TransferSeamLineFlags
1908 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1910 using SignDataTreeType =
typename BoolTreeType::template ValueConverter<SignDataType>::Type;
1911 using SignDataLeafNodeType =
typename SignDataTreeType::LeafNodeType;
1913 TransferSeamLineFlags(
const std::vector<SignDataLeafNodeType*>& signFlagsLeafNodes,
1914 const BoolTreeType& maskTree)
1915 : mSignFlagsNodes(signFlagsLeafNodes.data())
1916 , mMaskTree(&maskTree)
1920 void operator()(
const tbb::blocked_range<size_t>& range)
const 1924 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1926 SignDataLeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1927 const Coord& origin = signFlagsNode.origin();
1929 const BoolLeafNodeType * maskNode = maskAcc.
probeConstLeaf(origin);
1930 if (!maskNode)
continue;
1932 using ValueOnCIter =
typename SignDataLeafNodeType::ValueOnCIter;
1934 for (ValueOnCIter it = signFlagsNode.cbeginValueOn(); it; ++it) {
1935 const Index offset = it.pos();
1937 if (maskNode->isValueOn(offset)) {
1938 signFlagsNode.setValueOnly(offset, it.getValue() | SEAM);
1947 SignDataLeafNodeType *
const *
const mSignFlagsNodes;
1948 BoolTreeType
const *
const mMaskTree;
1952 template <
typename TreeType>
1953 struct MaskSeamLineVoxels
1955 using LeafNodeType =
typename TreeType::LeafNodeType;
1956 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1958 MaskSeamLineVoxels(
const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1959 const TreeType& signFlagsTree,
1961 : mSignFlagsNodes(signFlagsLeafNodes.data())
1962 , mSignFlagsTree(&signFlagsTree)
1968 MaskSeamLineVoxels(MaskSeamLineVoxels& rhs, tbb::split)
1969 : mSignFlagsNodes(rhs.mSignFlagsNodes)
1970 , mSignFlagsTree(rhs.mSignFlagsTree)
1976 void join(MaskSeamLineVoxels& rhs) { mMask->merge(*rhs.mMask); }
1978 void operator()(
const tbb::blocked_range<size_t>& range)
1980 using ValueOnCIter =
typename LeafNodeType::ValueOnCIter;
1981 using ValueType =
typename LeafNodeType::ValueType;
1987 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1989 LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1992 for (ValueOnCIter it = signFlagsNode.cbeginValueOn(); it; ++it) {
1994 const ValueType flags = it.getValue();
1996 if (!(flags & SEAM) && (flags & EDGES)) {
1998 ijk = it.getCoord();
2000 bool isSeamLineVoxel =
false;
2002 if (flags & XEDGE) {
2004 isSeamLineVoxel = (signFlagsAcc.
getValue(ijk) & SEAM);
2006 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2008 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2012 if (!isSeamLineVoxel && flags & YEDGE) {
2014 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2016 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2018 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2022 if (!isSeamLineVoxel && flags & ZEDGE) {
2024 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2026 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2028 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.
getValue(ijk) & SEAM);
2032 if (isSeamLineVoxel) {
2033 maskAcc.
setValue(it.getCoord(),
true);
2042 LeafNodeType *
const *
const mSignFlagsNodes;
2043 TreeType
const *
const mSignFlagsTree;
2044 BoolTreeType mTempMask;
2045 BoolTreeType *
const mMask;
2049 template<
typename SignDataTreeType>
2051 markSeamLineData(SignDataTreeType& signFlagsTree,
const SignDataTreeType& refSignFlagsTree)
2053 using SignDataType =
typename SignDataTreeType::ValueType;
2054 using SignDataLeafNodeType =
typename SignDataTreeType::LeafNodeType;
2055 using BoolTreeType =
typename SignDataTreeType::template ValueConverter<bool>::Type;
2057 std::vector<SignDataLeafNodeType*> signFlagsLeafNodes;
2058 signFlagsTree.getNodes(signFlagsLeafNodes);
2060 const tbb::blocked_range<size_t> nodeRange(0, signFlagsLeafNodes.size());
2062 tbb::parallel_for(nodeRange,
2063 SetSeamLineFlags<SignDataTreeType>(signFlagsLeafNodes, refSignFlagsTree));
2065 BoolTreeType seamLineMaskTree(
false);
2067 MaskSeamLineVoxels<SignDataTreeType>
2068 maskSeamLine(signFlagsLeafNodes, signFlagsTree, seamLineMaskTree);
2070 tbb::parallel_reduce(nodeRange, maskSeamLine);
2072 tbb::parallel_for(nodeRange,
2073 TransferSeamLineFlags<BoolTreeType, SignDataType>(signFlagsLeafNodes, seamLineMaskTree));
2080 template <
typename InputGr
idType>
2081 struct MergeVoxelRegions
2083 using InputTreeType =
typename InputGridType::TreeType;
2084 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
2085 using InputValueType =
typename InputLeafNodeType::ValueType;
2087 using FloatTreeType =
typename InputTreeType::template ValueConverter<float>::Type;
2088 using FloatLeafNodeType =
typename FloatTreeType::LeafNodeType;
2091 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
2092 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
2094 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
2095 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
2097 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
2098 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2100 MergeVoxelRegions(
const InputGridType& inputGrid,
2101 const Index32TreeType& pointIndexTree,
2102 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2103 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2106 bool invertSurfaceOrientation);
2108 void setSpatialAdaptivity(
const FloatGridType& grid)
2110 mSpatialAdaptivityTree = &grid.tree();
2111 mSpatialAdaptivityTransform = &grid.transform();
2114 void setAdaptivityMask(
const BoolTreeType& mask)
2119 void setRefSignFlagsData(
const Int16TreeType& signFlagsData,
float internalAdaptivity)
2121 mRefSignFlagsTree = &signFlagsData;
2122 mInternalAdaptivity = internalAdaptivity;
2125 void operator()(
const tbb::blocked_range<size_t>&)
const;
2128 InputTreeType
const *
const mInputTree;
2131 Index32TreeType
const *
const mPointIndexTree;
2132 Index32LeafNodeType *
const *
const mPointIndexNodes;
2133 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
2135 InputValueType mIsovalue;
2136 float mSurfaceAdaptivity, mInternalAdaptivity;
2137 bool mInvertSurfaceOrientation;
2139 FloatTreeType
const * mSpatialAdaptivityTree;
2140 BoolTreeType
const * mMaskTree;
2141 Int16TreeType
const * mRefSignFlagsTree;
2146 template <
typename InputGr
idType>
2147 MergeVoxelRegions<InputGridType>::MergeVoxelRegions(
2148 const InputGridType& inputGrid,
2149 const Index32TreeType& pointIndexTree,
2150 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2151 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2154 bool invertSurfaceOrientation)
2155 : mInputTree(&inputGrid.tree())
2156 , mInputTransform(&inputGrid.transform())
2157 , mPointIndexTree(&pointIndexTree)
2158 , mPointIndexNodes(pointIndexLeafNodes.data())
2159 , mSignFlagsNodes(signFlagsLeafNodes.data())
2161 , mSurfaceAdaptivity(adaptivity)
2162 , mInternalAdaptivity(adaptivity)
2163 , mInvertSurfaceOrientation(invertSurfaceOrientation)
2164 , mSpatialAdaptivityTree(
nullptr)
2165 , mMaskTree(
nullptr)
2166 , mRefSignFlagsTree(
nullptr)
2167 , mSpatialAdaptivityTransform(
nullptr)
2172 template <
typename InputGr
idType>
2174 MergeVoxelRegions<InputGridType>::operator()(
const tbb::blocked_range<size_t>& range)
const 2177 using Vec3sLeafNodeType =
typename InputLeafNodeType::template ValueConverter<Vec3sType>::Type;
2185 std::unique_ptr<FloatTreeAccessor> spatialAdaptivityAcc;
2186 if (mSpatialAdaptivityTree && mSpatialAdaptivityTransform) {
2187 spatialAdaptivityAcc.reset(
new FloatTreeAccessor(*mSpatialAdaptivityTree));
2190 std::unique_ptr<BoolTreeAccessor> maskAcc;
2192 maskAcc.reset(
new BoolTreeAccessor(*mMaskTree));
2195 std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
2196 if (mRefSignFlagsTree) {
2197 refSignFlagsAcc.reset(
new Int16TreeAccessor(*mRefSignFlagsTree));
2200 InputTreeAccessor inputAcc(*mInputTree);
2201 Index32TreeAccessor pointIndexAcc(*mPointIndexTree);
2203 BoolLeafNodeType mask;
2205 const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<InputValueType>();
2206 std::unique_ptr<Vec3sLeafNodeType> gradientNode;
2209 const int LeafDim = InputLeafNodeType::DIM;
2211 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
2213 mask.setValuesOff();
2215 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
2216 Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
2218 const Coord& origin = pointIndexNode.origin();
2220 end[0] = origin[0] + LeafDim;
2221 end[1] = origin[1] + LeafDim;
2222 end[2] = origin[2] + LeafDim;
2226 const BoolLeafNodeType* maskLeaf = maskAcc->probeConstLeaf(origin);
2227 if (maskLeaf !=
nullptr) {
2228 for (
typename BoolLeafNodeType::ValueOnCIter it = maskLeaf->cbeginValueOn();
2231 mask.setActiveState(it.getCoord() & ~1u,
true);
2236 float adaptivity = (refSignFlagsAcc && !refSignFlagsAcc->probeConstLeaf(origin)) ?
2237 mInternalAdaptivity : mSurfaceAdaptivity;
2239 bool useGradients = adaptivity < 1.0f;
2242 FloatLeafNodeType adaptivityLeaf(origin, adaptivity);
2244 if (spatialAdaptivityAcc) {
2245 useGradients =
false;
2246 for (
Index offset = 0; offset < FloatLeafNodeType::NUM_VALUES; ++offset) {
2247 ijk = adaptivityLeaf.offsetToGlobalCoord(offset);
2248 ijk = mSpatialAdaptivityTransform->worldToIndexCellCentered(
2249 mInputTransform->indexToWorld(ijk));
2250 float weight = spatialAdaptivityAcc->getValue(ijk);
2251 float adaptivityValue = weight * adaptivity;
2252 if (adaptivityValue < 1.0f) useGradients =
true;
2253 adaptivityLeaf.setValueOnly(offset, adaptivityValue);
2258 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
2259 const Int16 flags = it.getValue();
2260 const unsigned char signs =
static_cast<unsigned char>(SIGNS & int(flags));
2262 if ((flags & SEAM) || !sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) {
2264 mask.setActiveState(it.getCoord() & ~1u,
true);
2266 }
else if (flags & EDGES) {
2268 bool maskRegion =
false;
2270 ijk = it.getCoord();
2271 if (!pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2273 if (!maskRegion && flags & XEDGE) {
2275 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2277 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2279 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2283 if (!maskRegion && flags & YEDGE) {
2285 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2287 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2289 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2293 if (!maskRegion && flags & ZEDGE) {
2295 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2297 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2299 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2304 mask.setActiveState(it.getCoord() & ~1u,
true);
2311 for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2312 for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2313 for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2314 if (!mask.isValueOn(ijk) && isNonManifold(inputAcc, ijk, mIsovalue, dim)) {
2315 mask.setActiveState(ijk,
true);
2326 gradientNode->setValuesOff();
2328 gradientNode.reset(
new Vec3sLeafNodeType());
2331 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
2332 ijk = it.getCoord();
2333 if (!mask.isValueOn(ijk & ~1u)) {
2337 if (invertGradientDir) {
2341 gradientNode->setValueOn(it.pos(), dir);
2348 for ( ; dim <= LeafDim; dim = dim << 1) {
2349 const unsigned coordMask = ~((dim << 1) - 1);
2350 for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2351 for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2352 for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2354 adaptivity = adaptivityLeaf.getValue(ijk);
2356 if (mask.isValueOn(ijk)
2357 || isNonManifold(inputAcc, ijk, mIsovalue, dim)
2358 || (useGradients && !isMergable(*gradientNode, ijk, dim, adaptivity)))
2360 mask.setActiveState(ijk & coordMask,
true);
2362 mergeVoxels(pointIndexNode, ijk, dim, regionId++);
2376 struct UniformPrimBuilder
2378 UniformPrimBuilder(): mIdx(0), mPolygonPool(
nullptr) {}
2380 void init(
const size_t upperBound,
PolygonPool& quadPool)
2382 mPolygonPool = &quadPool;
2387 template<
typename IndexType>
2391 mPolygonPool->quad(mIdx) = verts;
2393 Vec4I& quad = mPolygonPool->quad(mIdx);
2399 mPolygonPool->quadFlags(mIdx) = flags;
2405 mPolygonPool->trimQuads(mIdx);
2415 struct AdaptivePrimBuilder
2417 AdaptivePrimBuilder() : mQuadIdx(0), mTriangleIdx(0), mPolygonPool(
nullptr) {}
2419 void init(
const size_t upperBound,
PolygonPool& polygonPool)
2421 mPolygonPool = &polygonPool;
2423 mPolygonPool->resetTriangles(upperBound);
2429 template<
typename IndexType>
2432 if (verts[0] != verts[1] && verts[0] != verts[2] && verts[0] != verts[3]
2433 && verts[1] != verts[2] && verts[1] != verts[3] && verts[2] != verts[3]) {
2434 mPolygonPool->quadFlags(mQuadIdx) = flags;
2435 addQuad(verts, reverse);
2437 verts[0] == verts[3] &&
2438 verts[1] != verts[2] &&
2439 verts[1] != verts[0] &&
2440 verts[2] != verts[0]) {
2441 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2442 addTriangle(verts[0], verts[1], verts[2], reverse);
2444 verts[1] == verts[2] &&
2445 verts[0] != verts[3] &&
2446 verts[0] != verts[1] &&
2447 verts[3] != verts[1]) {
2448 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2449 addTriangle(verts[0], verts[1], verts[3], reverse);
2451 verts[0] == verts[1] &&
2452 verts[2] != verts[3] &&
2453 verts[2] != verts[0] &&
2454 verts[3] != verts[0]) {
2455 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2456 addTriangle(verts[0], verts[2], verts[3], reverse);
2458 verts[2] == verts[3] &&
2459 verts[0] != verts[1] &&
2460 verts[0] != verts[2] &&
2461 verts[1] != verts[2]) {
2462 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2463 addTriangle(verts[0], verts[1], verts[2], reverse);
2470 mPolygonPool->trimQuads(mQuadIdx,
true);
2471 mPolygonPool->trimTrinagles(mTriangleIdx,
true);
2476 template<
typename IndexType>
2480 mPolygonPool->quad(mQuadIdx) = verts;
2482 Vec4I& quad = mPolygonPool->quad(mQuadIdx);
2491 void addTriangle(
unsigned v0,
unsigned v1,
unsigned v2,
bool reverse)
2493 Vec3I& prim = mPolygonPool->triangle(mTriangleIdx);
2507 size_t mQuadIdx, mTriangleIdx;
2512 template<
typename SignAccT,
typename IdxAccT,
typename PrimBuilder>
2515 bool invertSurfaceOrientation,
2518 const Vec3i& offsets,
2520 const SignAccT& signAcc,
2521 const IdxAccT& idxAcc,
2522 PrimBuilder& mesher)
2524 using IndexType =
typename IdxAccT::ValueType;
2527 const bool isActive = idxAcc.probeValue(ijk, v0);
2534 bool isInside = flags & INSIDE;
2536 isInside = invertSurfaceOrientation ? !isInside : isInside;
2541 if (flags & XEDGE) {
2543 quad[0] = v0 + offsets[0];
2547 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2548 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2549 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][5] - 1 : 0;
2553 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2554 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2555 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][7] - 1 : 0;
2559 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2560 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2561 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][3] - 1 : 0;
2564 mesher.addPrim(quad, isInside, tag[
bool(refFlags & XEDGE)]);
2571 if (flags & YEDGE) {
2573 quad[0] = v0 + offsets[1];
2577 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2578 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2579 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][12] - 1 : 0;
2583 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2584 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2585 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][11] - 1 : 0;
2589 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2590 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2591 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][10] - 1 : 0;
2594 mesher.addPrim(quad, isInside, tag[
bool(refFlags & YEDGE)]);
2601 if (flags & ZEDGE) {
2603 quad[0] = v0 + offsets[2];
2607 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2608 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2609 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][8] - 1 : 0;
2613 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2614 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2615 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][6] - 1 : 0;
2619 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2620 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2621 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][2] - 1 : 0;
2624 mesher.addPrim(quad, !isInside, tag[
bool(refFlags & ZEDGE)]);
2633 template<
typename InputTreeType>
2634 struct MaskTileBorders
2636 using InputValueType =
typename InputTreeType::ValueType;
2637 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
2640 MaskTileBorders(
const InputTreeType& inputTree, InputValueType iso,
2641 BoolTreeType& mask,
const Vec4i* tileArray)
2642 : mInputTree(&inputTree)
2646 , mTileArray(tileArray)
2650 MaskTileBorders(MaskTileBorders& rhs, tbb::split)
2651 : mInputTree(rhs.mInputTree)
2652 , mIsovalue(rhs.mIsovalue)
2655 , mTileArray(rhs.mTileArray)
2659 void join(MaskTileBorders& rhs) { mMask->merge(*rhs.mMask); }
2661 void operator()(
const tbb::blocked_range<size_t>&);
2664 InputTreeType
const *
const mInputTree;
2665 InputValueType
const mIsovalue;
2666 BoolTreeType mTempMask;
2667 BoolTreeType *
const mMask;
2668 Vec4i const *
const mTileArray;
2672 template<
typename InputTreeType>
2674 MaskTileBorders<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
2681 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
2683 const Vec4i& tile = mTileArray[n];
2685 bbox.min()[0] = tile[0];
2686 bbox.min()[1] = tile[1];
2687 bbox.min()[2] = tile[2];
2688 bbox.max() = bbox.min();
2689 bbox.max().offset(tile[3]);
2691 InputValueType value = mInputTree->background();
2693 const bool isInside = isInsideValue(inputTreeAcc.
getValue(bbox.min()), mIsovalue);
2694 const int valueDepth = inputTreeAcc.
getValueDepth(bbox.min());
2702 bool processRegion =
true;
2704 processRegion = isInside != isInsideValue(inputTreeAcc.
getValue(nijk), mIsovalue);
2707 if (processRegion) {
2710 region.min()[0] = region.max()[0] = ijk[0];
2711 mMask->fill(region,
false);
2718 processRegion =
true;
2720 processRegion = (!inputTreeAcc.
probeValue(ijk, value)
2721 && isInside != isInsideValue(value, mIsovalue));
2724 if (processRegion) {
2727 region.min()[0] = region.max()[0] = ijk[0];
2728 mMask->fill(region,
false);
2738 processRegion =
true;
2740 processRegion = isInside != isInsideValue(inputTreeAcc.
getValue(nijk), mIsovalue);
2743 if (processRegion) {
2746 region.min()[1] = region.max()[1] = ijk[1];
2747 mMask->fill(region,
false);
2754 processRegion =
true;
2756 processRegion = (!inputTreeAcc.
probeValue(ijk, value)
2757 && isInside != isInsideValue(value, mIsovalue));
2760 if (processRegion) {
2763 region.min()[1] = region.max()[1] = ijk[1];
2764 mMask->fill(region,
false);
2774 processRegion =
true;
2776 processRegion = isInside != isInsideValue(inputTreeAcc.
getValue(nijk), mIsovalue);
2779 if (processRegion) {
2782 region.min()[2] = region.max()[2] = ijk[2];
2783 mMask->fill(region,
false);
2789 processRegion =
true;
2791 processRegion = (!inputTreeAcc.
probeValue(ijk, value)
2792 && isInside != isInsideValue(value, mIsovalue));
2795 if (processRegion) {
2798 region.min()[2] = region.max()[2] = ijk[2];
2799 mMask->fill(region,
false);
2805 template<
typename InputTreeType>
2807 maskActiveTileBorders(
const InputTreeType& inputTree,
typename InputTreeType::ValueType iso,
2808 typename InputTreeType::template ValueConverter<bool>::Type& mask)
2810 typename InputTreeType::ValueOnCIter tileIter(inputTree);
2811 tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2813 size_t tileCount = 0;
2814 for ( ; tileIter; ++tileIter) {
2818 if (tileCount > 0) {
2819 std::unique_ptr<Vec4i[]> tiles(
new Vec4i[tileCount]);
2824 tileIter = inputTree.cbeginValueOn();
2825 tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2827 for (; tileIter; ++tileIter) {
2828 Vec4i& tile = tiles[index++];
2829 tileIter.getBoundingBox(bbox);
2830 tile[0] = bbox.min()[0];
2831 tile[1] = bbox.min()[1];
2832 tile[2] = bbox.min()[2];
2833 tile[3] = bbox.max()[0] - bbox.min()[0];
2836 MaskTileBorders<InputTreeType> op(inputTree, iso, mask, tiles.get());
2837 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, tileCount), op);
2849 PointListCopy(
const PointList& pointsIn, std::vector<Vec3s>& pointsOut)
2850 : mPointsIn(pointsIn) , mPointsOut(pointsOut)
2854 void operator()(
const tbb::blocked_range<size_t>& range)
const 2856 for (
size_t n = range.begin(); n < range.end(); ++n) {
2857 mPointsOut[n] = mPointsIn[n];
2863 std::vector<Vec3s>& mPointsOut;
2871 struct LeafNodeVoxelOffsets
2873 using IndexVector = std::vector<Index>;
2875 template<
typename LeafNodeType>
2876 void constructOffsetList();
2879 const IndexVector& core()
const {
return mCore; }
2883 const IndexVector& minX()
const {
return mMinX; }
2886 const IndexVector& maxX()
const {
return mMaxX; }
2890 const IndexVector& minY()
const {
return mMinY; }
2893 const IndexVector& maxY()
const {
return mMaxY; }
2897 const IndexVector& minZ()
const {
return mMinZ; }
2900 const IndexVector& maxZ()
const {
return mMaxZ; }
2904 const IndexVector& internalNeighborsX()
const {
return mInternalNeighborsX; }
2907 const IndexVector& internalNeighborsY()
const {
return mInternalNeighborsY; }
2910 const IndexVector& internalNeighborsZ()
const {
return mInternalNeighborsZ; }
2914 IndexVector mCore, mMinX, mMaxX, mMinY, mMaxY, mMinZ, mMaxZ,
2915 mInternalNeighborsX, mInternalNeighborsY, mInternalNeighborsZ;
2919 template<
typename LeafNodeType>
2921 LeafNodeVoxelOffsets::constructOffsetList()
2925 mCore.reserve((LeafNodeType::DIM - 2) * (LeafNodeType::DIM - 2));
2927 for (
Index x = 1; x < (LeafNodeType::DIM - 1); ++x) {
2928 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2929 for (
Index y = 1; y < (LeafNodeType::DIM - 1); ++y) {
2930 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2931 for (
Index z = 1; z < (LeafNodeType::DIM - 1); ++z) {
2932 mCore.push_back(offsetXY + z);
2938 mInternalNeighborsX.clear();
2939 mInternalNeighborsX.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2941 for (
Index x = 0; x < (LeafNodeType::DIM - 1); ++x) {
2942 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2943 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2944 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2945 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2946 mInternalNeighborsX.push_back(offsetXY + z);
2952 mInternalNeighborsY.clear();
2953 mInternalNeighborsY.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2955 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
2956 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2957 for (
Index y = 0; y < (LeafNodeType::DIM - 1); ++y) {
2958 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2959 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2960 mInternalNeighborsY.push_back(offsetXY + z);
2966 mInternalNeighborsZ.clear();
2967 mInternalNeighborsZ.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2969 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
2970 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2971 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2972 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2973 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
2974 mInternalNeighborsZ.push_back(offsetXY + z);
2981 mMinX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
2983 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2984 const Index offsetXY = (y << LeafNodeType::LOG2DIM);
2985 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2986 mMinX.push_back(offsetXY + z);
2993 mMaxX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
2995 const Index offsetX = (LeafNodeType::DIM - 1) << (2 * LeafNodeType::LOG2DIM);
2996 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2997 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2998 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2999 mMaxX.push_back(offsetXY + z);
3006 mMinY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3008 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3009 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3010 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
3011 mMinY.push_back(offsetX + z);
3018 mMaxY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3020 const Index offsetY = (LeafNodeType::DIM - 1) << LeafNodeType::LOG2DIM;
3021 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3022 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3023 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
3024 mMaxY.push_back(offsetX + offsetY + z);
3031 mMinZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3033 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3034 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3035 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
3036 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3037 mMinZ.push_back(offsetXY);
3044 mMaxZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3046 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3047 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3048 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
3049 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3050 mMaxZ.push_back(offsetXY + (LeafNodeType::DIM - 1));
3061 template<
typename AccessorT,
int _AXIS>
3062 struct VoxelEdgeAccessor {
3064 enum { AXIS = _AXIS };
3067 VoxelEdgeAccessor(AccessorT& _acc) : acc(_acc) {}
3069 void set(Coord ijk) {
3071 acc.setActiveState(ijk);
3073 acc.setActiveState(ijk);
3075 acc.setActiveState(ijk);
3077 acc.setActiveState(ijk);
3078 }
else if (_AXIS == 1) {
3079 acc.setActiveState(ijk);
3081 acc.setActiveState(ijk);
3083 acc.setActiveState(ijk);
3085 acc.setActiveState(ijk);
3087 acc.setActiveState(ijk);
3089 acc.setActiveState(ijk);
3091 acc.setActiveState(ijk);
3093 acc.setActiveState(ijk);
3102 template<
typename VoxelEdgeAcc,
typename LeafNode>
3104 evalInternalVoxelEdges(VoxelEdgeAcc& edgeAcc,
const LeafNode& leafnode,
3105 const LeafNodeVoxelOffsets& voxels,
const typename LeafNode::ValueType iso)
3108 const std::vector<Index>* offsets = &voxels.internalNeighborsZ();
3110 if (VoxelEdgeAcc::AXIS == 0) {
3111 nvo = LeafNode::DIM * LeafNode::DIM;
3112 offsets = &voxels.internalNeighborsX();
3113 }
else if (VoxelEdgeAcc::AXIS == 1) {
3114 nvo = LeafNode::DIM;
3115 offsets = &voxels.internalNeighborsY();
3118 for (
size_t n = 0, N = offsets->size(); n < N; ++n) {
3119 const Index& pos = (*offsets)[n];
3120 bool isActive = leafnode.isValueOn(pos) || leafnode.isValueOn(pos + nvo);
3121 if (isActive && (isInsideValue(leafnode.getValue(pos), iso) !=
3122 isInsideValue(leafnode.getValue(pos + nvo), iso))) {
3123 edgeAcc.set(leafnode.offsetToGlobalCoord(pos));
3132 template<
typename LeafNode,
typename TreeAcc,
typename VoxelEdgeAcc>
3134 evalExtrenalVoxelEdges(VoxelEdgeAcc& edgeAcc, TreeAcc& acc,
const LeafNode& lhsNode,
3135 const LeafNodeVoxelOffsets& voxels,
const typename LeafNode::ValueType iso)
3137 const std::vector<Index>* lhsOffsets = &voxels.maxX();
3138 const std::vector<Index>* rhsOffsets = &voxels.minX();
3139 Coord ijk = lhsNode.origin();
3141 if (VoxelEdgeAcc::AXIS == 0) {
3142 ijk[0] += LeafNode::DIM;
3143 }
else if (VoxelEdgeAcc::AXIS == 1) {
3144 ijk[1] += LeafNode::DIM;
3145 lhsOffsets = &voxels.maxY();
3146 rhsOffsets = &voxels.minY();
3147 }
else if (VoxelEdgeAcc::AXIS == 2) {
3148 ijk[2] += LeafNode::DIM;
3149 lhsOffsets = &voxels.maxZ();
3150 rhsOffsets = &voxels.minZ();
3153 typename LeafNode::ValueType
value;
3154 const LeafNode* rhsNodePt = acc.probeConstLeaf(ijk);
3157 for (
size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3158 const Index& pos = (*lhsOffsets)[n];
3159 bool isActive = lhsNode.isValueOn(pos) || rhsNodePt->isValueOn((*rhsOffsets)[n]);
3160 if (isActive && (isInsideValue(lhsNode.getValue(pos), iso) !=
3161 isInsideValue(rhsNodePt->getValue((*rhsOffsets)[n]), iso))) {
3162 edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3165 }
else if (!acc.probeValue(ijk, value)) {
3166 const bool inside = isInsideValue(value, iso);
3167 for (
size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3168 const Index& pos = (*lhsOffsets)[n];
3169 if (lhsNode.isValueOn(pos) && (inside != isInsideValue(lhsNode.getValue(pos), iso))) {
3170 edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3180 template<
typename LeafNode,
typename TreeAcc,
typename VoxelEdgeAcc>
3182 evalExtrenalVoxelEdgesInv(VoxelEdgeAcc& edgeAcc, TreeAcc& acc,
const LeafNode& leafnode,
3183 const LeafNodeVoxelOffsets& voxels,
const typename LeafNode::ValueType iso)
3185 Coord ijk = leafnode.origin();
3186 if (VoxelEdgeAcc::AXIS == 0) --ijk[0];
3187 else if (VoxelEdgeAcc::AXIS == 1) --ijk[1];
3188 else if (VoxelEdgeAcc::AXIS == 2) --ijk[2];
3190 typename LeafNode::ValueType
value;
3191 if (!acc.probeConstLeaf(ijk) && !acc.probeValue(ijk, value)) {
3193 const std::vector<Index>* offsets = &voxels.internalNeighborsX();
3194 if (VoxelEdgeAcc::AXIS == 1) offsets = &voxels.internalNeighborsY();
3195 else if (VoxelEdgeAcc::AXIS == 2) offsets = &voxels.internalNeighborsZ();
3197 const bool inside = isInsideValue(value, iso);
3198 for (
size_t n = 0, N = offsets->size(); n < N; ++n) {
3200 const Index& pos = (*offsets)[n];
3201 if (leafnode.isValueOn(pos)
3202 && (inside != isInsideValue(leafnode.getValue(pos), iso)))
3204 ijk = leafnode.offsetToGlobalCoord(pos);
3205 if (VoxelEdgeAcc::AXIS == 0) --ijk[0];
3206 else if (VoxelEdgeAcc::AXIS == 1) --ijk[1];
3207 else if (VoxelEdgeAcc::AXIS == 2) --ijk[2];
3217 template<
typename InputTreeType>
3218 struct IdentifyIntersectingVoxels
3220 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3221 using InputValueType =
typename InputLeafNodeType::ValueType;
3223 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3225 IdentifyIntersectingVoxels(
3226 const InputTreeType& inputTree,
3227 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3228 BoolTreeType& intersectionTree,
3229 InputValueType iso);
3231 IdentifyIntersectingVoxels(IdentifyIntersectingVoxels&, tbb::split);
3232 void operator()(
const tbb::blocked_range<size_t>&);
3233 void join(
const IdentifyIntersectingVoxels& rhs) {
3234 mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3239 InputLeafNodeType
const *
const *
const mInputNodes;
3241 BoolTreeType mIntersectionTree;
3244 LeafNodeVoxelOffsets mOffsetData;
3245 const LeafNodeVoxelOffsets* mOffsets;
3247 InputValueType mIsovalue;
3251 template<
typename InputTreeType>
3252 IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
3253 const InputTreeType& inputTree,
3254 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3255 BoolTreeType& intersectionTree,
3257 : mInputAccessor(inputTree)
3258 , mInputNodes(inputLeafNodes.data())
3259 , mIntersectionTree(
false)
3260 , mIntersectionAccessor(intersectionTree)
3262 , mOffsets(&mOffsetData)
3265 mOffsetData.constructOffsetList<InputLeafNodeType>();
3269 template<
typename InputTreeType>
3270 IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
3271 IdentifyIntersectingVoxels& rhs, tbb::split)
3272 : mInputAccessor(rhs.mInputAccessor.tree())
3273 , mInputNodes(rhs.mInputNodes)
3274 , mIntersectionTree(
false)
3275 , mIntersectionAccessor(mIntersectionTree)
3277 , mOffsets(rhs.mOffsets)
3278 , mIsovalue(rhs.mIsovalue)
3283 template<
typename InputTreeType>
3285 IdentifyIntersectingVoxels<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3287 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3288 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3289 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3291 for (
size_t n = range.begin(); n != range.end(); ++n) {
3293 const InputLeafNodeType& node = *mInputNodes[n];
3296 evalInternalVoxelEdges(xEdgeAcc, node, *mOffsets, mIsovalue);
3298 evalInternalVoxelEdges(yEdgeAcc, node, *mOffsets, mIsovalue);
3300 evalInternalVoxelEdges(zEdgeAcc, node, *mOffsets, mIsovalue);
3303 evalExtrenalVoxelEdges(xEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3305 evalExtrenalVoxelEdges(yEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3307 evalExtrenalVoxelEdges(zEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3313 evalExtrenalVoxelEdgesInv(xEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3315 evalExtrenalVoxelEdgesInv(yEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3317 evalExtrenalVoxelEdgesInv(zEdgeAcc, mInputAccessor, node, *mOffsets, mIsovalue);
3322 template<
typename InputTreeType>
3324 identifySurfaceIntersectingVoxels(
3325 typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3326 const InputTreeType& inputTree,
3327 typename InputTreeType::ValueType isovalue)
3329 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3331 std::vector<const InputLeafNodeType*> inputLeafNodes;
3332 inputTree.getNodes(inputLeafNodes);
3334 IdentifyIntersectingVoxels<InputTreeType> op(
3335 inputTree, inputLeafNodes, intersectionTree, isovalue);
3337 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, inputLeafNodes.size()), op);
3339 maskActiveTileBorders(inputTree, isovalue, intersectionTree);
3346 template<
typename InputTreeType>
3347 struct MaskIntersectingVoxels
3349 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3350 using InputValueType =
typename InputLeafNodeType::ValueType;
3352 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3353 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3355 MaskIntersectingVoxels(
3356 const InputTreeType& inputTree,
3357 const std::vector<BoolLeafNodeType*>& nodes,
3358 BoolTreeType& intersectionTree,
3359 InputValueType iso);
3361 MaskIntersectingVoxels(MaskIntersectingVoxels&, tbb::split);
3362 void operator()(
const tbb::blocked_range<size_t>&);
3363 void join(
const MaskIntersectingVoxels& rhs) {
3364 mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3369 BoolLeafNodeType
const *
const *
const mNodes;
3371 BoolTreeType mIntersectionTree;
3374 InputValueType mIsovalue;
3378 template<
typename InputTreeType>
3379 MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
3380 const InputTreeType& inputTree,
3381 const std::vector<BoolLeafNodeType*>& nodes,
3382 BoolTreeType& intersectionTree,
3384 : mInputAccessor(inputTree)
3385 , mNodes(nodes.data())
3386 , mIntersectionTree(
false)
3387 , mIntersectionAccessor(intersectionTree)
3393 template<
typename InputTreeType>
3394 MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
3395 MaskIntersectingVoxels& rhs, tbb::split)
3396 : mInputAccessor(rhs.mInputAccessor.tree())
3397 , mNodes(rhs.mNodes)
3398 , mIntersectionTree(
false)
3399 , mIntersectionAccessor(mIntersectionTree)
3400 , mIsovalue(rhs.mIsovalue)
3405 template<
typename InputTreeType>
3407 MaskIntersectingVoxels<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3409 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3410 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3411 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3414 InputValueType iso(mIsovalue);
3416 for (
size_t n = range.begin(); n != range.end(); ++n) {
3418 const BoolLeafNodeType& node = *mNodes[n];
3420 for (
typename BoolLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3422 if (!it.getValue()) {
3424 ijk = it.getCoord();
3426 const bool inside = isInsideValue(mInputAccessor.getValue(ijk), iso);
3428 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(1, 0, 0)), iso)) {
3432 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 1, 0)), iso)) {
3436 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 0, 1)), iso)) {
3445 template<
typename BoolTreeType>
3446 struct MaskBorderVoxels
3448 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3450 MaskBorderVoxels(
const BoolTreeType& maskTree,
3451 const std::vector<BoolLeafNodeType*>& maskNodes,
3452 BoolTreeType& borderTree)
3453 : mMaskTree(&maskTree)
3454 , mMaskNodes(maskNodes.data())
3455 , mTmpBorderTree(
false)
3456 , mBorderTree(&borderTree)
3460 MaskBorderVoxels(MaskBorderVoxels& rhs, tbb::split)
3461 : mMaskTree(rhs.mMaskTree)
3462 , mMaskNodes(rhs.mMaskNodes)
3463 , mTmpBorderTree(
false)
3464 , mBorderTree(&mTmpBorderTree)
3468 void join(MaskBorderVoxels& rhs) { mBorderTree->merge(*rhs.mBorderTree); }
3470 void operator()(
const tbb::blocked_range<size_t>& range)
3476 for (
size_t n = range.begin(); n != range.end(); ++n) {
3478 const BoolLeafNodeType& node = *mMaskNodes[n];
3480 for (
typename BoolLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3482 ijk = it.getCoord();
3484 const bool lhs = it.getValue();
3487 bool isEdgeVoxel =
false;
3490 isEdgeVoxel = (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3493 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3496 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3499 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3503 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3506 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3509 isEdgeVoxel = isEdgeVoxel || (maskAcc.
probeValue(ijk, rhs) && lhs != rhs);
3520 BoolTreeType
const *
const mMaskTree;
3521 BoolLeafNodeType
const *
const *
const mMaskNodes;
3523 BoolTreeType mTmpBorderTree;
3524 BoolTreeType *
const mBorderTree;
3528 template<
typename BoolTreeType>
3529 struct SyncMaskValues
3531 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3533 SyncMaskValues(
const std::vector<BoolLeafNodeType*>& nodes,
const BoolTreeType& mask)
3534 : mNodes(nodes.data())
3539 void operator()(
const tbb::blocked_range<size_t>& range)
const 3541 using ValueOnIter =
typename BoolLeafNodeType::ValueOnIter;
3545 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3547 BoolLeafNodeType& node = *mNodes[n];
3549 const BoolLeafNodeType * maskNode = maskTreeAcc.
probeConstLeaf(node.origin());
3552 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3553 const Index pos = it.pos();
3554 if (maskNode->getValue(pos)) {
3555 node.setValueOnly(pos,
true);
3563 BoolLeafNodeType *
const *
const mNodes;
3564 BoolTreeType
const *
const mMaskTree;
3571 template<
typename BoolTreeType>
3574 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3576 MaskSurface(
const std::vector<BoolLeafNodeType*>& nodes,
const BoolTreeType& mask,
3578 : mNodes(nodes.data())
3580 , mInputTransform(inputTransform)
3581 , mMaskTransform(maskTransform)
3582 , mInvertMask(invert)
3586 void operator()(
const tbb::blocked_range<size_t>& range)
const 3588 using ValueOnIter =
typename BoolLeafNodeType::ValueOnIter;
3592 const bool matchingTransforms = mInputTransform == mMaskTransform;
3593 const bool maskState = mInvertMask;
3595 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3597 BoolLeafNodeType& node = *mNodes[n];
3599 if (matchingTransforms) {
3601 const BoolLeafNodeType * maskNode = maskTreeAcc.
probeConstLeaf(node.origin());
3605 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3606 const Index pos = it.pos();
3607 if (maskNode->isValueOn(pos) == maskState) {
3608 node.setValueOnly(pos,
true);
3614 if (maskTreeAcc.
isValueOn(node.origin()) == maskState) {
3615 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3616 node.setValueOnly(it.pos(),
true);
3626 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3628 ijk = mMaskTransform.worldToIndexCellCentered(
3629 mInputTransform.indexToWorld(it.getCoord()));
3631 if (maskTreeAcc.
isValueOn(ijk) == maskState) {
3632 node.setValueOnly(it.pos(),
true);
3641 BoolLeafNodeType *
const *
const mNodes;
3642 BoolTreeType
const *
const mMaskTree;
3645 bool const mInvertMask;
3649 template<
typename InputGr
idType>
3652 typename InputGridType::TreeType::template ValueConverter<bool>::Type& intersectionTree,
3653 typename InputGridType::TreeType::template ValueConverter<bool>::Type& borderTree,
3654 const InputGridType& inputGrid,
3657 typename InputGridType::ValueType isovalue)
3659 using InputTreeType =
typename InputGridType::TreeType;
3660 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3661 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3664 if (maskGrid && maskGrid->type() == BoolGridType::gridType()) {
3667 const InputTreeType& inputTree = inputGrid.tree();
3669 const BoolGridType * surfaceMask =
static_cast<const BoolGridType*
>(maskGrid.get());
3671 const BoolTreeType& maskTree = surfaceMask->tree();
3677 std::vector<BoolLeafNodeType*> intersectionLeafNodes;
3678 intersectionTree.getNodes(intersectionLeafNodes);
3680 tbb::parallel_for(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()),
3681 MaskSurface<BoolTreeType>(
3682 intersectionLeafNodes, maskTree, transform, maskTransform, invertMask));
3687 MaskBorderVoxels<BoolTreeType> borderOp(
3688 intersectionTree, intersectionLeafNodes, borderTree);
3689 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), borderOp);
3694 BoolTreeType tmpIntersectionTree(
false);
3696 MaskIntersectingVoxels<InputTreeType> op(
3697 inputTree, intersectionLeafNodes, tmpIntersectionTree, isovalue);
3699 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), op);
3701 std::vector<BoolLeafNodeType*> tmpIntersectionLeafNodes;
3702 tmpIntersectionTree.getNodes(tmpIntersectionLeafNodes);
3704 tbb::parallel_for(tbb::blocked_range<size_t>(0, tmpIntersectionLeafNodes.size()),
3705 SyncMaskValues<BoolTreeType>(tmpIntersectionLeafNodes, intersectionTree));
3707 intersectionTree.clear();
3708 intersectionTree.merge(tmpIntersectionTree);
3716 template<
typename InputTreeType>
3717 struct ComputeAuxiliaryData
3719 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3720 using InputValueType =
typename InputLeafNodeType::ValueType;
3724 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
3725 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
3728 ComputeAuxiliaryData(
const InputTreeType& inputTree,
3729 const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3730 Int16TreeType& signFlagsTree,
3731 Index32TreeType& pointIndexTree,
3732 InputValueType iso);
3734 ComputeAuxiliaryData(ComputeAuxiliaryData&, tbb::split);
3735 void operator()(
const tbb::blocked_range<size_t>&);
3736 void join(
const ComputeAuxiliaryData& rhs) {
3737 mSignFlagsAccessor.tree().merge(rhs.mSignFlagsAccessor.tree());
3738 mPointIndexAccessor.tree().merge(rhs.mPointIndexAccessor.tree());
3743 BoolLeafNodeType
const *
const *
const mIntersectionNodes;
3745 Int16TreeType mSignFlagsTree;
3747 Index32TreeType mPointIndexTree;
3750 const InputValueType mIsovalue;
3754 template<
typename InputTreeType>
3755 ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(
3756 const InputTreeType& inputTree,
3757 const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3758 Int16TreeType& signFlagsTree,
3759 Index32TreeType& pointIndexTree,
3761 : mInputAccessor(inputTree)
3762 , mIntersectionNodes(intersectionLeafNodes.data())
3764 , mSignFlagsAccessor(signFlagsTree)
3766 , mPointIndexAccessor(pointIndexTree)
3773 template<
typename InputTreeType>
3774 ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(ComputeAuxiliaryData& rhs, tbb::split)
3775 : mInputAccessor(rhs.mInputAccessor.tree())
3776 , mIntersectionNodes(rhs.mIntersectionNodes)
3778 , mSignFlagsAccessor(mSignFlagsTree)
3780 , mPointIndexAccessor(mPointIndexTree)
3781 , mIsovalue(rhs.mIsovalue)
3786 template<
typename InputTreeType>
3788 ComputeAuxiliaryData<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3790 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
3794 typename std::unique_ptr<Int16LeafNodeType> signsNodePt(
new Int16LeafNodeType(ijk, 0));
3796 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3798 const BoolLeafNodeType& maskNode = *mIntersectionNodes[n];
3799 const Coord& origin = maskNode.origin();
3801 const InputLeafNodeType *leafPt = mInputAccessor.probeConstLeaf(origin);
3803 if (!signsNodePt.get()) signsNodePt.reset(
new Int16LeafNodeType(origin, 0));
3804 else signsNodePt->setOrigin(origin);
3806 bool updatedNode =
false;
3808 for (
typename BoolLeafNodeType::ValueOnCIter it = maskNode.cbeginValueOn(); it; ++it) {
3810 const Index pos = it.pos();
3811 ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
3814 ijk[0] <
int(BoolLeafNodeType::DIM - 1) &&
3815 ijk[1] <
int(BoolLeafNodeType::DIM - 1) &&
3816 ijk[2] <
int(BoolLeafNodeType::DIM - 1) ) {
3817 getCellVertexValues(*leafPt, pos, cellVertexValues);
3819 getCellVertexValues(mInputAccessor, origin + ijk, cellVertexValues);
3822 uint8_t signFlags = computeSignFlags(cellVertexValues, mIsovalue);
3824 if (signFlags != 0 && signFlags != 0xFF) {
3826 const bool inside = signFlags & 0x1;
3828 int edgeFlags = inside ? INSIDE : 0;
3830 if (!it.getValue()) {
3831 edgeFlags |= inside != ((signFlags & 0x02) != 0) ? XEDGE : 0;
3832 edgeFlags |= inside != ((signFlags & 0x10) != 0) ? YEDGE : 0;
3833 edgeFlags |= inside != ((signFlags & 0x08) != 0) ? ZEDGE : 0;
3836 const uint8_t ambiguousCellFlags = sAmbiguousFace[signFlags];
3837 if (ambiguousCellFlags != 0) {
3838 correctCellSigns(signFlags, ambiguousCellFlags, mInputAccessor,
3839 origin + ijk, mIsovalue);
3842 edgeFlags |= int(signFlags);
3844 signsNodePt->setValueOn(pos,
Int16(edgeFlags));
3850 typename Index32TreeType::LeafNodeType* idxNode = mPointIndexAccessor.touchLeaf(origin);
3851 idxNode->topologyUnion(*signsNodePt);
3854 for (
auto it = idxNode->beginValueOn(); it; ++it) {
3855 idxNode->setValueOnly(it.pos(), 0);
3858 mSignFlagsAccessor.addLeaf(signsNodePt.release());
3864 template<
typename InputTreeType>
3866 computeAuxiliaryData(
3867 typename InputTreeType::template ValueConverter<Int16>::Type& signFlagsTree,
3868 typename InputTreeType::template ValueConverter<Index32>::Type& pointIndexTree,
3869 const typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3870 const InputTreeType& inputTree,
3871 typename InputTreeType::ValueType isovalue)
3873 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3874 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3876 std::vector<const BoolLeafNodeType*> intersectionLeafNodes;
3877 intersectionTree.getNodes(intersectionLeafNodes);
3879 ComputeAuxiliaryData<InputTreeType> op(
3880 inputTree, intersectionLeafNodes, signFlagsTree, pointIndexTree, isovalue);
3882 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), op);
3889 template<Index32 LeafNodeLog2Dim>
3890 struct LeafNodePointCount
3894 LeafNodePointCount(
const std::vector<Int16LeafNodeType*>& leafNodes,
3895 std::unique_ptr<
Index32[]>& leafNodeCount)
3896 : mLeafNodes(leafNodes.data())
3897 , mData(leafNodeCount.get())
3901 void operator()(
const tbb::blocked_range<size_t>& range)
const {
3903 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3907 Int16 const * p = mLeafNodes[n]->buffer().data();
3908 Int16 const *
const endP = p + Int16LeafNodeType::SIZE;
3911 count +=
Index32(sEdgeGroupTable[(SIGNS & *p)][0]);
3920 Int16LeafNodeType *
const *
const mLeafNodes;
3925 template<
typename Po
intIndexLeafNode>
3926 struct AdaptiveLeafNodePointCount
3930 AdaptiveLeafNodePointCount(
const std::vector<PointIndexLeafNode*>& pointIndexNodes,
3931 const std::vector<Int16LeafNodeType*>& signDataNodes,
3932 std::unique_ptr<
Index32[]>& leafNodeCount)
3933 : mPointIndexNodes(pointIndexNodes.data())
3934 , mSignDataNodes(signDataNodes.data())
3935 , mData(leafNodeCount.get())
3939 void operator()(
const tbb::blocked_range<size_t>& range)
const 3943 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3946 const Int16LeafNodeType& signNode = *mSignDataNodes[n];
3950 std::set<IndexType> uniqueRegions;
3957 count += size_t(sEdgeGroupTable[(SIGNS & signNode.getValue(it.pos()))][0]);
3959 uniqueRegions.insert(
id);
3963 mData[n] =
Index32(count + uniqueRegions.size());
3969 Int16LeafNodeType
const *
const *
const mSignDataNodes;
3974 template<
typename Po
intIndexLeafNode>
3979 MapPoints(
const std::vector<PointIndexLeafNode*>& pointIndexNodes,
3980 const std::vector<Int16LeafNodeType*>& signDataNodes,
3981 std::unique_ptr<
Index32[]>& leafNodeCount)
3982 : mPointIndexNodes(pointIndexNodes.data())
3983 , mSignDataNodes(signDataNodes.data())
3984 , mData(leafNodeCount.get())
3988 void operator()(
const tbb::blocked_range<size_t>& range)
const {
3990 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3992 const Int16LeafNodeType& signNode = *mSignDataNodes[n];
3995 Index32 pointOffset = mData[n];
3998 const Index pos = it.pos();
4000 const int signs = SIGNS & int(signNode.getValue(pos));
4001 pointOffset +=
Index32(sEdgeGroupTable[signs][0]);
4008 Int16LeafNodeType
const *
const *
const mSignDataNodes;
4015 template<
typename TreeType,
typename PrimBuilder>
4016 struct ComputePolygons
4018 using Int16TreeType =
typename TreeType::template ValueConverter<Int16>::Type;
4019 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
4021 using Index32TreeType =
typename TreeType::template ValueConverter<Index32>::Type;
4022 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
4026 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4027 const Int16TreeType& signFlagsTree,
4028 const Index32TreeType& idxTree,
4030 bool invertSurfaceOrientation);
4032 void setRefSignTree(
const Int16TreeType * r) { mRefSignFlagsTree = r; }
4034 void operator()(
const tbb::blocked_range<size_t>&)
const;
4037 Int16LeafNodeType *
const *
const mSignFlagsLeafNodes;
4038 Int16TreeType
const *
const mSignFlagsTree;
4039 Int16TreeType
const * mRefSignFlagsTree;
4040 Index32TreeType
const *
const mIndexTree;
4042 bool const mInvertSurfaceOrientation;
4046 template<
typename TreeType,
typename PrimBuilder>
4047 ComputePolygons<TreeType, PrimBuilder>::ComputePolygons(
4048 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4049 const Int16TreeType& signFlagsTree,
4050 const Index32TreeType& idxTree,
4052 bool invertSurfaceOrientation)
4053 : mSignFlagsLeafNodes(signFlagsLeafNodes.data())
4054 , mSignFlagsTree(&signFlagsTree)
4055 , mRefSignFlagsTree(
nullptr)
4056 , mIndexTree(&idxTree)
4057 , mPolygonPoolList(&polygons)
4058 , mInvertSurfaceOrientation(invertSurfaceOrientation)
4062 template<
typename InputTreeType,
typename PrimBuilder>
4064 ComputePolygons<InputTreeType, PrimBuilder>::operator()(
const tbb::blocked_range<size_t>& range)
const 4067 Int16ValueAccessor signAcc(*mSignFlagsTree);
4071 const bool invertSurfaceOrientation = mInvertSurfaceOrientation;
4078 std::unique_ptr<Int16ValueAccessor> refSignAcc;
4079 if (mRefSignFlagsTree) refSignAcc.reset(
new Int16ValueAccessor(*mRefSignFlagsTree));
4081 for (
size_t n = range.begin(); n != range.end(); ++n) {
4083 const Int16LeafNodeType& node = *mSignFlagsLeafNodes[n];
4084 origin = node.origin();
4088 typename Int16LeafNodeType::ValueOnCIter iter = node.cbeginValueOn();
4089 for (; iter; ++iter) {
4090 if (iter.getValue() & XEDGE) ++edgeCount;
4091 if (iter.getValue() & YEDGE) ++edgeCount;
4092 if (iter.getValue() & ZEDGE) ++edgeCount;
4095 if(edgeCount == 0)
continue;
4097 mesher.init(edgeCount, (*mPolygonPoolList)[n]);
4099 const Int16LeafNodeType *signleafPt = signAcc.probeConstLeaf(origin);
4100 const Index32LeafNodeType *idxLeafPt = idxAcc.
probeConstLeaf(origin);
4102 if (!signleafPt || !idxLeafPt)
continue;
4105 const Int16LeafNodeType *refSignLeafPt =
nullptr;
4106 if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(origin);
4110 for (iter = node.cbeginValueOn(); iter; ++iter) {
4111 ijk = iter.getCoord();
4113 Int16 flags = iter.getValue();
4115 if (!(flags & 0xE00))
continue;
4118 if (refSignLeafPt) {
4119 refFlags = refSignLeafPt->getValue(iter.pos());
4126 const uint8_t cell = uint8_t(SIGNS & flags);
4128 if (sEdgeGroupTable[cell][0] > 1) {
4129 offsets[0] = (sEdgeGroupTable[cell][1] - 1);
4130 offsets[1] = (sEdgeGroupTable[cell][9] - 1);
4131 offsets[2] = (sEdgeGroupTable[cell][4] - 1);
4134 if (ijk[0] > origin[0] && ijk[1] > origin[1] && ijk[2] > origin[2]) {
4135 constructPolygons(invertSurfaceOrientation,
4136 flags, refFlags, offsets, ijk, *signleafPt, *idxLeafPt, mesher);
4138 constructPolygons(invertSurfaceOrientation,
4139 flags, refFlags, offsets, ijk, signAcc, idxAcc, mesher);
4152 template<
typename T>
4155 CopyArray(T * outputArray,
const T * inputArray,
size_t outputOffset = 0)
4156 : mOutputArray(outputArray), mInputArray(inputArray), mOutputOffset(outputOffset)
4160 void operator()(
const tbb::blocked_range<size_t>& inputArrayRange)
const 4162 const size_t offset = mOutputOffset;
4163 for (
size_t n = inputArrayRange.begin(), N = inputArrayRange.end(); n < N; ++n) {
4164 mOutputArray[offset + n] = mInputArray[n];
4169 T *
const mOutputArray;
4170 T
const *
const mInputArray;
4171 size_t const mOutputOffset;
4175 struct FlagAndCountQuadsToSubdivide
4178 const std::vector<uint8_t>& pointFlags,
4180 std::unique_ptr<
unsigned[]>& numQuadsToDivide)
4181 : mPolygonPoolList(&polygons)
4182 , mPointFlags(pointFlags.data())
4183 , mPoints(points.get())
4184 , mNumQuadsToDivide(numQuadsToDivide.get())
4188 void operator()(
const tbb::blocked_range<size_t>& range)
const 4190 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4197 for (
size_t i = 0, I = polygons.
numQuads(); i < I; ++i) {
4205 const bool edgePoly = mPointFlags[quad[0]] || mPointFlags[quad[1]]
4206 || mPointFlags[quad[2]] || mPointFlags[quad[3]];
4208 if (!edgePoly)
continue;
4210 const Vec3s& p0 = mPoints[quad[0]];
4211 const Vec3s& p1 = mPoints[quad[1]];
4212 const Vec3s& p2 = mPoints[quad[2]];
4213 const Vec3s& p3 = mPoints[quad[3]];
4215 if (!isPlanarQuad(p0, p1, p2, p3, 1e-6f)) {
4222 mNumQuadsToDivide[n] = count;
4228 uint8_t
const *
const mPointFlags;
4229 Vec3s const *
const mPoints;
4230 unsigned *
const mNumQuadsToDivide;
4234 struct SubdivideQuads
4240 std::unique_ptr<
unsigned[]>& numQuadsToDivide,
4241 std::unique_ptr<
unsigned[]>& centroidOffsets)
4242 : mPolygonPoolList(&polygons)
4243 , mPoints(points.get())
4244 , mCentroids(centroids.get())
4245 , mNumQuadsToDivide(numQuadsToDivide.get())
4246 , mCentroidOffsets(centroidOffsets.get())
4247 , mPointCount(pointCount)
4251 void operator()(
const tbb::blocked_range<size_t>& range)
const 4253 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4257 const size_t nonplanarCount = size_t(mNumQuadsToDivide[n]);
4259 if (nonplanarCount > 0) {
4265 size_t offset = mCentroidOffsets[n];
4267 size_t triangleIdx = 0;
4269 for (
size_t i = 0, I = polygons.
numQuads(); i < I; ++i) {
4271 const char quadFlags = polygons.
quadFlags(i);
4274 unsigned newPointIdx = unsigned(offset + mPointCount);
4278 mCentroids[offset] = (mPoints[quad[0]] + mPoints[quad[1]] +
4279 mPoints[quad[2]] + mPoints[quad[3]]) * 0.25f;
4286 triangle[0] = quad[0];
4287 triangle[1] = newPointIdx;
4288 triangle[2] = quad[3];
4298 triangle[0] = quad[0];
4299 triangle[1] = quad[1];
4300 triangle[2] = newPointIdx;
4310 triangle[0] = quad[1];
4311 triangle[1] = quad[2];
4312 triangle[2] = newPointIdx;
4323 triangle[0] = quad[2];
4324 triangle[1] = quad[3];
4325 triangle[2] = newPointIdx;
4336 for (
size_t i = 0, I = polygons.
numTriangles(); i < I; ++i) {
4343 for (
size_t i = 0, I = polygons.
numQuads(); i < I; ++i) {
4347 tmpPolygons.
quad(quadIdx) = quad;
4353 polygons.
copy(tmpPolygons);
4360 Vec3s const *
const mPoints;
4361 Vec3s *
const mCentroids;
4362 unsigned *
const mNumQuadsToDivide;
4363 unsigned *
const mCentroidOffsets;
4364 size_t const mPointCount;
4369 subdivideNonplanarSeamLineQuads(
4371 size_t polygonPoolListSize,
4373 size_t& pointListSize,
4374 std::vector<uint8_t>& pointFlags)
4376 const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4378 std::unique_ptr<unsigned[]> numQuadsToDivide(
new unsigned[polygonPoolListSize]);
4380 tbb::parallel_for(polygonPoolListRange,
4381 FlagAndCountQuadsToSubdivide(polygonPoolList, pointFlags, pointList, numQuadsToDivide));
4383 std::unique_ptr<unsigned[]> centroidOffsets(
new unsigned[polygonPoolListSize]);
4385 size_t centroidCount = 0;
4389 for (
size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4390 centroidOffsets[n] = sum;
4391 sum += numQuadsToDivide[n];
4393 centroidCount = size_t(sum);
4396 std::unique_ptr<Vec3s[]> centroidList(
new Vec3s[centroidCount]);
4398 tbb::parallel_for(polygonPoolListRange,
4399 SubdivideQuads(polygonPoolList, pointList, pointListSize,
4400 centroidList, numQuadsToDivide, centroidOffsets));
4402 if (centroidCount > 0) {
4404 const size_t newPointListSize = centroidCount + pointListSize;
4406 std::unique_ptr<openvdb::Vec3s[]> newPointList(
new openvdb::Vec3s[newPointListSize]);
4408 tbb::parallel_for(tbb::blocked_range<size_t>(0, pointListSize),
4409 CopyArray<Vec3s>(newPointList.get(), pointList.get()));
4411 tbb::parallel_for(tbb::blocked_range<size_t>(0, newPointListSize - pointListSize),
4412 CopyArray<Vec3s>(newPointList.get(), centroidList.get(), pointListSize));
4414 pointListSize = newPointListSize;
4415 pointList.swap(newPointList);
4416 pointFlags.resize(pointListSize, 0);
4421 struct ReviseSeamLineFlags
4424 const std::vector<uint8_t>& pointFlags)
4425 : mPolygonPoolList(&polygons)
4426 , mPointFlags(pointFlags.data())
4430 void operator()(
const tbb::blocked_range<size_t>& range)
const 4432 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4436 for (
size_t i = 0, I = polygons.
numQuads(); i < I; ++i) {
4444 const bool hasSeamLinePoint =
4445 mPointFlags[verts[0]] || mPointFlags[verts[1]] ||
4446 mPointFlags[verts[2]] || mPointFlags[verts[3]];
4448 if (!hasSeamLinePoint) {
4449 flags &= ~POLYFLAG_FRACTURE_SEAM;
4454 for (
size_t i = 0, I = polygons.
numTriangles(); i < I; ++i) {
4462 const bool hasSeamLinePoint =
4463 mPointFlags[verts[0]] || mPointFlags[verts[1]] || mPointFlags[verts[2]];
4465 if (!hasSeamLinePoint) {
4466 flags &= ~POLYFLAG_FRACTURE_SEAM;
4477 uint8_t
const *
const mPointFlags;
4482 reviseSeamLineFlags(
PolygonPoolList& polygonPoolList,
size_t polygonPoolListSize,
4483 std::vector<uint8_t>& pointFlags)
4485 tbb::parallel_for(tbb::blocked_range<size_t>(0, polygonPoolListSize),
4486 ReviseSeamLineFlags(polygonPoolList, pointFlags));
4493 template<
typename InputTreeType>
4494 struct MaskDisorientedTrianglePoints
4496 MaskDisorientedTrianglePoints(
const InputTreeType& inputTree,
const PolygonPoolList& polygons,
4497 const PointList& pointList, std::unique_ptr<uint8_t[]>& pointMask,
4499 : mInputTree(&inputTree)
4500 , mPolygonPoolList(&polygons)
4501 , mPointList(&pointList)
4502 , mPointMask(pointMask.get())
4503 , mTransform(transform)
4504 , mInvertSurfaceOrientation(invertSurfaceOrientation)
4508 void operator()(
const tbb::blocked_range<size_t>& range)
const 4510 using ValueType =
typename InputTreeType::LeafNodeType::ValueType;
4513 Vec3s centroid, normal;
4516 const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<ValueType>();
4518 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4520 const PolygonPool& polygons = (*mPolygonPoolList)[n];
4522 for (
size_t i = 0, I = polygons.
numTriangles(); i < I; ++i) {
4526 const Vec3s& v0 = (*mPointList)[verts[0]];
4527 const Vec3s& v1 = (*mPointList)[verts[1]];
4528 const Vec3s& v2 = (*mPointList)[verts[2]];
4530 normal = (v2 - v0).cross((v1 - v0));
4533 centroid = (v0 + v1 + v2) * (1.0f / 3.0f);
4534 ijk = mTransform.worldToIndexCellCentered(centroid);
4539 if (invertGradientDir) {
4544 if (dir.dot(normal) < -0.5f) {
4549 mPointMask[verts[0]] = 1;
4550 mPointMask[verts[1]] = 1;
4551 mPointMask[verts[2]] = 1;
4560 InputTreeType
const *
const mInputTree;
4563 uint8_t *
const mPointMask;
4565 bool const mInvertSurfaceOrientation;
4569 template<
typename InputTree>
4571 relaxDisorientedTriangles(
4572 bool invertSurfaceOrientation,
4573 const InputTree& inputTree,
4576 size_t polygonPoolListSize,
4578 const size_t pointListSize)
4580 const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4582 std::unique_ptr<uint8_t[]> pointMask(
new uint8_t[pointListSize]);
4583 fillArray(pointMask.get(), uint8_t(0), pointListSize);
4585 tbb::parallel_for(polygonPoolListRange,
4586 MaskDisorientedTrianglePoints<InputTree>(
4587 inputTree, polygonPoolList, pointList, pointMask, transform, invertSurfaceOrientation));
4589 std::unique_ptr<uint8_t[]> pointUpdates(
new uint8_t[pointListSize]);
4590 fillArray(pointUpdates.get(), uint8_t(0), pointListSize);
4592 std::unique_ptr<Vec3s[]> newPoints(
new Vec3s[pointListSize]);
4593 fillArray(newPoints.get(),
Vec3s(0.0f, 0.0f, 0.0f), pointListSize);
4595 for (
size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4599 for (
size_t i = 0, I = polygons.
numQuads(); i < I; ++i) {
4602 for (
int v = 0; v < 4; ++v) {
4604 const unsigned pointIdx = verts[v];
4606 if (pointMask[pointIdx] == 1) {
4608 newPoints[pointIdx] +=
4609 pointList[verts[0]] + pointList[verts[1]] +
4610 pointList[verts[2]] + pointList[verts[3]];
4612 pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 4);
4617 for (
size_t i = 0, I = polygons.
numTriangles(); i < I; ++i) {
4620 for (
int v = 0; v < 3; ++v) {
4622 const unsigned pointIdx = verts[v];
4624 if (pointMask[pointIdx] == 1) {
4625 newPoints[pointIdx] +=
4626 pointList[verts[0]] + pointList[verts[1]] + pointList[verts[2]];
4628 pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 3);
4634 for (
size_t n = 0, N = pointListSize; n < N; ++n) {
4635 if (pointUpdates[n] > 0) {
4636 const double weight = 1.0 / double(pointUpdates[n]);
4637 pointList[n] = newPoints[n] * float(weight);
4651 PolygonPool::PolygonPool()
4655 , mTriangles(nullptr)
4656 , mQuadFlags(nullptr)
4657 , mTriangleFlags(nullptr)
4664 : mNumQuads(numQuads)
4665 , mNumTriangles(numTriangles)
4668 , mQuadFlags(new char[mNumQuads])
4669 , mTriangleFlags(new char[mNumTriangles])
4680 for (
size_t i = 0; i < mNumQuads; ++i) {
4681 mQuads[i] = rhs.mQuads[i];
4682 mQuadFlags[i] = rhs.mQuadFlags[i];
4685 for (
size_t i = 0; i < mNumTriangles; ++i) {
4686 mTriangles[i] = rhs.mTriangles[i];
4687 mTriangleFlags[i] = rhs.mTriangleFlags[i];
4697 mQuadFlags.reset(
new char[mNumQuads]);
4705 mQuads.reset(
nullptr);
4706 mQuadFlags.reset(
nullptr);
4713 mNumTriangles = size;
4715 mTriangleFlags.reset(
new char[mNumTriangles]);
4723 mTriangles.reset(
nullptr);
4724 mTriangleFlags.reset(
nullptr);
4731 if (!(n < mNumQuads))
return false;
4736 mQuads.reset(
nullptr);
4740 std::unique_ptr<char[]> flags(
new char[n]);
4742 for (
size_t i = 0; i < n; ++i) {
4743 quads[i] = mQuads[i];
4744 flags[i] = mQuadFlags[i];
4748 mQuadFlags.swap(flags);
4760 if (!(n < mNumTriangles))
return false;
4765 mTriangles.reset(
nullptr);
4768 std::unique_ptr<openvdb::Vec3I[]> triangles(
new openvdb::Vec3I[n]);
4769 std::unique_ptr<char[]> flags(
new char[n]);
4771 for (
size_t i = 0; i < n; ++i) {
4772 triangles[i] = mTriangles[i];
4773 flags[i] = mTriangleFlags[i];
4776 mTriangles.swap(triangles);
4777 mTriangleFlags.swap(flags);
4794 , mSeamPointListSize(0)
4795 , mPolygonPoolListSize(0)
4796 , mIsovalue(isovalue)
4797 , mPrimAdaptivity(adaptivity)
4798 , mSecAdaptivity(0.0)
4800 , mSurfaceMaskGrid(
GridBase::ConstPtr())
4801 , mAdaptivityGrid(
GridBase::ConstPtr())
4802 , mAdaptivityMaskTree(
TreeBase::ConstPtr())
4805 , mInvertSurfaceMask(false)
4806 , mRelaxDisorientedTriangles(relaxDisorientedTriangles)
4807 , mQuantizedSeamPoints(nullptr)
4817 mSecAdaptivity = secAdaptivity;
4822 mSeamPointListSize = 0;
4823 mQuantizedSeamPoints.reset(
nullptr);
4830 mSurfaceMaskGrid = mask;
4831 mInvertSurfaceMask = invertMask;
4838 mAdaptivityGrid = grid;
4845 mAdaptivityMaskTree = tree;
4849 template<
typename InputGr
idType>
4855 using InputTreeType =
typename InputGridType::TreeType;
4856 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
4857 using InputValueType =
typename InputLeafNodeType::ValueType;
4861 using FloatTreeType =
typename InputTreeType::template ValueConverter<float>::Type;
4863 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
4864 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
4865 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
4866 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
4867 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
4872 mPolygonPoolListSize = 0;
4874 mPointFlags.clear();
4879 const InputValueType isovalue = InputValueType(mIsovalue);
4880 const float adaptivityThreshold = float(mPrimAdaptivity);
4881 const bool adaptive = mPrimAdaptivity > 1e-7 || mSecAdaptivity > 1e-7;
4887 const bool invertSurfaceOrientation = (!volume_to_mesh_internal::isBoolValue<InputValueType>()
4892 const InputTreeType& inputTree = inputGrid.tree();
4894 BoolTreeType intersectionTree(
false), adaptivityMask(
false);
4896 if (mAdaptivityMaskTree && mAdaptivityMaskTree->type() == BoolTreeType::treeType()) {
4897 const BoolTreeType *refAdaptivityMask=
4898 static_cast<const BoolTreeType*
>(mAdaptivityMaskTree.get());
4899 adaptivityMask.topologyUnion(*refAdaptivityMask);
4902 Int16TreeType signFlagsTree(0);
4908 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
4909 intersectionTree, inputTree, isovalue);
4911 volume_to_mesh_internal::applySurfaceMask(intersectionTree, adaptivityMask,
4912 inputGrid, mSurfaceMaskGrid, mInvertSurfaceMask, isovalue);
4914 if (intersectionTree.empty())
return;
4916 volume_to_mesh_internal::computeAuxiliaryData(
4917 signFlagsTree, pointIndexTree, intersectionTree, inputTree, isovalue);
4919 intersectionTree.clear();
4921 std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
4922 pointIndexTree.getNodes(pointIndexLeafNodes);
4924 std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
4925 signFlagsTree.getNodes(signFlagsLeafNodes);
4927 const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
4932 Int16TreeType* refSignFlagsTree =
nullptr;
4933 Index32TreeType* refPointIndexTree =
nullptr;
4934 InputTreeType
const* refInputTree =
nullptr;
4936 if (mRefGrid && mRefGrid->type() == InputGridType::gridType()) {
4938 const InputGridType* refGrid =
static_cast<const InputGridType*
>(mRefGrid.get());
4939 refInputTree = &refGrid->tree();
4941 if (!mRefSignTree && !mRefIdxTree) {
4945 typename Int16TreeType::Ptr refSignFlagsTreePt(
new Int16TreeType(0));
4946 typename Index32TreeType::Ptr refPointIndexTreePt(
4949 BoolTreeType refIntersectionTree(
false);
4951 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
4952 refIntersectionTree, *refInputTree, isovalue);
4954 volume_to_mesh_internal::computeAuxiliaryData(*refSignFlagsTreePt,
4955 *refPointIndexTreePt, refIntersectionTree, *refInputTree, isovalue);
4957 mRefSignTree = refSignFlagsTreePt;
4958 mRefIdxTree = refPointIndexTreePt;
4961 if (mRefSignTree && mRefIdxTree) {
4965 refSignFlagsTree =
static_cast<Int16TreeType*
>(mRefSignTree.get());
4966 refPointIndexTree =
static_cast<Index32TreeType*
>(mRefIdxTree.get());
4970 if (refSignFlagsTree && refPointIndexTree) {
4974 volume_to_mesh_internal::markSeamLineData(signFlagsTree, *refSignFlagsTree);
4976 if (mSeamPointListSize == 0) {
4980 std::vector<Int16LeafNodeType*> refSignFlagsLeafNodes;
4981 refSignFlagsTree->getNodes(refSignFlagsLeafNodes);
4983 std::unique_ptr<Index32[]> leafNodeOffsets(
4984 new Index32[refSignFlagsLeafNodes.size()]);
4986 tbb::parallel_for(tbb::blocked_range<size_t>(0, refSignFlagsLeafNodes.size()),
4987 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>(
4988 refSignFlagsLeafNodes, leafNodeOffsets));
4992 for (
size_t n = 0, N = refSignFlagsLeafNodes.size(); n < N; ++n) {
4993 const Index32 tmp = leafNodeOffsets[n];
4994 leafNodeOffsets[n] = count;
4997 mSeamPointListSize = size_t(count);
5000 if (mSeamPointListSize != 0) {
5002 mQuantizedSeamPoints.reset(
new uint32_t[mSeamPointListSize]);
5004 memset(mQuantizedSeamPoints.get(), 0,
sizeof(uint32_t) * mSeamPointListSize);
5006 std::vector<Index32LeafNodeType*> refPointIndexLeafNodes;
5007 refPointIndexTree->getNodes(refPointIndexLeafNodes);
5009 tbb::parallel_for(tbb::blocked_range<size_t>(0, refPointIndexLeafNodes.size()),
5010 volume_to_mesh_internal::MapPoints<Index32LeafNodeType>(
5011 refPointIndexLeafNodes, refSignFlagsLeafNodes, leafNodeOffsets));
5015 if (mSeamPointListSize != 0) {
5017 tbb::parallel_for(auxiliaryLeafNodeRange,
5018 volume_to_mesh_internal::SeamLineWeights<InputTreeType>(
5019 signFlagsLeafNodes, inputTree, *refPointIndexTree, *refSignFlagsTree,
5020 mQuantizedSeamPoints.get(), isovalue));
5025 const bool referenceMeshing = refSignFlagsTree && refPointIndexTree && refInputTree;
5030 std::unique_ptr<Index32[]> leafNodeOffsets(
new Index32[signFlagsLeafNodes.size()]);
5033 volume_to_mesh_internal::MergeVoxelRegions<InputGridType> mergeOp(
5034 inputGrid, pointIndexTree, pointIndexLeafNodes, signFlagsLeafNodes,
5035 isovalue, adaptivityThreshold, invertSurfaceOrientation);
5037 if (mAdaptivityGrid && mAdaptivityGrid->type() == FloatGridType::gridType()) {
5038 const FloatGridType* adaptivityGrid =
5039 static_cast<const FloatGridType*
>(mAdaptivityGrid.get());
5040 mergeOp.setSpatialAdaptivity(*adaptivityGrid);
5043 if (!adaptivityMask.empty()) {
5044 mergeOp.setAdaptivityMask(adaptivityMask);
5047 if (referenceMeshing) {
5048 mergeOp.setRefSignFlagsData(*refSignFlagsTree,
float(mSecAdaptivity));
5051 tbb::parallel_for(auxiliaryLeafNodeRange, mergeOp);
5053 volume_to_mesh_internal::AdaptiveLeafNodePointCount<Index32LeafNodeType>
5054 op(pointIndexLeafNodes, signFlagsLeafNodes, leafNodeOffsets);
5056 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5060 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
5061 op(signFlagsLeafNodes, leafNodeOffsets);
5063 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5069 for (
size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
5070 const Index32 tmp = leafNodeOffsets[n];
5075 mPointListSize = size_t(pointCount);
5077 mPointFlags.clear();
5084 volume_to_mesh_internal::ComputePoints<InputTreeType>
5085 op(mPoints.get(), inputTree, pointIndexLeafNodes,
5086 signFlagsLeafNodes, leafNodeOffsets, transform, mIsovalue);
5088 if (referenceMeshing) {
5089 mPointFlags.resize(mPointListSize);
5090 op.setRefData(*refInputTree, *refPointIndexTree, *refSignFlagsTree,
5091 mQuantizedSeamPoints.get(), mPointFlags.data());
5094 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5100 mPolygonPoolListSize = signFlagsLeafNodes.size();
5101 mPolygons.reset(
new PolygonPool[mPolygonPoolListSize]);
5105 using PrimBuilder = volume_to_mesh_internal::AdaptivePrimBuilder;
5107 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
5108 op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5109 mPolygons, invertSurfaceOrientation);
5111 if (referenceMeshing) {
5112 op.setRefSignTree(refSignFlagsTree);
5115 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5119 using PrimBuilder = volume_to_mesh_internal::UniformPrimBuilder;
5121 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
5122 op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5123 mPolygons, invertSurfaceOrientation);
5125 if (referenceMeshing) {
5126 op.setRefSignTree(refSignFlagsTree);
5129 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5133 signFlagsTree.clear();
5134 pointIndexTree.clear();
5137 if (adaptive && mRelaxDisorientedTriangles) {
5138 volume_to_mesh_internal::relaxDisorientedTriangles(invertSurfaceOrientation,
5139 inputTree, transform, mPolygons, mPolygonPoolListSize, mPoints, mPointListSize);
5143 if (referenceMeshing) {
5144 volume_to_mesh_internal::subdivideNonplanarSeamLineQuads(
5145 mPolygons, mPolygonPoolListSize, mPoints, mPointListSize, mPointFlags);
5147 volume_to_mesh_internal::reviseSeamLineFlags(mPolygons, mPolygonPoolListSize, mPointFlags);
5160 template<
typename Gr
idType>
5164 std::vector<Vec3s>& points,
5165 std::vector<Vec3I>& triangles,
5166 std::vector<Vec4I>& quads,
5169 bool relaxDisorientedTriangles)
5171 VolumeToMesh mesher(isovalue, adaptivity, relaxDisorientedTriangles);
5179 volume_to_mesh_internal::PointListCopy ptnCpy(mesher.
pointList(), points);
5180 tbb::parallel_for(tbb::blocked_range<size_t>(0, points.size()), ptnCpy);
5187 size_t numQuads = 0, numTriangles = 0;
5189 openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
5190 numTriangles += polygons.numTriangles();
5191 numQuads += polygons.numQuads();
5195 triangles.resize(numTriangles);
5197 quads.resize(numQuads);
5201 size_t qIdx = 0, tIdx = 0;
5203 openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
5205 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
5206 quads[qIdx++] = polygons.quad(i);
5209 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
5210 triangles[tIdx++] = polygons.triangle(i);
5216 template<
typename Gr
idType>
5220 std::vector<Vec3s>&,
5221 std::vector<Vec3I>&,
5222 std::vector<Vec4I>&,
5234 template<
typename Gr
idType>
5238 std::vector<Vec3s>& points,
5239 std::vector<Vec3I>& triangles,
5240 std::vector<Vec4I>& quads,
5243 bool relaxDisorientedTriangles)
5245 doVolumeToMesh(grid, points, triangles, quads, isovalue, adaptivity, relaxDisorientedTriangles);
5249 template<
typename Gr
idType>
5253 std::vector<Vec3s>& points,
5254 std::vector<Vec4I>& quads,
5257 std::vector<Vec3I> triangles;
5258 doVolumeToMesh(grid, points, triangles, quads, isovalue, 0.0,
true);
5267 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 5269 #ifdef OPENVDB_INSTANTIATE_VOLUMETOMESH 5273 #define _FUNCTION(TreeT) \ 5274 void volumeToMesh(const Grid<TreeT>&, std::vector<Vec3s>&, std::vector<Vec4I>&, double) 5278 #define _FUNCTION(TreeT) \ 5279 void volumeToMesh(const Grid<TreeT>&, std::vector<Vec3s>&, std::vector<Vec3I>&, std::vector<Vec4I>&, double, double, bool) 5283 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION 5290 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:226
SharedPtr< const GridBase > ConstPtr
Definition: Grid.h:81
Gradient operators defined in index space of various orders.
Definition: Operators.h:99
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:88
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
OPENVDB_API const Index32 INVALID_IDX
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:37
Base class for typed trees.
Definition: Tree.h:36
Abstract base class for typed grids.
Definition: Grid.h:77
#define OPENVDB_NUMERIC_TREE_INSTANTIATE(Function)
Definition: version.h.in:148
Vec3< int32_t > Vec3i
Definition: Vec3.h:665
T & z()
Definition: Vec3.h:91
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1086
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:219
Mat3< double > Mat3d
Definition: Mat3.h:848
Definition: Exceptions.h:65
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
SharedPtr< TreeBase > Ptr
Definition: Tree.h:39
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:238
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:250
SharedPtr< const TreeBase > ConstPtr
Definition: Tree.h:40
Vec4< int32_t > Vec4i
Definition: Vec4.h:563
Mat3 transpose() const
returns transpose of this
Definition: Mat3.h:468
int16_t Int16
Definition: Types.h:55
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:195
bool diagonalizeSymmetricMatrix(const Mat3< T > &input, Mat3< T > &Q, Vec3< T > &D, unsigned int MAX_ITERATIONS=250)
Use Jacobi iterations to decompose a symmetric 3x3 matrix (diagonalize and compute eigenvectors) ...
Definition: Mat3.h:751
Definition: Exceptions.h:13
ValueT value
Definition: GridBuilder.h:1287
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:384
Index32 Index
Definition: Types.h:54
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition: Vec3.h:366
Definition: Exceptions.h:64
Vec3< float > Vec3s
Definition: Vec3.h:667
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:229
uint32_t Index32
Definition: Types.h:52
Definition: ValueAccessor.h:182
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202