11#ifndef OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
12#define OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
25#include <tbb/blocked_range.h>
26#include <tbb/parallel_for.h>
27#include <tbb/parallel_reduce.h>
28#include <tbb/parallel_sort.h>
48template<
typename Gr
idType>
49inline typename GridType::ValueType lsutilGridMax()
51 return std::numeric_limits<typename GridType::ValueType>::max();
54template<
typename Gr
idType>
55inline typename GridType::ValueType lsutilGridZero()
57 return zeroVal<typename GridType::ValueType>();
80template<
class Gr
idType>
84 typename GridType::ValueType cutoffDistance = lsutilGridMax<GridType>());
97template<
class Gr
idOrTreeType>
98typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
100 const GridOrTreeType& volume,
101 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>());
124template<
typename Gr
idOrTreeType>
125typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
127 const GridOrTreeType& volume,
128 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>(),
129 const typename TreeAdapter<GridOrTreeType>::TreeType::template ValueConverter<bool>::Type*
138template<
typename Gr
idOrTreeType>
139typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
148template<
typename Gr
idOrTreeType>
151 std::vector<
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks);
161template<
typename Gr
idOrTreeType>
164 std::vector<typename GridOrTreeType::Ptr>& segments);
175template<
typename Gr
idOrTreeType>
177segmentSDF(
const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments);
198template<
class Gr
idType>
202 bool removeDisconnectedInterior =
false,
203 bool rebuildNarrowBand =
true,
204 float halfWidth = 3.0f);
214namespace level_set_util_internal {
217template<
typename LeafNodeType>
218struct MaskInteriorVoxels {
220 using ValueType =
typename LeafNodeType::ValueType;
221 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
224 ValueType isovalue,
const LeafNodeType ** nodes, BoolLeafNodeType ** maskNodes)
225 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
229 void operator()(
const tbb::blocked_range<size_t>& range)
const {
231 BoolLeafNodeType * maskNodePt =
nullptr;
233 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
235 mMaskNodes[n] =
nullptr;
236 const LeafNodeType& node = *mNodes[n];
239 maskNodePt =
new BoolLeafNodeType(node.origin(),
false);
241 maskNodePt->setOrigin(node.origin());
244 const ValueType* values = &node.getValue(0);
245 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
246 if (values[i] < mIsovalue) maskNodePt->setValueOn(i,
true);
249 if (maskNodePt->onVoxelCount() > 0) {
250 mMaskNodes[n] = maskNodePt;
251 maskNodePt =
nullptr;
258 LeafNodeType
const *
const *
const mNodes;
259 BoolLeafNodeType **
const mMaskNodes;
260 ValueType
const mIsovalue;
264template<
typename TreeType,
typename InternalNodeType>
265struct MaskInteriorTiles {
267 using ValueType =
typename TreeType::ValueType;
269 MaskInteriorTiles(ValueType isovalue,
const TreeType& tree, InternalNodeType ** maskNodes)
270 : mTree(&tree), mMaskNodes(maskNodes), mIsovalue(isovalue) { }
272 void operator()(
const tbb::blocked_range<size_t>& range)
const {
273 tree::ValueAccessor<const TreeType> acc(*mTree);
274 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
275 typename InternalNodeType::ValueAllIter it = mMaskNodes[n]->beginValueAll();
277 if (acc.getValue(it.getCoord()) < mIsovalue) {
285 TreeType
const *
const mTree;
286 InternalNodeType **
const mMaskNodes;
287 ValueType
const mIsovalue;
291template<
typename TreeType>
294 using ValueType =
typename TreeType::ValueType;
295 using LeafNodeType =
typename TreeType::LeafNodeType;
297 PopulateTree(TreeType& tree, LeafNodeType** leafnodes,
298 const size_t * nodexIndexMap, ValueType background)
299 : mNewTree(background)
302 , mNodeIndexMap(nodexIndexMap)
306 PopulateTree(PopulateTree& rhs, tbb::split)
307 : mNewTree(rhs.mNewTree.background())
310 , mNodeIndexMap(rhs.mNodeIndexMap)
314 void operator()(
const tbb::blocked_range<size_t>& range) {
316 tree::ValueAccessor<TreeType> acc(*mTreePt);
319 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
320 for (
size_t i = mNodeIndexMap[n], I = mNodeIndexMap[n + 1]; i < I; ++i) {
321 if (mNodes[i] !=
nullptr) acc.addLeaf(mNodes[i]);
325 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
326 acc.addLeaf(mNodes[n]);
331 void join(PopulateTree& rhs) { mTreePt->merge(*rhs.mTreePt); }
335 TreeType *
const mTreePt;
336 LeafNodeType **
const mNodes;
337 size_t const *
const mNodeIndexMap;
342template<
typename LeafNodeType>
343struct LabelBoundaryVoxels {
345 using ValueType =
typename LeafNodeType::ValueType;
346 using CharLeafNodeType = tree::LeafNode<char, LeafNodeType::LOG2DIM>;
349 ValueType isovalue,
const LeafNodeType ** nodes, CharLeafNodeType ** maskNodes)
350 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
354 void operator()(
const tbb::blocked_range<size_t>& range)
const {
356 CharLeafNodeType * maskNodePt =
nullptr;
358 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
360 mMaskNodes[n] =
nullptr;
361 const LeafNodeType& node = *mNodes[n];
364 maskNodePt =
new CharLeafNodeType(node.origin(), 1);
366 maskNodePt->setOrigin(node.origin());
369 typename LeafNodeType::ValueOnCIter it;
370 for (it = node.cbeginValueOn(); it; ++it) {
371 maskNodePt->setValueOn(it.pos(), ((*it - mIsovalue) < 0.0) ? 0 : 1);
374 if (maskNodePt->onVoxelCount() > 0) {
375 mMaskNodes[n] = maskNodePt;
376 maskNodePt =
nullptr;
383 LeafNodeType
const *
const *
const mNodes;
384 CharLeafNodeType **
const mMaskNodes;
385 ValueType
const mIsovalue;
389template<
typename LeafNodeType>
390struct FlipRegionSign {
391 using ValueType =
typename LeafNodeType::ValueType;
393 FlipRegionSign(LeafNodeType ** nodes) : mNodes(nodes) { }
395 void operator()(
const tbb::blocked_range<size_t>& range)
const {
396 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
397 ValueType* values =
const_cast<ValueType*
>(&mNodes[n]->getValue(0));
398 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
399 values[i] = values[i] < 0 ? 1 : -1;
404 LeafNodeType **
const mNodes;
408template<
typename LeafNodeType>
409struct FindMinVoxelValue {
411 using ValueType =
typename LeafNodeType::ValueType;
413 FindMinVoxelValue(LeafNodeType
const *
const *
const leafnodes)
414 : minValue(std::numeric_limits<ValueType>::
max())
419 FindMinVoxelValue(FindMinVoxelValue& rhs, tbb::split)
420 : minValue(std::numeric_limits<ValueType>::
max())
425 void operator()(
const tbb::blocked_range<size_t>& range) {
426 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
427 const ValueType* data = mNodes[n]->buffer().data();
428 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
429 minValue = std::min(minValue, data[i]);
434 void join(FindMinVoxelValue& rhs) { minValue = std::min(minValue, rhs.minValue); }
438 LeafNodeType
const *
const *
const mNodes;
442template<
typename InternalNodeType>
443struct FindMinTileValue {
445 using ValueType =
typename InternalNodeType::ValueType;
447 FindMinTileValue(InternalNodeType
const *
const *
const nodes)
448 : minValue(std::numeric_limits<ValueType>::
max())
453 FindMinTileValue(FindMinTileValue& rhs, tbb::split)
454 : minValue(std::numeric_limits<ValueType>::
max())
459 void operator()(
const tbb::blocked_range<size_t>& range) {
460 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
461 typename InternalNodeType::ValueAllCIter it = mNodes[n]->beginValueAll();
463 minValue = std::min(minValue, *it);
468 void join(FindMinTileValue& rhs) { minValue = std::min(minValue, rhs.minValue); }
472 InternalNodeType
const *
const *
const mNodes;
476template<
typename LeafNodeType>
477struct SDFVoxelsToFogVolume {
479 using ValueType =
typename LeafNodeType::ValueType;
481 SDFVoxelsToFogVolume(LeafNodeType ** nodes, ValueType cutoffDistance)
482 : mNodes(nodes), mWeight(ValueType(1.0) / cutoffDistance)
486 void operator()(
const tbb::blocked_range<size_t>& range)
const {
488 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
490 LeafNodeType& node = *mNodes[n];
493 ValueType* values = node.buffer().data();
494 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
495 values[i] = values[i] > ValueType(0.0) ? ValueType(0.0) : values[i] * mWeight;
496 if (values[i] > ValueType(0.0)) node.setValueOn(i);
499 if (node.onVoxelCount() == 0) {
506 LeafNodeType **
const mNodes;
507 ValueType
const mWeight;
511template<
typename TreeType,
typename InternalNodeType>
512struct SDFTilesToFogVolume {
514 SDFTilesToFogVolume(
const TreeType& tree, InternalNodeType ** nodes)
515 : mTree(&tree), mNodes(nodes) { }
517 void operator()(
const tbb::blocked_range<size_t>& range)
const {
519 using ValueType =
typename TreeType::ValueType;
520 tree::ValueAccessor<const TreeType> acc(*mTree);
522 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
523 typename InternalNodeType::ValueAllIter it = mNodes[n]->beginValueAll();
525 if (acc.getValue(it.getCoord()) < ValueType(0.0)) {
526 it.setValue(ValueType(1.0));
533 TreeType
const *
const mTree;
534 InternalNodeType **
const mNodes;
538template<
typename TreeType>
539struct FillMaskBoundary {
541 using ValueType =
typename TreeType::ValueType;
542 using LeafNodeType =
typename TreeType::LeafNodeType;
543 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
544 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
546 FillMaskBoundary(
const TreeType& tree, ValueType isovalue,
const BoolTreeType& fillMask,
547 const BoolLeafNodeType ** fillNodes, BoolLeafNodeType ** newNodes)
549 , mFillMask(&fillMask)
550 , mFillNodes(fillNodes)
551 , mNewNodes(newNodes)
552 , mIsovalue(isovalue)
556 void operator()(
const tbb::blocked_range<size_t>& range)
const {
558 tree::ValueAccessor<const BoolTreeType> maskAcc(*mFillMask);
559 tree::ValueAccessor<const TreeType> distAcc(*mTree);
561 std::unique_ptr<char[]> valueMask(
new char[BoolLeafNodeType::SIZE]);
563 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
565 mNewNodes[n] =
nullptr;
566 const BoolLeafNodeType& node = *mFillNodes[n];
567 const Coord& origin = node.origin();
569 const bool denseNode = node.isDense();
574 int denseNeighbors = 0;
576 const BoolLeafNodeType* neighborNode =
577 maskAcc.probeConstLeaf(origin.offsetBy(-1, 0, 0));
578 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
580 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(BoolLeafNodeType::DIM, 0, 0));
581 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
583 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, -1, 0));
584 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
586 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, BoolLeafNodeType::DIM, 0));
587 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
589 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, -1));
590 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
592 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, BoolLeafNodeType::DIM));
593 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
595 if (denseNeighbors == 6)
continue;
599 memset(valueMask.get(), 0,
sizeof(
char) * BoolLeafNodeType::SIZE);
601 const typename TreeType::LeafNodeType* distNode = distAcc.probeConstLeaf(origin);
605 bool earlyTermination =
false;
609 evalInternalNeighborsP(valueMask.get(), node, *distNode);
610 evalInternalNeighborsN(valueMask.get(), node, *distNode);
611 }
else if (distAcc.getValue(origin) > mIsovalue) {
612 earlyTermination = evalInternalNeighborsP(valueMask.get(), node);
613 if (!earlyTermination) {
614 earlyTermination = evalInternalNeighborsN(valueMask.get(), node);
621 if (!earlyTermination) {
622 evalExternalNeighborsX<true>(valueMask.get(), node, maskAcc, distAcc);
623 evalExternalNeighborsX<false>(valueMask.get(), node, maskAcc, distAcc);
624 evalExternalNeighborsY<true>(valueMask.get(), node, maskAcc, distAcc);
625 evalExternalNeighborsY<false>(valueMask.get(), node, maskAcc, distAcc);
626 evalExternalNeighborsZ<true>(valueMask.get(), node, maskAcc, distAcc);
627 evalExternalNeighborsZ<false>(valueMask.get(), node, maskAcc, distAcc);
632 int numBoundaryValues = 0;
633 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
634 numBoundaryValues += valueMask[i] == 1;
637 if (numBoundaryValues > 0) {
638 mNewNodes[n] =
new BoolLeafNodeType(origin,
false);
639 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
640 if (valueMask[i] == 1) mNewNodes[n]->setValueOn(i);
648 void evalInternalNeighborsP(
char* valueMask,
const BoolLeafNodeType& node,
649 const LeafNodeType& distNode)
const
651 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
652 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
653 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
654 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
655 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
656 const Index pos = yPos + z;
658 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
660 if (!node.isValueOn(pos + 1) && distNode.getValue(pos + 1) > mIsovalue) {
667 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
668 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
669 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
670 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
671 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
672 const Index pos = yPos + z;
674 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
676 if (!node.isValueOn(pos + BoolLeafNodeType::DIM) &&
677 distNode.getValue(pos + BoolLeafNodeType::DIM) > mIsovalue) {
684 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
685 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
686 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
687 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
688 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
689 const Index pos = yPos + z;
691 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
693 if (!node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
694 (distNode.getValue(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
704 bool evalInternalNeighborsP(
char* valueMask,
const BoolLeafNodeType& node)
const {
706 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
707 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
708 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
709 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
710 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
711 const Index pos = yPos + z;
713 if (node.isValueOn(pos) && !node.isValueOn(pos + 1)) {
721 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
722 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
723 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
724 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
725 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
726 const Index pos = yPos + z;
728 if (node.isValueOn(pos) && !node.isValueOn(pos + BoolLeafNodeType::DIM)) {
736 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
737 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
738 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
739 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
740 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
741 const Index pos = yPos + z;
743 if (node.isValueOn(pos) &&
744 !node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
757 void evalInternalNeighborsN(
char* valueMask,
const BoolLeafNodeType& node,
758 const LeafNodeType& distNode)
const
760 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
761 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
762 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
763 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
764 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
765 const Index pos = yPos + z;
767 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
769 if (!node.isValueOn(pos - 1) && distNode.getValue(pos - 1) > mIsovalue) {
776 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
777 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
778 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
779 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
780 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
781 const Index pos = yPos + z;
783 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
785 if (!node.isValueOn(pos - BoolLeafNodeType::DIM) &&
786 distNode.getValue(pos - BoolLeafNodeType::DIM) > mIsovalue) {
793 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
794 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
795 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
796 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
797 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
798 const Index pos = yPos + z;
800 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
802 if (!node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
803 (distNode.getValue(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
814 bool evalInternalNeighborsN(
char* valueMask,
const BoolLeafNodeType& node)
const {
816 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
817 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
818 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
819 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
820 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
821 const Index pos = yPos + z;
823 if (node.isValueOn(pos) && !node.isValueOn(pos - 1)) {
831 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
832 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
833 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
834 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
835 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
836 const Index pos = yPos + z;
838 if (node.isValueOn(pos) && !node.isValueOn(pos - BoolLeafNodeType::DIM)) {
846 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
847 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
848 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
849 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
850 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
851 const Index pos = yPos + z;
853 if (node.isValueOn(pos) &&
854 !node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
869 template<
bool UpWind>
870 void evalExternalNeighborsX(
char* valueMask,
const BoolLeafNodeType& node,
871 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
872 const tree::ValueAccessor<const TreeType>& distAcc)
const {
874 const Coord& origin = node.origin();
875 Coord ijk(0, 0, 0), nijk;
880 ijk[0] = int(BoolLeafNodeType::DIM) - 1;
883 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
885 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
886 const Index yPos = xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
888 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
889 const Index pos = yPos + ijk[2];
891 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
893 nijk = origin + ijk.offsetBy(step, 0, 0);
895 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
904 template<
bool UpWind>
905 void evalExternalNeighborsY(
char* valueMask,
const BoolLeafNodeType& node,
906 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
907 const tree::ValueAccessor<const TreeType>& distAcc)
const {
909 const Coord& origin = node.origin();
910 Coord ijk(0, 0, 0), nijk;
915 ijk[1] = int(BoolLeafNodeType::DIM) - 1;
918 const Index yPos = ijk[1] << int(BoolLeafNodeType::LOG2DIM);
920 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
921 const Index xPos = yPos + (ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM)));
923 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
924 const Index pos = xPos + ijk[2];
926 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
928 nijk = origin + ijk.offsetBy(0, step, 0);
929 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
938 template<
bool UpWind>
939 void evalExternalNeighborsZ(
char* valueMask,
const BoolLeafNodeType& node,
940 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
941 const tree::ValueAccessor<const TreeType>& distAcc)
const {
943 const Coord& origin = node.origin();
944 Coord ijk(0, 0, 0), nijk;
949 ijk[2] = int(BoolLeafNodeType::DIM) - 1;
952 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
953 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
955 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
956 const Index pos = ijk[2] + xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
958 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
960 nijk = origin + ijk.offsetBy(0, 0, step);
961 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
971 TreeType
const *
const mTree;
972 BoolTreeType
const *
const mFillMask;
973 BoolLeafNodeType
const *
const *
const mFillNodes;
974 BoolLeafNodeType **
const mNewNodes;
975 ValueType
const mIsovalue;
981template <
class TreeType>
982typename TreeType::template ValueConverter<char>::Type::Ptr
983computeEnclosedRegionMask(
const TreeType& tree,
typename TreeType::ValueType isovalue,
984 const typename TreeType::template ValueConverter<bool>::Type* fillMask)
986 using LeafNodeType =
typename TreeType::LeafNodeType;
987 using RootNodeType =
typename TreeType::RootNodeType;
988 using NodeChainType =
typename RootNodeType::NodeChainType;
989 using InternalNodeType =
typename NodeChainType::template Get<1>;
991 using CharTreeType =
typename TreeType::template ValueConverter<char>::Type;
992 using CharLeafNodeType =
typename CharTreeType::LeafNodeType;
994 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
995 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
997 const TreeType* treePt = &tree;
999 size_t numLeafNodes = 0, numInternalNodes = 0;
1001 std::vector<const LeafNodeType*> nodes;
1002 std::vector<size_t> leafnodeCount;
1006 std::vector<const InternalNodeType*> internalNodes;
1007 treePt->getNodes(internalNodes);
1009 numInternalNodes = internalNodes.size();
1011 leafnodeCount.push_back(0);
1012 for (
size_t n = 0; n < numInternalNodes; ++n) {
1013 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
1016 numLeafNodes = leafnodeCount.back();
1019 nodes.reserve(numLeafNodes);
1021 for (
size_t n = 0; n < numInternalNodes; ++n) {
1022 internalNodes[n]->getNodes(nodes);
1027 std::unique_ptr<CharLeafNodeType*[]> maskNodes(
new CharLeafNodeType*[numLeafNodes]);
1029 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1030 LabelBoundaryVoxels<LeafNodeType>(isovalue, nodes.data(), maskNodes.get()));
1033 typename CharTreeType::Ptr maskTree(
new CharTreeType(1));
1035 PopulateTree<CharTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(), 1);
1036 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1040 std::vector<CharLeafNodeType*> extraMaskNodes;
1044 std::vector<const BoolLeafNodeType*> fillMaskNodes;
1045 fillMask->getNodes(fillMaskNodes);
1047 std::unique_ptr<BoolLeafNodeType*[]> boundaryMaskNodes(
1048 new BoolLeafNodeType*[fillMaskNodes.size()]);
1050 tbb::parallel_for(tbb::blocked_range<size_t>(0, fillMaskNodes.size()),
1051 FillMaskBoundary<TreeType>(tree, isovalue, *fillMask, fillMaskNodes.data(),
1052 boundaryMaskNodes.get()));
1054 tree::ValueAccessor<CharTreeType> maskAcc(*maskTree);
1056 for (
size_t n = 0, N = fillMaskNodes.size(); n < N; ++n) {
1058 if (boundaryMaskNodes[n] ==
nullptr)
continue;
1060 const BoolLeafNodeType& boundaryNode = *boundaryMaskNodes[n];
1061 const Coord& origin = boundaryNode.origin();
1063 CharLeafNodeType* maskNodePt = maskAcc.probeLeaf(origin);
1066 maskNodePt = maskAcc.touchLeaf(origin);
1067 extraMaskNodes.push_back(maskNodePt);
1070 char* data = maskNodePt->buffer().data();
1072 typename BoolLeafNodeType::ValueOnCIter it = boundaryNode.cbeginValueOn();
1074 if (data[it.pos()] != 0) data[it.pos()] = -1;
1077 delete boundaryMaskNodes[n];
1082 tools::traceExteriorBoundaries(*maskTree);
1085 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1086 FlipRegionSign<CharLeafNodeType>(maskNodes.get()));
1088 if (!extraMaskNodes.empty()) {
1089 tbb::parallel_for(tbb::blocked_range<size_t>(0, extraMaskNodes.size()),
1090 FlipRegionSign<CharLeafNodeType>(extraMaskNodes.data()));
1094 tools::signedFloodFill(*maskTree);
1100template <
class TreeType>
1101typename TreeType::template ValueConverter<bool>::Type::Ptr
1102computeInteriorMask(
const TreeType& tree,
typename TreeType::ValueType iso)
1104 using ValueType =
typename TreeType::ValueType;
1105 using LeafNodeType =
typename TreeType::LeafNodeType;
1106 using RootNodeType =
typename TreeType::RootNodeType;
1107 using NodeChainType =
typename RootNodeType::NodeChainType;
1108 using InternalNodeType =
typename NodeChainType::template Get<1>;
1110 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1111 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1112 using BoolRootNodeType =
typename BoolTreeType::RootNodeType;
1113 using BoolNodeChainType =
typename BoolRootNodeType::NodeChainType;
1114 using BoolInternalNodeType =
typename BoolNodeChainType::template Get<1>;
1124 static_cast<ValueType
>(tree.background() - math::Tolerance<ValueType>::value()));
1126 size_t numLeafNodes = 0, numInternalNodes = 0;
1128 std::vector<const LeafNodeType*> nodes;
1129 std::vector<size_t> leafnodeCount;
1133 std::vector<const InternalNodeType*> internalNodes;
1134 tree.getNodes(internalNodes);
1136 numInternalNodes = internalNodes.size();
1138 leafnodeCount.push_back(0);
1139 for (
size_t n = 0; n < numInternalNodes; ++n) {
1140 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
1143 numLeafNodes = leafnodeCount.back();
1146 nodes.reserve(numLeafNodes);
1148 for (
size_t n = 0; n < numInternalNodes; ++n) {
1149 internalNodes[n]->getNodes(nodes);
1154 std::unique_ptr<BoolLeafNodeType*[]> maskNodes(
new BoolLeafNodeType*[numLeafNodes]);
1156 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1157 MaskInteriorVoxels<LeafNodeType>(iso, nodes.data(), maskNodes.get()));
1161 typename BoolTreeType::Ptr maskTree(
new BoolTreeType(
false));
1163 PopulateTree<BoolTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(),
false);
1164 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1168 std::vector<BoolInternalNodeType*> internalMaskNodes;
1169 maskTree->getNodes(internalMaskNodes);
1171 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalMaskNodes.size()),
1172 MaskInteriorTiles<TreeType, BoolInternalNodeType>(iso, tree, internalMaskNodes.data()));
1174 tree::ValueAccessor<const TreeType> acc(tree);
1176 typename BoolTreeType::ValueAllIter it(*maskTree);
1177 it.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 2);
1180 if (acc.getValue(it.getCoord()) < iso) {
1182 it.setActiveState(
true);
1190template<
typename InputTreeType>
1191struct MaskIsovalueCrossingVoxels
1193 using InputValueType =
typename InputTreeType::ValueType;
1194 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1195 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
1196 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1198 MaskIsovalueCrossingVoxels(
1199 const InputTreeType& inputTree,
1200 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
1201 BoolTreeType& maskTree,
1203 : mInputAccessor(inputTree)
1204 , mInputNodes(!inputLeafNodes.
empty() ? &inputLeafNodes.front() : nullptr)
1206 , mMaskAccessor(maskTree)
1211 MaskIsovalueCrossingVoxels(MaskIsovalueCrossingVoxels& rhs, tbb::split)
1212 : mInputAccessor(rhs.mInputAccessor.tree())
1213 , mInputNodes(rhs.mInputNodes)
1215 , mMaskAccessor(mMaskTree)
1216 , mIsovalue(rhs.mIsovalue)
1220 void operator()(
const tbb::blocked_range<size_t>& range) {
1222 const InputValueType iso = mIsovalue;
1225 BoolLeafNodeType* maskNodePt =
nullptr;
1227 for (
size_t n = range.begin(); mInputNodes && (n != range.end()); ++n) {
1229 const InputLeafNodeType& node = *mInputNodes[n];
1231 if (!maskNodePt) maskNodePt =
new BoolLeafNodeType(node.origin(),
false);
1232 else maskNodePt->setOrigin(node.origin());
1234 bool collectedData =
false;
1236 for (
typename InputLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
1238 bool isUnder = *it < iso;
1240 ijk = it.getCoord();
1243 bool signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1248 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1254 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1260 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1266 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1272 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1277 collectedData =
true;
1278 maskNodePt->setValueOn(it.pos(),
true);
1282 if (collectedData) {
1283 mMaskAccessor.addLeaf(maskNodePt);
1284 maskNodePt =
nullptr;
1291 void join(MaskIsovalueCrossingVoxels& rhs) {
1292 mMaskAccessor.tree().merge(rhs.mMaskAccessor.tree());
1296 tree::ValueAccessor<const InputTreeType> mInputAccessor;
1297 InputLeafNodeType
const *
const *
const mInputNodes;
1299 BoolTreeType mMaskTree;
1300 tree::ValueAccessor<BoolTreeType> mMaskAccessor;
1302 InputValueType mIsovalue;
1309template<
typename NodeType>
1310struct NodeMaskSegment
1312 using Ptr = SharedPtr<NodeMaskSegment>;
1313 using NodeMaskType =
typename NodeType::NodeMaskType;
1315 NodeMaskSegment() : connections(), mask(false), origin(0,0,0), visited(false) {}
1317 std::vector<NodeMaskSegment*> connections;
1324template<
typename NodeType>
1326nodeMaskSegmentation(
const NodeType& node,
1327 std::vector<
typename NodeMaskSegment<NodeType>::Ptr>& segments)
1329 using NodeMaskType =
typename NodeType::NodeMaskType;
1330 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1331 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1333 NodeMaskType nodeMask(node.getValueMask());
1334 std::deque<Index> indexList;
1336 while (!nodeMask.isOff()) {
1338 NodeMaskSegmentTypePtr segment(
new NodeMaskSegmentType());
1339 segment->origin = node.origin();
1341 NodeMaskType& mask = segment->mask;
1343 indexList.push_back(nodeMask.findFirstOn());
1344 nodeMask.setOff(indexList.back());
1347 while (!indexList.empty()) {
1349 const Index pos = indexList.back();
1350 indexList.pop_back();
1352 if (mask.isOn(pos))
continue;
1355 ijk = NodeType::offsetToLocalCoord(pos);
1357 Index npos = pos - 1;
1358 if (ijk[2] != 0 && nodeMask.isOn(npos)) {
1359 nodeMask.setOff(npos);
1360 indexList.push_back(npos);
1364 if (ijk[2] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1365 nodeMask.setOff(npos);
1366 indexList.push_back(npos);
1369 npos = pos - NodeType::DIM;
1370 if (ijk[1] != 0 && nodeMask.isOn(npos)) {
1371 nodeMask.setOff(npos);
1372 indexList.push_back(npos);
1375 npos = pos + NodeType::DIM;
1376 if (ijk[1] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1377 nodeMask.setOff(npos);
1378 indexList.push_back(npos);
1381 npos = pos - NodeType::DIM * NodeType::DIM;
1382 if (ijk[0] != 0 && nodeMask.isOn(npos)) {
1383 nodeMask.setOff(npos);
1384 indexList.push_back(npos);
1387 npos = pos + NodeType::DIM * NodeType::DIM;
1388 if (ijk[0] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1389 nodeMask.setOff(npos);
1390 indexList.push_back(npos);
1395 segments.push_back(segment);
1400template<
typename NodeType>
1401struct SegmentNodeMask
1403 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1404 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1405 using NodeMaskSegmentVector =
typename std::vector<NodeMaskSegmentTypePtr>;
1407 SegmentNodeMask(std::vector<NodeType*>& nodes, NodeMaskSegmentVector* nodeMaskArray)
1408 : mNodes(!nodes.
empty() ? &nodes.front() : nullptr)
1409 , mNodeMaskArray(nodeMaskArray)
1413 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1414 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1415 NodeType& node = *mNodes[n];
1416 nodeMaskSegmentation(node, mNodeMaskArray[n]);
1419 Coord& origin =
const_cast<Coord&
>(node.origin());
1420 origin[0] =
static_cast<int>(n);
1424 NodeType *
const *
const mNodes;
1425 NodeMaskSegmentVector *
const mNodeMaskArray;
1429template<
typename TreeType,
typename NodeType>
1430struct ConnectNodeMaskSegments
1432 using NodeMaskType =
typename NodeType::NodeMaskType;
1433 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1434 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1435 using NodeMaskSegmentVector =
typename std::vector<NodeMaskSegmentTypePtr>;
1437 ConnectNodeMaskSegments(
const TreeType& tree, NodeMaskSegmentVector* nodeMaskArray)
1439 , mNodeMaskArray(nodeMaskArray)
1443 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1445 tree::ValueAccessor<const TreeType> acc(*mTree);
1447 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1449 NodeMaskSegmentVector& segments = mNodeMaskArray[n];
1450 if (segments.empty())
continue;
1452 std::vector<std::set<NodeMaskSegmentType*> > connections(segments.size());
1454 Coord ijk = segments[0]->origin;
1456 const NodeType* node = acc.template probeConstNode<NodeType>(ijk);
1457 if (!node)
continue;
1461 ijk[2] += NodeType::DIM;
1462 const NodeType* nodeZUp = acc.template probeConstNode<NodeType>(ijk);
1463 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1464 const NodeType* nodeZDown = acc.template probeConstNode<NodeType>(ijk);
1465 ijk[2] += NodeType::DIM;
1467 ijk[1] += NodeType::DIM;
1468 const NodeType* nodeYUp = acc.template probeConstNode<NodeType>(ijk);
1469 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1470 const NodeType* nodeYDown = acc.template probeConstNode<NodeType>(ijk);
1471 ijk[1] += NodeType::DIM;
1473 ijk[0] += NodeType::DIM;
1474 const NodeType* nodeXUp = acc.template probeConstNode<NodeType>(ijk);
1475 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1476 const NodeType* nodeXDown = acc.template probeConstNode<NodeType>(ijk);
1477 ijk[0] += NodeType::DIM;
1479 const Index startPos = node->getValueMask().findFirstOn();
1480 for (Index pos = startPos; pos < NodeMaskType::SIZE; ++pos) {
1482 if (!node->isValueOn(pos))
continue;
1484 ijk = NodeType::offsetToLocalCoord(pos);
1487 #if _MSC_FULL_VER >= 190000000 && _MSC_FULL_VER < 190024210
1489 volatile Index npos = 0;
1498 npos = pos + (NodeType::DIM - 1);
1499 if (nodeZDown && nodeZDown->isValueOn(npos)) {
1500 NodeMaskSegmentType* nsegment =
1501 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZDown)], npos);
1502 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1503 connections[idx].insert(nsegment);
1505 }
else if (ijk[2] == (NodeType::DIM - 1)) {
1506 npos = pos - (NodeType::DIM - 1);
1507 if (nodeZUp && nodeZUp->isValueOn(npos)) {
1508 NodeMaskSegmentType* nsegment =
1509 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZUp)], npos);
1510 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1511 connections[idx].insert(nsegment);
1516 npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1517 if (nodeYDown && nodeYDown->isValueOn(npos)) {
1518 NodeMaskSegmentType* nsegment =
1519 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYDown)], npos);
1520 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1521 connections[idx].insert(nsegment);
1523 }
else if (ijk[1] == (NodeType::DIM - 1)) {
1524 npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1525 if (nodeYUp && nodeYUp->isValueOn(npos)) {
1526 NodeMaskSegmentType* nsegment =
1527 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYUp)], npos);
1528 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1529 connections[idx].insert(nsegment);
1534 npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1535 if (nodeXDown && nodeXDown->isValueOn(npos)) {
1536 NodeMaskSegmentType* nsegment =
1537 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXDown)], npos);
1538 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1539 connections[idx].insert(nsegment);
1541 }
else if (ijk[0] == (NodeType::DIM - 1)) {
1542 npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1543 if (nodeXUp && nodeXUp->isValueOn(npos)) {
1544 NodeMaskSegmentType* nsegment =
1545 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXUp)], npos);
1546 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1547 connections[idx].insert(nsegment);
1552 for (
size_t i = 0, I = connections.size(); i < I; ++i) {
1554 typename std::set<NodeMaskSegmentType*>::iterator
1555 it = connections[i].begin(), end = connections[i].end();
1557 std::vector<NodeMaskSegmentType*>& segmentConnections = segments[i]->connections;
1558 segmentConnections.reserve(connections.size());
1559 for (; it != end; ++it) {
1560 segmentConnections.push_back(*it);
1568 static inline size_t getNodeOffset(
const NodeType& node) {
1569 return static_cast<size_t>(node.origin()[0]);
1572 static inline NodeMaskSegmentType*
1573 findNodeMaskSegment(NodeMaskSegmentVector& segments, Index pos)
1575 NodeMaskSegmentType* segment =
nullptr;
1577 for (
size_t n = 0, N = segments.size(); n < N; ++n) {
1578 if (segments[n]->mask.isOn(pos)) {
1579 segment = segments[n].get();
1588 findNodeMaskSegmentIndex(NodeMaskSegmentVector& segments, Index pos)
1590 for (Index n = 0, N =
Index(segments.size()); n < N; ++n) {
1591 if (segments[n]->mask.isOn(pos))
return n;
1596 TreeType
const *
const mTree;
1597 NodeMaskSegmentVector *
const mNodeMaskArray;
1601template<
typename TreeType>
1602struct MaskSegmentGroup
1604 using LeafNodeType =
typename TreeType::LeafNodeType;
1605 using TreeTypePtr =
typename TreeType::Ptr;
1606 using NodeMaskSegmentType = NodeMaskSegment<LeafNodeType>;
1608 MaskSegmentGroup(
const std::vector<NodeMaskSegmentType*>& segments)
1609 : mSegments(!segments.
empty() ? &segments.front() : nullptr)
1610 , mTree(new TreeType(false))
1614 MaskSegmentGroup(
const MaskSegmentGroup& rhs, tbb::split)
1615 : mSegments(rhs.mSegments)
1616 , mTree(new TreeType(false))
1620 TreeTypePtr& mask() {
return mTree; }
1622 void join(MaskSegmentGroup& rhs) { mTree->merge(*rhs.mTree); }
1624 void operator()(
const tbb::blocked_range<size_t>& range) {
1626 tree::ValueAccessor<TreeType> acc(*mTree);
1628 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1629 NodeMaskSegmentType& segment = *mSegments[n];
1630 LeafNodeType* node = acc.touchLeaf(segment.origin);
1631 node->getValueMask() |= segment.mask;
1636 NodeMaskSegmentType *
const *
const mSegments;
1644template<
typename TreeType>
1645struct ExpandLeafNodeRegion
1647 using ValueType =
typename TreeType::ValueType;
1648 using LeafNodeType =
typename TreeType::LeafNodeType;
1649 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
1651 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1652 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1656 ExpandLeafNodeRegion(
const TreeType& distTree, BoolTreeType& maskTree,
1657 std::vector<BoolLeafNodeType*>& maskNodes)
1658 : mDistTree(&distTree)
1659 , mMaskTree(&maskTree)
1660 , mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
1661 , mNewMaskTree(false)
1665 ExpandLeafNodeRegion(
const ExpandLeafNodeRegion& rhs, tbb::split)
1666 : mDistTree(rhs.mDistTree)
1667 , mMaskTree(rhs.mMaskTree)
1668 , mMaskNodes(rhs.mMaskNodes)
1669 , mNewMaskTree(false)
1673 BoolTreeType& newMaskTree() {
return mNewMaskTree; }
1675 void join(ExpandLeafNodeRegion& rhs) { mNewMaskTree.merge(rhs.mNewMaskTree); }
1677 void operator()(
const tbb::blocked_range<size_t>& range) {
1679 using NodeType = LeafNodeType;
1681 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1682 tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
1683 tree::ValueAccessor<BoolTreeType> newMaskAcc(mNewMaskTree);
1685 NodeMaskType maskZUp, maskZDown, maskYUp, maskYDown, maskXUp, maskXDown;
1687 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1689 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1690 if (maskNode.isEmpty())
continue;
1692 Coord ijk = maskNode.origin(), nijk;
1694 const LeafNodeType* distNode = distAcc.probeConstLeaf(ijk);
1695 if (!distNode)
continue;
1697 const ValueType *dataZUp =
nullptr, *dataZDown =
nullptr,
1698 *dataYUp =
nullptr, *dataYDown =
nullptr,
1699 *dataXUp =
nullptr, *dataXDown =
nullptr;
1701 ijk[2] += NodeType::DIM;
1702 getData(ijk, distAcc, maskAcc, maskZUp, dataZUp);
1703 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1704 getData(ijk, distAcc, maskAcc, maskZDown, dataZDown);
1705 ijk[2] += NodeType::DIM;
1707 ijk[1] += NodeType::DIM;
1708 getData(ijk, distAcc, maskAcc, maskYUp, dataYUp);
1709 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1710 getData(ijk, distAcc, maskAcc, maskYDown, dataYDown);
1711 ijk[1] += NodeType::DIM;
1713 ijk[0] += NodeType::DIM;
1714 getData(ijk, distAcc, maskAcc, maskXUp, dataXUp);
1715 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1716 getData(ijk, distAcc, maskAcc, maskXDown, dataXDown);
1717 ijk[0] += NodeType::DIM;
1719 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
1721 const Index pos = it.pos();
1722 const ValueType val = std::abs(distNode->getValue(pos));
1724 ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
1725 nijk = ijk + maskNode.origin();
1727 if (dataZUp && ijk[2] == (BoolLeafNodeType::DIM - 1)) {
1728 const Index npos = pos - (NodeType::DIM - 1);
1729 if (maskZUp.isOn(npos) && std::abs(dataZUp[npos]) > val) {
1730 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, 1));
1732 }
else if (dataZDown && ijk[2] == 0) {
1733 const Index npos = pos + (NodeType::DIM - 1);
1734 if (maskZDown.isOn(npos) && std::abs(dataZDown[npos]) > val) {
1735 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, -1));
1739 if (dataYUp && ijk[1] == (BoolLeafNodeType::DIM - 1)) {
1740 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1741 if (maskYUp.isOn(npos) && std::abs(dataYUp[npos]) > val) {
1742 newMaskAcc.setValueOn(nijk.offsetBy(0, 1, 0));
1744 }
else if (dataYDown && ijk[1] == 0) {
1745 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1746 if (maskYDown.isOn(npos) && std::abs(dataYDown[npos]) > val) {
1747 newMaskAcc.setValueOn(nijk.offsetBy(0, -1, 0));
1751 if (dataXUp && ijk[0] == (BoolLeafNodeType::DIM - 1)) {
1752 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1753 if (maskXUp.isOn(npos) && std::abs(dataXUp[npos]) > val) {
1754 newMaskAcc.setValueOn(nijk.offsetBy(1, 0, 0));
1756 }
else if (dataXDown && ijk[0] == 0) {
1757 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1758 if (maskXDown.isOn(npos) && std::abs(dataXDown[npos]) > val) {
1759 newMaskAcc.setValueOn(nijk.offsetBy(-1, 0, 0));
1770 getData(
const Coord& ijk, tree::ValueAccessor<const TreeType>& distAcc,
1771 tree::ValueAccessor<const BoolTreeType>& maskAcc, NodeMaskType& mask,
1772 const ValueType*& data)
1774 const LeafNodeType* node = distAcc.probeConstLeaf(ijk);
1776 data = node->buffer().data();
1777 mask = node->getValueMask();
1778 const BoolLeafNodeType* maskNodePt = maskAcc.probeConstLeaf(ijk);
1779 if (maskNodePt) mask -= maskNodePt->getValueMask();
1783 TreeType
const *
const mDistTree;
1784 BoolTreeType *
const mMaskTree;
1785 BoolLeafNodeType **
const mMaskNodes;
1787 BoolTreeType mNewMaskTree;
1791template<
typename TreeType>
1792struct FillLeafNodeVoxels
1794 using ValueType =
typename TreeType::ValueType;
1795 using LeafNodeType =
typename TreeType::LeafNodeType;
1796 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
1797 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
1799 FillLeafNodeVoxels(
const TreeType& tree, std::vector<BoolLeafNodeType*>& maskNodes)
1800 : mTree(&tree), mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
1804 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1806 tree::ValueAccessor<const TreeType> distAcc(*mTree);
1808 std::vector<Index> indexList;
1809 indexList.reserve(NodeMaskType::SIZE);
1811 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1813 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1815 const LeafNodeType * distNode = distAcc.probeConstLeaf(maskNode.origin());
1816 if (!distNode)
continue;
1818 NodeMaskType mask(distNode->getValueMask());
1819 NodeMaskType& narrowbandMask = maskNode.getValueMask();
1821 for (Index pos = narrowbandMask.findFirstOn(); pos < NodeMaskType::SIZE; ++pos) {
1822 if (narrowbandMask.isOn(pos)) indexList.push_back(pos);
1825 mask -= narrowbandMask;
1826 narrowbandMask.setOff();
1828 const ValueType* data = distNode->buffer().data();
1831 while (!indexList.empty()) {
1833 const Index pos = indexList.back();
1834 indexList.pop_back();
1836 if (narrowbandMask.isOn(pos))
continue;
1837 narrowbandMask.setOn(pos);
1839 const ValueType dist = std::abs(data[pos]);
1841 ijk = LeafNodeType::offsetToLocalCoord(pos);
1843 Index npos = pos - 1;
1844 if (ijk[2] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1846 indexList.push_back(npos);
1850 if ((ijk[2] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1851 && std::abs(data[npos]) > dist)
1854 indexList.push_back(npos);
1857 npos = pos - LeafNodeType::DIM;
1858 if (ijk[1] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1860 indexList.push_back(npos);
1863 npos = pos + LeafNodeType::DIM;
1864 if ((ijk[1] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1865 && std::abs(data[npos]) > dist)
1868 indexList.push_back(npos);
1871 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1872 if (ijk[0] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1874 indexList.push_back(npos);
1877 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1878 if ((ijk[0] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1879 && std::abs(data[npos]) > dist)
1882 indexList.push_back(npos);
1888 TreeType
const *
const mTree;
1889 BoolLeafNodeType **
const mMaskNodes;
1893template<
typename TreeType>
1894struct ExpandNarrowbandMask
1896 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1897 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1898 using BoolTreeTypePtr =
typename BoolTreeType::Ptr;
1900 ExpandNarrowbandMask(
const TreeType& tree, std::vector<BoolTreeTypePtr>& segments)
1901 : mTree(&tree), mSegments(!segments.
empty() ? &segments.front() : nullptr)
1905 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1907 const TreeType& distTree = *mTree;
1908 std::vector<BoolLeafNodeType*> nodes;
1910 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1912 BoolTreeType& narrowBandMask = *mSegments[n];
1914 BoolTreeType candidateMask(narrowBandMask,
false, TopologyCopy());
1919 candidateMask.getNodes(nodes);
1920 if (nodes.empty())
break;
1922 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
1924 tbb::parallel_for(nodeRange, FillLeafNodeVoxels<TreeType>(distTree, nodes));
1926 narrowBandMask.topologyUnion(candidateMask);
1928 ExpandLeafNodeRegion<TreeType> op(distTree, narrowBandMask, nodes);
1929 tbb::parallel_reduce(nodeRange, op);
1931 if (op.newMaskTree().empty())
break;
1933 candidateMask.clear();
1934 candidateMask.merge(op.newMaskTree());
1939 TreeType
const *
const mTree;
1940 BoolTreeTypePtr *
const mSegments;
1944template<
typename TreeType>
1947 using TreeTypePtr =
typename TreeType::Ptr;
1948 using ValueType =
typename TreeType::ValueType;
1949 using LeafNodeType =
typename TreeType::LeafNodeType;
1950 using RootNodeType =
typename TreeType::RootNodeType;
1951 using NodeChainType =
typename RootNodeType::NodeChainType;
1952 using InternalNodeType =
typename NodeChainType::template Get<1>;
1954 FloodFillSign(
const TreeType& tree, std::vector<TreeTypePtr>& segments)
1956 , mSegments(!segments.
empty() ? &segments.front() : nullptr)
1957 , mMinValue(ValueType(0.0))
1959 ValueType minSDFValue = std::numeric_limits<ValueType>::max();
1962 std::vector<const InternalNodeType*> nodes;
1963 tree.getNodes(nodes);
1965 if (!nodes.empty()) {
1966 FindMinTileValue<InternalNodeType> minOp(nodes.data());
1967 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1968 minSDFValue = std::min(minSDFValue, minOp.minValue);
1972 if (minSDFValue > ValueType(0.0)) {
1973 std::vector<const LeafNodeType*> nodes;
1974 tree.getNodes(nodes);
1975 if (!nodes.empty()) {
1976 FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
1977 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1978 minSDFValue = std::min(minSDFValue, minOp.minValue);
1982 mMinValue = minSDFValue;
1985 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1986 const ValueType interiorValue = -std::abs(mMinValue);
1987 const ValueType exteriorValue = std::abs(mTree->background());
1988 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1989 tools::signedFloodFillWithValues(*mSegments[n], exteriorValue, interiorValue);
1995 TreeType
const *
const mTree;
1996 TreeTypePtr *
const mSegments;
1997 ValueType mMinValue;
2001template<
typename TreeType>
2004 using TreeTypePtr =
typename TreeType::Ptr;
2005 using ValueType =
typename TreeType::ValueType;
2006 using LeafNodeType =
typename TreeType::LeafNodeType;
2008 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2009 using BoolTreeTypePtr =
typename BoolTreeType::Ptr;
2010 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2012 MaskedCopy(
const TreeType& tree, std::vector<TreeTypePtr>& segments,
2013 std::vector<BoolTreeTypePtr>& masks)
2015 , mSegments(!segments.
empty() ? &segments.front() : nullptr)
2016 , mMasks(!masks.
empty() ? &masks.front() : nullptr)
2020 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2022 std::vector<const BoolLeafNodeType*> nodes;
2024 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2026 const BoolTreeType& mask = *mMasks[n];
2029 mask.getNodes(nodes);
2031 Copy op(*mTree, nodes);
2032 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
2033 mSegments[n] = op.outputTree();
2040 Copy(
const TreeType& inputTree, std::vector<const BoolLeafNodeType*>& maskNodes)
2041 : mInputTree(&inputTree)
2042 , mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
2043 , mOutputTreePtr(new TreeType(inputTree.background()))
2047 Copy(
const Copy& rhs, tbb::split)
2048 : mInputTree(rhs.mInputTree)
2049 , mMaskNodes(rhs.mMaskNodes)
2050 , mOutputTreePtr(new TreeType(mInputTree->background()))
2054 TreeTypePtr& outputTree() {
return mOutputTreePtr; }
2056 void join(Copy& rhs) { mOutputTreePtr->merge(*rhs.mOutputTreePtr); }
2058 void operator()(
const tbb::blocked_range<size_t>& range) {
2060 tree::ValueAccessor<const TreeType> inputAcc(*mInputTree);
2061 tree::ValueAccessor<TreeType> outputAcc(*mOutputTreePtr);
2063 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2065 const BoolLeafNodeType& maskNode = *mMaskNodes[n];
2066 if (maskNode.isEmpty())
continue;
2068 const Coord& ijk = maskNode.origin();
2070 const LeafNodeType* inputNode = inputAcc.probeConstLeaf(ijk);
2073 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
2075 for (
typename BoolLeafNodeType::ValueOnCIter it = maskNode.cbeginValueOn();
2078 const Index idx = it.pos();
2079 outputNode->setValueOn(idx, inputNode->getValue(idx));
2082 const int valueDepth = inputAcc.getValueDepth(ijk);
2083 if (valueDepth >= 0) {
2084 outputAcc.addTile(TreeType::RootNodeType::LEVEL - valueDepth,
2085 ijk, inputAcc.getValue(ijk),
true);
2092 TreeType
const *
const mInputTree;
2093 BoolLeafNodeType
const *
const *
const mMaskNodes;
2094 TreeTypePtr mOutputTreePtr;
2097 TreeType
const *
const mTree;
2098 TreeTypePtr *
const mSegments;
2099 BoolTreeTypePtr *
const mMasks;
2106template<
typename VolumePtrType>
2107struct ComputeActiveVoxelCount
2109 ComputeActiveVoxelCount(std::vector<VolumePtrType>& segments,
size_t *countArray)
2110 : mSegments(!segments.
empty() ? &segments.front() : nullptr)
2111 , mCountArray(countArray)
2115 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2116 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2117 mCountArray[n] = mSegments[n]->activeVoxelCount();
2121 VolumePtrType *
const mSegments;
2122 size_t *
const mCountArray;
2128 GreaterCount(
const size_t *countArray) : mCountArray(countArray) {}
2130 inline bool operator() (
const size_t& lhs,
const size_t& rhs)
const
2132 return (mCountArray[lhs] > mCountArray[rhs]);
2135 size_t const *
const mCountArray;
2141template<
typename TreeType>
2142struct GridOrTreeConstructor
2144 using TreeTypePtr =
typename TreeType::Ptr;
2145 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2147 static BoolTreePtrType constructMask(
const TreeType&, BoolTreePtrType& maskTree)
2148 {
return maskTree; }
2149 static TreeTypePtr construct(
const TreeType&, TreeTypePtr& tree) {
return tree; }
2153template<
typename TreeType>
2154struct GridOrTreeConstructor<
Grid<TreeType> >
2157 using GridTypePtr =
typename Grid<TreeType>::Ptr;
2158 using TreeTypePtr =
typename TreeType::Ptr;
2160 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2161 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2162 using BoolGridType = Grid<BoolTreeType>;
2163 using BoolGridPtrType =
typename BoolGridType::Ptr;
2165 static BoolGridPtrType constructMask(
const GridType& grid, BoolTreePtrType& maskTree) {
2166 BoolGridPtrType maskGrid(BoolGridType::create(maskTree));
2167 maskGrid->setTransform(grid.transform().copy());
2171 static GridTypePtr construct(
const GridType& grid, TreeTypePtr& maskTree) {
2172 GridTypePtr maskGrid(GridType::create(maskTree));
2173 maskGrid->setTransform(grid.transform().copy());
2174 maskGrid->insertMeta(grid);
2188template <
class Gr
idType>
2192 using ValueType =
typename GridType::ValueType;
2193 using TreeType =
typename GridType::TreeType;
2194 using LeafNodeType =
typename TreeType::LeafNodeType;
2195 using RootNodeType =
typename TreeType::RootNodeType;
2196 using NodeChainType =
typename RootNodeType::NodeChainType;
2197 using InternalNodeType =
typename NodeChainType::template Get<1>;
2201 TreeType&
tree = grid.tree();
2203 size_t numLeafNodes = 0, numInternalNodes = 0;
2205 std::vector<LeafNodeType*> nodes;
2206 std::vector<size_t> leafnodeCount;
2210 std::vector<InternalNodeType*> internalNodes;
2211 tree.getNodes(internalNodes);
2213 numInternalNodes = internalNodes.size();
2215 leafnodeCount.push_back(0);
2216 for (
size_t n = 0; n < numInternalNodes; ++n) {
2217 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
2220 numLeafNodes = leafnodeCount.back();
2223 nodes.reserve(numLeafNodes);
2225 for (
size_t n = 0; n < numInternalNodes; ++n) {
2226 internalNodes[n]->stealNodes(nodes,
tree.background(),
false);
2230 ValueType minSDFValue = std::numeric_limits<ValueType>::max();
2233 level_set_util_internal::FindMinTileValue<InternalNodeType> minOp(internalNodes.data());
2234 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), minOp);
2235 minSDFValue = std::min(minSDFValue, minOp.minValue);
2238 if (minSDFValue > ValueType(0.0)) {
2239 level_set_util_internal::FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
2240 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
2241 minSDFValue = std::min(minSDFValue, minOp.minValue);
2244 cutoffDistance = -std::abs(cutoffDistance);
2245 cutoffDistance = minSDFValue > cutoffDistance ? minSDFValue : cutoffDistance;
2251 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2252 level_set_util_internal::SDFVoxelsToFogVolume<LeafNodeType>(nodes.data(), cutoffDistance));
2255 typename TreeType::Ptr newTree(
new TreeType(ValueType(0.0)));
2257 level_set_util_internal::PopulateTree<TreeType> populate(
2258 *newTree, nodes.data(), leafnodeCount.data(), 0);
2259 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
2262 std::vector<InternalNodeType*> internalNodes;
2263 newTree->getNodes(internalNodes);
2265 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalNodes.size()),
2266 level_set_util_internal::SDFTilesToFogVolume<TreeType, InternalNodeType>(
2267 tree, internalNodes.data()));
2272 typename TreeType::ValueAllIter it(*newTree);
2273 it.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 2);
2276 if (acc.
getValue(it.getCoord()) < ValueType(0.0)) {
2277 it.setValue(ValueType(1.0));
2278 it.setActiveState(
true);
2286 typename TreeType::ValueAllIter it(
tree);
2287 it.setMaxDepth(TreeType::ValueAllIter::ROOT_DEPTH);
2289 if (it.getValue() < ValueType(0.0)) {
2290 newTree->addTile(TreeType::ValueAllIter::ROOT_LEVEL, it.getCoord(),
2291 ValueType(1.0),
true);
2296 grid.setTree(newTree);
2304template <
class Gr
idOrTreeType>
2305typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2311 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2312 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(
tree, isovalue);
2314 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2319template<
typename Gr
idOrTreeType>
2320typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2322 typename GridOrTreeType::ValueType isovalue,
2329 using CharTreePtrType =
typename TreeType::template ValueConverter<char>::Type::Ptr;
2330 CharTreePtrType regionMask = level_set_util_internal::computeEnclosedRegionMask(
2331 tree, isovalue, fillMask);
2333 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2334 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(*regionMask, 0);
2336 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2344template<
typename Gr
idOrTreeType>
2345typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2351 std::vector<const typename TreeType::LeafNodeType*> nodes;
2352 tree.getNodes(nodes);
2354 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2355 typename BoolTreeType::Ptr mask(
new BoolTreeType(
false));
2357 level_set_util_internal::MaskIsovalueCrossingVoxels<TreeType> op(
tree, nodes, *mask, isovalue);
2358 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
2360 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2368template<
typename Gr
idOrTreeType>
2371 std::vector<
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks)
2374 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2375 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2376 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2377 using BoolGridOrTreePtrType =
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr;
2379 using NodeMaskSegmentType = level_set_util_internal::NodeMaskSegment<BoolLeafNodeType>;
2380 using NodeMaskSegmentPtrType =
typename NodeMaskSegmentType::Ptr;
2381 using NodeMaskSegmentPtrVector =
typename std::vector<NodeMaskSegmentPtrType>;
2382 using NodeMaskSegmentRawPtrVector =
typename std::vector<NodeMaskSegmentType*>;
2393 if (topologyMask.hasActiveTiles()) {
2394 topologyMask.voxelizeActiveTiles();
2397 std::vector<BoolLeafNodeType*> leafnodes;
2398 topologyMask.getNodes(leafnodes);
2400 if (leafnodes.empty())
return;
2405 std::unique_ptr<NodeMaskSegmentPtrVector[]> nodeSegmentArray(
2406 new NodeMaskSegmentPtrVector[leafnodes.size()]);
2408 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2409 level_set_util_internal::SegmentNodeMask<BoolLeafNodeType>(
2410 leafnodes, nodeSegmentArray.get()));
2415 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2416 level_set_util_internal::ConnectNodeMaskSegments<BoolTreeType, BoolLeafNodeType>(
2417 topologyMask, nodeSegmentArray.get()));
2419 topologyMask.clear();
2421 size_t nodeSegmentCount = 0;
2422 for (
size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2423 nodeSegmentCount += nodeSegmentArray[n].size();
2428 std::deque<NodeMaskSegmentRawPtrVector> nodeSegmentGroups;
2430 NodeMaskSegmentType* nextSegment = nodeSegmentArray[0][0].get();
2431 while (nextSegment) {
2433 nodeSegmentGroups.push_back(NodeMaskSegmentRawPtrVector());
2435 std::vector<NodeMaskSegmentType*>& segmentGroup = nodeSegmentGroups.back();
2436 segmentGroup.reserve(nodeSegmentCount);
2438 std::deque<NodeMaskSegmentType*> segmentQueue;
2439 segmentQueue.push_back(nextSegment);
2440 nextSegment =
nullptr;
2442 while (!segmentQueue.empty()) {
2444 NodeMaskSegmentType* segment = segmentQueue.back();
2445 segmentQueue.pop_back();
2447 if (segment->visited)
continue;
2448 segment->visited =
true;
2450 segmentGroup.push_back(segment);
2453 std::vector<NodeMaskSegmentType*>& connections = segment->connections;
2454 for (
size_t n = 0, N = connections.size(); n < N; ++n) {
2455 if (!connections[n]->visited) segmentQueue.push_back(connections[n]);
2460 for (
size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2461 NodeMaskSegmentPtrVector& nodeSegments = nodeSegmentArray[n];
2462 for (
size_t i = 0, I = nodeSegments.size(); i < I; ++i) {
2463 if (!nodeSegments[i]->visited) nextSegment = nodeSegments[i].get();
2470 if (nodeSegmentGroups.size() == 1) {
2476 if (mask->hasActiveTiles()) {
2477 mask->voxelizeActiveTiles();
2481 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2484 }
else if (nodeSegmentGroups.size() > 1) {
2486 for (
size_t n = 0, N = nodeSegmentGroups.size(); n < N; ++n) {
2488 NodeMaskSegmentRawPtrVector& segmentGroup = nodeSegmentGroups[n];
2490 level_set_util_internal::MaskSegmentGroup<BoolTreeType> op(segmentGroup);
2491 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, segmentGroup.size()), op);
2494 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2495 volume, op.mask()));
2501 if (masks.size() > 1) {
2502 const size_t segmentCount = masks.size();
2504 std::unique_ptr<size_t[]> segmentOrderArray(
new size_t[segmentCount]);
2505 std::unique_ptr<size_t[]> voxelCountArray(
new size_t[segmentCount]);
2507 for (
size_t n = 0; n < segmentCount; ++n) {
2508 segmentOrderArray[n] = n;
2511 tbb::parallel_for(tbb::blocked_range<size_t>(0, segmentCount),
2512 level_set_util_internal::ComputeActiveVoxelCount<BoolGridOrTreePtrType>(
2513 masks, voxelCountArray.get()));
2515 size_t *begin = segmentOrderArray.get();
2516 tbb::parallel_sort(begin, begin + masks.size(), level_set_util_internal::GreaterCount(
2517 voxelCountArray.get()));
2519 std::vector<BoolGridOrTreePtrType> orderedMasks;
2520 orderedMasks.reserve(masks.size());
2522 for (
size_t n = 0; n < segmentCount; ++n) {
2523 orderedMasks.push_back(masks[segmentOrderArray[n]]);
2526 masks.swap(orderedMasks);
2532template<
typename Gr
idOrTreeType>
2535 std::vector<typename GridOrTreeType::Ptr>& segments)
2538 using TreePtrType =
typename TreeType::Ptr;
2539 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2540 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2545 std::vector<BoolTreePtrType> maskSegmentArray;
2550 const size_t numSegments = std::max(
size_t(1), maskSegmentArray.size());
2551 std::vector<TreePtrType> outputSegmentArray(numSegments);
2553 if (maskSegmentArray.empty()) {
2556 outputSegmentArray[0] = TreePtrType(
new TreeType(inputTree.background()));
2557 }
else if (numSegments == 1) {
2559 TreePtrType segment(
new TreeType(inputTree));
2562 if (segment->leafCount() != inputTree.leafCount()) {
2563 segment->topologyIntersection(*maskSegmentArray[0]);
2565 outputSegmentArray[0] = segment;
2567 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2568 tbb::parallel_for(segmentRange,
2569 level_set_util_internal::MaskedCopy<TreeType>(inputTree, outputSegmentArray,
2573 for (
auto& segment : outputSegmentArray) {
2575 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2581template<
typename Gr
idOrTreeType>
2583segmentSDF(
const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments)
2586 using TreePtrType =
typename TreeType::Ptr;
2587 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2588 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2596 std::vector<BoolTreePtrType> maskSegmentArray;
2599 const size_t numSegments = std::max(
size_t(1), maskSegmentArray.size());
2600 std::vector<TreePtrType> outputSegmentArray(numSegments);
2602 if (maskSegmentArray.empty()) {
2605 outputSegmentArray[0] = TreePtrType(
new TreeType(inputTree.background()));
2607 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2610 tbb::parallel_for(segmentRange,
2611 level_set_util_internal::ExpandNarrowbandMask<TreeType>(inputTree, maskSegmentArray));
2615 tbb::parallel_for(segmentRange, level_set_util_internal::MaskedCopy<TreeType>(
2616 inputTree, outputSegmentArray, maskSegmentArray));
2618 tbb::parallel_for(segmentRange,
2619 level_set_util_internal::FloodFillSign<TreeType>(inputTree, outputSegmentArray));
2622 for (
auto& segment : outputSegmentArray) {
2624 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2633template<
class Gr
idType>
2637 bool removeDisconnectedInterior,
2638 bool rebuildNarrowBand,
2641 using ValueType =
typename GridType::ValueType;
2642 using TreeType =
typename GridType::TreeType;
2643 using LeafNodeType =
typename TreeType::LeafNodeType;
2645 TreeType& distTree = grid.tree();
2646 const ValueType voxelSize = ValueType(grid.transform().voxelSize()[0]);
2652 ValueType maxSqDist(0);
2654 std::vector<LeafNodeType*> nodes;
2655 nodes.reserve(distTree.leafCount());
2656 distTree.getNodes(nodes);
2658 const ValueType invVoxel = ValueType(1) / voxelSize;
2660 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2661 [&](
const tbb::blocked_range<size_t>& r) {
2662 for (size_t i = r.begin(); i != r.end(); ++i) {
2663 for (auto iter = nodes[i]->beginValueOn(); iter; ++iter) {
2664 ValueType d = *iter * invVoxel;
2665 ValueType sign = d < ValueType(0) ? ValueType(-1) : ValueType(1);
2666 iter.setValue(sign * d * d);
2671 const auto mm =
minMax(distTree);
2672 maxSqDist = mm.max();
2677 const ValueType voxelDistSqLimit(0.75*9);
2678 if (maxSqDist > voxelDistSqLimit) {
2679 std::vector<LeafNodeType*> nodes;
2680 nodes.reserve(distTree.leafCount());
2681 distTree.getNodes(nodes);
2683 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2684 [&](
const tbb::blocked_range<size_t>& r) {
2685 for (size_t i = r.begin(); i != r.end(); ++i) {
2686 for (auto iter = nodes[i]->beginValueOn(); iter; ++iter) {
2687 if (std::abs(*iter) > voxelDistSqLimit) {
2688 nodes[i]->setValueOff(iter.pos());
2694 pruneInactive(distTree,
true);
2699 traceExteriorBoundaries(distTree);
2702 if (removeDisconnectedInterior) {
2703 std::vector<LeafNodeType*> nodes;
2704 nodes.reserve(distTree.leafCount());
2705 distTree.getNodes(nodes);
2707 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
2711 tbb::parallel_for(nodeRange,
2712 mesh_to_volume_internal::ValidateIntersectingVoxels<TreeType>(
2716 tbb::parallel_for(nodeRange,
2717 [&](
const tbb::blocked_range<size_t>& r) {
2718 for (
size_t i = r.begin(); i != r.end(); ++i) {
2719 for (
auto iter = nodes[i]->beginValueOn(); iter; ++iter) {
2720 if (*iter > ValueType(0.75)) nodes[i]->setValueOff(iter.pos());
2730 std::vector<LeafNodeType*> nodes;
2731 nodes.reserve(distTree.leafCount());
2732 distTree.getNodes(nodes);
2734 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2735 mesh_to_volume_internal::TransformValues<TreeType>(
2736 nodes, voxelSize,
false));
2740 const auto mm =
minMax(distTree);
2741 const ValueType exteriorWidth = mm.max();
2742 const ValueType interiorWidth = mm.min();
2744 distTree.root().setBackground(exteriorWidth,
false);
2747 grid.setGridClass(GRID_LEVEL_SET);
2750 if (rebuildNarrowBand) {
2751 const int dilationCount =
static_cast<int>(math::RoundUp(halfWidth));
2752 tools::dilateActiveValues(distTree, dilationCount,
2753 tools::NN_FACE, tools::PRESERVE_TILES);
2755 util::NullInterrupter interrupter;
2756 LevelSetFilter<GridType, GridType, util::NullInterrupter> filter(grid, &interrupter);
2758 filter.setSpatialScheme(math::FIRST_BIAS);
2759 filter.setTemporalScheme(math::TVD_RK1);
2761 filter.setSpatialScheme(math::HJWENO5_BIAS);
2762 filter.setTemporalScheme(math::TVD_RK3);
2765 filter.setNormCount(dilationCount);
2769 const ValueType bandWidth = voxelSize * ValueType(halfWidth);
2770 tools::pruneLevelSet(distTree, bandWidth, -bandWidth);
2780#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
2782#ifdef OPENVDB_INSTANTIATE_LEVELSETUTIL
2786#define _FUNCTION(TreeT) \
2787 void sdfToFogVolume(Grid<TreeT>&, TreeT::ValueType)
2791#define _FUNCTION(TreeT) \
2792 TreeT::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const TreeT&, TreeT::ValueType)
2796#define _FUNCTION(TreeT) \
2797 Grid<TreeT>::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const Grid<TreeT>&, TreeT::ValueType)
2801#define _FUNCTION(TreeT) \
2802 TreeT::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\
2803 const TreeT&, TreeT::ValueType, \
2804 const TreeAdapter<TreeT>::TreeType::ValueConverter<bool>::Type*)
2808#define _FUNCTION(TreeT) \
2809 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\
2810 const Grid<TreeT>&, TreeT::ValueType, \
2811 const TreeAdapter<Grid<TreeT>>::TreeType::ValueConverter<bool>::Type*)
2815#define _FUNCTION(TreeT) \
2816 TreeT::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const TreeT&, TreeT::ValueType)
2820#define _FUNCTION(TreeT) \
2821 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const Grid<TreeT>&, TreeT::ValueType)
2825#define _FUNCTION(TreeT) \
2826 void extractActiveVoxelSegmentMasks(\
2827 const TreeT&, std::vector<TreeT::ValueConverter<bool>::Type::Ptr>&)
2831#define _FUNCTION(TreeT) \
2832 void extractActiveVoxelSegmentMasks(\
2833 const Grid<TreeT>&, std::vector<Grid<TreeT>::ValueConverter<bool>::Type::Ptr>&)
2837#define _FUNCTION(TreeT) \
2838 void segmentActiveVoxels(const TreeT&, std::vector<TreeT::Ptr>&)
2842#define _FUNCTION(TreeT) \
2843 void segmentActiveVoxels(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&)
2847#define _FUNCTION(TreeT) \
2848 void segmentSDF(const TreeT&, std::vector<TreeT::Ptr>&)
2852#define _FUNCTION(TreeT) \
2853 void segmentSDF(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&)
2857#define _FUNCTION(TreeT) \
2858 void distanceFieldToSDF(Grid<TreeT>&, bool, bool, float)
Functions to count tiles, nodes or voxels in a grid.
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Implementation of morphological dilation and erosion.
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition ValueAccessor.h:455
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is '\0'
Definition Util.h:156
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:219
Definition PointDataGrid.h:170
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
Index32 Index
Definition Types.h:34
@ GRID_FOG_VOLUME
Definition Types.h:527
openvdb::GridBase Grid
Definition Utils.h:43
Definition Exceptions.h:13
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition Grid.h:1058
static NonConstTreeType & tree(NonConstTreeType &t)
Definition Grid.h:1074
_TreeType TreeType
Definition Grid.h:1059
#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:284
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:228
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)
Definition version.h.in:232