10#ifndef OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
11#define OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
20#include <tbb/blocked_range.h>
21#include <tbb/parallel_for.h>
22#include <tbb/parallel_reduce.h>
23#include <tbb/task_arena.h>
54template<
typename Gr
idType>
58 std::vector<Vec3s>& points,
59 std::vector<Vec4I>& quads,
60 double isovalue = 0.0);
83template<
typename Gr
idType>
87 std::vector<Vec3s>& points,
88 std::vector<Vec3I>& triangles,
89 std::vector<Vec4I>& quads,
90 double isovalue = 0.0,
91 double adaptivity = 0.0,
92 bool relaxDisorientedTriangles =
true);
121 const size_t&
numQuads()
const {
return mNumQuads; }
136 const char&
quadFlags(
size_t n)
const {
return mQuadFlags[n]; }
145 inline bool trimQuads(
const size_t n,
bool reallocate =
false);
146 inline bool trimTriangles(
const size_t n,
bool reallocate =
false);
158 size_t mNumQuads, mNumTriangles;
159 std::unique_ptr<openvdb::Vec4I[]> mQuads;
160 std::unique_ptr<openvdb::Vec3I[]> mTriangles;
161 std::unique_ptr<char[]> mQuadFlags, mTriangleFlags;
183 VolumeToMesh(
double isovalue = 0,
double adaptivity = 0,
bool relaxDisorientedTriangles =
true);
199 const std::vector<uint8_t>&
pointFlags()
const {
return mPointFlags; }
208 template<
typename InputGr
idType>
209 void operator()(
const InputGridType&);
262 size_t mPointListSize, mSeamPointListSize, mPolygonPoolListSize;
263 double mIsovalue, mPrimAdaptivity, mSecAdaptivity;
270 bool mInvertSurfaceMask, mRelaxDisorientedTriangles;
272 std::unique_ptr<uint32_t[]> mQuantizedSeamPoints;
273 std::vector<uint8_t> mPointFlags;
287 const std::vector<Vec3d>&
points,
288 const std::vector<Vec3d>& normals)
294 if (
points.empty())
return avgPos;
296 for (
size_t n = 0, N =
points.size(); n < N; ++n) {
300 avgPos /= double(
points.size());
304 double m00=0,m01=0,m02=0,
311 for (
size_t n = 0, N =
points.size(); n < N; ++n) {
313 const Vec3d& n_ref = normals[n];
316 m00 += n_ref[0] * n_ref[0];
317 m11 += n_ref[1] * n_ref[1];
318 m22 += n_ref[2] * n_ref[2];
320 m01 += n_ref[0] * n_ref[1];
321 m02 += n_ref[0] * n_ref[2];
322 m12 += n_ref[1] * n_ref[2];
325 rhs += n_ref * n_ref.
dot(
points[n] - avgPos);
348 diagonalizeSymmetricMatrix(A, eigenVectors, eigenValues, 300);
353 double tolerance = std::max(std::abs(eigenValues[0]), std::abs(eigenValues[1]));
354 tolerance = std::max(tolerance, std::abs(eigenValues[2]));
358 for (
int i = 0; i < 3; ++i ) {
359 if (std::abs(eigenValues[i]) < tolerance) {
363 D[i][i] = 1.0 / eigenValues[i];
370 return avgPos + pseudoInv * rhs;
385namespace volume_to_mesh_internal {
387template<
typename ValueType>
390 FillArray(ValueType* array,
const ValueType& v) : mArray(array), mValue(v) { }
392 void operator()(
const tbb::blocked_range<size_t>& range)
const {
393 const ValueType v = mValue;
394 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
399 ValueType *
const mArray;
400 const ValueType mValue;
404template<
typename ValueType>
406fillArray(ValueType* array,
const ValueType& val,
const size_t length)
408 const auto grainSize = std::max<size_t>(
409 length / tbb::this_task_arena::max_concurrency(), 1024);
410 const tbb::blocked_range<size_t> range(0, length, grainSize);
411 tbb::parallel_for(range, FillArray<ValueType>(array, val), tbb::simple_partitioner());
416enum { SIGNS = 0xFF, EDGES = 0xE00, INSIDE = 0x100,
417 XEDGE = 0x200, YEDGE = 0x400, ZEDGE = 0x800, SEAM = 0x1000};
421const bool sAdaptable[256] = {
422 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,
423 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,
424 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,
425 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,
426 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,
427 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,
428 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,
429 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};
433const unsigned char sAmbiguousFace[256] = {
434 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,
435 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,
436 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,
437 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,
438 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,
439 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,
440 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,
441 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};
447const unsigned char sEdgeGroupTable[256][13] = {
448 {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},
449 {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},
450 {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},
451 {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},
452 {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},
453 {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},
454 {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},
455 {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},
456 {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},
457 {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},
458 {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},
459 {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},
460 {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},
461 {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},
462 {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},
463 {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},
464 {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},
465 {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},
466 {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},
467 {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},
468 {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},
469 {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},
470 {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},
471 {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},
472 {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},
473 {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},
474 {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},
475 {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},
476 {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},
477 {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},
478 {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},
479 {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},
480 {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},
481 {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},
482 {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},
483 {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},
484 {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},
485 {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},
486 {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},
487 {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},
488 {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},
489 {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},
490 {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},
491 {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},
492 {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},
493 {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},
494 {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},
495 {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},
496 {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},
497 {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},
498 {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},
499 {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},
500 {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},
501 {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},
502 {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},
503 {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},
504 {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},
505 {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},
506 {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},
507 {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},
508 {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},
509 {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},
510 {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},
511 {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},
512 {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},
513 {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},
514 {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},
515 {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},
516 {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},
517 {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},
518 {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},
519 {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},
520 {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},
521 {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},
522 {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},
523 {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},
524 {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},
525 {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},
526 {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},
527 {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},
528 {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},
529 {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},
530 {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},
531 {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},
532 {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},
533 {0,0,0,0,0,0,0,0,0,0,0,0,0}};
539 const Vec3d& p0,
const Vec3d& p1,
540 const Vec3d& p2,
const Vec3d& p3,
541 const double epsilon = 0.001)
544 Vec3d normal = (p2-p0).cross(p1-p3);
546 const Vec3d centroid = (p0 + p1 + p2 + p3);
547 const double d = centroid.
dot(normal) * 0.25;
551 double absDist = std::abs(p0.dot(normal) - d);
552 if (absDist > epsilon)
return false;
554 absDist = std::abs(p1.dot(normal) - d);
555 if (absDist > epsilon)
return false;
557 absDist = std::abs(p2.dot(normal) - d);
558 if (absDist > epsilon)
return false;
560 absDist = std::abs(p3.dot(normal) - d);
561 if (absDist > epsilon)
return false;
574 MASK_FIRST_10_BITS = 0x000003FF,
575 MASK_DIRTY_BIT = 0x80000000,
576 MASK_INVALID_BIT = 0x40000000
580packPoint(
const Vec3d& v)
585 OPENVDB_ASSERT(!(v.x() > 1.0) && !(v.y() > 1.0) && !(v.z() > 1.0));
586 OPENVDB_ASSERT(!(v.x() < 0.0) && !(v.y() < 0.0) && !(v.z() < 0.0));
588 data |= (uint32_t(v.x() * 1023.0) & MASK_FIRST_10_BITS) << 20;
589 data |= (uint32_t(v.y() * 1023.0) & MASK_FIRST_10_BITS) << 10;
590 data |= (uint32_t(v.z() * 1023.0) & MASK_FIRST_10_BITS);
596unpackPoint(uint32_t data)
599 v.
z() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
601 v.y() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
603 v.x() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
613inline bool isBoolValue() {
return false; }
616inline bool isBoolValue<bool>() {
return true; }
619inline bool isInsideValue(T value, T isovalue) {
return value < isovalue; }
622inline bool isInsideValue<bool>(
bool value,
bool ) {
return value; }
627template <
typename LeafT,
628 bool IsBool = std::is_same<typename LeafT::ValueType, bool>::value>
629struct LeafBufferAccessor
631 using T =
typename LeafT::ValueType;
632 LeafBufferAccessor(
const LeafT& leaf) : mData(leaf.buffer().data()) {}
633 inline T get(
const Index idx)
const {
return mData[idx]; }
634 const T*
const mData;
637template <
typename LeafT>
638struct LeafBufferAccessor<LeafT, true>
641 LeafBufferAccessor(
const LeafT& leaf) : mLeaf(leaf) {}
642 inline T get(
const Index idx)
const {
return mLeaf.getValue(idx); }
648template <
typename LeafT>
649bool isInternalLeafCoord(
const Coord& ijk)
652 ijk[0] < int(LeafT::DIM - 1) &&
653 ijk[1] < int(LeafT::DIM - 1) &&
654 ijk[2] < int(LeafT::DIM - 1);
659template<
typename AccessorT,
typename ValueT>
661getCellVertexValues(
const AccessorT& accessor,
663 std::array<ValueT, 8>& values)
665 values[0] = ValueT(accessor.getValue(ijk));
667 values[1] = ValueT(accessor.getValue(ijk));
669 values[2] = ValueT(accessor.getValue(ijk));
671 values[3] = ValueT(accessor.getValue(ijk));
673 values[4] = ValueT(accessor.getValue(ijk));
675 values[5] = ValueT(accessor.getValue(ijk));
677 values[6] = ValueT(accessor.getValue(ijk));
679 values[7] = ValueT(accessor.getValue(ijk));
684template<
typename LeafT,
typename ValueT>
686getCellVertexValues(
const LeafT& leaf,
688 std::array<ValueT, 8>& values)
690 const LeafBufferAccessor<LeafT> acc(leaf);
692 values[0] = ValueT(acc.get(offset));
693 values[3] = ValueT(acc.get(offset + 1));
694 values[4] = ValueT(acc.get(offset + LeafT::DIM));
695 values[7] = ValueT(acc.get(offset + LeafT::DIM + 1));
696 values[1] = ValueT(acc.get(offset + (LeafT::DIM * LeafT::DIM)));
697 values[2] = ValueT(acc.get(offset + (LeafT::DIM * LeafT::DIM) + 1));
698 values[5] = ValueT(acc.get(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM));
699 values[6] = ValueT(acc.get(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1));
703template<
typename ValueType>
705computeSignFlags(
const std::array<ValueType, 8>& values,
const ValueType iso)
708 signs |= isInsideValue(values[0], iso) ? 1u : 0u;
709 signs |= isInsideValue(values[1], iso) ? 2u : 0u;
710 signs |= isInsideValue(values[2], iso) ? 4u : 0u;
711 signs |= isInsideValue(values[3], iso) ? 8u : 0u;
712 signs |= isInsideValue(values[4], iso) ? 16u : 0u;
713 signs |= isInsideValue(values[5], iso) ? 32u : 0u;
714 signs |= isInsideValue(values[6], iso) ? 64u : 0u;
715 signs |= isInsideValue(values[7], iso) ? 128u : 0u;
716 return uint8_t(signs);
722template<
typename AccessorT>
724evalCellSigns(
const AccessorT& accessor,
const Coord& ijk,
typename AccessorT::ValueType iso)
728 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 1u;
730 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 2u;
732 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 4u;
734 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 8u;
735 coord[1] += 1; coord[2] = ijk[2];
736 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 16u;
738 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 32u;
740 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 64u;
742 if (isInsideValue(accessor.getValue(coord), iso)) signs |= 128u;
743 return uint8_t(signs);
749template<
typename LeafT>
751evalCellSigns(
const LeafT& leaf,
const Index offset,
typename LeafT::ValueType iso)
753 const LeafBufferAccessor<LeafT> acc(leaf);
756 if (isInsideValue(acc.get(offset), iso)) signs |= 1u;
757 if (isInsideValue(acc.get(offset + (LeafT::DIM * LeafT::DIM)), iso)) signs |= 2u;
758 if (isInsideValue(acc.get(offset + (LeafT::DIM * LeafT::DIM) + 1), iso)) signs |= 4u;
759 if (isInsideValue(acc.get(offset + 1), iso)) signs |= 8u;
760 if (isInsideValue(acc.get(offset + LeafT::DIM), iso)) signs |= 16u;
761 if (isInsideValue(acc.get(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM), iso)) signs |= 32u;
762 if (isInsideValue(acc.get(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1), iso)) signs |= 64u;
763 if (isInsideValue(acc.get(offset + LeafT::DIM + 1), iso)) signs |= 128u;
764 return uint8_t(signs);
770template<
class AccessorT>
772correctCellSigns(uint8_t& signs,
774 const AccessorT& acc,
776 const typename AccessorT::ValueType iso)
781 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 3) signs = uint8_t(~signs);
785 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 4) signs = uint8_t(~signs);
789 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 1) signs = uint8_t(~signs);
793 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 2) signs = uint8_t(~signs);
797 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 6) signs = uint8_t(~signs);
801 if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 5) signs = uint8_t(~signs);
809template<
class AccessorT>
811isNonManifold(
const AccessorT& accessor,
const Coord& ijk,
812 typename AccessorT::ValueType isovalue,
const int dim)
814 const int hDim = dim >> 1;
818 p[0] = isInsideValue(accessor.getValue(coord), isovalue);
820 p[1] = isInsideValue(accessor.getValue(coord), isovalue);
822 p[2] = isInsideValue(accessor.getValue(coord), isovalue);
824 p[3] = isInsideValue(accessor.getValue(coord), isovalue);
825 coord[1] += dim; coord[2] = ijk[2];
826 p[4] = isInsideValue(accessor.getValue(coord), isovalue);
828 p[5] = isInsideValue(accessor.getValue(coord), isovalue);
830 p[6] = isInsideValue(accessor.getValue(coord), isovalue);
832 p[7] = isInsideValue(accessor.getValue(coord), isovalue);
836 if (p[0]) signs |= 1u;
837 if (p[1]) signs |= 2u;
838 if (p[2]) signs |= 4u;
839 if (p[3]) signs |= 8u;
840 if (p[4]) signs |= 16u;
841 if (p[5]) signs |= 32u;
842 if (p[6]) signs |= 64u;
843 if (p[7]) signs |= 128u;
844 if (!sAdaptable[signs])
return true;
849 const int i = ijk[0], ip = ijk[0] + hDim, ipp = ijk[0] + dim;
850 const int j = ijk[1], jp = ijk[1] + hDim, jpp = ijk[1] + dim;
851 const int k = ijk[2], kp = ijk[2] + hDim, kpp = ijk[2] + dim;
854 coord.reset(ip, j, k);
855 m = isInsideValue(accessor.getValue(coord), isovalue);
856 if (p[0] != m && p[1] != m)
return true;
859 coord.reset(ipp, j, kp);
860 m = isInsideValue(accessor.getValue(coord), isovalue);
861 if (p[1] != m && p[2] != m)
return true;
864 coord.reset(ip, j, kpp);
865 m = isInsideValue(accessor.getValue(coord), isovalue);
866 if (p[2] != m && p[3] != m)
return true;
869 coord.reset(i, j, kp);
870 m = isInsideValue(accessor.getValue(coord), isovalue);
871 if (p[0] != m && p[3] != m)
return true;
874 coord.reset(ip, jpp, k);
875 m = isInsideValue(accessor.getValue(coord), isovalue);
876 if (p[4] != m && p[5] != m)
return true;
879 coord.reset(ipp, jpp, kp);
880 m = isInsideValue(accessor.getValue(coord), isovalue);
881 if (p[5] != m && p[6] != m)
return true;
884 coord.reset(ip, jpp, kpp);
885 m = isInsideValue(accessor.getValue(coord), isovalue);
886 if (p[6] != m && p[7] != m)
return true;
889 coord.reset(i, jpp, kp);
890 m = isInsideValue(accessor.getValue(coord), isovalue);
891 if (p[7] != m && p[4] != m)
return true;
894 coord.reset(i, jp, k);
895 m = isInsideValue(accessor.getValue(coord), isovalue);
896 if (p[0] != m && p[4] != m)
return true;
899 coord.reset(ipp, jp, k);
900 m = isInsideValue(accessor.getValue(coord), isovalue);
901 if (p[1] != m && p[5] != m)
return true;
904 coord.reset(ipp, jp, kpp);
905 m = isInsideValue(accessor.getValue(coord), isovalue);
906 if (p[2] != m && p[6] != m)
return true;
910 coord.reset(i, jp, kpp);
911 m = isInsideValue(accessor.getValue(coord), isovalue);
912 if (p[3] != m && p[7] != m)
return true;
918 coord.reset(ip, jp, k);
919 m = isInsideValue(accessor.getValue(coord), isovalue);
920 if (p[0] != m && p[1] != m && p[4] != m && p[5] != m)
return true;
923 coord.reset(ipp, jp, kp);
924 m = isInsideValue(accessor.getValue(coord), isovalue);
925 if (p[1] != m && p[2] != m && p[5] != m && p[6] != m)
return true;
928 coord.reset(ip, jp, kpp);
929 m = isInsideValue(accessor.getValue(coord), isovalue);
930 if (p[2] != m && p[3] != m && p[6] != m && p[7] != m)
return true;
933 coord.reset(i, jp, kp);
934 m = isInsideValue(accessor.getValue(coord), isovalue);
935 if (p[0] != m && p[3] != m && p[4] != m && p[7] != m)
return true;
938 coord.reset(ip, j, kp);
939 m = isInsideValue(accessor.getValue(coord), isovalue);
940 if (p[0] != m && p[1] != m && p[2] != m && p[3] != m)
return true;
943 coord.reset(ip, jpp, kp);
944 m = isInsideValue(accessor.getValue(coord), isovalue);
945 if (p[4] != m && p[5] != m && p[6] != m && p[7] != m)
return true;
948 coord.reset(ip, jp, kp);
949 m = isInsideValue(accessor.getValue(coord), isovalue);
950 if (p[0] != m && p[1] != m && p[2] != m && p[3] != m &&
951 p[4] != m && p[5] != m && p[6] != m && p[7] != m)
return true;
960template <
class LeafType>
962mergeVoxels(LeafType& leaf,
const Coord& start,
const int dim,
const int regionId)
965 const Coord end = start.offsetBy(dim);
967 for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
968 for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
969 for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
970 leaf.setValueOnly(ijk, regionId);
979template <
class LeafType>
981isMergeable(
const LeafType& leaf,
984 typename LeafType::ValueType::value_type adaptivity)
986 if (adaptivity < 1e-6)
return false;
988 using VecT =
typename LeafType::ValueType;
990 const Coord end = start.offsetBy(dim);
992 std::vector<VecT> norms;
993 for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) {
994 for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) {
995 for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) {
996 if (!leaf.isValueOn(ijk))
continue;
997 norms.push_back(leaf.getValue(ijk));
1002 const size_t N = norms.size();
1003 for (
size_t ni = 0; ni < N; ++ni) {
1004 VecT n_i = norms[ni];
1005 for (
size_t nj = 0; nj < N; ++nj) {
1006 VecT n_j = norms[nj];
1007 if ((1.0 - n_i.dot(n_j)) > adaptivity)
return false;
1018inline double evalZeroCrossing(
double v0,
double v1,
double iso) {
return (iso - v0) / (v1 - v0); }
1023computePoint(
const std::array<double, 8>& values,
1024 const unsigned char signs,
1025 const unsigned char edgeGroup,
1028 Vec3d avg(0.0, 0.0, 0.0);
1031 if (sEdgeGroupTable[signs][1] == edgeGroup) {
1032 avg[0] += evalZeroCrossing(values[0], values[1], iso);
1036 if (sEdgeGroupTable[signs][2] == edgeGroup) {
1038 avg[2] += evalZeroCrossing(values[1], values[2], iso);
1042 if (sEdgeGroupTable[signs][3] == edgeGroup) {
1043 avg[0] += evalZeroCrossing(values[3], values[2], iso);
1048 if (sEdgeGroupTable[signs][4] == edgeGroup) {
1049 avg[2] += evalZeroCrossing(values[0], values[3], iso);
1053 if (sEdgeGroupTable[signs][5] == edgeGroup) {
1054 avg[0] += evalZeroCrossing(values[4], values[5], iso);
1059 if (sEdgeGroupTable[signs][6] == edgeGroup) {
1062 avg[2] += evalZeroCrossing(values[5], values[6], iso);
1066 if (sEdgeGroupTable[signs][7] == edgeGroup) {
1067 avg[0] += evalZeroCrossing(values[7], values[6], iso);
1073 if (sEdgeGroupTable[signs][8] == edgeGroup) {
1075 avg[2] += evalZeroCrossing(values[4], values[7], iso);
1079 if (sEdgeGroupTable[signs][9] == edgeGroup) {
1080 avg[1] += evalZeroCrossing(values[0], values[4], iso);
1084 if (sEdgeGroupTable[signs][10] == edgeGroup) {
1086 avg[1] += evalZeroCrossing(values[1], values[5], iso);
1090 if (sEdgeGroupTable[signs][11] == edgeGroup) {
1092 avg[1] += evalZeroCrossing(values[2], values[6], iso);
1097 if (sEdgeGroupTable[signs][12] == edgeGroup) {
1098 avg[1] += evalZeroCrossing(values[3], values[7], iso);
1104 const double w = 1.0 / double(samples);
1115computeMaskedPoint(Vec3d& avg,
1116 const std::array<double, 8>& values,
1117 const unsigned char signs,
1118 const unsigned char signsMask,
1119 const unsigned char edgeGroup,
1122 avg =
Vec3d(0.0, 0.0, 0.0);
1125 if (sEdgeGroupTable[signs][1] == edgeGroup &&
1126 sEdgeGroupTable[signsMask][1] == 0) {
1127 avg[0] += evalZeroCrossing(values[0], values[1], iso);
1131 if (sEdgeGroupTable[signs][2] == edgeGroup &&
1132 sEdgeGroupTable[signsMask][2] == 0) {
1134 avg[2] += evalZeroCrossing(values[1], values[2], iso);
1138 if (sEdgeGroupTable[signs][3] == edgeGroup &&
1139 sEdgeGroupTable[signsMask][3] == 0) {
1140 avg[0] += evalZeroCrossing(values[3], values[2], iso);
1145 if (sEdgeGroupTable[signs][4] == edgeGroup &&
1146 sEdgeGroupTable[signsMask][4] == 0) {
1147 avg[2] += evalZeroCrossing(values[0], values[3], iso);
1151 if (sEdgeGroupTable[signs][5] == edgeGroup &&
1152 sEdgeGroupTable[signsMask][5] == 0) {
1153 avg[0] += evalZeroCrossing(values[4], values[5], iso);
1158 if (sEdgeGroupTable[signs][6] == edgeGroup &&
1159 sEdgeGroupTable[signsMask][6] == 0) {
1162 avg[2] += evalZeroCrossing(values[5], values[6], iso);
1166 if (sEdgeGroupTable[signs][7] == edgeGroup &&
1167 sEdgeGroupTable[signsMask][7] == 0) {
1168 avg[0] += evalZeroCrossing(values[7], values[6], iso);
1174 if (sEdgeGroupTable[signs][8] == edgeGroup &&
1175 sEdgeGroupTable[signsMask][8] == 0) {
1177 avg[2] += evalZeroCrossing(values[4], values[7], iso);
1181 if (sEdgeGroupTable[signs][9] == edgeGroup &&
1182 sEdgeGroupTable[signsMask][9] == 0) {
1183 avg[1] += evalZeroCrossing(values[0], values[4], iso);
1187 if (sEdgeGroupTable[signs][10] == edgeGroup &&
1188 sEdgeGroupTable[signsMask][10] == 0) {
1190 avg[1] += evalZeroCrossing(values[1], values[5], iso);
1194 if (sEdgeGroupTable[signs][11] == edgeGroup &&
1195 sEdgeGroupTable[signsMask][11] == 0) {
1197 avg[1] += evalZeroCrossing(values[2], values[6], iso);
1202 if (sEdgeGroupTable[signs][12] == edgeGroup &&
1203 sEdgeGroupTable[signsMask][12] == 0) {
1204 avg[1] += evalZeroCrossing(values[3], values[7], iso);
1210 const double w = 1.0 / double(samples);
1221computeWeightedPoint(
const Vec3d& p,
1222 const std::array<double, 8>& values,
1223 const unsigned char signs,
1224 const unsigned char edgeGroup,
1227 std::vector<Vec3d> samples;
1230 Vec3d avg(0.0, 0.0, 0.0);
1232 if (sEdgeGroupTable[signs][1] == edgeGroup) {
1233 avg[0] = evalZeroCrossing(values[0], values[1], iso);
1237 samples.push_back(avg);
1240 if (sEdgeGroupTable[signs][2] == edgeGroup) {
1243 avg[2] = evalZeroCrossing(values[1], values[2], iso);
1245 samples.push_back(avg);
1248 if (sEdgeGroupTable[signs][3] == edgeGroup) {
1249 avg[0] = evalZeroCrossing(values[3], values[2], iso);
1253 samples.push_back(avg);
1256 if (sEdgeGroupTable[signs][4] == edgeGroup) {
1259 avg[2] = evalZeroCrossing(values[0], values[3], iso);
1261 samples.push_back(avg);
1264 if (sEdgeGroupTable[signs][5] == edgeGroup) {
1265 avg[0] = evalZeroCrossing(values[4], values[5], iso);
1269 samples.push_back(avg);
1272 if (sEdgeGroupTable[signs][6] == edgeGroup) {
1275 avg[2] = evalZeroCrossing(values[5], values[6], iso);
1277 samples.push_back(avg);
1280 if (sEdgeGroupTable[signs][7] == edgeGroup) {
1281 avg[0] = evalZeroCrossing(values[7], values[6], iso);
1285 samples.push_back(avg);
1288 if (sEdgeGroupTable[signs][8] == edgeGroup) {
1291 avg[2] = evalZeroCrossing(values[4], values[7], iso);
1293 samples.push_back(avg);
1296 if (sEdgeGroupTable[signs][9] == edgeGroup) {
1298 avg[1] = evalZeroCrossing(values[0], values[4], iso);
1301 samples.push_back(avg);
1304 if (sEdgeGroupTable[signs][10] == edgeGroup) {
1306 avg[1] = evalZeroCrossing(values[1], values[5], iso);
1309 samples.push_back(avg);
1312 if (sEdgeGroupTable[signs][11] == edgeGroup) {
1314 avg[1] = evalZeroCrossing(values[2], values[6], iso);
1317 samples.push_back(avg);
1320 if (sEdgeGroupTable[signs][12] == edgeGroup) {
1322 avg[1] = evalZeroCrossing(values[3], values[7], iso);
1325 samples.push_back(avg);
1329 if (samples.size() == 1) {
1330 return samples.front();
1333 std::vector<double> weights;
1334 weights.reserve(samples.size());
1336 for (
const Vec3d& s : samples) {
1337 weights.emplace_back((s-p).lengthSqr());
1340 double minWeight = weights.front();
1341 double maxWeight = weights.front();
1343 for (
size_t i = 1, I = weights.size(); i < I; ++i) {
1344 minWeight = std::min(minWeight, weights[i]);
1345 maxWeight = std::max(maxWeight, weights[i]);
1348 const double offset = maxWeight + minWeight * 0.1;
1349 for (
size_t i = 0, I = weights.size(); i < I; ++i) {
1350 weights[i] = offset - weights[i];
1353 double weightSum = 0.0;
1354 for (
size_t i = 0, I = weights.size(); i < I; ++i) {
1355 weightSum += weights[i];
1359 for (
size_t i = 0, I = samples.size(); i < I; ++i) {
1360 avg += samples[i] * (weights[i] / weightSum);
1370computeCellPoints(std::array<Vec3d, 4>& points,
1371 const std::array<double, 8>& values,
1372 const unsigned char signs,
1376 for (
size_t n = 1, N = sEdgeGroupTable[signs][0] + 1; n < N; ++n, ++offset) {
1378 points[offset] = computePoint(values, signs, uint8_t(n), iso);
1388matchEdgeGroup(
unsigned char groupId,
unsigned char lhsSigns,
unsigned char rhsSigns)
1391 for (
size_t i = 1; i <= 12; ++i) {
1392 if (sEdgeGroupTable[lhsSigns][i] == groupId && sEdgeGroupTable[rhsSigns][i] != 0) {
1393 id = sEdgeGroupTable[rhsSigns][i];
1406computeCellPoints(std::array<Vec3d, 4>& points,
1407 std::array<bool, 4>& weightedPointMask,
1408 const std::array<double, 8>& lhsValues,
1409 const std::array<double, 8>& rhsValues,
1410 const unsigned char lhsSigns,
1411 const unsigned char rhsSigns,
1413 const size_t pointIdx,
1414 const uint32_t * seamPointArray)
1417 for (
size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n, ++offset)
1420 const int id = matchEdgeGroup(uint8_t(n), lhsSigns, rhsSigns);
1424 const unsigned char e = uint8_t(
id);
1425 const uint32_t quantizedPoint = seamPointArray[pointIdx + (
id - 1)];
1427 if ((quantizedPoint & MASK_DIRTY_BIT) && !(quantizedPoint & MASK_INVALID_BIT)) {
1428 const Vec3d p = unpackPoint(quantizedPoint);
1429 points[offset] = computeWeightedPoint(p, rhsValues, rhsSigns, e, iso);
1430 weightedPointMask[offset] =
true;
1432 points[offset] = computePoint(rhsValues, rhsSigns, e, iso);
1433 weightedPointMask[offset] =
false;
1437 points[offset] = computePoint(lhsValues, lhsSigns, uint8_t(n), iso);
1438 weightedPointMask[offset] =
false;
1445template <
typename InputTreeType>
1448 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1449 using InputValueType =
typename InputLeafNodeType::ValueType;
1451 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
1452 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
1454 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
1455 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
1457 ComputePoints(Vec3s * pointArray,
1458 const InputTreeType& inputTree,
1459 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1460 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1461 const std::unique_ptr<Index32[]>& leafNodeOffsets,
1462 const math::Transform& xform,
1465 void setRefData(
const InputTreeType& refInputTree,
1466 const Index32TreeType& refPointIndexTree,
1467 const Int16TreeType& refSignFlagsTree,
1468 const uint32_t * quantizedSeamLinePoints,
1469 uint8_t * seamLinePointsFlags);
1471 void operator()(
const tbb::blocked_range<size_t>&)
const;
1474 Vec3s *
const mPoints;
1475 InputTreeType
const *
const mInputTree;
1476 Index32LeafNodeType *
const *
const mPointIndexNodes;
1477 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
1478 Index32 const *
const mNodeOffsets;
1479 math::Transform
const mTransform;
1480 double const mIsovalue;
1482 InputTreeType
const * mRefInputTree;
1483 Index32TreeType
const * mRefPointIndexTree;
1484 Int16TreeType
const * mRefSignFlagsTree;
1485 uint32_t
const * mQuantizedSeamLinePoints;
1486 uint8_t * mSeamLinePointsFlags;
1490template <
typename InputTreeType>
1491ComputePoints<InputTreeType>::ComputePoints(
1493 const InputTreeType& inputTree,
1494 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
1495 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1496 const std::unique_ptr<Index32[]>& leafNodeOffsets,
1497 const math::Transform& xform,
1499 : mPoints(pointArray)
1500 , mInputTree(&inputTree)
1501 , mPointIndexNodes(pointIndexLeafNodes.data())
1502 , mSignFlagsNodes(signFlagsLeafNodes.data())
1503 , mNodeOffsets(leafNodeOffsets.get())
1506 , mRefInputTree(nullptr)
1507 , mRefPointIndexTree(nullptr)
1508 , mRefSignFlagsTree(nullptr)
1509 , mQuantizedSeamLinePoints(nullptr)
1510 , mSeamLinePointsFlags(nullptr)
1514template <
typename InputTreeType>
1516ComputePoints<InputTreeType>::setRefData(
1517 const InputTreeType& refInputTree,
1518 const Index32TreeType& refPointIndexTree,
1519 const Int16TreeType& refSignFlagsTree,
1520 const uint32_t * quantizedSeamLinePoints,
1521 uint8_t * seamLinePointsFlags)
1523 mRefInputTree = &refInputTree;
1524 mRefPointIndexTree = &refPointIndexTree;
1525 mRefSignFlagsTree = &refSignFlagsTree;
1526 mQuantizedSeamLinePoints = quantizedSeamLinePoints;
1527 mSeamLinePointsFlags = seamLinePointsFlags;
1530template <
typename InputTreeType>
1532ComputePoints<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
const
1538 using IndexType =
typename Index32TreeType::ValueType;
1541 using IndexArrayMap = std::map<IndexType, IndexArray>;
1543 InputTreeAccessor inputAcc(*mInputTree);
1547 std::array<Vec3d, 4>
points;
1548 std::array<bool, 4> weightedPointMask;
1549 std::array<double, 8> values, refValues;
1550 const double iso = mIsovalue;
1554 std::unique_ptr<InputTreeAccessor> refInputAcc;
1555 std::unique_ptr<Index32TreeAccessor> refPointIndexAcc;
1556 std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
1558 const bool hasReferenceData = mRefInputTree && mRefPointIndexTree && mRefSignFlagsTree;
1560 if (hasReferenceData) {
1561 refInputAcc.reset(
new InputTreeAccessor(*mRefInputTree));
1562 refPointIndexAcc.reset(
new Index32TreeAccessor(*mRefPointIndexTree));
1563 refSignFlagsAcc.reset(
new Int16TreeAccessor(*mRefSignFlagsTree));
1566 for (
size_t n = range.begin(), N = range.end(); n != N; ++n)
1568 Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
1569 const Coord& origin = pointIndexNode.origin();
1571 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1572 const InputLeafNodeType * inputNode = inputAcc.probeConstLeaf(origin);
1575 const InputLeafNodeType * refInputNode =
nullptr;
1576 const Index32LeafNodeType * refPointIndexNode =
nullptr;
1577 const Int16LeafNodeType * refSignFlagsNode =
nullptr;
1579 if (hasReferenceData) {
1580 refInputNode = refInputAcc->probeConstLeaf(origin);
1581 refPointIndexNode = refPointIndexAcc->probeConstLeaf(origin);
1582 refSignFlagsNode = refSignFlagsAcc->probeConstLeaf(origin);
1585 IndexType pointOffset = IndexType(mNodeOffsets[n]);
1586 IndexArrayMap regions;
1588 auto*
const pidxData = pointIndexNode.buffer().data();
1589 const auto*
const sfData = signFlagsNode.buffer().data();
1591 for (
auto it = pointIndexNode.beginValueOn(); it; ++it)
1593 const Index offset = it.pos();
1594 IndexType&
id = pidxData[offset];
1598 regions[id].push_back(offset);
1605 const Int16 flags = sfData[offset];
1606 const 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 && isInternalLeafCoord<InputLeafNodeType>(ijk);
1621 if (inclusiveCell) getCellVertexValues(*inputNode, offset, values);
1622 else getCellVertexValues(inputAcc, ijk, values);
1624 size_t count, weightcount;
1626 if (refSigns == 0) {
1627 count = computeCellPoints(
points, values, signs, iso);
1630 if (inclusiveCell && refInputNode) {
1631 getCellVertexValues(*refInputNode, offset, refValues);
1633 getCellVertexValues(*refInputAcc, ijk, refValues);
1635 count = computeCellPoints(
points, weightedPointMask, values, refValues, signs, refSigns,
1636 iso, refPointIndexNode->getValue(offset), mQuantizedSeamLinePoints);
1637 weightcount = count;
1640 xyz = ijk.asVec3d();
1642 for (
size_t i = 0; i < count; ++i) {
1647 if (!std::isfinite(point[0]) ||
1648 !std::isfinite(point[1]) ||
1649 !std::isfinite(point[2]))
1652 "VolumeToMesh encountered NaNs or infs in the input VDB!"
1653 " Hint: Check the input and consider using the \"Diagnostics\" tool "
1654 "to detect and resolve the NaNs.");
1658 point = mTransform.indexToWorld(point);
1660 Vec3s& pos = mPoints[pointOffset];
1661 pos[0] = float(point[0]);
1662 pos[1] = float(point[1]);
1663 pos[2] = float(point[2]);
1665 if (mSeamLinePointsFlags && weightcount && weightedPointMask[i]) {
1666 mSeamLinePointsFlags[pointOffset] = uint8_t(1);
1674 for (
auto it = regions.begin(); it != regions.end(); ++it)
1679 for (
size_t i = 0, I = voxels.size(); i < I; ++i) {
1681 const Index offset = voxels[i];
1682 ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1684 const bool inclusiveCell = inputNode && isInternalLeafCoord<InputLeafNodeType>(ijk);
1688 pidxData[offset] = pointOffset;
1690 const uint8_t signs = uint8_t(SIGNS & sfData[offset]);
1692 if (inclusiveCell) getCellVertexValues(*inputNode, offset, values);
1693 else getCellVertexValues(inputAcc, ijk, values);
1695 computeCellPoints(
points, values, signs, iso);
1697 avg[0] += double(ijk[0]) +
points[0][0];
1698 avg[1] += double(ijk[1]) +
points[0][1];
1699 avg[2] += double(ijk[2]) +
points[0][2];
1702 if (voxels.size() > 1) {
1703 const double w = 1.0 / double(voxels.size());
1707 avg = mTransform.indexToWorld(avg);
1709 Vec3s& pos = mPoints[pointOffset];
1710 pos[0] = float(avg[0]);
1711 pos[1] = float(avg[1]);
1712 pos[2] = float(avg[2]);
1723template <
typename InputTreeType>
1724struct SeamLineWeights
1726 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1727 using InputValueType =
typename InputLeafNodeType::ValueType;
1729 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
1730 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
1732 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
1733 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
1735 SeamLineWeights(
const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
1736 const InputTreeType& inputTree,
1737 const Index32TreeType& refPointIndexTree,
1738 const Int16TreeType& refSignFlagsTree,
1739 uint32_t * quantizedPoints,
1741 : mSignFlagsNodes(signFlagsLeafNodes.data())
1742 , mInputTree(&inputTree)
1743 , mRefPointIndexTree(&refPointIndexTree)
1744 , mRefSignFlagsTree(&refSignFlagsTree)
1745 , mQuantizedPoints(quantizedPoints)
1750 void operator()(
const tbb::blocked_range<size_t>& range)
const
1752 tree::ValueAccessor<const InputTreeType> inputTreeAcc(*mInputTree);
1753 tree::ValueAccessor<const Index32TreeType> pointIndexTreeAcc(*mRefPointIndexTree);
1754 tree::ValueAccessor<const Int16TreeType> signFlagsTreeAcc(*mRefSignFlagsTree);
1756 std::array<double, 8> values;
1757 const double iso = double(mIsovalue);
1761 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1763 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1764 const Coord& origin = signFlagsNode.origin();
1766 const Int16LeafNodeType * refSignNode = signFlagsTreeAcc.probeConstLeaf(origin);
1767 if (!refSignNode)
continue;
1769 const Index32LeafNodeType* refPointIndexNode =
1770 pointIndexTreeAcc.probeConstLeaf(origin);
1771 if (!refPointIndexNode)
continue;
1773 const InputLeafNodeType* inputNode = inputTreeAcc.probeConstLeaf(origin);
1775 const auto*
const sfData = signFlagsNode.buffer().data();
1776 const auto*
const rfIdxData = refPointIndexNode->buffer().data();
1777 const auto*
const rsData = refSignNode->buffer().data();
1779 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it)
1781 const Index offset = it.pos();
1782 const Int16 flags = sfData[offset];
1784 ijk = Index32LeafNodeType::offsetToLocalCoord(offset);
1786 const bool inclusiveCell = inputNode && isInternalLeafCoord<InputLeafNodeType>(ijk);
1790 if ((flags & SEAM) && refSignNode->isValueOn(offset)) {
1792 const uint8_t lhsSigns = uint8_t(SIGNS & flags);
1793 const uint8_t rhsSigns = uint8_t(SIGNS & rsData[offset]);
1795 if (inclusiveCell) getCellVertexValues(*inputNode, offset, values);
1796 else getCellVertexValues(inputTreeAcc, ijk, values);
1798 for (
unsigned i = 1, I = sEdgeGroupTable[lhsSigns][0] + 1; i < I; ++i) {
1800 const int id = matchEdgeGroup(uint8_t(i), lhsSigns, rhsSigns);
1804 uint32_t& data = mQuantizedPoints[rfIdxData[offset] + (
id - 1)];
1806 if (!(data & MASK_DIRTY_BIT)) {
1808 const int samples = computeMaskedPoint(
1809 pos, values, lhsSigns, rhsSigns, uint8_t(i), iso);
1811 if (samples > 0) data = packPoint(pos);
1812 else data = MASK_INVALID_BIT;
1814 data |= MASK_DIRTY_BIT;
1824 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
1825 InputTreeType
const *
const mInputTree;
1826 Index32TreeType
const *
const mRefPointIndexTree;
1827 Int16TreeType
const *
const mRefSignFlagsTree;
1828 uint32_t *
const mQuantizedPoints;
1829 InputValueType
const mIsovalue;
1833template <
typename TreeType>
1834struct SetSeamLineFlags
1836 using LeafNodeType =
typename TreeType::LeafNodeType;
1838 SetSeamLineFlags(
const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1839 const TreeType& refSignFlagsTree)
1840 : mSignFlagsNodes(signFlagsLeafNodes.data())
1841 , mRefSignFlagsTree(&refSignFlagsTree)
1845 void operator()(
const tbb::blocked_range<size_t>& range)
const
1847 tree::ValueAccessor<const TreeType> refSignFlagsTreeAcc(*mRefSignFlagsTree);
1849 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1851 LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1852 const Coord& origin = signFlagsNode.origin();
1854 const LeafNodeType* refSignNode = refSignFlagsTreeAcc.probeConstLeaf(origin);
1855 if (!refSignNode)
continue;
1857 const auto*
const rsData = refSignNode->buffer().data();
1858 auto*
const sfData = signFlagsNode.buffer().data();
1860 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
1861 const Index offset = it.pos();
1863 const uint8_t rhsSigns = uint8_t(rsData[offset] & SIGNS);
1865 if (sEdgeGroupTable[rhsSigns][0] > 0) {
1867 typename LeafNodeType::ValueType& value = sfData[offset];
1868 const uint8_t lhsSigns = uint8_t(value & SIGNS);
1870 if (rhsSigns != lhsSigns) {
1881 LeafNodeType *
const *
const mSignFlagsNodes;
1882 TreeType
const *
const mRefSignFlagsTree;
1886template <
typename BoolTreeType,
typename SignDataType>
1887struct TransferSeamLineFlags
1889 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1891 using SignDataTreeType =
typename BoolTreeType::template ValueConverter<SignDataType>::Type;
1892 using SignDataLeafNodeType =
typename SignDataTreeType::LeafNodeType;
1894 TransferSeamLineFlags(
const std::vector<SignDataLeafNodeType*>& signFlagsLeafNodes,
1895 const BoolTreeType& maskTree)
1896 : mSignFlagsNodes(signFlagsLeafNodes.data())
1897 , mMaskTree(&maskTree)
1901 void operator()(
const tbb::blocked_range<size_t>& range)
const
1903 tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
1905 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1907 SignDataLeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1908 const Coord& origin = signFlagsNode.origin();
1910 const BoolLeafNodeType * maskNode = maskAcc.probeConstLeaf(origin);
1911 if (!maskNode)
continue;
1913 auto*
const sfData = signFlagsNode.buffer().data();
1915 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
1916 const Index offset = it.pos();
1918 if (maskNode->isValueOn(offset)) {
1919 sfData[offset] |= SEAM;
1926 SignDataLeafNodeType *
const *
const mSignFlagsNodes;
1927 BoolTreeType
const *
const mMaskTree;
1931template <
typename TreeType>
1932struct MaskSeamLineVoxels
1934 using LeafNodeType =
typename TreeType::LeafNodeType;
1935 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1937 MaskSeamLineVoxels(
const std::vector<LeafNodeType*>& signFlagsLeafNodes,
1938 const TreeType& signFlagsTree,
1940 : mSignFlagsNodes(signFlagsLeafNodes.data())
1941 , mSignFlagsTree(&signFlagsTree)
1947 MaskSeamLineVoxels(MaskSeamLineVoxels& rhs, tbb::split)
1948 : mSignFlagsNodes(rhs.mSignFlagsNodes)
1949 , mSignFlagsTree(rhs.mSignFlagsTree)
1955 void join(MaskSeamLineVoxels& rhs) { mMask->merge(*rhs.mMask); }
1957 void operator()(
const tbb::blocked_range<size_t>& range)
1959 using ValueOnCIter =
typename LeafNodeType::ValueOnCIter;
1960 using ValueType =
typename LeafNodeType::ValueType;
1962 tree::ValueAccessor<const TreeType> signFlagsAcc(*mSignFlagsTree);
1963 tree::ValueAccessor<BoolTreeType> maskAcc(*mMask);
1966 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
1968 LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
1969 auto*
const sfData = signFlagsNode.buffer().data();
1971 for (ValueOnCIter it = signFlagsNode.cbeginValueOn(); it; ++it) {
1973 const ValueType flags = sfData[it.pos()];
1975 if (!(flags & SEAM) && (flags & EDGES)) {
1977 ijk = it.getCoord();
1979 bool isSeamLineVoxel =
false;
1981 if (flags & XEDGE) {
1983 isSeamLineVoxel = (signFlagsAcc.getValue(ijk) & SEAM);
1985 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
1987 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
1991 if (!isSeamLineVoxel && flags & YEDGE) {
1993 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
1995 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
1997 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2001 if (!isSeamLineVoxel && flags & ZEDGE) {
2003 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2005 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2007 isSeamLineVoxel = isSeamLineVoxel || (signFlagsAcc.getValue(ijk) & SEAM);
2011 if (isSeamLineVoxel) {
2012 maskAcc.setValue(it.getCoord(),
true);
2021 LeafNodeType *
const *
const mSignFlagsNodes;
2022 TreeType
const *
const mSignFlagsTree;
2023 BoolTreeType mTempMask;
2024 BoolTreeType *
const mMask;
2028template<
typename SignDataTreeType>
2030markSeamLineData(SignDataTreeType& signFlagsTree,
const SignDataTreeType& refSignFlagsTree)
2032 using SignDataType =
typename SignDataTreeType::ValueType;
2033 using SignDataLeafNodeType =
typename SignDataTreeType::LeafNodeType;
2034 using BoolTreeType =
typename SignDataTreeType::template ValueConverter<bool>::Type;
2036 std::vector<SignDataLeafNodeType*> signFlagsLeafNodes;
2037 signFlagsTree.getNodes(signFlagsLeafNodes);
2039 const tbb::blocked_range<size_t> nodeRange(0, signFlagsLeafNodes.size());
2041 tbb::parallel_for(nodeRange,
2042 SetSeamLineFlags<SignDataTreeType>(signFlagsLeafNodes, refSignFlagsTree));
2044 BoolTreeType seamLineMaskTree(
false);
2046 MaskSeamLineVoxels<SignDataTreeType>
2047 maskSeamLine(signFlagsLeafNodes, signFlagsTree, seamLineMaskTree);
2049 tbb::parallel_reduce(nodeRange, maskSeamLine);
2051 tbb::parallel_for(nodeRange,
2052 TransferSeamLineFlags<BoolTreeType, SignDataType>(signFlagsLeafNodes, seamLineMaskTree));
2059template <
typename InputGr
idType>
2060struct MergeVoxelRegions
2062 using InputTreeType =
typename InputGridType::TreeType;
2063 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
2064 using InputValueType =
typename InputLeafNodeType::ValueType;
2066 using FloatTreeType =
typename InputTreeType::template ValueConverter<float>::Type;
2067 using FloatLeafNodeType =
typename FloatTreeType::LeafNodeType;
2068 using FloatGridType = Grid<FloatTreeType>;
2070 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
2071 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
2073 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
2074 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
2076 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
2077 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2079 using MaskTreeType =
typename InputTreeType::template ValueConverter<ValueMask>::Type;
2080 using MaskLeafNodeType =
typename MaskTreeType::LeafNodeType;
2082 MergeVoxelRegions(
const InputGridType& inputGrid,
2083 const Index32TreeType& pointIndexTree,
2084 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2085 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2088 bool invertSurfaceOrientation);
2090 void setSpatialAdaptivity(
const FloatGridType& grid)
2092 mSpatialAdaptivityTree = &grid.tree();
2093 mSpatialAdaptivityTransform = &grid.transform();
2096 void setAdaptivityMask(
const BoolTreeType& mask)
2101 void setRefSignFlagsData(
const Int16TreeType& signFlagsData,
float internalAdaptivity)
2103 mRefSignFlagsTree = &signFlagsData;
2104 mInternalAdaptivity = internalAdaptivity;
2107 void operator()(
const tbb::blocked_range<size_t>&)
const;
2110 InputTreeType
const *
const mInputTree;
2111 math::Transform
const *
const mInputTransform;
2113 Index32TreeType
const *
const mPointIndexTree;
2114 Index32LeafNodeType *
const *
const mPointIndexNodes;
2115 Int16LeafNodeType
const *
const *
const mSignFlagsNodes;
2117 InputValueType mIsovalue;
2118 float mSurfaceAdaptivity, mInternalAdaptivity;
2119 bool mInvertSurfaceOrientation;
2121 FloatTreeType
const * mSpatialAdaptivityTree;
2122 BoolTreeType
const * mMaskTree;
2123 Int16TreeType
const * mRefSignFlagsTree;
2124 math::Transform
const * mSpatialAdaptivityTransform;
2128template <
typename InputGr
idType>
2129MergeVoxelRegions<InputGridType>::MergeVoxelRegions(
2130 const InputGridType& inputGrid,
2131 const Index32TreeType& pointIndexTree,
2132 const std::vector<Index32LeafNodeType*>& pointIndexLeafNodes,
2133 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
2136 bool invertSurfaceOrientation)
2137 : mInputTree(&inputGrid.
tree())
2138 , mInputTransform(&inputGrid.transform())
2139 , mPointIndexTree(&pointIndexTree)
2140 , mPointIndexNodes(pointIndexLeafNodes.data())
2141 , mSignFlagsNodes(signFlagsLeafNodes.data())
2143 , mSurfaceAdaptivity(adaptivity)
2144 , mInternalAdaptivity(adaptivity)
2145 , mInvertSurfaceOrientation(invertSurfaceOrientation)
2146 , mSpatialAdaptivityTree(nullptr)
2147 , mMaskTree(nullptr)
2148 , mRefSignFlagsTree(nullptr)
2149 , mSpatialAdaptivityTransform(nullptr)
2154template <
typename InputGr
idType>
2156MergeVoxelRegions<InputGridType>::operator()(
const tbb::blocked_range<size_t>& range)
const
2159 using Vec3sLeafNodeType =
typename InputLeafNodeType::template ValueConverter<Vec3sType>::Type;
2167 std::unique_ptr<FloatTreeAccessor> spatialAdaptivityAcc;
2168 if (mSpatialAdaptivityTree && mSpatialAdaptivityTransform) {
2169 spatialAdaptivityAcc.reset(
new FloatTreeAccessor(*mSpatialAdaptivityTree));
2172 std::unique_ptr<BoolTreeAccessor> maskAcc;
2174 maskAcc.reset(
new BoolTreeAccessor(*mMaskTree));
2177 std::unique_ptr<Int16TreeAccessor> refSignFlagsAcc;
2178 if (mRefSignFlagsTree) {
2179 refSignFlagsAcc.reset(
new Int16TreeAccessor(*mRefSignFlagsTree));
2182 InputTreeAccessor inputAcc(*mInputTree);
2183 Index32TreeAccessor pointIndexAcc(*mPointIndexTree);
2185 MaskLeafNodeType mask;
2187 const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<InputValueType>();
2188 std::unique_ptr<Vec3sLeafNodeType> gradientNode;
2191 const int LeafDim = InputLeafNodeType::DIM;
2193 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
2195 mask.setValuesOff();
2197 const Int16LeafNodeType& signFlagsNode = *mSignFlagsNodes[n];
2198 Index32LeafNodeType& pointIndexNode = *mPointIndexNodes[n];
2200 const Coord& origin = pointIndexNode.origin();
2205 const BoolLeafNodeType* maskLeaf = maskAcc->probeConstLeaf(origin);
2206 if (maskLeaf !=
nullptr) {
2207 for (
auto it = maskLeaf->cbeginValueOn(); it; ++it)
2209 mask.setActiveState(it.getCoord() & ~1u,
true);
2214 float adaptivity = (refSignFlagsAcc && !refSignFlagsAcc->probeConstLeaf(origin)) ?
2215 mInternalAdaptivity : mSurfaceAdaptivity;
2217 bool useGradients = adaptivity < 1.0f;
2220 FloatLeafNodeType adaptivityLeaf(origin, adaptivity);
2222 if (spatialAdaptivityAcc) {
2223 useGradients =
false;
2224 for (
Index offset = 0; offset < FloatLeafNodeType::NUM_VALUES; ++offset) {
2225 ijk = adaptivityLeaf.offsetToGlobalCoord(offset);
2226 ijk = mSpatialAdaptivityTransform->worldToIndexCellCentered(
2227 mInputTransform->indexToWorld(ijk));
2228 float weight = spatialAdaptivityAcc->getValue(ijk);
2229 float adaptivityValue = weight * adaptivity;
2230 if (adaptivityValue < 1.0f) useGradients =
true;
2231 adaptivityLeaf.setValueOnly(offset, adaptivityValue);
2236 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it) {
2237 const Int16 flags = it.getValue();
2238 const unsigned char signs =
static_cast<unsigned char>(SIGNS & int(flags));
2240 if ((flags & SEAM) || !sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) {
2242 mask.setActiveState(it.getCoord() & ~1u,
true);
2244 }
else if (flags & EDGES) {
2246 bool maskRegion =
false;
2248 ijk = it.getCoord();
2249 if (!pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2251 if (!maskRegion && flags & XEDGE) {
2253 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2255 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2257 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2261 if (!maskRegion && flags & YEDGE) {
2263 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2265 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2267 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2271 if (!maskRegion && flags & ZEDGE) {
2273 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2275 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2277 if (!maskRegion && !pointIndexAcc.isValueOn(ijk)) maskRegion =
true;
2282 mask.setActiveState(it.getCoord() & ~1u,
true);
2289 for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2290 for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2291 for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2292 if (!mask.isValueOn(ijk) && isNonManifold(inputAcc, ijk, mIsovalue, dim)) {
2293 mask.setActiveState(ijk,
true);
2304 gradientNode->setValuesOff();
2306 gradientNode.reset(
new Vec3sLeafNodeType());
2309 for (
auto it = signFlagsNode.cbeginValueOn(); it; ++it)
2311 ijk = it.getCoord();
2312 if (!mask.isValueOn(ijk & ~1u))
2317 if (invertGradientDir) {
2321 gradientNode->setValueOn(it.pos(), dir);
2328 for ( ; dim <= LeafDim; dim = dim << 1) {
2329 const unsigned coordMask = ~((dim << 1) - 1);
2330 for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
2331 for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
2332 for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
2334 adaptivity = adaptivityLeaf.getValue(ijk);
2336 if (mask.isValueOn(ijk)
2337 || isNonManifold(inputAcc, ijk, mIsovalue, dim)
2338 || (useGradients && !isMergeable(*gradientNode, ijk, dim, adaptivity)))
2340 mask.setActiveState(ijk & coordMask,
true);
2342 mergeVoxels(pointIndexNode, ijk, dim, regionId++);
2356struct UniformPrimBuilder
2358 UniformPrimBuilder(): mIdx(0), mPolygonPool(nullptr) {}
2360 void init(
const size_t upperBound, PolygonPool& quadPool)
2362 mPolygonPool = &quadPool;
2363 mPolygonPool->resetQuads(upperBound);
2367 template<
typename IndexType>
2368 void addPrim(
const math::Vec4<IndexType>& verts,
bool reverse,
char flags = 0)
2371 mPolygonPool->quad(mIdx) = verts;
2373 Vec4I& quad = mPolygonPool->quad(mIdx);
2379 mPolygonPool->quadFlags(mIdx) = flags;
2385 mPolygonPool->trimQuads(mIdx);
2390 PolygonPool* mPolygonPool;
2395struct AdaptivePrimBuilder
2397 AdaptivePrimBuilder() : mQuadIdx(0), mTriangleIdx(0), mPolygonPool(nullptr) {}
2399 void init(
const size_t upperBound, PolygonPool& polygonPool)
2401 mPolygonPool = &polygonPool;
2402 mPolygonPool->resetQuads(upperBound);
2403 mPolygonPool->resetTriangles(upperBound);
2409 template<
typename IndexType>
2410 void addPrim(
const math::Vec4<IndexType>& verts,
bool reverse,
char flags = 0)
2412 if (verts[0] != verts[1] && verts[0] != verts[2] && verts[0] != verts[3]
2413 && verts[1] != verts[2] && verts[1] != verts[3] && verts[2] != verts[3]) {
2414 mPolygonPool->quadFlags(mQuadIdx) = flags;
2415 addQuad(verts, reverse);
2417 verts[0] == verts[3] &&
2418 verts[1] != verts[2] &&
2419 verts[1] != verts[0] &&
2420 verts[2] != verts[0]) {
2421 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2422 addTriangle(verts[0], verts[1], verts[2], reverse);
2424 verts[1] == verts[2] &&
2425 verts[0] != verts[3] &&
2426 verts[0] != verts[1] &&
2427 verts[3] != verts[1]) {
2428 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2429 addTriangle(verts[0], verts[1], verts[3], reverse);
2431 verts[0] == verts[1] &&
2432 verts[2] != verts[3] &&
2433 verts[2] != verts[0] &&
2434 verts[3] != verts[0]) {
2435 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2436 addTriangle(verts[0], verts[2], verts[3], reverse);
2438 verts[2] == verts[3] &&
2439 verts[0] != verts[1] &&
2440 verts[0] != verts[2] &&
2441 verts[1] != verts[2]) {
2442 mPolygonPool->triangleFlags(mTriangleIdx) = flags;
2443 addTriangle(verts[0], verts[1], verts[2], reverse);
2450 mPolygonPool->trimQuads(mQuadIdx,
true);
2451 mPolygonPool->trimTriangles(mTriangleIdx,
true);
2456 template<
typename IndexType>
2457 void addQuad(
const math::Vec4<IndexType>& verts,
bool reverse)
2460 mPolygonPool->quad(mQuadIdx) = verts;
2462 Vec4I& quad = mPolygonPool->quad(mQuadIdx);
2471 void addTriangle(
unsigned v0,
unsigned v1,
unsigned v2,
bool reverse)
2473 Vec3I& prim = mPolygonPool->triangle(mTriangleIdx);
2487 size_t mQuadIdx, mTriangleIdx;
2488 PolygonPool *mPolygonPool;
2492template<
typename SignAccT,
typename IdxAccT,
typename PrimBuilder>
2495 bool invertSurfaceOrientation,
2498 const Vec3i& offsets,
2500 const SignAccT& signAcc,
2501 const IdxAccT& idxAcc,
2502 PrimBuilder& mesher)
2504 using IndexType =
typename IdxAccT::ValueType;
2507 const bool isActive = idxAcc.probeValue(ijk, v0);
2511 tag[0] = (flags & SEAM) ? POLYFLAG_FRACTURE_SEAM : 0;
2512 tag[1] = tag[0] | char(POLYFLAG_EXTERIOR);
2514 bool isInside = flags & INSIDE;
2516 isInside = invertSurfaceOrientation ? !isInside : isInside;
2521 if (flags & XEDGE) {
2523 quad[0] = v0 + offsets[0];
2527 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2528 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2529 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][5] - 1 : 0;
2533 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2534 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2535 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][7] - 1 : 0;
2539 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2540 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2541 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][3] - 1 : 0;
2544 mesher.addPrim(quad, isInside, tag[
bool(refFlags & XEDGE)]);
2551 if (flags & YEDGE) {
2553 quad[0] = v0 + offsets[1];
2557 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2558 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2559 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][12] - 1 : 0;
2563 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2564 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2565 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][11] - 1 : 0;
2569 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2570 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2571 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][10] - 1 : 0;
2574 mesher.addPrim(quad, isInside, tag[
bool(refFlags & YEDGE)]);
2581 if (flags & ZEDGE) {
2583 quad[0] = v0 + offsets[2];
2587 bool activeValues = idxAcc.probeValue(coord, quad[1]);
2588 uint8_t cell = uint8_t(SIGNS & signAcc.getValue(coord));
2589 quad[1] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][8] - 1 : 0;
2593 activeValues = activeValues && idxAcc.probeValue(coord, quad[2]);
2594 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2595 quad[2] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][6] - 1 : 0;
2599 activeValues = activeValues && idxAcc.probeValue(coord, quad[3]);
2600 cell = uint8_t(SIGNS & signAcc.getValue(coord));
2601 quad[3] += sEdgeGroupTable[cell][0] > 1 ? sEdgeGroupTable[cell][2] - 1 : 0;
2604 mesher.addPrim(quad, !isInside, tag[
bool(refFlags & ZEDGE)]);
2613template<
typename InputTreeType>
2614struct MaskTileBorders
2616 using InputValueType =
typename InputTreeType::ValueType;
2617 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
2620 MaskTileBorders(
const InputTreeType& inputTree, InputValueType iso,
2621 BoolTreeType& mask,
const Vec4i* tileArray)
2622 : mInputTree(&inputTree)
2626 , mTileArray(tileArray)
2630 MaskTileBorders(MaskTileBorders& rhs, tbb::split)
2631 : mInputTree(rhs.mInputTree)
2632 , mIsovalue(rhs.mIsovalue)
2635 , mTileArray(rhs.mTileArray)
2639 void join(MaskTileBorders& rhs) { mMask->merge(*rhs.mMask); }
2641 void operator()(
const tbb::blocked_range<size_t>&);
2644 InputTreeType
const *
const mInputTree;
2645 InputValueType
const mIsovalue;
2646 BoolTreeType mTempMask;
2647 BoolTreeType *
const mMask;
2648 Vec4i const *
const mTileArray;
2652template<
typename InputTreeType>
2654MaskTileBorders<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
2661 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
2663 const Vec4i& tile = mTileArray[n];
2665 bbox.min()[0] = tile[0];
2666 bbox.min()[1] = tile[1];
2667 bbox.min()[2] = tile[2];
2668 bbox.max() = bbox.min();
2669 bbox.max().offset(tile[3]);
2671 InputValueType value = mInputTree->background();
2673 const bool isInside = isInsideValue(inputTreeAcc.getValue(bbox.min()), mIsovalue);
2674 const int valueDepth = inputTreeAcc.getValueDepth(bbox.min());
2682 bool processRegion =
true;
2683 if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2684 processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2687 if (processRegion) {
2690 region.min()[0] = region.max()[0] = ijk[0];
2691 mMask->fill(region,
false);
2698 processRegion =
true;
2699 if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2700 processRegion = (!inputTreeAcc.probeValue(ijk, value)
2701 && isInside != isInsideValue(value, mIsovalue));
2704 if (processRegion) {
2707 region.min()[0] = region.max()[0] = ijk[0];
2708 mMask->fill(region,
false);
2718 processRegion =
true;
2719 if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2720 processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2723 if (processRegion) {
2726 region.min()[1] = region.max()[1] = ijk[1];
2727 mMask->fill(region,
false);
2734 processRegion =
true;
2735 if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2736 processRegion = (!inputTreeAcc.probeValue(ijk, value)
2737 && isInside != isInsideValue(value, mIsovalue));
2740 if (processRegion) {
2743 region.min()[1] = region.max()[1] = ijk[1];
2744 mMask->fill(region,
false);
2754 processRegion =
true;
2755 if (valueDepth >= inputTreeAcc.getValueDepth(nijk)) {
2756 processRegion = isInside != isInsideValue(inputTreeAcc.getValue(nijk), mIsovalue);
2759 if (processRegion) {
2762 region.min()[2] = region.max()[2] = ijk[2];
2763 mMask->fill(region,
false);
2769 processRegion =
true;
2770 if (valueDepth >= inputTreeAcc.getValueDepth(ijk)) {
2771 processRegion = (!inputTreeAcc.probeValue(ijk, value)
2772 && isInside != isInsideValue(value, mIsovalue));
2775 if (processRegion) {
2778 region.min()[2] = region.max()[2] = ijk[2];
2779 mMask->fill(region,
false);
2785template<
typename InputTreeType>
2787maskActiveTileBorders(
const InputTreeType& inputTree,
2788 const typename InputTreeType::ValueType iso,
2789 typename InputTreeType::template ValueConverter<bool>::Type& mask)
2791 typename InputTreeType::ValueOnCIter tileIter(inputTree);
2792 tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2794 size_t tileCount = 0;
2795 for ( ; tileIter; ++tileIter) {
2799 if (tileCount > 0) {
2800 std::unique_ptr<Vec4i[]> tiles(
new Vec4i[tileCount]);
2805 tileIter = inputTree.cbeginValueOn();
2806 tileIter.setMaxDepth(InputTreeType::ValueOnCIter::LEAF_DEPTH - 1);
2808 for (; tileIter; ++tileIter) {
2809 Vec4i& tile = tiles[index++];
2810 tileIter.getBoundingBox(bbox);
2811 tile[0] = bbox.min()[0];
2812 tile[1] = bbox.min()[1];
2813 tile[2] = bbox.min()[2];
2814 tile[3] = bbox.max()[0] - bbox.min()[0];
2817 MaskTileBorders<InputTreeType> op(inputTree, iso, mask, tiles.get());
2818 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, tileCount), op);
2830 PointListCopy(
const PointList& pointsIn, std::vector<Vec3s>& pointsOut)
2831 : mPointsIn(pointsIn) , mPointsOut(pointsOut)
2835 void operator()(
const tbb::blocked_range<size_t>& range)
const
2837 for (
size_t n = range.begin(); n < range.end(); ++n) {
2838 mPointsOut[n] = mPointsIn[n];
2844 std::vector<Vec3s>& mPointsOut;
2852struct LeafNodeVoxelOffsets
2854 using IndexVector = std::vector<Index>;
2856 template<
typename LeafNodeType>
2857 void constructOffsetList();
2860 const IndexVector& core()
const {
return mCore; }
2864 const IndexVector& minX()
const {
return mMinX; }
2867 const IndexVector& maxX()
const {
return mMaxX; }
2871 const IndexVector& minY()
const {
return mMinY; }
2874 const IndexVector& maxY()
const {
return mMaxY; }
2878 const IndexVector& minZ()
const {
return mMinZ; }
2881 const IndexVector& maxZ()
const {
return mMaxZ; }
2885 const IndexVector& internalNeighborsX()
const {
return mInternalNeighborsX; }
2888 const IndexVector& internalNeighborsY()
const {
return mInternalNeighborsY; }
2891 const IndexVector& internalNeighborsZ()
const {
return mInternalNeighborsZ; }
2895 IndexVector mCore, mMinX, mMaxX, mMinY, mMaxY, mMinZ, mMaxZ,
2896 mInternalNeighborsX, mInternalNeighborsY, mInternalNeighborsZ;
2900template<
typename LeafNodeType>
2902LeafNodeVoxelOffsets::constructOffsetList()
2906 mCore.reserve((LeafNodeType::DIM - 2) * (LeafNodeType::DIM - 2));
2908 for (
Index x = 1; x < (LeafNodeType::DIM - 1); ++x) {
2909 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2910 for (
Index y = 1; y < (LeafNodeType::DIM - 1); ++y) {
2911 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2912 for (
Index z = 1; z < (LeafNodeType::DIM - 1); ++z) {
2913 mCore.push_back(offsetXY + z);
2919 mInternalNeighborsX.clear();
2920 mInternalNeighborsX.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2922 for (
Index x = 0; x < (LeafNodeType::DIM - 1); ++x) {
2923 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2924 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2925 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2926 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2927 mInternalNeighborsX.push_back(offsetXY + z);
2933 mInternalNeighborsY.clear();
2934 mInternalNeighborsY.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2936 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
2937 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2938 for (
Index y = 0; y < (LeafNodeType::DIM - 1); ++y) {
2939 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2940 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2941 mInternalNeighborsY.push_back(offsetXY + z);
2947 mInternalNeighborsZ.clear();
2948 mInternalNeighborsZ.reserve(LeafNodeType::SIZE - (LeafNodeType::DIM * LeafNodeType::DIM));
2950 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
2951 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2952 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2953 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2954 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
2955 mInternalNeighborsZ.push_back(offsetXY + z);
2962 mMinX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
2964 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2965 const Index offsetXY = (y << LeafNodeType::LOG2DIM);
2966 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2967 mMinX.push_back(offsetXY + z);
2974 mMaxX.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
2976 const Index offsetX = (LeafNodeType::DIM - 1) << (2 * LeafNodeType::LOG2DIM);
2977 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
2978 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
2979 for (
Index z = 0; z < LeafNodeType::DIM; ++z) {
2980 mMaxX.push_back(offsetXY + z);
2987 mMinY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
2989 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
2990 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
2991 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
2992 mMinY.push_back(offsetX + z);
2999 mMaxY.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3001 const Index offsetY = (LeafNodeType::DIM - 1) << LeafNodeType::LOG2DIM;
3002 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3003 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3004 for (
Index z = 0; z < (LeafNodeType::DIM - 1); ++z) {
3005 mMaxY.push_back(offsetX + offsetY + z);
3012 mMinZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3014 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3015 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3016 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
3017 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3018 mMinZ.push_back(offsetXY);
3025 mMaxZ.reserve(LeafNodeType::DIM * LeafNodeType::DIM);
3027 for (
Index x = 0; x < LeafNodeType::DIM; ++x) {
3028 const Index offsetX = x << (2 * LeafNodeType::LOG2DIM);
3029 for (
Index y = 0; y < LeafNodeType::DIM; ++y) {
3030 const Index offsetXY = offsetX + (y << LeafNodeType::LOG2DIM);
3031 mMaxZ.push_back(offsetXY + (LeafNodeType::DIM - 1));
3042template<
typename AccessorT,
int _AXIS>
3043struct VoxelEdgeAccessor
3045 enum { AXIS = _AXIS };
3048 VoxelEdgeAccessor(AccessorT& _acc) : acc(_acc) {}
3050 void set(Coord ijk) {
3052 acc.setActiveState(ijk);
3054 acc.setActiveState(ijk);
3056 acc.setActiveState(ijk);
3058 acc.setActiveState(ijk);
3059 }
else if (_AXIS == 1) {
3060 acc.setActiveState(ijk);
3062 acc.setActiveState(ijk);
3064 acc.setActiveState(ijk);
3066 acc.setActiveState(ijk);
3068 acc.setActiveState(ijk);
3070 acc.setActiveState(ijk);
3072 acc.setActiveState(ijk);
3074 acc.setActiveState(ijk);
3083template<
typename VoxelEdgeAcc,
typename LeafNodeT>
3085evalInternalVoxelEdges(VoxelEdgeAcc& edgeAcc,
3086 const LeafNodeT& leafnode,
3087 const LeafNodeVoxelOffsets& voxels,
3088 const typename LeafNodeT::ValueType iso)
3091 const std::vector<Index>* offsets = &voxels.internalNeighborsZ();
3093 if (VoxelEdgeAcc::AXIS == 0) {
3094 nvo = LeafNodeT::DIM * LeafNodeT::DIM;
3095 offsets = &voxels.internalNeighborsX();
3096 }
else if (VoxelEdgeAcc::AXIS == 1) {
3097 nvo = LeafNodeT::DIM;
3098 offsets = &voxels.internalNeighborsY();
3101 const LeafBufferAccessor<LeafNodeT> lhsAcc(leafnode);
3103 for (
size_t n = 0, N = offsets->size(); n < N; ++n) {
3104 const Index& pos = (*offsets)[n];
3105 const bool isActive = leafnode.isValueOn(pos) || leafnode.isValueOn(pos + nvo);
3106 if (isActive && (isInsideValue(lhsAcc.get(pos), iso) !=
3107 isInsideValue(lhsAcc.get((pos + nvo)), iso))) {
3108 edgeAcc.set(leafnode.offsetToGlobalCoord(pos));
3117template<
typename LeafNodeT,
typename TreeAcc,
typename VoxelEdgeAcc>
3119evalExternalVoxelEdges(VoxelEdgeAcc& edgeAcc,
3121 const LeafNodeT& lhsNode,
3122 const LeafNodeVoxelOffsets& voxels,
3123 const typename LeafNodeT::ValueType iso)
3125 const std::vector<Index>* lhsOffsets = &voxels.maxX();
3126 const std::vector<Index>* rhsOffsets = &voxels.minX();
3127 Coord ijk = lhsNode.origin();
3129 if (VoxelEdgeAcc::AXIS == 0) {
3130 ijk[0] += LeafNodeT::DIM;
3131 }
else if (VoxelEdgeAcc::AXIS == 1) {
3132 ijk[1] += LeafNodeT::DIM;
3133 lhsOffsets = &voxels.maxY();
3134 rhsOffsets = &voxels.minY();
3135 }
else if (VoxelEdgeAcc::AXIS == 2) {
3136 ijk[2] += LeafNodeT::DIM;
3137 lhsOffsets = &voxels.maxZ();
3138 rhsOffsets = &voxels.minZ();
3141 typename LeafNodeT::ValueType value;
3142 const LeafNodeT* rhsNodePt = acc.probeConstLeaf(ijk);
3144 const LeafBufferAccessor<LeafNodeT> lhsAcc(lhsNode);
3147 const LeafBufferAccessor<LeafNodeT> rhsAcc(*rhsNodePt);
3149 for (
size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3150 const Index& pos = (*lhsOffsets)[n];
3151 bool isActive = lhsNode.isValueOn(pos) || rhsNodePt->isValueOn((*rhsOffsets)[n]);
3152 if (isActive && (isInsideValue(lhsAcc.get(pos), iso) !=
3153 isInsideValue(rhsAcc.get((*rhsOffsets)[n]), iso))) {
3154 edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3157 }
else if (!acc.probeValue(ijk, value)) {
3158 const bool inside = isInsideValue(value, iso);
3159 for (
size_t n = 0, N = lhsOffsets->size(); n < N; ++n) {
3160 const Index& pos = (*lhsOffsets)[n];
3161 if (lhsNode.isValueOn(pos) && (inside != isInsideValue(lhsAcc.get(pos), iso))) {
3162 edgeAcc.set(lhsNode.offsetToGlobalCoord(pos));
3172template<
typename LeafNodeT,
typename TreeAcc,
typename VoxelEdgeAcc>
3174evalExternalVoxelEdgesInv(VoxelEdgeAcc& edgeAcc,
3176 const LeafNodeT& leafnode,
3177 const LeafNodeVoxelOffsets& voxels,
3178 const typename LeafNodeT::ValueType iso)
3180 Coord ijk = leafnode.origin();
3181 if (VoxelEdgeAcc::AXIS == 0) --ijk[0];
3182 else if (VoxelEdgeAcc::AXIS == 1) --ijk[1];
3183 else if (VoxelEdgeAcc::AXIS == 2) --ijk[2];
3185 typename LeafNodeT::ValueType value;
3186 if (!acc.probeConstLeaf(ijk) && !acc.probeValue(ijk, value)) {
3188 const std::vector<Index>* offsets = &voxels.internalNeighborsX();
3189 if (VoxelEdgeAcc::AXIS == 1) offsets = &voxels.internalNeighborsY();
3190 else if (VoxelEdgeAcc::AXIS == 2) offsets = &voxels.internalNeighborsZ();
3192 const LeafBufferAccessor<LeafNodeT> lhsAcc(leafnode);
3194 const bool inside = isInsideValue(value, iso);
3195 for (
size_t n = 0, N = offsets->size(); n < N; ++n) {
3197 const Index& pos = (*offsets)[n];
3198 if (leafnode.isValueOn(pos)
3199 && (inside != isInsideValue(lhsAcc.get(pos), iso)))
3201 ijk = leafnode.offsetToGlobalCoord(pos);
3202 if (VoxelEdgeAcc::AXIS == 0) --ijk[0];
3203 else if (VoxelEdgeAcc::AXIS == 1) --ijk[1];
3204 else if (VoxelEdgeAcc::AXIS == 2) --ijk[2];
3213template<
typename InputTreeType>
3214struct IdentifyIntersectingVoxels
3216 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3217 using InputValueType =
typename InputLeafNodeType::ValueType;
3219 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3221 IdentifyIntersectingVoxels(
3222 const InputTreeType& inputTree,
3223 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3224 const LeafNodeVoxelOffsets& offsets,
3225 BoolTreeType& intersectionTree,
3226 InputValueType iso);
3228 IdentifyIntersectingVoxels(IdentifyIntersectingVoxels&, tbb::split);
3229 void operator()(
const tbb::blocked_range<size_t>&);
3230 void join(
const IdentifyIntersectingVoxels& rhs) {
3231 mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3235 tree::ValueAccessor<const InputTreeType> mInputAccessor;
3236 InputLeafNodeType
const *
const *
const mInputNodes;
3238 BoolTreeType mIntersectionTree;
3239 tree::ValueAccessor<BoolTreeType> mIntersectionAccessor;
3241 const LeafNodeVoxelOffsets& mOffsets;
3242 const InputValueType mIsovalue;
3246template<
typename InputTreeType>
3247IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
3248 const InputTreeType& inputTree,
3249 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
3250 const LeafNodeVoxelOffsets& offsets,
3251 BoolTreeType& intersectionTree,
3253 : mInputAccessor(inputTree)
3254 , mInputNodes(inputLeafNodes.data())
3255 , mIntersectionTree(false)
3256 , mIntersectionAccessor(intersectionTree)
3263template<
typename InputTreeType>
3264IdentifyIntersectingVoxels<InputTreeType>::IdentifyIntersectingVoxels(
3265 IdentifyIntersectingVoxels& rhs, tbb::split)
3266 : mInputAccessor(rhs.mInputAccessor.
tree())
3267 , mInputNodes(rhs.mInputNodes)
3268 , mIntersectionTree(false)
3269 , mIntersectionAccessor(mIntersectionTree)
3270 , mOffsets(rhs.mOffsets)
3271 , mIsovalue(rhs.mIsovalue)
3276template<
typename InputTreeType>
3278IdentifyIntersectingVoxels<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3280 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3281 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3282 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3284 for (
size_t n = range.begin(); n != range.end(); ++n) {
3286 const InputLeafNodeType& node = *mInputNodes[n];
3289 evalInternalVoxelEdges(xEdgeAcc, node, mOffsets, mIsovalue);
3291 evalInternalVoxelEdges(yEdgeAcc, node, mOffsets, mIsovalue);
3293 evalInternalVoxelEdges(zEdgeAcc, node, mOffsets, mIsovalue);
3296 evalExternalVoxelEdges(xEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3298 evalExternalVoxelEdges(yEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3300 evalExternalVoxelEdges(zEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3306 evalExternalVoxelEdgesInv(xEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3308 evalExternalVoxelEdgesInv(yEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3310 evalExternalVoxelEdgesInv(zEdgeAcc, mInputAccessor, node, mOffsets, mIsovalue);
3315template<
typename InputTreeType>
3317identifySurfaceIntersectingVoxels(
3318 typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3319 const InputTreeType& inputTree,
3320 typename InputTreeType::ValueType isovalue)
3322 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3324 std::vector<const InputLeafNodeType*> inputLeafNodes;
3325 inputTree.getNodes(inputLeafNodes);
3327 LeafNodeVoxelOffsets offsets;
3328 offsets.constructOffsetList<InputLeafNodeType>();
3330 IdentifyIntersectingVoxels<InputTreeType> op(
3331 inputTree, inputLeafNodes, offsets, intersectionTree, isovalue);
3333 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, inputLeafNodes.size()), op);
3335 maskActiveTileBorders(inputTree, isovalue, intersectionTree);
3342template<
typename InputTreeType>
3343struct MaskIntersectingVoxels
3345 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3346 using InputValueType =
typename InputLeafNodeType::ValueType;
3348 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3349 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3351 MaskIntersectingVoxels(
3352 const InputTreeType& inputTree,
3353 const std::vector<BoolLeafNodeType*>& nodes,
3354 BoolTreeType& intersectionTree,
3355 InputValueType iso);
3357 MaskIntersectingVoxels(MaskIntersectingVoxels&, tbb::split);
3358 void operator()(
const tbb::blocked_range<size_t>&);
3359 void join(
const MaskIntersectingVoxels& rhs) {
3360 mIntersectionAccessor.tree().merge(rhs.mIntersectionAccessor.tree());
3364 tree::ValueAccessor<const InputTreeType> mInputAccessor;
3365 BoolLeafNodeType
const *
const *
const mNodes;
3367 BoolTreeType mIntersectionTree;
3368 tree::ValueAccessor<BoolTreeType> mIntersectionAccessor;
3370 const InputValueType mIsovalue;
3374template<
typename InputTreeType>
3375MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
3376 const InputTreeType& inputTree,
3377 const std::vector<BoolLeafNodeType*>& nodes,
3378 BoolTreeType& intersectionTree,
3380 : mInputAccessor(inputTree)
3381 , mNodes(nodes.data())
3382 , mIntersectionTree(false)
3383 , mIntersectionAccessor(intersectionTree)
3389template<
typename InputTreeType>
3390MaskIntersectingVoxels<InputTreeType>::MaskIntersectingVoxels(
3391 MaskIntersectingVoxels& rhs, tbb::split)
3392 : mInputAccessor(rhs.mInputAccessor.
tree())
3393 , mNodes(rhs.mNodes)
3394 , mIntersectionTree(false)
3395 , mIntersectionAccessor(mIntersectionTree)
3396 , mIsovalue(rhs.mIsovalue)
3401template<
typename InputTreeType>
3403MaskIntersectingVoxels<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3405 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 0> xEdgeAcc(mIntersectionAccessor);
3406 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 1> yEdgeAcc(mIntersectionAccessor);
3407 VoxelEdgeAccessor<tree::ValueAccessor<BoolTreeType>, 2> zEdgeAcc(mIntersectionAccessor);
3411 for (
size_t n = range.begin(); n != range.end(); ++n) {
3413 const BoolLeafNodeType& node = *mNodes[n];
3415 for (
auto it = node.cbeginValueOn(); it; ++it) {
3417 if (!it.getValue()) {
3419 ijk = it.getCoord();
3421 const bool inside = isInsideValue(mInputAccessor.getValue(ijk), mIsovalue);
3423 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(1, 0, 0)), mIsovalue)) {
3427 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 1, 0)), mIsovalue)) {
3431 if (inside != isInsideValue(mInputAccessor.getValue(ijk.offsetBy(0, 0, 1)), mIsovalue)) {
3440template<
typename BoolTreeType>
3441struct MaskBorderVoxels
3443 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3445 MaskBorderVoxels(
const BoolTreeType& maskTree,
3446 const std::vector<BoolLeafNodeType*>& maskNodes,
3447 BoolTreeType& borderTree)
3448 : mMaskTree(&maskTree)
3449 , mMaskNodes(maskNodes.data())
3450 , mTmpBorderTree(false)
3451 , mBorderTree(&borderTree) {}
3453 MaskBorderVoxels(MaskBorderVoxels& rhs, tbb::split)
3454 : mMaskTree(rhs.mMaskTree)
3455 , mMaskNodes(rhs.mMaskNodes)
3456 , mTmpBorderTree(false)
3457 , mBorderTree(&mTmpBorderTree) {}
3459 void join(MaskBorderVoxels& rhs) { mBorderTree->merge(*rhs.mBorderTree); }
3461 void operator()(
const tbb::blocked_range<size_t>& range)
3463 tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
3464 tree::ValueAccessor<BoolTreeType> borderAcc(*mBorderTree);
3467 for (
size_t n = range.begin(); n != range.end(); ++n) {
3469 const BoolLeafNodeType& node = *mMaskNodes[n];
3471 for (
auto it = node.cbeginValueOn(); it; ++it) {
3473 ijk = it.getCoord();
3475 const bool lhs = it.getValue();
3478 bool isEdgeVoxel =
false;
3481 isEdgeVoxel = (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3484 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3487 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3490 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3494 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3497 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3500 isEdgeVoxel = isEdgeVoxel || (maskAcc.probeValue(ijk, rhs) && lhs != rhs);
3504 borderAcc.setValue(ijk,
true);
3511 BoolTreeType
const *
const mMaskTree;
3512 BoolLeafNodeType
const *
const *
const mMaskNodes;
3514 BoolTreeType mTmpBorderTree;
3515 BoolTreeType *
const mBorderTree;
3519template<
typename BoolTreeType>
3520struct SyncMaskValues
3522 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3524 SyncMaskValues(
const std::vector<BoolLeafNodeType*>& nodes,
const BoolTreeType& mask)
3525 : mNodes(nodes.data())
3526 , mMaskTree(&mask) {}
3528 void operator()(
const tbb::blocked_range<size_t>& range)
const
3530 using ValueOnIter =
typename BoolLeafNodeType::ValueOnIter;
3532 tree::ValueAccessor<const BoolTreeType> maskTreeAcc(*mMaskTree);
3534 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3536 BoolLeafNodeType& node = *mNodes[n];
3538 const BoolLeafNodeType * maskNode = maskTreeAcc.probeConstLeaf(node.origin());
3541 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3542 const Index pos = it.pos();
3543 if (maskNode->getValue(pos)) {
3544 node.setValueOnly(pos,
true);
3552 BoolLeafNodeType *
const *
const mNodes;
3553 BoolTreeType
const *
const mMaskTree;
3560template<
typename BoolTreeType>
3563 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3565 MaskSurface(
const std::vector<BoolLeafNodeType*>& nodes,
3566 const BoolTreeType& mask,
3567 const math::Transform& inputTransform,
3568 const math::Transform& maskTransform,
3570 : mNodes(nodes.data())
3572 , mInputTransform(inputTransform)
3573 , mMaskTransform(maskTransform)
3574 , mMatchingTransforms(mInputTransform == mMaskTransform)
3575 , mInvertMask(invert) {}
3577 void operator()(
const tbb::blocked_range<size_t>& range)
const
3579 using ValueOnIter =
typename BoolLeafNodeType::ValueOnIter;
3581 tree::ValueAccessor<const BoolTreeType> maskTreeAcc(*mMaskTree);
3583 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3585 BoolLeafNodeType& node = *mNodes[n];
3587 if (mMatchingTransforms) {
3589 const BoolLeafNodeType * maskNode = maskTreeAcc.probeConstLeaf(node.origin());
3593 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3594 const Index pos = it.pos();
3595 if (maskNode->isValueOn(pos) == mInvertMask) {
3596 node.setValueOnly(pos,
true);
3602 if (maskTreeAcc.isValueOn(node.origin()) == mInvertMask) {
3603 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3604 node.setValueOnly(it.pos(),
true);
3614 for (ValueOnIter it = node.beginValueOn(); it; ++it) {
3616 ijk = mMaskTransform.worldToIndexCellCentered(
3617 mInputTransform.indexToWorld(it.getCoord()));
3619 if (maskTreeAcc.isValueOn(ijk) == mInvertMask) {
3620 node.setValueOnly(it.pos(),
true);
3629 BoolLeafNodeType *
const *
const mNodes;
3630 BoolTreeType
const *
const mMaskTree;
3631 const math::Transform& mInputTransform;
3632 const math::Transform& mMaskTransform;
3633 const bool mMatchingTransforms;
3634 const bool mInvertMask;
3638template<
typename InputGr
idType>
3641 typename InputGridType::TreeType::template ValueConverter<bool>::Type& intersectionTree,
3642 typename InputGridType::TreeType::template ValueConverter<bool>::Type& borderTree,
3643 const InputGridType& inputGrid,
3645 const bool invertMask,
3646 const typename InputGridType::ValueType isovalue)
3648 using InputTreeType =
typename InputGridType::TreeType;
3649 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3650 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3653 if (!maskGrid)
return;
3654 if (maskGrid->type() != BoolGridType::gridType())
return;
3657 const InputTreeType& inputTree = inputGrid.tree();
3659 const BoolGridType * surfaceMask =
static_cast<const BoolGridType*
>(maskGrid.get());
3661 const BoolTreeType& maskTree = surfaceMask->tree();
3666 std::vector<BoolLeafNodeType*> intersectionLeafNodes;
3667 intersectionTree.getNodes(intersectionLeafNodes);
3669 const tbb::blocked_range<size_t> intersectionRange(0, intersectionLeafNodes.size());
3671 tbb::parallel_for(intersectionRange,
3672 MaskSurface<BoolTreeType>(
3673 intersectionLeafNodes, maskTree, transform, maskTransform, invertMask));
3678 MaskBorderVoxels<BoolTreeType> borderOp(
3679 intersectionTree, intersectionLeafNodes, borderTree);
3680 tbb::parallel_reduce(intersectionRange, borderOp);
3685 BoolTreeType tmpIntersectionTree(
false);
3687 MaskIntersectingVoxels<InputTreeType> op(
3688 inputTree, intersectionLeafNodes, tmpIntersectionTree, isovalue);
3690 tbb::parallel_reduce(intersectionRange, op);
3692 std::vector<BoolLeafNodeType*> tmpIntersectionLeafNodes;
3693 tmpIntersectionTree.getNodes(tmpIntersectionLeafNodes);
3695 tbb::parallel_for(tbb::blocked_range<size_t>(0, tmpIntersectionLeafNodes.size()),
3696 SyncMaskValues<BoolTreeType>(tmpIntersectionLeafNodes, intersectionTree));
3698 intersectionTree.clear();
3699 intersectionTree.merge(tmpIntersectionTree);
3706template<
typename InputTreeType>
3707struct ComputeAuxiliaryData
3709 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
3710 using InputValueType =
typename InputLeafNodeType::ValueType;
3712 using BoolLeafNodeType = tree::LeafNode<bool, InputLeafNodeType::LOG2DIM>;
3714 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
3715 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
3718 ComputeAuxiliaryData(
const InputTreeType& inputTree,
3719 const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3720 Int16TreeType& signFlagsTree,
3721 Index32TreeType& pointIndexTree,
3722 InputValueType iso);
3724 ComputeAuxiliaryData(ComputeAuxiliaryData&, tbb::split);
3725 void operator()(
const tbb::blocked_range<size_t>&);
3726 void join(
const ComputeAuxiliaryData& rhs) {
3727 mSignFlagsAccessor.tree().merge(rhs.mSignFlagsAccessor.tree());
3728 mPointIndexAccessor.tree().merge(rhs.mPointIndexAccessor.tree());
3732 tree::ValueAccessor<const InputTreeType> mInputAccessor;
3733 BoolLeafNodeType
const *
const *
const mIntersectionNodes;
3735 Int16TreeType mSignFlagsTree;
3736 tree::ValueAccessor<Int16TreeType> mSignFlagsAccessor;
3737 Index32TreeType mPointIndexTree;
3738 tree::ValueAccessor<Index32TreeType> mPointIndexAccessor;
3740 const InputValueType mIsovalue;
3744template<
typename InputTreeType>
3745ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(
3746 const InputTreeType& inputTree,
3747 const std::vector<const BoolLeafNodeType*>& intersectionLeafNodes,
3748 Int16TreeType& signFlagsTree,
3749 Index32TreeType& pointIndexTree,
3751 : mInputAccessor(inputTree)
3752 , mIntersectionNodes(intersectionLeafNodes.data())
3754 , mSignFlagsAccessor(signFlagsTree)
3755 , mPointIndexTree(std::numeric_limits<
Index32>::
max())
3756 , mPointIndexAccessor(pointIndexTree)
3759 pointIndexTree.root().setBackground(std::numeric_limits<Index32>::max(),
false);
3763template<
typename InputTreeType>
3764ComputeAuxiliaryData<InputTreeType>::ComputeAuxiliaryData(ComputeAuxiliaryData& rhs, tbb::split)
3765 : mInputAccessor(rhs.mInputAccessor.
tree())
3766 , mIntersectionNodes(rhs.mIntersectionNodes)
3768 , mSignFlagsAccessor(mSignFlagsTree)
3769 , mPointIndexTree(std::numeric_limits<
Index32>::
max())
3770 , mPointIndexAccessor(mPointIndexTree)
3771 , mIsovalue(rhs.mIsovalue)
3776template<
typename InputTreeType>
3778ComputeAuxiliaryData<InputTreeType>::operator()(
const tbb::blocked_range<size_t>& range)
3780 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
3783 std::array<InputValueType, 8> cellVertexValues;
3784 std::unique_ptr<Int16LeafNodeType> signsNodePt(
nullptr);
3786 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3788 const BoolLeafNodeType& maskNode = *mIntersectionNodes[n];
3789 const Coord& origin = maskNode.origin();
3791 const InputLeafNodeType* leafPt = mInputAccessor.probeConstLeaf(origin);
3793 if (!signsNodePt.get()) signsNodePt.
reset(
new Int16LeafNodeType(origin, 0));
3794 else signsNodePt->setOrigin(origin);
3796 bool updatedNode =
false;
3798 for (
auto it = maskNode.cbeginValueOn(); it; ++it) {
3800 const Index pos = it.pos();
3801 ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
3803 const bool inclusiveCell = leafPt && isInternalLeafCoord<InputLeafNodeType>(ijk);
3805 if (inclusiveCell) getCellVertexValues(*leafPt, pos, cellVertexValues);
3806 else getCellVertexValues(mInputAccessor, origin + ijk, cellVertexValues);
3808 uint8_t signFlags = computeSignFlags(cellVertexValues, mIsovalue);
3810 if (signFlags != 0 && signFlags != 0xFF) {
3812 const bool inside = signFlags & 0x1;
3814 int edgeFlags = inside ? INSIDE : 0;
3816 if (!it.getValue()) {
3817 edgeFlags |= inside != ((signFlags & 0x02) != 0) ? XEDGE : 0;
3818 edgeFlags |= inside != ((signFlags & 0x10) != 0) ? YEDGE : 0;
3819 edgeFlags |= inside != ((signFlags & 0x08) != 0) ? ZEDGE : 0;
3822 const uint8_t ambiguousCellFlags = sAmbiguousFace[signFlags];
3823 if (ambiguousCellFlags != 0) {
3824 correctCellSigns(signFlags, ambiguousCellFlags, mInputAccessor,
3825 origin + ijk, mIsovalue);
3828 edgeFlags |= int(signFlags);
3830 signsNodePt->setValueOn(pos,
Int16(edgeFlags));
3836 typename Index32TreeType::LeafNodeType* idxNode =
3837 mPointIndexAccessor.touchLeaf(origin);
3838 idxNode->topologyUnion(*signsNodePt);
3841 auto*
const idxData = idxNode->buffer().data();
3842 for (
auto it = idxNode->beginValueOn(); it; ++it) {
3843 idxData[it.pos()] = 0;
3846 mSignFlagsAccessor.addLeaf(signsNodePt.release());
3852template<
typename InputTreeType>
3854computeAuxiliaryData(
3855 typename InputTreeType::template ValueConverter<Int16>::Type& signFlagsTree,
3856 typename InputTreeType::template ValueConverter<Index32>::Type& pointIndexTree,
3857 const typename InputTreeType::template ValueConverter<bool>::Type& intersectionTree,
3858 const InputTreeType& inputTree,
3859 typename InputTreeType::ValueType isovalue)
3861 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
3862 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
3864 std::vector<const BoolLeafNodeType*> intersectionLeafNodes;
3865 intersectionTree.getNodes(intersectionLeafNodes);
3867 ComputeAuxiliaryData<InputTreeType> op(
3868 inputTree, intersectionLeafNodes, signFlagsTree, pointIndexTree, isovalue);
3870 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, intersectionLeafNodes.size()), op);
3877template<Index32 LeafNodeLog2Dim>
3878struct LeafNodePointCount
3880 using Int16LeafNodeType = tree::LeafNode<Int16, LeafNodeLog2Dim>;
3882 LeafNodePointCount(
const std::vector<Int16LeafNodeType*>& leafNodes,
3883 std::unique_ptr<Index32[]>& leafNodeCount)
3884 : mLeafNodes(leafNodes.data())
3885 , mData(leafNodeCount.get()) {}
3887 void operator()(
const tbb::blocked_range<size_t>& range)
const {
3889 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3893 Int16 const * p = mLeafNodes[n]->buffer().data();
3894 Int16 const *
const endP = p + Int16LeafNodeType::SIZE;
3897 count +=
Index32(sEdgeGroupTable[(SIGNS & *p)][0]);
3906 Int16LeafNodeType *
const *
const mLeafNodes;
3911template<
typename Po
intIndexLeafNode>
3912struct AdaptiveLeafNodePointCount
3914 using Int16LeafNodeType = tree::LeafNode<Int16, PointIndexLeafNode::LOG2DIM>;
3916 AdaptiveLeafNodePointCount(
const std::vector<PointIndexLeafNode*>& pointIndexNodes,
3917 const std::vector<Int16LeafNodeType*>& signDataNodes,
3918 std::unique_ptr<Index32[]>& leafNodeCount)
3919 : mPointIndexNodes(pointIndexNodes.data())
3920 , mSignDataNodes(signDataNodes.data())
3921 , mData(leafNodeCount.get()) {}
3923 void operator()(
const tbb::blocked_range<size_t>& range)
const
3925 using IndexType =
typename PointIndexLeafNode::ValueType;
3927 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3929 const PointIndexLeafNode& node = *mPointIndexNodes[n];
3930 const Int16LeafNodeType& signNode = *mSignDataNodes[n];
3934 std::set<IndexType> uniqueRegions;
3936 for (
typename PointIndexLeafNode::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
3938 IndexType
id = it.getValue();
3941 count += size_t(sEdgeGroupTable[(SIGNS & signNode.getValue(it.pos()))][0]);
3942 }
else if (
id != IndexType(util::INVALID_IDX)) {
3943 uniqueRegions.insert(
id);
3947 mData[n] =
Index32(count + uniqueRegions.size());
3952 PointIndexLeafNode
const *
const *
const mPointIndexNodes;
3953 Int16LeafNodeType
const *
const *
const mSignDataNodes;
3958template<
typename Po
intIndexLeafNode>
3961 using Int16LeafNodeType = tree::LeafNode<Int16, PointIndexLeafNode::LOG2DIM>;
3963 MapPoints(
const std::vector<PointIndexLeafNode*>& pointIndexNodes,
3964 const std::vector<Int16LeafNodeType*>& signDataNodes,
3965 std::unique_ptr<Index32[]>& leafNodeCount)
3966 : mPointIndexNodes(pointIndexNodes.data())
3967 , mSignDataNodes(signDataNodes.data())
3968 , mData(leafNodeCount.get()) {}
3970 void operator()(
const tbb::blocked_range<size_t>& range)
const {
3972 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
3974 const Int16LeafNodeType& signNode = *mSignDataNodes[n];
3975 PointIndexLeafNode& indexNode = *mPointIndexNodes[n];
3977 Index32 pointOffset = mData[n];
3979 for (
auto it = indexNode.beginValueOn(); it; ++it) {
3980 const Index pos = it.pos();
3981 indexNode.setValueOnly(pos, pointOffset);
3982 const int signs = SIGNS & int(signNode.getValue(pos));
3983 pointOffset +=
Index32(sEdgeGroupTable[signs][0]);
3989 PointIndexLeafNode *
const *
const mPointIndexNodes;
3990 Int16LeafNodeType
const *
const *
const mSignDataNodes;
3995template<
typename TreeType,
typename PrimBuilder>
3996struct ComputePolygons
3998 using Int16TreeType =
typename TreeType::template ValueConverter<Int16>::Type;
3999 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
4001 using Index32TreeType =
typename TreeType::template ValueConverter<Index32>::Type;
4002 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
4005 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4006 const Int16TreeType& signFlagsTree,
4007 const Index32TreeType& idxTree,
4008 PolygonPoolList& polygons,
4009 bool invertSurfaceOrientation);
4011 void setRefSignTree(
const Int16TreeType * r) { mRefSignFlagsTree = r; }
4013 void operator()(
const tbb::blocked_range<size_t>&)
const;
4016 Int16LeafNodeType *
const *
const mSignFlagsLeafNodes;
4017 Int16TreeType
const *
const mSignFlagsTree;
4018 Int16TreeType
const * mRefSignFlagsTree;
4019 Index32TreeType
const *
const mIndexTree;
4021 bool const mInvertSurfaceOrientation;
4025template<
typename TreeType,
typename PrimBuilder>
4026ComputePolygons<TreeType, PrimBuilder>::ComputePolygons(
4027 const std::vector<Int16LeafNodeType*>& signFlagsLeafNodes,
4028 const Int16TreeType& signFlagsTree,
4029 const Index32TreeType& idxTree,
4030 PolygonPoolList& polygons,
4031 bool invertSurfaceOrientation)
4032 : mSignFlagsLeafNodes(signFlagsLeafNodes.data())
4033 , mSignFlagsTree(&signFlagsTree)
4034 , mRefSignFlagsTree(nullptr)
4035 , mIndexTree(&idxTree)
4036 , mPolygonPoolList(&polygons)
4037 , mInvertSurfaceOrientation(invertSurfaceOrientation)
4041template<
typename InputTreeType,
typename PrimBuilder>
4043ComputePolygons<InputTreeType, PrimBuilder>::operator()(
const tbb::blocked_range<size_t>& range)
const
4046 Int16ValueAccessor signAcc(*mSignFlagsTree);
4050 const bool invertSurfaceOrientation = mInvertSurfaceOrientation;
4057 std::unique_ptr<Int16ValueAccessor> refSignAcc;
4058 if (mRefSignFlagsTree) refSignAcc.
reset(
new Int16ValueAccessor(*mRefSignFlagsTree));
4060 for (
size_t n = range.begin(); n != range.end(); ++n) {
4062 const Int16LeafNodeType& node = *mSignFlagsLeafNodes[n];
4063 origin = node.origin();
4067 typename Int16LeafNodeType::ValueOnCIter iter = node.cbeginValueOn();
4068 for (; iter; ++iter) {
4069 if (iter.getValue() & XEDGE) ++edgeCount;
4070 if (iter.getValue() & YEDGE) ++edgeCount;
4071 if (iter.getValue() & ZEDGE) ++edgeCount;
4074 if (edgeCount == 0)
continue;
4076 mesher.init(edgeCount, (*mPolygonPoolList)[n]);
4078 const Int16LeafNodeType *signleafPt = signAcc.probeConstLeaf(origin);
4079 const Index32LeafNodeType *idxLeafPt = idxAcc.probeConstLeaf(origin);
4081 if (!signleafPt || !idxLeafPt)
continue;
4083 const Int16LeafNodeType *refSignLeafPt =
nullptr;
4084 if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(origin);
4088 for (iter = node.cbeginValueOn(); iter; ++iter) {
4089 ijk = iter.getCoord();
4091 const Int16 flags = iter.getValue();
4092 if (!(flags & 0xE00))
continue;
4095 if (refSignLeafPt) {
4096 refFlags = refSignLeafPt->getValue(iter.pos());
4099 const uint8_t cell = uint8_t(SIGNS & flags);
4101 if (sEdgeGroupTable[cell][0] > 1) {
4102 offsets[0] = (sEdgeGroupTable[cell][1] - 1);
4103 offsets[1] = (sEdgeGroupTable[cell][9] - 1);
4104 offsets[2] = (sEdgeGroupTable[cell][4] - 1);
4110 if (ijk[0] > origin[0] && ijk[1] > origin[1] && ijk[2] > origin[2]) {
4111 constructPolygons(invertSurfaceOrientation,
4112 flags, refFlags, offsets, ijk, *signleafPt, *idxLeafPt, mesher);
4114 constructPolygons(invertSurfaceOrientation,
4115 flags, refFlags, offsets, ijk, signAcc, idxAcc, mesher);
4131 CopyArray(T * outputArray,
const T * inputArray,
size_t outputOffset = 0)
4132 : mOutputArray(outputArray), mInputArray(inputArray), mOutputOffset(outputOffset)
4136 void operator()(
const tbb::blocked_range<size_t>& inputArrayRange)
const
4138 const size_t offset = mOutputOffset;
4139 for (
size_t n = inputArrayRange.begin(), N = inputArrayRange.end(); n < N; ++n) {
4140 mOutputArray[offset + n] = mInputArray[n];
4145 T *
const mOutputArray;
4146 T
const *
const mInputArray;
4147 size_t const mOutputOffset;
4151struct FlagAndCountQuadsToSubdivide
4153 FlagAndCountQuadsToSubdivide(PolygonPoolList& polygons,
4154 const std::vector<uint8_t>& pointFlags,
4156 std::unique_ptr<
unsigned[]>& numQuadsToDivide)
4157 : mPolygonPoolList(&polygons)
4158 , mPointFlags(pointFlags.data())
4159 , mPoints(points.get())
4160 , mNumQuadsToDivide(numQuadsToDivide.get())
4164 void operator()(
const tbb::blocked_range<size_t>& range)
const
4166 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4168 PolygonPool& polygons = (*mPolygonPoolList)[n];
4173 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4175 char& flags = polygons.quadFlags(i);
4177 if ((flags & POLYFLAG_FRACTURE_SEAM) && !(flags & POLYFLAG_EXTERIOR)) {
4179 Vec4I& quad = polygons.quad(i);
4181 const bool edgePoly = mPointFlags[quad[0]] || mPointFlags[quad[1]]
4182 || mPointFlags[quad[2]] || mPointFlags[quad[3]];
4184 if (!edgePoly)
continue;
4186 const Vec3s& p0 = mPoints[quad[0]];
4187 const Vec3s& p1 = mPoints[quad[1]];
4188 const Vec3s& p2 = mPoints[quad[2]];
4189 const Vec3s& p3 = mPoints[quad[3]];
4191 if (!isPlanarQuad(p0, p1, p2, p3, 1e-6f)) {
4198 mNumQuadsToDivide[n] = count;
4204 uint8_t
const *
const mPointFlags;
4205 Vec3s const *
const mPoints;
4206 unsigned *
const mNumQuadsToDivide;
4210struct SubdivideQuads
4212 SubdivideQuads(PolygonPoolList& polygons,
4216 std::unique_ptr<
unsigned[]>& numQuadsToDivide,
4217 std::unique_ptr<
unsigned[]>& centroidOffsets)
4218 : mPolygonPoolList(&polygons)
4219 , mPoints(points.get())
4220 , mCentroids(centroids.get())
4221 , mNumQuadsToDivide(numQuadsToDivide.get())
4222 , mCentroidOffsets(centroidOffsets.get())
4227 void operator()(
const tbb::blocked_range<size_t>& range)
const
4229 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4231 PolygonPool& polygons = (*mPolygonPoolList)[n];
4233 const size_t nonplanarCount = size_t(mNumQuadsToDivide[n]);
4235 if (nonplanarCount > 0) {
4237 PolygonPool tmpPolygons;
4238 tmpPolygons.resetQuads(polygons.numQuads() - nonplanarCount);
4239 tmpPolygons.resetTriangles(polygons.numTriangles() +
size_t(4) * nonplanarCount);
4241 size_t offset = mCentroidOffsets[n];
4243 size_t triangleIdx = 0;
4245 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4247 const char quadFlags = polygons.quadFlags(i);
4248 if (!(quadFlags & POLYFLAG_SUBDIVIDED))
continue;
4250 unsigned newPointIdx = unsigned(offset + mPointCount);
4254 mCentroids[offset] = (mPoints[quad[0]] + mPoints[quad[1]] +
4255 mPoints[quad[2]] + mPoints[quad[3]]) * 0.25f;
4260 Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4262 triangle[0] = quad[0];
4263 triangle[1] = newPointIdx;
4264 triangle[2] = quad[3];
4266 tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4272 Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4274 triangle[0] = quad[0];
4275 triangle[1] = quad[1];
4276 triangle[2] = newPointIdx;
4278 tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4284 Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4286 triangle[0] = quad[1];
4287 triangle[1] = quad[2];
4288 triangle[2] = newPointIdx;
4290 tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4297 Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
4299 triangle[0] = quad[2];
4300 triangle[1] = quad[3];
4301 triangle[2] = newPointIdx;
4303 tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
4308 quad[0] = util::INVALID_IDX;
4312 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4313 tmpPolygons.triangle(triangleIdx) = polygons.triangle(i);
4314 tmpPolygons.triangleFlags(triangleIdx) = polygons.triangleFlags(i);
4319 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4322 if (quad[0] != util::INVALID_IDX) {
4323 tmpPolygons.quad(quadIdx) = quad;
4324 tmpPolygons.quadFlags(quadIdx) = polygons.quadFlags(i);
4329 polygons.copy(tmpPolygons);
4336 Vec3s const *
const mPoints;
4337 Vec3s *
const mCentroids;
4338 unsigned *
const mNumQuadsToDivide;
4339 unsigned *
const mCentroidOffsets;
4340 size_t const mPointCount;
4345subdivideNonplanarSeamLineQuads(
4346 PolygonPoolList& polygonPoolList,
4347 size_t polygonPoolListSize,
4348 PointList& pointList,
4349 size_t& pointListSize,
4350 std::vector<uint8_t>& pointFlags)
4352 const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4354 std::unique_ptr<unsigned[]> numQuadsToDivide(
new unsigned[polygonPoolListSize]);
4356 tbb::parallel_for(polygonPoolListRange,
4357 FlagAndCountQuadsToSubdivide(polygonPoolList, pointFlags, pointList, numQuadsToDivide));
4359 std::unique_ptr<unsigned[]> centroidOffsets(
new unsigned[polygonPoolListSize]);
4361 size_t centroidCount = 0;
4365 for (
size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4366 centroidOffsets[n] = sum;
4367 sum += numQuadsToDivide[n];
4369 centroidCount = size_t(sum);
4372 std::unique_ptr<Vec3s[]> centroidList(
new Vec3s[centroidCount]);
4374 tbb::parallel_for(polygonPoolListRange,
4375 SubdivideQuads(polygonPoolList, pointList, pointListSize,
4376 centroidList, numQuadsToDivide, centroidOffsets));
4378 if (centroidCount > 0) {
4380 const size_t newPointListSize = centroidCount + pointListSize;
4382 std::unique_ptr<openvdb::Vec3s[]> newPointList(
new openvdb::Vec3s[newPointListSize]);
4384 tbb::parallel_for(tbb::blocked_range<size_t>(0, pointListSize),
4385 CopyArray<Vec3s>(newPointList.get(), pointList.get()));
4387 tbb::parallel_for(tbb::blocked_range<size_t>(0, newPointListSize - pointListSize),
4388 CopyArray<Vec3s>(newPointList.get(), centroidList.get(), pointListSize));
4390 pointListSize = newPointListSize;
4391 pointList.swap(newPointList);
4392 pointFlags.resize(pointListSize, 0);
4397struct ReviseSeamLineFlags
4399 ReviseSeamLineFlags(PolygonPoolList& polygons,
4400 const std::vector<uint8_t>& pointFlags)
4401 : mPolygonPoolList(&polygons)
4402 , mPointFlags(pointFlags.data())
4406 void operator()(
const tbb::blocked_range<size_t>& range)
const
4408 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4410 PolygonPool& polygons = (*mPolygonPoolList)[n];
4412 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4414 char& flags = polygons.quadFlags(i);
4416 if (flags & POLYFLAG_FRACTURE_SEAM) {
4420 const bool hasSeamLinePoint =
4421 mPointFlags[verts[0]] || mPointFlags[verts[1]] ||
4422 mPointFlags[verts[2]] || mPointFlags[verts[3]];
4424 if (!hasSeamLinePoint) {
4425 flags &= ~POLYFLAG_FRACTURE_SEAM;
4430 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4432 char& flags = polygons.triangleFlags(i);
4434 if (flags & POLYFLAG_FRACTURE_SEAM) {
4438 const bool hasSeamLinePoint =
4439 mPointFlags[verts[0]] || mPointFlags[verts[1]] || mPointFlags[verts[2]];
4441 if (!hasSeamLinePoint) {
4442 flags &= ~POLYFLAG_FRACTURE_SEAM;
4453 uint8_t
const *
const mPointFlags;
4458reviseSeamLineFlags(PolygonPoolList& polygonPoolList,
size_t polygonPoolListSize,
4459 std::vector<uint8_t>& pointFlags)
4461 tbb::parallel_for(tbb::blocked_range<size_t>(0, polygonPoolListSize),
4462 ReviseSeamLineFlags(polygonPoolList, pointFlags));
4469template<
typename InputTreeType>
4470struct MaskDisorientedTrianglePoints
4472 MaskDisorientedTrianglePoints(
const InputTreeType& inputTree,
const PolygonPoolList& polygons,
4473 const PointList& pointList, std::unique_ptr<uint8_t[]>& pointMask,
4474 const math::Transform& transform,
bool invertSurfaceOrientation)
4475 : mInputTree(&inputTree)
4476 , mPolygonPoolList(&polygons)
4477 , mPointList(&pointList)
4478 , mPointMask(pointMask.get())
4479 , mTransform(transform)
4480 , mInvertSurfaceOrientation(invertSurfaceOrientation)
4484 void operator()(
const tbb::blocked_range<size_t>& range)
const
4486 using ValueType =
typename InputTreeType::LeafNodeType::ValueType;
4488 tree::ValueAccessor<const InputTreeType> inputAcc(*mInputTree);
4489 Vec3s centroid, normal;
4492 const bool invertGradientDir = mInvertSurfaceOrientation || isBoolValue<ValueType>();
4494 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
4496 const PolygonPool& polygons = (*mPolygonPoolList)[n];
4498 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4500 const Vec3I& verts = polygons.triangle(i);
4502 const Vec3s& v0 = (*mPointList)[verts[0]];
4503 const Vec3s& v1 = (*mPointList)[verts[1]];
4504 const Vec3s& v2 = (*mPointList)[verts[2]];
4506 normal = (v2 - v0).cross((v1 - v0));
4509 centroid = (v0 + v1 + v2) * (1.0f / 3.0f);
4510 ijk = mTransform.worldToIndexCellCentered(centroid);
4512 Vec3s dir( math::ISGradient<math::CD_2ND>::result(inputAcc, ijk) );
4515 if (invertGradientDir) {
4520 if (dir.dot(normal) < -0.5f) {
4525 mPointMask[verts[0]] = 1;
4526 mPointMask[verts[1]] = 1;
4527 mPointMask[verts[2]] = 1;
4536 InputTreeType
const *
const mInputTree;
4539 uint8_t *
const mPointMask;
4540 math::Transform
const mTransform;
4541 bool const mInvertSurfaceOrientation;
4545template<
typename InputTree>
4547relaxDisorientedTriangles(
4548 bool invertSurfaceOrientation,
4549 const InputTree& inputTree,
4551 PolygonPoolList& polygonPoolList,
4552 size_t polygonPoolListSize,
4553 PointList& pointList,
4554 const size_t pointListSize)
4556 const tbb::blocked_range<size_t> polygonPoolListRange(0, polygonPoolListSize);
4558 std::unique_ptr<uint8_t[]> pointMask(
new uint8_t[pointListSize]);
4559 fillArray(pointMask.get(), uint8_t(0), pointListSize);
4561 tbb::parallel_for(polygonPoolListRange,
4562 MaskDisorientedTrianglePoints<InputTree>(
4563 inputTree, polygonPoolList, pointList, pointMask, transform, invertSurfaceOrientation));
4565 std::unique_ptr<uint8_t[]> pointUpdates(
new uint8_t[pointListSize]);
4566 fillArray(pointUpdates.get(), uint8_t(0), pointListSize);
4568 std::unique_ptr<Vec3s[]> newPoints(
new Vec3s[pointListSize]);
4569 fillArray(newPoints.get(),
Vec3s(0.0f, 0.0f, 0.0f), pointListSize);
4571 for (
size_t n = 0, N = polygonPoolListSize; n < N; ++n) {
4573 PolygonPool& polygons = polygonPoolList[n];
4575 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4578 for (
int v = 0; v < 4; ++v) {
4580 const unsigned pointIdx = verts[v];
4582 if (pointMask[pointIdx] == 1) {
4584 newPoints[pointIdx] +=
4585 pointList[verts[0]] + pointList[verts[1]] +
4586 pointList[verts[2]] + pointList[verts[3]];
4588 pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 4);
4593 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4596 for (
int v = 0; v < 3; ++v) {
4598 const unsigned pointIdx = verts[v];
4600 if (pointMask[pointIdx] == 1) {
4601 newPoints[pointIdx] +=
4602 pointList[verts[0]] + pointList[verts[1]] + pointList[verts[2]];
4604 pointUpdates[pointIdx] = uint8_t(pointUpdates[pointIdx] + 3);
4610 for (
size_t n = 0, N = pointListSize; n < N; ++n) {
4611 if (pointUpdates[n] > 0) {
4612 const double weight = 1.0 / double(pointUpdates[n]);
4613 pointList[n] = newPoints[n] * float(weight);
4619template<
typename Gr
idType>
4622 const GridType& grid,
4623 std::vector<Vec3s>&
points,
4624 std::vector<Vec3I>& triangles,
4625 std::vector<Vec4I>& quads,
4628 bool relaxDisorientedTriangles)
4630 static_assert(std::is_scalar<typename GridType::ValueType>::value,
4631 "volume to mesh conversion is supported only for scalar grids");
4633 VolumeToMesh mesher(isovalue, adaptivity, relaxDisorientedTriangles);
4638 points.resize(mesher.pointListSize());
4641 volume_to_mesh_internal::PointListCopy ptnCpy(mesher.pointList(),
points);
4642 tbb::parallel_for(tbb::blocked_range<size_t>(0,
points.size()), ptnCpy);
4643 mesher.pointList().reset(
nullptr);
4649 size_t numQuads = 0, numTriangles = 0;
4650 for (
size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
4651 openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
4652 numTriangles += polygons.numTriangles();
4653 numQuads += polygons.numQuads();
4657 triangles.resize(numTriangles);
4659 quads.resize(numQuads);
4663 size_t qIdx = 0, tIdx = 0;
4664 for (
size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
4665 openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
4667 for (
size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
4668 quads[qIdx++] = polygons.quad(i);
4671 for (
size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
4672 triangles[tIdx++] = polygons.triangle(i);
4690 , mTriangles(nullptr)
4691 , mQuadFlags(nullptr)
4692 , mTriangleFlags(nullptr)
4703 , mQuadFlags(new char[mNumQuads])
4704 , mTriangleFlags(new char[mNumTriangles])
4715 for (
size_t i = 0; i < mNumQuads; ++i) {
4716 mQuads[i] = rhs.mQuads[i];
4717 mQuadFlags[i] = rhs.mQuadFlags[i];
4720 for (
size_t i = 0; i < mNumTriangles; ++i) {
4721 mTriangles[i] = rhs.mTriangles[i];
4722 mTriangleFlags[i] = rhs.mTriangleFlags[i];
4732 mQuadFlags.reset(
new char[mNumQuads]);
4740 mQuads.reset(
nullptr);
4741 mQuadFlags.reset(
nullptr);
4748 mNumTriangles = size;
4750 mTriangleFlags.reset(
new char[mNumTriangles]);
4758 mTriangles.reset(
nullptr);
4759 mTriangleFlags.reset(
nullptr);
4766 if (!(n < mNumQuads))
return false;
4771 mQuads.reset(
nullptr);
4775 std::unique_ptr<char[]> flags(
new char[n]);
4777 for (
size_t i = 0; i < n; ++i) {
4778 quads[i] = mQuads[i];
4779 flags[i] = mQuadFlags[i];
4783 mQuadFlags.swap(flags);
4795 if (!(n < mNumTriangles))
return false;
4800 mTriangles.reset(
nullptr);
4803 std::unique_ptr<openvdb::Vec3I[]> triangles(
new openvdb::Vec3I[n]);
4804 std::unique_ptr<char[]> flags(
new char[n]);
4806 for (
size_t i = 0; i < n; ++i) {
4807 triangles[i] = mTriangles[i];
4808 flags[i] = mTriangleFlags[i];
4811 mTriangles.swap(triangles);
4812 mTriangleFlags.swap(flags);
4829 , mSeamPointListSize(0)
4830 , mPolygonPoolListSize(0)
4831 , mIsovalue(isovalue)
4832 , mPrimAdaptivity(adaptivity)
4833 , mSecAdaptivity(0.0)
4835 , mSurfaceMaskGrid(
GridBase::ConstPtr())
4836 , mAdaptivityGrid(
GridBase::ConstPtr())
4837 , mAdaptivityMaskTree(
TreeBase::ConstPtr())
4840 , mInvertSurfaceMask(false)
4841 , mRelaxDisorientedTriangles(relaxDisorientedTriangles)
4842 , mQuantizedSeamPoints(nullptr)
4852 mSecAdaptivity = secAdaptivity;
4857 mSeamPointListSize = 0;
4858 mQuantizedSeamPoints.reset(
nullptr);
4865 mSurfaceMaskGrid = mask;
4866 mInvertSurfaceMask = invertMask;
4873 mAdaptivityGrid = grid;
4880 mAdaptivityMaskTree =
tree;
4884template<
typename InputGr
idType>
4890 using InputTreeType =
typename InputGridType::TreeType;
4891 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
4892 using InputValueType =
typename InputLeafNodeType::ValueType;
4896 using FloatTreeType =
typename InputTreeType::template ValueConverter<float>::Type;
4898 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
4899 using Int16TreeType =
typename InputTreeType::template ValueConverter<Int16>::Type;
4900 using Int16LeafNodeType =
typename Int16TreeType::LeafNodeType;
4901 using Index32TreeType =
typename InputTreeType::template ValueConverter<Index32>::Type;
4902 using Index32LeafNodeType =
typename Index32TreeType::LeafNodeType;
4907 mPolygonPoolListSize = 0;
4909 mPointFlags.
clear();
4914 const InputValueType isovalue = InputValueType(mIsovalue);
4915 const float adaptivityThreshold = float(mPrimAdaptivity);
4916 const bool adaptive = mPrimAdaptivity > 1e-7 || mSecAdaptivity > 1e-7;
4922 const bool invertSurfaceOrientation = (!volume_to_mesh_internal::isBoolValue<InputValueType>()
4927 const InputTreeType& inputTree = inputGrid.tree();
4929 BoolTreeType intersectionTree(
false), adaptivityMask(
false);
4931 if (mAdaptivityMaskTree && mAdaptivityMaskTree->type() == BoolTreeType::treeType()) {
4932 const BoolTreeType *refAdaptivityMask=
4933 static_cast<const BoolTreeType*
>(mAdaptivityMaskTree.get());
4934 adaptivityMask.topologyUnion(*refAdaptivityMask);
4937 Int16TreeType signFlagsTree(0);
4938 Index32TreeType pointIndexTree(std::numeric_limits<Index32>::max());
4943 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
4944 intersectionTree, inputTree, isovalue);
4946 volume_to_mesh_internal::applySurfaceMask(intersectionTree, adaptivityMask,
4947 inputGrid, mSurfaceMaskGrid, mInvertSurfaceMask, isovalue);
4949 if (intersectionTree.empty())
return;
4951 volume_to_mesh_internal::computeAuxiliaryData(
4952 signFlagsTree, pointIndexTree, intersectionTree, inputTree, isovalue);
4954 intersectionTree.clear();
4956 std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
4957 pointIndexTree.getNodes(pointIndexLeafNodes);
4959 std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
4960 signFlagsTree.getNodes(signFlagsLeafNodes);
4962 const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
4967 Int16TreeType* refSignFlagsTree =
nullptr;
4968 Index32TreeType* refPointIndexTree =
nullptr;
4969 InputTreeType
const* refInputTree =
nullptr;
4971 if (mRefGrid && mRefGrid->type() == InputGridType::gridType()) {
4973 const InputGridType* refGrid =
static_cast<const InputGridType*
>(mRefGrid.get());
4974 refInputTree = &refGrid->tree();
4976 if (!mRefSignTree && !mRefIdxTree) {
4980 typename Int16TreeType::Ptr refSignFlagsTreePt(
new Int16TreeType(0));
4981 typename Index32TreeType::Ptr refPointIndexTreePt(
4982 new Index32TreeType(std::numeric_limits<Index32>::max()));
4984 BoolTreeType refIntersectionTree(
false);
4986 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
4987 refIntersectionTree, *refInputTree, isovalue);
4989 volume_to_mesh_internal::computeAuxiliaryData(*refSignFlagsTreePt,
4990 *refPointIndexTreePt, refIntersectionTree, *refInputTree, isovalue);
4992 mRefSignTree = refSignFlagsTreePt;
4993 mRefIdxTree = refPointIndexTreePt;
4996 if (mRefSignTree && mRefIdxTree) {
5000 refSignFlagsTree =
static_cast<Int16TreeType*
>(mRefSignTree.get());
5001 refPointIndexTree =
static_cast<Index32TreeType*
>(mRefIdxTree.get());
5005 if (refSignFlagsTree && refPointIndexTree) {
5009 volume_to_mesh_internal::markSeamLineData(signFlagsTree, *refSignFlagsTree);
5011 if (mSeamPointListSize == 0) {
5015 std::vector<Int16LeafNodeType*> refSignFlagsLeafNodes;
5016 refSignFlagsTree->getNodes(refSignFlagsLeafNodes);
5018 std::unique_ptr<Index32[]> leafNodeOffsets(
5019 new Index32[refSignFlagsLeafNodes.size()]);
5021 tbb::parallel_for(tbb::blocked_range<size_t>(0, refSignFlagsLeafNodes.size()),
5022 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>(
5023 refSignFlagsLeafNodes, leafNodeOffsets));
5027 for (
size_t n = 0, N = refSignFlagsLeafNodes.size(); n < N; ++n) {
5028 const Index32 tmp = leafNodeOffsets[n];
5029 leafNodeOffsets[n] = count;
5032 mSeamPointListSize = size_t(count);
5035 if (mSeamPointListSize != 0) {
5037 mQuantizedSeamPoints.reset(
new uint32_t[mSeamPointListSize]);
5039 std::memset(mQuantizedSeamPoints.get(), 0,
sizeof(uint32_t) * mSeamPointListSize);
5041 std::vector<Index32LeafNodeType*> refPointIndexLeafNodes;
5042 refPointIndexTree->getNodes(refPointIndexLeafNodes);
5044 tbb::parallel_for(tbb::blocked_range<size_t>(0, refPointIndexLeafNodes.size()),
5045 volume_to_mesh_internal::MapPoints<Index32LeafNodeType>(
5046 refPointIndexLeafNodes, refSignFlagsLeafNodes, leafNodeOffsets));
5050 if (mSeamPointListSize != 0) {
5052 tbb::parallel_for(auxiliaryLeafNodeRange,
5053 volume_to_mesh_internal::SeamLineWeights<InputTreeType>(
5054 signFlagsLeafNodes, inputTree, *refPointIndexTree, *refSignFlagsTree,
5055 mQuantizedSeamPoints.get(), isovalue));
5060 const bool referenceMeshing = refSignFlagsTree && refPointIndexTree && refInputTree;
5065 std::unique_ptr<Index32[]> leafNodeOffsets(
new Index32[signFlagsLeafNodes.size()]);
5068 volume_to_mesh_internal::MergeVoxelRegions<InputGridType> mergeOp(
5069 inputGrid, pointIndexTree, pointIndexLeafNodes, signFlagsLeafNodes,
5070 isovalue, adaptivityThreshold, invertSurfaceOrientation);
5072 if (mAdaptivityGrid && mAdaptivityGrid->type() == FloatGridType::gridType()) {
5073 const FloatGridType* adaptivityGrid =
5074 static_cast<const FloatGridType*
>(mAdaptivityGrid.get());
5075 mergeOp.setSpatialAdaptivity(*adaptivityGrid);
5078 if (!adaptivityMask.empty()) {
5079 mergeOp.setAdaptivityMask(adaptivityMask);
5082 if (referenceMeshing) {
5083 mergeOp.setRefSignFlagsData(*refSignFlagsTree,
float(mSecAdaptivity));
5086 tbb::parallel_for(auxiliaryLeafNodeRange, mergeOp);
5088 volume_to_mesh_internal::AdaptiveLeafNodePointCount<Index32LeafNodeType>
5089 op(pointIndexLeafNodes, signFlagsLeafNodes, leafNodeOffsets);
5091 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5095 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
5096 op(signFlagsLeafNodes, leafNodeOffsets);
5098 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5104 for (
size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
5105 const Index32 tmp = leafNodeOffsets[n];
5106 leafNodeOffsets[n] = pointCount;
5110 mPointListSize = size_t(pointCount);
5112 mPointFlags.clear();
5119 volume_to_mesh_internal::ComputePoints<InputTreeType>
5120 op(mPoints.get(), inputTree, pointIndexLeafNodes,
5121 signFlagsLeafNodes, leafNodeOffsets, transform, mIsovalue);
5123 if (referenceMeshing) {
5124 mPointFlags.resize(mPointListSize);
5125 op.setRefData(*refInputTree, *refPointIndexTree, *refSignFlagsTree,
5126 mQuantizedSeamPoints.get(), mPointFlags.data());
5129 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5135 mPolygonPoolListSize = signFlagsLeafNodes.size();
5136 mPolygons.reset(
new PolygonPool[mPolygonPoolListSize]);
5140 using PrimBuilder = volume_to_mesh_internal::AdaptivePrimBuilder;
5142 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
5143 op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5144 mPolygons, invertSurfaceOrientation);
5146 if (referenceMeshing) {
5147 op.setRefSignTree(refSignFlagsTree);
5150 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5154 using PrimBuilder = volume_to_mesh_internal::UniformPrimBuilder;
5156 volume_to_mesh_internal::ComputePolygons<Int16TreeType, PrimBuilder>
5157 op(signFlagsLeafNodes, signFlagsTree, pointIndexTree,
5158 mPolygons, invertSurfaceOrientation);
5160 if (referenceMeshing) {
5161 op.setRefSignTree(refSignFlagsTree);
5164 tbb::parallel_for(auxiliaryLeafNodeRange, op);
5168 signFlagsTree.clear();
5169 pointIndexTree.clear();
5172 if (adaptive && mRelaxDisorientedTriangles) {
5173 volume_to_mesh_internal::relaxDisorientedTriangles(invertSurfaceOrientation,
5174 inputTree, transform, mPolygons, mPolygonPoolListSize, mPoints, mPointListSize);
5178 if (referenceMeshing) {
5179 volume_to_mesh_internal::subdivideNonplanarSeamLineQuads(
5180 mPolygons, mPolygonPoolListSize, mPoints, mPointListSize, mPointFlags);
5182 volume_to_mesh_internal::reviseSeamLineFlags(mPolygons, mPolygonPoolListSize, mPointFlags);
5191template<
typename Gr
idType>
5193 const GridType& grid,
5194 std::vector<Vec3s>&
points,
5195 std::vector<Vec3I>& triangles,
5196 std::vector<Vec4I>& quads,
5199 bool relaxDisorientedTriangles)
5201 volume_to_mesh_internal::doVolumeToMesh(grid,
points, triangles, quads,
5202 isovalue, adaptivity, relaxDisorientedTriangles);
5205template<
typename Gr
idType>
5207 const GridType& grid,
5208 std::vector<Vec3s>&
points,
5209 std::vector<Vec4I>& quads,
5212 std::vector<Vec3I> triangles;
5222#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
5224#ifdef OPENVDB_INSTANTIATE_VOLUMETOMESH
5228#define _FUNCTION(TreeT) \
5229 void volumeToMesh(const Grid<TreeT>&, std::vector<Vec3s>&, std::vector<Vec4I>&, double)
5233#define _FUNCTION(TreeT) \
5234 void volumeToMesh(const Grid<TreeT>&, std::vector<Vec3s>&, std::vector<Vec3I>&, std::vector<Vec4I>&, double, double, bool)
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
Abstract base class for typed grids.
Definition Grid.h:79
SharedPtr< const GridBase > ConstPtr
Definition Grid.h:82
Container class that associates a tree with a transform and metadata.
Definition Grid.h:571
void clear() override
Empty this grid, so that all voxels become inactive background voxels.
Definition Grid.h:727
Definition Exceptions.h:65
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition Coord.h:92
Coord & reset(Int32 x, Int32 y, Int32 z)
Reset all three coordinates with the specified arguments.
Definition Coord.h:70
Mat3 transpose() const
returns transpose of this
Definition Mat3.h:454
static const Mat3< double > & identity()
Definition Mat3.h:121
T dot(const Vec3< T > &v) const
Dot product.
Definition Vec3.h:192
T & z()
Definition Vec3.h:88
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition Vec3.h:363
SharedPtr< TreeBase > Ptr
Definition Tree.h:40
SharedPtr< const TreeBase > ConstPtr
Definition Tree.h:41
@ IndexArray
Definition NanoVDB.h:415
Mat3< double > Mat3d
Definition Mat3.h:833
Vec3< double > Vec3d
Definition Vec3.h:708
Vec4< int32_t > Vec4i
Definition Vec4.h:602
Vec3< int32_t > Vec3i
Definition Vec3.h:705
Vec3< float > Vec3s
Definition Vec3.h:707
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition PointDataGrid.h:48
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
constexpr Index32 INVALID_IDX
Definition Util.h:19
Index32 Index
Definition Types.h:34
math::Vec4< Index32 > Vec4I
Definition Types.h:69
int16_t Int16
Definition Types.h:35
@ GRID_LEVEL_SET
Definition Types.h:526
uint32_t Index32
Definition Types.h:32
math::Vec3< Index32 > Vec3I
Definition Types.h:54
tree::TreeBase TreeBase
Definition Grid.h:27
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
static Vec3< typename Accessor::ValueType > result(const Accessor &grid, const Coord &ijk)
Definition Operators.h:103
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:291
#define OPENVDB_NUMERIC_TREE_INSTANTIATE(Function)
Definition version.h.in:236