11 #ifndef OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED 12 #define OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED 21 #include <tbb/blocked_range.h> 22 #include <tbb/parallel_for.h> 23 #include <tbb/parallel_reduce.h> 24 #include <tbb/parallel_sort.h> 44 template<
typename Gr
idType>
45 inline typename GridType::ValueType lsutilGridMax()
50 template<
typename Gr
idType>
51 inline typename GridType::ValueType lsutilGridZero()
53 return zeroVal<typename GridType::ValueType>();
76 template<
class Gr
idType>
80 typename GridType::ValueType cutoffDistance = lsutilGridMax<GridType>());
93 template<
class Gr
idOrTreeType>
94 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
96 const GridOrTreeType& volume,
97 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>());
120 template<
typename Gr
idOrTreeType>
121 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
123 const GridOrTreeType& volume,
124 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>(),
125 const typename TreeAdapter<GridOrTreeType>::TreeType::template ValueConverter<bool>::Type*
134 template<
typename Gr
idOrTreeType>
135 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
144 template<
typename Gr
idOrTreeType>
147 std::vector<
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks);
157 template<
typename Gr
idOrTreeType>
160 std::vector<typename GridOrTreeType::Ptr>& segments);
171 template<
typename Gr
idOrTreeType>
173 segmentSDF(
const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments);
183 namespace level_set_util_internal {
186 template<
typename LeafNodeType>
187 struct MaskInteriorVoxels {
189 using ValueType =
typename LeafNodeType::ValueType;
190 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
193 ValueType isovalue,
const LeafNodeType ** nodes, BoolLeafNodeType ** maskNodes)
194 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
198 void operator()(
const tbb::blocked_range<size_t>& range)
const {
200 BoolLeafNodeType * maskNodePt =
nullptr;
202 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
204 mMaskNodes[n] =
nullptr;
205 const LeafNodeType& node = *mNodes[n];
208 maskNodePt =
new BoolLeafNodeType(node.origin(),
false);
210 maskNodePt->setOrigin(node.origin());
213 const ValueType* values = &node.getValue(0);
214 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
215 if (values[i] < mIsovalue) maskNodePt->setValueOn(i,
true);
218 if (maskNodePt->onVoxelCount() > 0) {
219 mMaskNodes[n] = maskNodePt;
220 maskNodePt =
nullptr;
227 LeafNodeType
const *
const *
const mNodes;
228 BoolLeafNodeType **
const mMaskNodes;
229 ValueType
const mIsovalue;
233 template<
typename TreeType,
typename InternalNodeType>
234 struct MaskInteriorTiles {
236 using ValueType =
typename TreeType::ValueType;
238 MaskInteriorTiles(ValueType isovalue,
const TreeType& tree, InternalNodeType ** maskNodes)
239 : mTree(&tree), mMaskNodes(maskNodes), mIsovalue(isovalue) { }
241 void operator()(
const tbb::blocked_range<size_t>& range)
const {
242 tree::ValueAccessor<const TreeType> acc(*mTree);
243 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
244 typename InternalNodeType::ValueAllIter it = mMaskNodes[n]->beginValueAll();
246 if (acc.getValue(it.getCoord()) < mIsovalue) {
254 TreeType
const *
const mTree;
255 InternalNodeType **
const mMaskNodes;
256 ValueType
const mIsovalue;
260 template<
typename TreeType>
261 struct PopulateTree {
263 using ValueType =
typename TreeType::ValueType;
264 using LeafNodeType =
typename TreeType::LeafNodeType;
266 PopulateTree(TreeType& tree, LeafNodeType** leafnodes,
267 const size_t * nodexIndexMap, ValueType background)
268 : mNewTree(background)
271 , mNodeIndexMap(nodexIndexMap)
276 : mNewTree(rhs.mNewTree.background())
279 , mNodeIndexMap(rhs.mNodeIndexMap)
283 void operator()(
const tbb::blocked_range<size_t>& range) {
285 tree::ValueAccessor<TreeType> acc(*mTreePt);
288 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
289 for (
size_t i = mNodeIndexMap[n], I = mNodeIndexMap[n + 1]; i < I; ++i) {
290 if (mNodes[i] !=
nullptr) acc.addLeaf(mNodes[i]);
294 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
295 acc.addLeaf(mNodes[n]);
300 void join(PopulateTree& rhs) { mTreePt->merge(*rhs.mTreePt); }
304 TreeType *
const mTreePt;
305 LeafNodeType **
const mNodes;
306 size_t const *
const mNodeIndexMap;
311 template<
typename LeafNodeType>
312 struct LabelBoundaryVoxels {
314 using ValueType =
typename LeafNodeType::ValueType;
315 using CharLeafNodeType = tree::LeafNode<char, LeafNodeType::LOG2DIM>;
318 ValueType isovalue,
const LeafNodeType ** nodes, CharLeafNodeType ** maskNodes)
319 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
323 void operator()(
const tbb::blocked_range<size_t>& range)
const {
325 CharLeafNodeType * maskNodePt =
nullptr;
327 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
329 mMaskNodes[n] =
nullptr;
330 const LeafNodeType& node = *mNodes[n];
333 maskNodePt =
new CharLeafNodeType(node.origin(), 1);
335 maskNodePt->setOrigin(node.origin());
338 typename LeafNodeType::ValueOnCIter it;
339 for (it = node.cbeginValueOn(); it; ++it) {
340 maskNodePt->setValueOn(it.pos(), ((*it - mIsovalue) < 0.0) ? 0 : 1);
343 if (maskNodePt->onVoxelCount() > 0) {
344 mMaskNodes[n] = maskNodePt;
345 maskNodePt =
nullptr;
352 LeafNodeType
const *
const *
const mNodes;
353 CharLeafNodeType **
const mMaskNodes;
354 ValueType
const mIsovalue;
358 template<
typename LeafNodeType>
359 struct FlipRegionSign {
360 using ValueType =
typename LeafNodeType::ValueType;
362 FlipRegionSign(LeafNodeType ** nodes) : mNodes(nodes) { }
364 void operator()(
const tbb::blocked_range<size_t>& range)
const {
365 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
366 ValueType* values =
const_cast<ValueType*
>(&mNodes[n]->getValue(0));
367 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
368 values[i] = values[i] < 0 ? 1 : -1;
373 LeafNodeType **
const mNodes;
377 template<
typename LeafNodeType>
378 struct FindMinVoxelValue {
380 using ValueType =
typename LeafNodeType::ValueType;
382 FindMinVoxelValue(LeafNodeType
const *
const *
const leafnodes)
383 : minValue(
std::numeric_limits<ValueType>::
max())
388 FindMinVoxelValue(FindMinVoxelValue& rhs,
tbb::split)
389 : minValue(
std::numeric_limits<ValueType>::
max())
394 void operator()(
const tbb::blocked_range<size_t>& range) {
395 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
396 const ValueType* data = mNodes[n]->buffer().data();
397 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
398 minValue =
std::min(minValue, data[i]);
403 void join(FindMinVoxelValue& rhs) { minValue =
std::min(minValue, rhs.minValue); }
407 LeafNodeType
const *
const *
const mNodes;
411 template<
typename InternalNodeType>
412 struct FindMinTileValue {
414 using ValueType =
typename InternalNodeType::ValueType;
416 FindMinTileValue(InternalNodeType
const *
const *
const nodes)
417 : minValue(
std::numeric_limits<ValueType>::
max())
422 FindMinTileValue(FindMinTileValue& rhs,
tbb::split)
423 : minValue(
std::numeric_limits<ValueType>::
max())
428 void operator()(
const tbb::blocked_range<size_t>& range) {
429 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
430 typename InternalNodeType::ValueAllCIter it = mNodes[n]->beginValueAll();
437 void join(FindMinTileValue& rhs) { minValue =
std::min(minValue, rhs.minValue); }
441 InternalNodeType
const *
const *
const mNodes;
445 template<
typename LeafNodeType>
446 struct SDFVoxelsToFogVolume {
448 using ValueType =
typename LeafNodeType::ValueType;
450 SDFVoxelsToFogVolume(LeafNodeType ** nodes, ValueType cutoffDistance)
451 : mNodes(nodes), mWeight(ValueType(1.0) / cutoffDistance)
455 void operator()(
const tbb::blocked_range<size_t>& range)
const {
457 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
459 LeafNodeType& node = *mNodes[n];
462 ValueType* values = node.buffer().data();
463 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
464 values[i] = values[i] > ValueType(0.0) ? ValueType(0.0) : values[i] * mWeight;
465 if (values[i] > ValueType(0.0)) node.setValueOn(i);
468 if (node.onVoxelCount() == 0) {
475 LeafNodeType **
const mNodes;
476 ValueType
const mWeight;
480 template<
typename TreeType,
typename InternalNodeType>
481 struct SDFTilesToFogVolume {
483 SDFTilesToFogVolume(
const TreeType& tree, InternalNodeType ** nodes)
484 : mTree(&tree), mNodes(nodes) { }
486 void operator()(
const tbb::blocked_range<size_t>& range)
const {
488 using ValueType =
typename TreeType::ValueType;
489 tree::ValueAccessor<const TreeType> acc(*mTree);
491 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
492 typename InternalNodeType::ValueAllIter it = mNodes[n]->beginValueAll();
494 if (acc.getValue(it.getCoord()) < ValueType(0.0)) {
495 it.setValue(ValueType(1.0));
502 TreeType
const *
const mTree;
503 InternalNodeType **
const mNodes;
507 template<
typename TreeType>
508 struct FillMaskBoundary {
510 using ValueType =
typename TreeType::ValueType;
511 using LeafNodeType =
typename TreeType::LeafNodeType;
512 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
513 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
515 FillMaskBoundary(
const TreeType& tree, ValueType isovalue,
const BoolTreeType& fillMask,
516 const BoolLeafNodeType ** fillNodes, BoolLeafNodeType ** newNodes)
518 , mFillMask(&fillMask)
519 , mFillNodes(fillNodes)
520 , mNewNodes(newNodes)
521 , mIsovalue(isovalue)
525 void operator()(
const tbb::blocked_range<size_t>& range)
const {
527 tree::ValueAccessor<const BoolTreeType> maskAcc(*mFillMask);
528 tree::ValueAccessor<const TreeType> distAcc(*mTree);
530 std::unique_ptr<char[]> valueMask(
new char[BoolLeafNodeType::SIZE]);
532 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
534 mNewNodes[n] =
nullptr;
535 const BoolLeafNodeType& node = *mFillNodes[n];
536 const Coord& origin = node.origin();
538 const bool denseNode = node.isDense();
543 int denseNeighbors = 0;
545 const BoolLeafNodeType* neighborNode =
546 maskAcc.probeConstLeaf(origin.offsetBy(-1, 0, 0));
547 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
549 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(BoolLeafNodeType::DIM, 0, 0));
550 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
552 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, -1, 0));
553 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
555 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, BoolLeafNodeType::DIM, 0));
556 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
558 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, -1));
559 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
561 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, BoolLeafNodeType::DIM));
562 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
564 if (denseNeighbors == 6)
continue;
568 memset(valueMask.get(), 0,
sizeof(char) * BoolLeafNodeType::SIZE);
570 const typename TreeType::LeafNodeType* distNode = distAcc.probeConstLeaf(origin);
574 bool earlyTermination =
false;
578 evalInternalNeighborsP(valueMask.get(), node, *distNode);
579 evalInternalNeighborsN(valueMask.get(), node, *distNode);
580 }
else if (distAcc.getValue(origin) > mIsovalue) {
581 earlyTermination = evalInternalNeighborsP(valueMask.get(), node);
582 if (!earlyTermination) {
583 earlyTermination = evalInternalNeighborsN(valueMask.get(), node);
590 if (!earlyTermination) {
591 evalExternalNeighborsX<true>(valueMask.get(), node, maskAcc, distAcc);
592 evalExternalNeighborsX<false>(valueMask.get(), node, maskAcc, distAcc);
593 evalExternalNeighborsY<true>(valueMask.get(), node, maskAcc, distAcc);
594 evalExternalNeighborsY<false>(valueMask.get(), node, maskAcc, distAcc);
595 evalExternalNeighborsZ<true>(valueMask.get(), node, maskAcc, distAcc);
596 evalExternalNeighborsZ<false>(valueMask.get(), node, maskAcc, distAcc);
601 int numBoundaryValues = 0;
602 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
603 numBoundaryValues += valueMask[i] == 1;
606 if (numBoundaryValues > 0) {
607 mNewNodes[n] =
new BoolLeafNodeType(origin,
false);
608 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
609 if (valueMask[i] == 1) mNewNodes[n]->setValueOn(i);
617 void evalInternalNeighborsP(
char* valueMask,
const BoolLeafNodeType& node,
618 const LeafNodeType& distNode)
const 620 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
621 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
622 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
623 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
624 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
625 const Index pos = yPos + z;
627 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
629 if (!node.isValueOn(pos + 1) && distNode.getValue(pos + 1) > mIsovalue) {
636 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
637 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
638 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
639 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
640 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
641 const Index pos = yPos + z;
643 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
645 if (!node.isValueOn(pos + BoolLeafNodeType::DIM) &&
646 distNode.getValue(pos + BoolLeafNodeType::DIM) > mIsovalue) {
653 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
654 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
655 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
656 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
657 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
658 const Index pos = yPos + z;
660 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
662 if (!node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
663 (distNode.getValue(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
673 bool evalInternalNeighborsP(
char* valueMask,
const BoolLeafNodeType& node)
const {
675 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
676 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
677 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
678 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
679 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
680 const Index pos = yPos + z;
682 if (node.isValueOn(pos) && !node.isValueOn(pos + 1)) {
690 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
691 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
692 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
693 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
694 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
695 const Index pos = yPos + z;
697 if (node.isValueOn(pos) && !node.isValueOn(pos + BoolLeafNodeType::DIM)) {
705 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
706 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
707 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
708 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
709 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
710 const Index pos = yPos + z;
712 if (node.isValueOn(pos) &&
713 !node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
726 void evalInternalNeighborsN(
char* valueMask,
const BoolLeafNodeType& node,
727 const LeafNodeType& distNode)
const 729 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
730 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
731 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
732 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
733 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
734 const Index pos = yPos + z;
736 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
738 if (!node.isValueOn(pos - 1) && distNode.getValue(pos - 1) > mIsovalue) {
745 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
746 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
747 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
748 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
749 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
750 const Index pos = yPos + z;
752 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
754 if (!node.isValueOn(pos - BoolLeafNodeType::DIM) &&
755 distNode.getValue(pos - BoolLeafNodeType::DIM) > mIsovalue) {
762 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
763 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
764 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
765 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
766 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
767 const Index pos = yPos + z;
769 if (valueMask[pos] != 0 || !node.isValueOn(pos))
continue;
771 if (!node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
772 (distNode.getValue(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
783 bool evalInternalNeighborsN(
char* valueMask,
const BoolLeafNodeType& node)
const {
785 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
786 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
787 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
788 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
789 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
790 const Index pos = yPos + z;
792 if (node.isValueOn(pos) && !node.isValueOn(pos - 1)) {
800 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
801 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
802 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
803 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
804 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
805 const Index pos = yPos + z;
807 if (node.isValueOn(pos) && !node.isValueOn(pos - BoolLeafNodeType::DIM)) {
815 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
816 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
817 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
818 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
819 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
820 const Index pos = yPos + z;
822 if (node.isValueOn(pos) &&
823 !node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
838 template<
bool UpWind>
839 void evalExternalNeighborsX(
char* valueMask,
const BoolLeafNodeType& node,
840 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
841 const tree::ValueAccessor<const TreeType>& distAcc)
const {
843 const Coord& origin = node.origin();
844 Coord ijk(0, 0, 0), nijk;
849 ijk[0] = int(BoolLeafNodeType::DIM) - 1;
852 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
854 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
855 const Index yPos = xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
857 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
858 const Index pos = yPos + ijk[2];
860 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
862 nijk = origin + ijk.offsetBy(step, 0, 0);
864 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
873 template<
bool UpWind>
874 void evalExternalNeighborsY(
char* valueMask,
const BoolLeafNodeType& node,
875 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
876 const tree::ValueAccessor<const TreeType>& distAcc)
const {
878 const Coord& origin = node.origin();
879 Coord ijk(0, 0, 0), nijk;
884 ijk[1] = int(BoolLeafNodeType::DIM) - 1;
887 const Index yPos = ijk[1] << int(BoolLeafNodeType::LOG2DIM);
889 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
890 const Index xPos = yPos + (ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM)));
892 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
893 const Index pos = xPos + ijk[2];
895 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
897 nijk = origin + ijk.offsetBy(0, step, 0);
898 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
907 template<
bool UpWind>
908 void evalExternalNeighborsZ(
char* valueMask,
const BoolLeafNodeType& node,
909 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
910 const tree::ValueAccessor<const TreeType>& distAcc)
const {
912 const Coord& origin = node.origin();
913 Coord ijk(0, 0, 0), nijk;
918 ijk[2] = int(BoolLeafNodeType::DIM) - 1;
921 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
922 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
924 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
925 const Index pos = ijk[2] + xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
927 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
929 nijk = origin + ijk.offsetBy(0, 0, step);
930 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
940 TreeType
const *
const mTree;
941 BoolTreeType
const *
const mFillMask;
942 BoolLeafNodeType
const *
const *
const mFillNodes;
943 BoolLeafNodeType **
const mNewNodes;
944 ValueType
const mIsovalue;
950 template <
class TreeType>
951 typename TreeType::template ValueConverter<char>::Type::Ptr
952 computeEnclosedRegionMask(
const TreeType& tree,
typename TreeType::ValueType isovalue,
953 const typename TreeType::template ValueConverter<bool>::Type* fillMask)
955 using LeafNodeType =
typename TreeType::LeafNodeType;
956 using RootNodeType =
typename TreeType::RootNodeType;
957 using NodeChainType =
typename RootNodeType::NodeChainType;
958 using InternalNodeType =
typename NodeChainType::template Get<1>;
960 using CharTreeType =
typename TreeType::template ValueConverter<char>::Type;
961 using CharLeafNodeType =
typename CharTreeType::LeafNodeType;
963 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
964 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
966 const TreeType* treePt = &tree;
968 size_t numLeafNodes = 0, numInternalNodes = 0;
970 std::vector<const LeafNodeType*> nodes;
971 std::vector<size_t> leafnodeCount;
975 std::vector<const InternalNodeType*> internalNodes;
976 treePt->getNodes(internalNodes);
978 numInternalNodes = internalNodes.size();
980 leafnodeCount.push_back(0);
981 for (
size_t n = 0; n < numInternalNodes; ++n) {
982 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
985 numLeafNodes = leafnodeCount.back();
988 nodes.reserve(numLeafNodes);
990 for (
size_t n = 0; n < numInternalNodes; ++n) {
991 internalNodes[n]->getNodes(nodes);
996 std::unique_ptr<CharLeafNodeType*[]> maskNodes(
new CharLeafNodeType*[numLeafNodes]);
998 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
999 LabelBoundaryVoxels<LeafNodeType>(isovalue, nodes.data(), maskNodes.get()));
1002 typename CharTreeType::Ptr maskTree(
new CharTreeType(1));
1004 PopulateTree<CharTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(), 1);
1005 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1009 std::vector<CharLeafNodeType*> extraMaskNodes;
1013 std::vector<const BoolLeafNodeType*> fillMaskNodes;
1014 fillMask->getNodes(fillMaskNodes);
1016 std::unique_ptr<BoolLeafNodeType*[]> boundaryMaskNodes(
1017 new BoolLeafNodeType*[fillMaskNodes.size()]);
1019 tbb::parallel_for(tbb::blocked_range<size_t>(0, fillMaskNodes.size()),
1020 FillMaskBoundary<TreeType>(tree, isovalue, *fillMask, fillMaskNodes.data(),
1021 boundaryMaskNodes.get()));
1023 tree::ValueAccessor<CharTreeType> maskAcc(*maskTree);
1025 for (
size_t n = 0, N = fillMaskNodes.size(); n < N; ++n) {
1027 if (boundaryMaskNodes[n] ==
nullptr)
continue;
1029 const BoolLeafNodeType& boundaryNode = *boundaryMaskNodes[n];
1030 const Coord& origin = boundaryNode.origin();
1032 CharLeafNodeType* maskNodePt = maskAcc.probeLeaf(origin);
1035 maskNodePt = maskAcc.touchLeaf(origin);
1036 extraMaskNodes.push_back(maskNodePt);
1039 char* data = maskNodePt->buffer().data();
1041 typename BoolLeafNodeType::ValueOnCIter it = boundaryNode.cbeginValueOn();
1043 if (data[it.pos()] != 0) data[it.pos()] = -1;
1046 delete boundaryMaskNodes[n];
1054 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1055 FlipRegionSign<CharLeafNodeType>(maskNodes.get()));
1057 if (!extraMaskNodes.empty()) {
1058 tbb::parallel_for(tbb::blocked_range<size_t>(0, extraMaskNodes.size()),
1059 FlipRegionSign<CharLeafNodeType>(extraMaskNodes.data()));
1069 template <
class TreeType>
1070 typename TreeType::template ValueConverter<bool>::Type::Ptr
1071 computeInteriorMask(
const TreeType& tree,
typename TreeType::ValueType iso)
1073 using ValueType =
typename TreeType::ValueType;
1074 using LeafNodeType =
typename TreeType::LeafNodeType;
1075 using RootNodeType =
typename TreeType::RootNodeType;
1076 using NodeChainType =
typename RootNodeType::NodeChainType;
1077 using InternalNodeType =
typename NodeChainType::template Get<1>;
1079 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1080 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1081 using BoolRootNodeType =
typename BoolTreeType::RootNodeType;
1082 using BoolNodeChainType =
typename BoolRootNodeType::NodeChainType;
1083 using BoolInternalNodeType =
typename BoolNodeChainType::template Get<1>;
1093 static_cast<ValueType>(tree.background() - math::Tolerance<ValueType>::value()));
1095 size_t numLeafNodes = 0, numInternalNodes = 0;
1097 std::vector<const LeafNodeType*> nodes;
1098 std::vector<size_t> leafnodeCount;
1102 std::vector<const InternalNodeType*> internalNodes;
1103 tree.getNodes(internalNodes);
1105 numInternalNodes = internalNodes.size();
1107 leafnodeCount.push_back(0);
1108 for (
size_t n = 0; n < numInternalNodes; ++n) {
1109 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
1112 numLeafNodes = leafnodeCount.back();
1115 nodes.reserve(numLeafNodes);
1117 for (
size_t n = 0; n < numInternalNodes; ++n) {
1118 internalNodes[n]->getNodes(nodes);
1123 std::unique_ptr<BoolLeafNodeType*[]> maskNodes(
new BoolLeafNodeType*[numLeafNodes]);
1125 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1126 MaskInteriorVoxels<LeafNodeType>(iso, nodes.data(), maskNodes.get()));
1130 typename BoolTreeType::Ptr maskTree(
new BoolTreeType(
false));
1132 PopulateTree<BoolTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(),
false);
1133 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1137 std::vector<BoolInternalNodeType*> internalMaskNodes;
1138 maskTree->getNodes(internalMaskNodes);
1140 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalMaskNodes.size()),
1141 MaskInteriorTiles<TreeType, BoolInternalNodeType>(iso, tree, internalMaskNodes.data()));
1143 tree::ValueAccessor<const TreeType> acc(tree);
1145 typename BoolTreeType::ValueAllIter it(*maskTree);
1146 it.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 2);
1149 if (acc.getValue(it.getCoord()) < iso) {
1151 it.setActiveState(
true);
1159 template<
typename InputTreeType>
1160 struct MaskIsovalueCrossingVoxels
1162 using InputValueType =
typename InputTreeType::ValueType;
1163 using InputLeafNodeType =
typename InputTreeType::LeafNodeType;
1164 using BoolTreeType =
typename InputTreeType::template ValueConverter<bool>::Type;
1165 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1167 MaskIsovalueCrossingVoxels(
1168 const InputTreeType& inputTree,
1169 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
1170 BoolTreeType& maskTree,
1172 : mInputAccessor(inputTree)
1173 , mInputNodes(!inputLeafNodes.
empty() ? &inputLeafNodes.front() : nullptr)
1175 , mMaskAccessor(maskTree)
1180 MaskIsovalueCrossingVoxels(MaskIsovalueCrossingVoxels& rhs,
tbb::split)
1181 : mInputAccessor(rhs.mInputAccessor.tree())
1182 , mInputNodes(rhs.mInputNodes)
1184 , mMaskAccessor(mMaskTree)
1185 , mIsovalue(rhs.mIsovalue)
1189 void operator()(
const tbb::blocked_range<size_t>& range) {
1191 const InputValueType iso = mIsovalue;
1194 BoolLeafNodeType* maskNodePt =
nullptr;
1196 for (
size_t n = range.begin(); mInputNodes && (n != range.end()); ++n) {
1198 const InputLeafNodeType& node = *mInputNodes[n];
1200 if (!maskNodePt) maskNodePt =
new BoolLeafNodeType(node.origin(),
false);
1201 else maskNodePt->setOrigin(node.origin());
1203 bool collectedData =
false;
1205 for (
typename InputLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
1207 bool isUnder = *it < iso;
1209 ijk = it.getCoord();
1212 bool signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1217 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1223 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1229 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1235 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1241 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso);
1246 collectedData =
true;
1247 maskNodePt->setValueOn(it.pos(),
true);
1251 if (collectedData) {
1252 mMaskAccessor.addLeaf(maskNodePt);
1253 maskNodePt =
nullptr;
1260 void join(MaskIsovalueCrossingVoxels& rhs) {
1261 mMaskAccessor.tree().merge(rhs.mMaskAccessor.tree());
1265 tree::ValueAccessor<const InputTreeType> mInputAccessor;
1266 InputLeafNodeType
const *
const *
const mInputNodes;
1268 BoolTreeType mMaskTree;
1269 tree::ValueAccessor<BoolTreeType> mMaskAccessor;
1271 InputValueType mIsovalue;
1278 template<
typename NodeType>
1279 struct NodeMaskSegment
1281 using Ptr = SharedPtr<NodeMaskSegment>;
1282 using NodeMaskType =
typename NodeType::NodeMaskType;
1284 NodeMaskSegment() : connections(), mask(false), origin(0,0,0), visited(false) {}
1286 std::vector<NodeMaskSegment*> connections;
1293 template<
typename NodeType>
1295 nodeMaskSegmentation(
const NodeType& node,
1296 std::vector<
typename NodeMaskSegment<NodeType>::Ptr>& segments)
1298 using NodeMaskType =
typename NodeType::NodeMaskType;
1299 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1300 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1302 NodeMaskType nodeMask(node.getValueMask());
1303 std::deque<Index> indexList;
1305 while (!nodeMask.isOff()) {
1307 NodeMaskSegmentTypePtr segment(
new NodeMaskSegmentType());
1308 segment->origin = node.origin();
1310 NodeMaskType& mask = segment->mask;
1312 indexList.push_back(nodeMask.findFirstOn());
1313 nodeMask.setOff(indexList.back());
1316 while (!indexList.empty()) {
1318 const Index pos = indexList.back();
1319 indexList.pop_back();
1321 if (mask.isOn(pos))
continue;
1324 ijk = NodeType::offsetToLocalCoord(pos);
1326 Index npos = pos - 1;
1327 if (ijk[2] != 0 && nodeMask.isOn(npos)) {
1328 nodeMask.setOff(npos);
1329 indexList.push_back(npos);
1333 if (ijk[2] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1334 nodeMask.setOff(npos);
1335 indexList.push_back(npos);
1338 npos = pos - NodeType::DIM;
1339 if (ijk[1] != 0 && nodeMask.isOn(npos)) {
1340 nodeMask.setOff(npos);
1341 indexList.push_back(npos);
1344 npos = pos + NodeType::DIM;
1345 if (ijk[1] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1346 nodeMask.setOff(npos);
1347 indexList.push_back(npos);
1350 npos = pos - NodeType::DIM * NodeType::DIM;
1351 if (ijk[0] != 0 && nodeMask.isOn(npos)) {
1352 nodeMask.setOff(npos);
1353 indexList.push_back(npos);
1356 npos = pos + NodeType::DIM * NodeType::DIM;
1357 if (ijk[0] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1358 nodeMask.setOff(npos);
1359 indexList.push_back(npos);
1364 segments.push_back(segment);
1369 template<
typename NodeType>
1370 struct SegmentNodeMask
1372 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1373 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1374 using NodeMaskSegmentVector =
typename std::vector<NodeMaskSegmentTypePtr>;
1376 SegmentNodeMask(std::vector<NodeType*>& nodes, NodeMaskSegmentVector* nodeMaskArray)
1377 : mNodes(!nodes.
empty() ? &nodes.front() : nullptr)
1378 , mNodeMaskArray(nodeMaskArray)
1382 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1383 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1384 NodeType& node = *mNodes[n];
1385 nodeMaskSegmentation(node, mNodeMaskArray[n]);
1388 Coord& origin =
const_cast<Coord&
>(node.origin());
1389 origin[0] =
static_cast<int>(n);
1393 NodeType *
const *
const mNodes;
1394 NodeMaskSegmentVector *
const mNodeMaskArray;
1398 template<
typename TreeType,
typename NodeType>
1399 struct ConnectNodeMaskSegments
1401 using NodeMaskType =
typename NodeType::NodeMaskType;
1402 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1403 using NodeMaskSegmentTypePtr =
typename NodeMaskSegmentType::Ptr;
1404 using NodeMaskSegmentVector =
typename std::vector<NodeMaskSegmentTypePtr>;
1406 ConnectNodeMaskSegments(
const TreeType& tree, NodeMaskSegmentVector* nodeMaskArray)
1408 , mNodeMaskArray(nodeMaskArray)
1412 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1414 tree::ValueAccessor<const TreeType> acc(*mTree);
1416 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1418 NodeMaskSegmentVector& segments = mNodeMaskArray[n];
1419 if (segments.empty())
continue;
1421 std::vector<std::set<NodeMaskSegmentType*> > connections(segments.size());
1423 Coord ijk = segments[0]->origin;
1425 const NodeType* node = acc.template probeConstNode<NodeType>(ijk);
1426 if (!node)
continue;
1430 ijk[2] += NodeType::DIM;
1431 const NodeType* nodeZUp = acc.template probeConstNode<NodeType>(ijk);
1432 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1433 const NodeType* nodeZDown = acc.template probeConstNode<NodeType>(ijk);
1434 ijk[2] += NodeType::DIM;
1436 ijk[1] += NodeType::DIM;
1437 const NodeType* nodeYUp = acc.template probeConstNode<NodeType>(ijk);
1438 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1439 const NodeType* nodeYDown = acc.template probeConstNode<NodeType>(ijk);
1440 ijk[1] += NodeType::DIM;
1442 ijk[0] += NodeType::DIM;
1443 const NodeType* nodeXUp = acc.template probeConstNode<NodeType>(ijk);
1444 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1445 const NodeType* nodeXDown = acc.template probeConstNode<NodeType>(ijk);
1446 ijk[0] += NodeType::DIM;
1448 const Index startPos = node->getValueMask().findFirstOn();
1449 for (Index pos = startPos; pos < NodeMaskType::SIZE; ++pos) {
1451 if (!node->isValueOn(pos))
continue;
1453 ijk = NodeType::offsetToLocalCoord(pos);
1455 #ifdef _MSC_FULL_VER 1456 #if _MSC_FULL_VER >= 190000000 && _MSC_FULL_VER < 190024210 1458 volatile Index npos = 0;
1467 npos = pos + (NodeType::DIM - 1);
1468 if (nodeZDown && nodeZDown->isValueOn(npos)) {
1469 NodeMaskSegmentType* nsegment =
1470 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZDown)], npos);
1471 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1472 connections[idx].insert(nsegment);
1474 }
else if (ijk[2] == (NodeType::DIM - 1)) {
1475 npos = pos - (NodeType::DIM - 1);
1476 if (nodeZUp && nodeZUp->isValueOn(npos)) {
1477 NodeMaskSegmentType* nsegment =
1478 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZUp)], npos);
1479 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1480 connections[idx].insert(nsegment);
1485 npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1486 if (nodeYDown && nodeYDown->isValueOn(npos)) {
1487 NodeMaskSegmentType* nsegment =
1488 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYDown)], npos);
1489 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1490 connections[idx].insert(nsegment);
1492 }
else if (ijk[1] == (NodeType::DIM - 1)) {
1493 npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1494 if (nodeYUp && nodeYUp->isValueOn(npos)) {
1495 NodeMaskSegmentType* nsegment =
1496 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYUp)], npos);
1497 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1498 connections[idx].insert(nsegment);
1503 npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1504 if (nodeXDown && nodeXDown->isValueOn(npos)) {
1505 NodeMaskSegmentType* nsegment =
1506 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXDown)], npos);
1507 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1508 connections[idx].insert(nsegment);
1510 }
else if (ijk[0] == (NodeType::DIM - 1)) {
1511 npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1512 if (nodeXUp && nodeXUp->isValueOn(npos)) {
1513 NodeMaskSegmentType* nsegment =
1514 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXUp)], npos);
1515 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1516 connections[idx].insert(nsegment);
1521 for (
size_t i = 0, I = connections.size(); i < I; ++i) {
1523 typename std::set<NodeMaskSegmentType*>::iterator
1524 it = connections[i].begin(), end = connections[i].end();
1526 std::vector<NodeMaskSegmentType*>& segmentConnections = segments[i]->connections;
1527 segmentConnections.reserve(connections.size());
1528 for (; it != end; ++it) {
1529 segmentConnections.push_back(*it);
1537 static inline size_t getNodeOffset(
const NodeType& node) {
1538 return static_cast<size_t>(node.origin()[0]);
1541 static inline NodeMaskSegmentType*
1542 findNodeMaskSegment(NodeMaskSegmentVector& segments, Index pos)
1544 NodeMaskSegmentType* segment =
nullptr;
1546 for (
size_t n = 0, N = segments.size(); n < N; ++n) {
1547 if (segments[n]->mask.isOn(pos)) {
1548 segment = segments[n].get();
1557 findNodeMaskSegmentIndex(NodeMaskSegmentVector& segments, Index pos)
1559 for (Index n = 0, N =
Index(segments.size()); n < N; ++n) {
1560 if (segments[n]->mask.isOn(pos))
return n;
1565 TreeType
const *
const mTree;
1566 NodeMaskSegmentVector *
const mNodeMaskArray;
1570 template<
typename TreeType>
1571 struct MaskSegmentGroup
1573 using LeafNodeType =
typename TreeType::LeafNodeType;
1574 using TreeTypePtr =
typename TreeType::Ptr;
1575 using NodeMaskSegmentType = NodeMaskSegment<LeafNodeType>;
1577 MaskSegmentGroup(
const std::vector<NodeMaskSegmentType*>& segments)
1578 : mSegments(!segments.
empty() ? &segments.front() : nullptr)
1579 , mTree(new TreeType(false))
1583 MaskSegmentGroup(
const MaskSegmentGroup& rhs,
tbb::split)
1584 : mSegments(rhs.mSegments)
1585 , mTree(new TreeType(false))
1589 TreeTypePtr& mask() {
return mTree; }
1591 void join(MaskSegmentGroup& rhs) { mTree->merge(*rhs.mTree); }
1593 void operator()(
const tbb::blocked_range<size_t>& range) {
1595 tree::ValueAccessor<TreeType> acc(*mTree);
1597 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1598 NodeMaskSegmentType& segment = *mSegments[n];
1599 LeafNodeType* node = acc.touchLeaf(segment.origin);
1600 node->getValueMask() |= segment.mask;
1605 NodeMaskSegmentType *
const *
const mSegments;
1613 template<
typename TreeType>
1614 struct ExpandLeafNodeRegion
1616 using ValueType =
typename TreeType::ValueType;
1617 using LeafNodeType =
typename TreeType::LeafNodeType;
1618 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
1620 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1621 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1625 ExpandLeafNodeRegion(
const TreeType& distTree, BoolTreeType& maskTree,
1626 std::vector<BoolLeafNodeType*>& maskNodes)
1627 : mDistTree(&distTree)
1628 , mMaskTree(&maskTree)
1629 , mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
1630 , mNewMaskTree(false)
1634 ExpandLeafNodeRegion(
const ExpandLeafNodeRegion& rhs,
tbb::split)
1635 : mDistTree(rhs.mDistTree)
1636 , mMaskTree(rhs.mMaskTree)
1637 , mMaskNodes(rhs.mMaskNodes)
1638 , mNewMaskTree(false)
1642 BoolTreeType& newMaskTree() {
return mNewMaskTree; }
1644 void join(ExpandLeafNodeRegion& rhs) { mNewMaskTree.merge(rhs.mNewMaskTree); }
1646 void operator()(
const tbb::blocked_range<size_t>& range) {
1648 using NodeType = LeafNodeType;
1650 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1651 tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
1652 tree::ValueAccessor<BoolTreeType> newMaskAcc(mNewMaskTree);
1654 NodeMaskType maskZUp, maskZDown, maskYUp, maskYDown, maskXUp, maskXDown;
1656 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1658 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1659 if (maskNode.isEmpty())
continue;
1661 Coord ijk = maskNode.origin(), nijk;
1663 const LeafNodeType* distNode = distAcc.probeConstLeaf(ijk);
1664 if (!distNode)
continue;
1666 const ValueType *dataZUp =
nullptr, *dataZDown =
nullptr,
1667 *dataYUp =
nullptr, *dataYDown =
nullptr,
1668 *dataXUp =
nullptr, *dataXDown =
nullptr;
1670 ijk[2] += NodeType::DIM;
1671 getData(ijk, distAcc, maskAcc, maskZUp, dataZUp);
1672 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1673 getData(ijk, distAcc, maskAcc, maskZDown, dataZDown);
1674 ijk[2] += NodeType::DIM;
1676 ijk[1] += NodeType::DIM;
1677 getData(ijk, distAcc, maskAcc, maskYUp, dataYUp);
1678 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1679 getData(ijk, distAcc, maskAcc, maskYDown, dataYDown);
1680 ijk[1] += NodeType::DIM;
1682 ijk[0] += NodeType::DIM;
1683 getData(ijk, distAcc, maskAcc, maskXUp, dataXUp);
1684 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1685 getData(ijk, distAcc, maskAcc, maskXDown, dataXDown);
1686 ijk[0] += NodeType::DIM;
1688 for (
typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
1690 const Index pos = it.pos();
1691 const ValueType val = std::abs(distNode->getValue(pos));
1693 ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
1694 nijk = ijk + maskNode.origin();
1696 if (dataZUp && ijk[2] == (BoolLeafNodeType::DIM - 1)) {
1697 const Index npos = pos - (NodeType::DIM - 1);
1698 if (maskZUp.isOn(npos) && std::abs(dataZUp[npos]) > val) {
1699 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, 1));
1701 }
else if (dataZDown && ijk[2] == 0) {
1702 const Index npos = pos + (NodeType::DIM - 1);
1703 if (maskZDown.isOn(npos) && std::abs(dataZDown[npos]) > val) {
1704 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, -1));
1708 if (dataYUp && ijk[1] == (BoolLeafNodeType::DIM - 1)) {
1709 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1710 if (maskYUp.isOn(npos) && std::abs(dataYUp[npos]) > val) {
1711 newMaskAcc.setValueOn(nijk.offsetBy(0, 1, 0));
1713 }
else if (dataYDown && ijk[1] == 0) {
1714 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1715 if (maskYDown.isOn(npos) && std::abs(dataYDown[npos]) > val) {
1716 newMaskAcc.setValueOn(nijk.offsetBy(0, -1, 0));
1720 if (dataXUp && ijk[0] == (BoolLeafNodeType::DIM - 1)) {
1721 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1722 if (maskXUp.isOn(npos) && std::abs(dataXUp[npos]) > val) {
1723 newMaskAcc.setValueOn(nijk.offsetBy(1, 0, 0));
1725 }
else if (dataXDown && ijk[0] == 0) {
1726 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1727 if (maskXDown.isOn(npos) && std::abs(dataXDown[npos]) > val) {
1728 newMaskAcc.setValueOn(nijk.offsetBy(-1, 0, 0));
1739 getData(
const Coord& ijk, tree::ValueAccessor<const TreeType>& distAcc,
1740 tree::ValueAccessor<const BoolTreeType>& maskAcc, NodeMaskType& mask,
1741 const ValueType*& data)
1743 const LeafNodeType* node = distAcc.probeConstLeaf(ijk);
1745 data = node->buffer().data();
1746 mask = node->getValueMask();
1747 const BoolLeafNodeType* maskNodePt = maskAcc.probeConstLeaf(ijk);
1748 if (maskNodePt) mask -= maskNodePt->getValueMask();
1752 TreeType
const *
const mDistTree;
1753 BoolTreeType *
const mMaskTree;
1754 BoolLeafNodeType **
const mMaskNodes;
1756 BoolTreeType mNewMaskTree;
1760 template<
typename TreeType>
1761 struct FillLeafNodeVoxels
1763 using ValueType =
typename TreeType::ValueType;
1764 using LeafNodeType =
typename TreeType::LeafNodeType;
1765 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
1766 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
1768 FillLeafNodeVoxels(
const TreeType& tree, std::vector<BoolLeafNodeType*>& maskNodes)
1769 : mTree(&tree), mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
1773 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1775 tree::ValueAccessor<const TreeType> distAcc(*mTree);
1777 std::vector<Index> indexList;
1778 indexList.reserve(NodeMaskType::SIZE);
1780 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1782 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1784 const LeafNodeType * distNode = distAcc.probeConstLeaf(maskNode.origin());
1785 if (!distNode)
continue;
1787 NodeMaskType mask(distNode->getValueMask());
1788 NodeMaskType& narrowbandMask = maskNode.getValueMask();
1790 for (Index pos = narrowbandMask.findFirstOn(); pos < NodeMaskType::SIZE; ++pos) {
1791 if (narrowbandMask.isOn(pos)) indexList.push_back(pos);
1794 mask -= narrowbandMask;
1795 narrowbandMask.setOff();
1797 const ValueType* data = distNode->buffer().data();
1800 while (!indexList.empty()) {
1802 const Index pos = indexList.back();
1803 indexList.pop_back();
1805 if (narrowbandMask.isOn(pos))
continue;
1806 narrowbandMask.setOn(pos);
1808 const ValueType dist = std::abs(data[pos]);
1810 ijk = LeafNodeType::offsetToLocalCoord(pos);
1812 Index npos = pos - 1;
1813 if (ijk[2] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1815 indexList.push_back(npos);
1819 if ((ijk[2] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1820 && std::abs(data[npos]) > dist)
1823 indexList.push_back(npos);
1826 npos = pos - LeafNodeType::DIM;
1827 if (ijk[1] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1829 indexList.push_back(npos);
1832 npos = pos + LeafNodeType::DIM;
1833 if ((ijk[1] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1834 && std::abs(data[npos]) > dist)
1837 indexList.push_back(npos);
1840 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1841 if (ijk[0] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1843 indexList.push_back(npos);
1846 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1847 if ((ijk[0] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1848 && std::abs(data[npos]) > dist)
1851 indexList.push_back(npos);
1857 TreeType
const *
const mTree;
1858 BoolLeafNodeType **
const mMaskNodes;
1862 template<
typename TreeType>
1863 struct ExpandNarrowbandMask
1865 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1866 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1867 using BoolTreeTypePtr =
typename BoolTreeType::Ptr;
1869 ExpandNarrowbandMask(
const TreeType& tree, std::vector<BoolTreeTypePtr>& segments)
1870 : mTree(&tree), mSegments(!segments.
empty() ? &segments.front() : nullptr)
1874 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1876 const TreeType& distTree = *mTree;
1877 std::vector<BoolLeafNodeType*> nodes;
1879 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1881 BoolTreeType& narrowBandMask = *mSegments[n];
1883 BoolTreeType candidateMask(narrowBandMask,
false, TopologyCopy());
1888 candidateMask.getNodes(nodes);
1889 if (nodes.empty())
break;
1891 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
1893 tbb::parallel_for(nodeRange, FillLeafNodeVoxels<TreeType>(distTree, nodes));
1895 narrowBandMask.topologyUnion(candidateMask);
1897 ExpandLeafNodeRegion<TreeType>
op(distTree, narrowBandMask, nodes);
1898 tbb::parallel_reduce(nodeRange,
op);
1900 if (
op.newMaskTree().empty())
break;
1902 candidateMask.clear();
1903 candidateMask.merge(
op.newMaskTree());
1908 TreeType
const *
const mTree;
1909 BoolTreeTypePtr *
const mSegments;
1913 template<
typename TreeType>
1914 struct FloodFillSign
1916 using TreeTypePtr =
typename TreeType::Ptr;
1917 using ValueType =
typename TreeType::ValueType;
1918 using LeafNodeType =
typename TreeType::LeafNodeType;
1919 using RootNodeType =
typename TreeType::RootNodeType;
1920 using NodeChainType =
typename RootNodeType::NodeChainType;
1921 using InternalNodeType =
typename NodeChainType::template Get<1>;
1923 FloodFillSign(
const TreeType& tree, std::vector<TreeTypePtr>& segments)
1925 , mSegments(!segments.
empty() ? &segments.front() : nullptr)
1926 , mMinValue(ValueType(0.0))
1931 std::vector<const InternalNodeType*> nodes;
1932 tree.getNodes(nodes);
1934 if (!nodes.empty()) {
1935 FindMinTileValue<InternalNodeType> minOp(nodes.data());
1936 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1937 minSDFValue =
std::min(minSDFValue, minOp.minValue);
1941 if (minSDFValue > ValueType(0.0)) {
1942 std::vector<const LeafNodeType*> nodes;
1943 tree.getNodes(nodes);
1944 if (!nodes.empty()) {
1945 FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
1946 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1947 minSDFValue =
std::min(minSDFValue, minOp.minValue);
1951 mMinValue = minSDFValue;
1954 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1955 const ValueType interiorValue = -std::abs(mMinValue);
1956 const ValueType exteriorValue = std::abs(mTree->background());
1957 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1964 TreeType
const *
const mTree;
1965 TreeTypePtr *
const mSegments;
1966 ValueType mMinValue;
1970 template<
typename TreeType>
1973 using TreeTypePtr =
typename TreeType::Ptr;
1974 using ValueType =
typename TreeType::ValueType;
1975 using LeafNodeType =
typename TreeType::LeafNodeType;
1977 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
1978 using BoolTreeTypePtr =
typename BoolTreeType::Ptr;
1979 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
1981 MaskedCopy(
const TreeType& tree, std::vector<TreeTypePtr>& segments,
1982 std::vector<BoolTreeTypePtr>& masks)
1984 , mSegments(!segments.
empty() ? &segments.front() : nullptr)
1985 , mMasks(!masks.
empty() ? &masks.front() : nullptr)
1989 void operator()(
const tbb::blocked_range<size_t>& range)
const {
1991 std::vector<const BoolLeafNodeType*> nodes;
1993 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
1995 const BoolTreeType& mask = *mMasks[n];
1998 mask.getNodes(nodes);
2000 Copy
op(*mTree, nodes);
2001 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()),
op);
2002 mSegments[n] =
op.outputTree();
2009 Copy(
const TreeType& inputTree, std::vector<const BoolLeafNodeType*>& maskNodes)
2010 : mInputTree(&inputTree)
2011 , mMaskNodes(!maskNodes.
empty() ? &maskNodes.front() : nullptr)
2012 , mOutputTreePtr(new TreeType(inputTree.background()))
2017 : mInputTree(rhs.mInputTree)
2018 , mMaskNodes(rhs.mMaskNodes)
2019 , mOutputTreePtr(new TreeType(mInputTree->background()))
2023 TreeTypePtr& outputTree() {
return mOutputTreePtr; }
2025 void join(Copy& rhs) { mOutputTreePtr->merge(*rhs.mOutputTreePtr); }
2027 void operator()(
const tbb::blocked_range<size_t>& range) {
2029 tree::ValueAccessor<const TreeType> inputAcc(*mInputTree);
2030 tree::ValueAccessor<TreeType> outputAcc(*mOutputTreePtr);
2032 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2034 const BoolLeafNodeType& maskNode = *mMaskNodes[n];
2035 if (maskNode.isEmpty())
continue;
2037 const Coord& ijk = maskNode.origin();
2039 const LeafNodeType* inputNode = inputAcc.probeConstLeaf(ijk);
2042 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
2044 for (
typename BoolLeafNodeType::ValueOnCIter it = maskNode.cbeginValueOn();
2047 const Index idx = it.pos();
2048 outputNode->setValueOn(idx, inputNode->getValue(idx));
2051 const int valueDepth = inputAcc.getValueDepth(ijk);
2052 if (valueDepth >= 0) {
2053 outputAcc.addTile(TreeType::RootNodeType::LEVEL - valueDepth,
2054 ijk, inputAcc.getValue(ijk),
true);
2061 TreeType
const *
const mInputTree;
2062 BoolLeafNodeType
const *
const *
const mMaskNodes;
2063 TreeTypePtr mOutputTreePtr;
2066 TreeType
const *
const mTree;
2067 TreeTypePtr *
const mSegments;
2068 BoolTreeTypePtr *
const mMasks;
2075 template<
typename VolumePtrType>
2076 struct ComputeActiveVoxelCount
2078 ComputeActiveVoxelCount(std::vector<VolumePtrType>& segments,
size_t *countArray)
2079 : mSegments(!segments.
empty() ? &segments.front() : nullptr)
2080 , mCountArray(countArray)
2084 void operator()(
const tbb::blocked_range<size_t>& range)
const {
2085 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
2086 mCountArray[n] = mSegments[n]->activeVoxelCount();
2090 VolumePtrType *
const mSegments;
2091 size_t *
const mCountArray;
2097 GreaterCount(
const size_t *countArray) : mCountArray(countArray) {}
2099 inline bool operator() (
const size_t& lhs,
const size_t& rhs)
const 2101 return (mCountArray[lhs] > mCountArray[rhs]);
2104 size_t const *
const mCountArray;
2110 template<
typename TreeType>
2111 struct GridOrTreeConstructor
2113 using TreeTypePtr =
typename TreeType::Ptr;
2114 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2116 static BoolTreePtrType constructMask(
const TreeType&, BoolTreePtrType& maskTree)
2117 {
return maskTree; }
2118 static TreeTypePtr construct(
const TreeType&, TreeTypePtr& tree) {
return tree; }
2122 template<
typename TreeType>
2123 struct GridOrTreeConstructor<
Grid<TreeType> >
2127 using TreeTypePtr =
typename TreeType::Ptr;
2129 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2130 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2131 using BoolGridType = Grid<BoolTreeType>;
2132 using BoolGridPtrType =
typename BoolGridType::Ptr;
2134 static BoolGridPtrType constructMask(
const GridType& grid, BoolTreePtrType& maskTree) {
2135 BoolGridPtrType maskGrid(BoolGridType::create(maskTree));
2136 maskGrid->setTransform(grid.transform().copy());
2140 static GridTypePtr construct(
const GridType& grid, TreeTypePtr& maskTree) {
2141 GridTypePtr maskGrid(GridType::create(maskTree));
2142 maskGrid->setTransform(grid.transform().copy());
2143 maskGrid->insertMeta(grid);
2157 template <
class Gr
idType>
2161 using ValueType =
typename GridType::ValueType;
2162 using TreeType =
typename GridType::TreeType;
2163 using LeafNodeType =
typename TreeType::LeafNodeType;
2164 using RootNodeType =
typename TreeType::RootNodeType;
2165 using NodeChainType =
typename RootNodeType::NodeChainType;
2166 using InternalNodeType =
typename NodeChainType::template Get<1>;
2170 TreeType& tree = grid.tree();
2172 size_t numLeafNodes = 0, numInternalNodes = 0;
2174 std::vector<LeafNodeType*> nodes;
2175 std::vector<size_t> leafnodeCount;
2179 std::vector<InternalNodeType*> internalNodes;
2180 tree.getNodes(internalNodes);
2182 numInternalNodes = internalNodes.size();
2184 leafnodeCount.push_back(0);
2185 for (
size_t n = 0; n < numInternalNodes; ++n) {
2186 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
2189 numLeafNodes = leafnodeCount.back();
2192 nodes.reserve(numLeafNodes);
2194 for (
size_t n = 0; n < numInternalNodes; ++n) {
2195 internalNodes[n]->stealNodes(nodes, tree.background(),
false);
2202 level_set_util_internal::FindMinTileValue<InternalNodeType> minOp(internalNodes.data());
2203 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), minOp);
2204 minSDFValue =
std::min(minSDFValue, minOp.minValue);
2207 if (minSDFValue > ValueType(0.0)) {
2208 level_set_util_internal::FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
2209 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
2210 minSDFValue =
std::min(minSDFValue, minOp.minValue);
2213 cutoffDistance = -std::abs(cutoffDistance);
2214 cutoffDistance = minSDFValue > cutoffDistance ? minSDFValue : cutoffDistance;
2220 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2221 level_set_util_internal::SDFVoxelsToFogVolume<LeafNodeType>(nodes.data(), cutoffDistance));
2224 typename TreeType::Ptr newTree(
new TreeType(ValueType(0.0)));
2226 level_set_util_internal::PopulateTree<TreeType> populate(
2227 *newTree, nodes.data(), leafnodeCount.data(), 0);
2228 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
2231 std::vector<InternalNodeType*> internalNodes;
2232 newTree->getNodes(internalNodes);
2234 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalNodes.size()),
2235 level_set_util_internal::SDFTilesToFogVolume<TreeType, InternalNodeType>(
2236 tree, internalNodes.data()));
2241 typename TreeType::ValueAllIter it(*newTree);
2242 it.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 2);
2245 if (acc.
getValue(it.getCoord()) < ValueType(0.0)) {
2246 it.setValue(ValueType(1.0));
2247 it.setActiveState(
true);
2255 typename TreeType::ValueAllIter it(tree);
2256 it.setMaxDepth(TreeType::ValueAllIter::ROOT_DEPTH);
2258 if (it.getValue() < ValueType(0.0)) {
2260 ValueType(1.0),
true);
2265 grid.setTree(newTree);
2273 template <
class Gr
idOrTreeType>
2274 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2275 sdfInteriorMask(
const GridOrTreeType& volume,
typename GridOrTreeType::ValueType isovalue)
2280 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2281 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(tree, isovalue);
2283 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2288 template<
typename Gr
idOrTreeType>
2289 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2291 typename GridOrTreeType::ValueType isovalue,
2298 using CharTreePtrType =
typename TreeType::template ValueConverter<char>::Type::Ptr;
2299 CharTreePtrType regionMask = level_set_util_internal::computeEnclosedRegionMask(
2300 tree, isovalue, fillMask);
2302 using BoolTreePtrType =
typename TreeType::template ValueConverter<bool>::Type::Ptr;
2303 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(*regionMask, 0);
2305 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2313 template<
typename Gr
idOrTreeType>
2314 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2320 std::vector<const typename TreeType::LeafNodeType*> nodes;
2321 tree.getNodes(nodes);
2323 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2324 typename BoolTreeType::Ptr mask(
new BoolTreeType(
false));
2326 level_set_util_internal::MaskIsovalueCrossingVoxels<TreeType>
op(tree, nodes, *mask, isovalue);
2327 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
2329 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2337 template<
typename Gr
idOrTreeType>
2340 std::vector<
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks)
2343 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2344 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2345 using BoolLeafNodeType =
typename BoolTreeType::LeafNodeType;
2346 using BoolGridOrTreePtrType =
typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr;
2348 using NodeMaskSegmentType = level_set_util_internal::NodeMaskSegment<BoolLeafNodeType>;
2349 using NodeMaskSegmentPtrType =
typename NodeMaskSegmentType::Ptr;
2350 using NodeMaskSegmentPtrVector =
typename std::vector<NodeMaskSegmentPtrType>;
2351 using NodeMaskSegmentRawPtrVector =
typename std::vector<NodeMaskSegmentType*>;
2357 BoolTreeType topologyMask(tree,
false,
TopologyCopy());
2362 if (topologyMask.hasActiveTiles()) {
2363 topologyMask.voxelizeActiveTiles();
2366 std::vector<BoolLeafNodeType*> leafnodes;
2367 topologyMask.getNodes(leafnodes);
2369 if (leafnodes.empty())
return;
2374 std::unique_ptr<NodeMaskSegmentPtrVector[]> nodeSegmentArray(
2375 new NodeMaskSegmentPtrVector[leafnodes.size()]);
2377 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2378 level_set_util_internal::SegmentNodeMask<BoolLeafNodeType>(
2379 leafnodes, nodeSegmentArray.get()));
2384 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2385 level_set_util_internal::ConnectNodeMaskSegments<BoolTreeType, BoolLeafNodeType>(
2386 topologyMask, nodeSegmentArray.get()));
2388 topologyMask.clear();
2390 size_t nodeSegmentCount = 0;
2391 for (
size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2392 nodeSegmentCount += nodeSegmentArray[n].size();
2397 std::deque<NodeMaskSegmentRawPtrVector> nodeSegmentGroups;
2399 NodeMaskSegmentType* nextSegment = nodeSegmentArray[0][0].get();
2400 while (nextSegment) {
2402 nodeSegmentGroups.push_back(NodeMaskSegmentRawPtrVector());
2404 std::vector<NodeMaskSegmentType*>& segmentGroup = nodeSegmentGroups.back();
2405 segmentGroup.reserve(nodeSegmentCount);
2407 std::deque<NodeMaskSegmentType*> segmentQueue;
2408 segmentQueue.push_back(nextSegment);
2409 nextSegment =
nullptr;
2411 while (!segmentQueue.empty()) {
2413 NodeMaskSegmentType* segment = segmentQueue.back();
2414 segmentQueue.pop_back();
2416 if (segment->visited)
continue;
2417 segment->visited =
true;
2419 segmentGroup.push_back(segment);
2422 std::vector<NodeMaskSegmentType*>& connections = segment->connections;
2423 for (
size_t n = 0, N = connections.size(); n < N; ++n) {
2424 if (!connections[n]->visited) segmentQueue.push_back(connections[n]);
2429 for (
size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2430 NodeMaskSegmentPtrVector& nodeSegments = nodeSegmentArray[n];
2431 for (
size_t i = 0, I = nodeSegments.size(); i < I; ++i) {
2432 if (!nodeSegments[i]->visited) nextSegment = nodeSegments[i].get();
2439 if (nodeSegmentGroups.size() == 1) {
2441 BoolTreePtrType mask(
new BoolTreeType(tree,
false,
TopologyCopy()));
2445 if (mask->hasActiveTiles()) {
2446 mask->voxelizeActiveTiles();
2450 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2453 }
else if (nodeSegmentGroups.size() > 1) {
2455 for (
size_t n = 0, N = nodeSegmentGroups.size(); n < N; ++n) {
2457 NodeMaskSegmentRawPtrVector& segmentGroup = nodeSegmentGroups[n];
2459 level_set_util_internal::MaskSegmentGroup<BoolTreeType>
op(segmentGroup);
2460 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, segmentGroup.size()), op);
2463 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2464 volume, op.mask()));
2470 if (masks.size() > 1) {
2471 const size_t segmentCount = masks.size();
2473 std::unique_ptr<size_t[]> segmentOrderArray(
new size_t[segmentCount]);
2474 std::unique_ptr<size_t[]> voxelCountArray(
new size_t[segmentCount]);
2476 for (
size_t n = 0; n < segmentCount; ++n) {
2477 segmentOrderArray[n] = n;
2480 tbb::parallel_for(tbb::blocked_range<size_t>(0, segmentCount),
2481 level_set_util_internal::ComputeActiveVoxelCount<BoolGridOrTreePtrType>(
2482 masks, voxelCountArray.get()));
2484 size_t *begin = segmentOrderArray.get();
2485 tbb::parallel_sort(begin, begin + masks.size(), level_set_util_internal::GreaterCount(
2486 voxelCountArray.get()));
2488 std::vector<BoolGridOrTreePtrType> orderedMasks;
2489 orderedMasks.reserve(masks.size());
2491 for (
size_t n = 0; n < segmentCount; ++n) {
2492 orderedMasks.push_back(masks[segmentOrderArray[n]]);
2495 masks.swap(orderedMasks);
2501 template<
typename Gr
idOrTreeType>
2504 std::vector<typename GridOrTreeType::Ptr>& segments)
2507 using TreePtrType =
typename TreeType::Ptr;
2508 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2509 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2514 std::vector<BoolTreePtrType> maskSegmentArray;
2519 const size_t numSegments =
std::max(
size_t(1), maskSegmentArray.size());
2520 std::vector<TreePtrType> outputSegmentArray(numSegments);
2522 if (maskSegmentArray.empty()) {
2525 outputSegmentArray[0] = TreePtrType(
new TreeType(inputTree.background()));
2526 }
else if (numSegments == 1) {
2528 TreePtrType segment(
new TreeType(inputTree));
2531 if (segment->leafCount() != inputTree.leafCount()) {
2532 segment->topologyIntersection(*maskSegmentArray[0]);
2534 outputSegmentArray[0] = segment;
2536 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2537 tbb::parallel_for(segmentRange,
2538 level_set_util_internal::MaskedCopy<TreeType>(inputTree, outputSegmentArray,
2542 for (
auto& segment : outputSegmentArray) {
2544 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2550 template<
typename Gr
idOrTreeType>
2552 segmentSDF(
const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments)
2555 using TreePtrType =
typename TreeType::Ptr;
2556 using BoolTreeType =
typename TreeType::template ValueConverter<bool>::Type;
2557 using BoolTreePtrType =
typename BoolTreeType::Ptr;
2565 std::vector<BoolTreePtrType> maskSegmentArray;
2568 const size_t numSegments =
std::max(
size_t(1), maskSegmentArray.size());
2569 std::vector<TreePtrType> outputSegmentArray(numSegments);
2571 if (maskSegmentArray.empty()) {
2574 outputSegmentArray[0] = TreePtrType(
new TreeType(inputTree.background()));
2576 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2579 tbb::parallel_for(segmentRange,
2580 level_set_util_internal::ExpandNarrowbandMask<TreeType>(inputTree, maskSegmentArray));
2584 tbb::parallel_for(segmentRange, level_set_util_internal::MaskedCopy<TreeType>(
2585 inputTree, outputSegmentArray, maskSegmentArray));
2587 tbb::parallel_for(segmentRange,
2588 level_set_util_internal::FloodFillSign<TreeType>(inputTree, outputSegmentArray));
2591 for (
auto& segment : outputSegmentArray) {
2593 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2604 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 2606 #ifdef OPENVDB_INSTANTIATE_LEVELSETUTIL 2610 #define _FUNCTION(TreeT) \ 2611 void sdfToFogVolume(Grid<TreeT>&, TreeT::ValueType) 2615 #define _FUNCTION(TreeT) \ 2616 TreeT::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const TreeT&, TreeT::ValueType) 2620 #define _FUNCTION(TreeT) \ 2621 Grid<TreeT>::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const Grid<TreeT>&, TreeT::ValueType) 2625 #define _FUNCTION(TreeT) \ 2626 TreeT::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\ 2627 const TreeT&, TreeT::ValueType, \ 2628 const TreeAdapter<TreeT>::TreeType::ValueConverter<bool>::Type*) 2632 #define _FUNCTION(TreeT) \ 2633 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\ 2634 const Grid<TreeT>&, TreeT::ValueType, \ 2635 const TreeAdapter<Grid<TreeT>>::TreeType::ValueConverter<bool>::Type*) 2639 #define _FUNCTION(TreeT) \ 2640 TreeT::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const TreeT&, TreeT::ValueType) 2644 #define _FUNCTION(TreeT) \ 2645 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const Grid<TreeT>&, TreeT::ValueType) 2649 #define _FUNCTION(TreeT) \ 2650 void extractActiveVoxelSegmentMasks(\ 2651 const TreeT&, std::vector<TreeT::ValueConverter<bool>::Type::Ptr>&) 2655 #define _FUNCTION(TreeT) \ 2656 void extractActiveVoxelSegmentMasks(\ 2657 const Grid<TreeT>&, std::vector<Grid<TreeT>::ValueConverter<bool>::Type::Ptr>&) 2661 #define _FUNCTION(TreeT) \ 2662 void segmentActiveVoxels(const TreeT&, std::vector<TreeT::Ptr>&) 2666 #define _FUNCTION(TreeT) \ 2667 void segmentActiveVoxels(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&) 2671 #define _FUNCTION(TreeT) \ 2672 void segmentSDF(const TreeT&, std::vector<TreeT::Ptr>&) 2676 #define _FUNCTION(TreeT) \ 2677 void segmentSDF(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&) 2681 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION 2688 #endif // OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
Index32 Index
Definition: Types.h:54
_TreeType TreeType
Definition: Grid.h:1061
static NonConstTreeType & tree(NonConstTreeType &t)
Definition: Grid.h:1076
void split(ContainerT &out, const std::string &in, const char delim)
Definition: Name.h:43
openvdb::GridBase Grid
Definition: Utils.h:34
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)
Definition: version.h.in:166
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1059
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
#define ROOT_LEVEL
Definition: CNanoVDB.h:53
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is '\0'
Definition: Util.h:144
SharedPtr< Grid > Ptr
Definition: Grid.h:573
Definition: Exceptions.h:13
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:219
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:455
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:162
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:683
#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:218