10 #ifndef OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
11 #define OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
20 #include <unordered_map>
21 #include <unordered_set>
43 template <
typename TreeT>
55 : mTree(&tree), mSteal(true) { }
58 : mTreePtr(treePtr), mTree(mTreePtr.get()), mSteal(true) { }
66 : mTree(&tree), mSteal(false)
82 void reset(
typename TreeType::Ptr treePtr,
Steal);
94 template<
typename NodeT>
101 template <
typename NodeT>
106 template <
typename NodeT>
124 typename TreeType::Ptr mTreePtr;
132 template <
typename TreeT>
135 std::unique_ptr<MaskTreeType>
ptr;
145 ptr.reset(
bool(other.
ptr) ? std::make_unique<MaskTreeType>(*other.
ptr) :
nullptr);
152 template <
typename TreeT>
156 using RootT =
typename MaskT::RootNodeType;
157 using LeafT =
typename MaskT::LeafNodeType;
160 bool operator()(RootT& root,
size_t)
const;
161 template<
typename NodeT>
162 bool operator()(NodeT& node,
size_t)
const;
178 template<
typename TreeT,
bool Union>
181 using ValueT =
typename TreeT::ValueType;
182 using RootT =
typename TreeT::RootNodeType;
183 using LeafT =
typename TreeT::LeafNodeType;
188 template <
typename TagT>
200 template <
typename TreesT,
typename TagT>
203 for (
auto* tree : trees) {
205 mTreesToMerge.emplace_back(*tree, tag);
214 : mTreesToMerge(trees) { }
220 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
223 bool empty()
const {
return mTreesToMerge.empty(); }
226 size_t size()
const {
return mTreesToMerge.size(); }
232 template<
typename NodeT>
233 bool operator()(NodeT& node,
size_t idx)
const;
241 const ValueT& background()
const;
243 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
244 mutable const ValueT* mBackground =
nullptr;
248 template <
typename TreeT>
251 template <
typename TreeT>
258 template<
typename TreeT>
261 using ValueT =
typename TreeT::ValueType;
262 using RootT =
typename TreeT::RootNodeType;
263 using LeafT =
typename TreeT::LeafNodeType;
268 template <
typename TagT>
280 size_t size()
const {
return 1; }
286 template<
typename NodeT>
287 bool operator()(NodeT& node,
size_t idx)
const;
295 const ValueT& background()
const;
296 const ValueT& otherBackground()
const;
301 mutable const ValueT* mBackground =
nullptr;
302 mutable const ValueT* mOtherBackground =
nullptr;
309 template<
typename TreeT>
312 using ValueT =
typename TreeT::ValueType;
313 using RootT =
typename TreeT::RootNodeType;
314 using LeafT =
typename TreeT::LeafNodeType;
318 template <
typename TagT>
319 SumMergeOp(TreeT& tree, TagT tag) { mTreesToMerge.emplace_back(tree, tag); }
328 template <
typename TreesT,
typename TagT>
331 for (
auto* tree : trees) {
333 mTreesToMerge.emplace_back(*tree, tag);
342 : mTreesToMerge(trees) { }
348 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
351 bool empty()
const {
return mTreesToMerge.empty(); }
354 size_t size()
const {
return mTreesToMerge.size(); }
360 template<
typename NodeT>
361 bool operator()(NodeT& node,
size_t idx)
const;
369 const ValueT& background()
const;
371 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
372 mutable const ValueT* mBackground =
nullptr;
379 template<
typename TreeT>
386 manager.foreachTopDown(op);
389 template<
typename TreeT>
392 return bool(mMaskTree.ptr);
395 template<
typename TreeT>
399 OPENVDB_THROW(RuntimeError,
"Cannot reset with empty Tree shared pointer.");
403 mTree = mTreePtr.get();
406 template<
typename TreeT>
410 return &mTree->root();
413 template<
typename TreeT>
414 template<
typename NodeT>
419 if (!mSteal && !this->
mask()->isValueOn(ijk))
return nullptr;
420 return mTree->template probeConstNode<NodeT>(ijk);
423 template<
typename TreeT>
424 template<
typename NodeT>
425 std::unique_ptr<NodeT>
430 return std::unique_ptr<NodeT>(
431 tree->root().template stealNode<NodeT>(ijk, mTree->root().background(),
false)
434 auto* child = this->probeConstNode<NodeT>(ijk);
436 assert(this->hasMask());
437 auto result = std::make_unique<NodeT>(*child);
439 this->
mask()->addTile(NodeT::LEVEL, ijk,
false,
false);
443 return std::unique_ptr<NodeT>();
446 template<
typename TreeT>
447 template<
typename NodeT>
452 if (NodeT::LEVEL == 0)
return;
456 auto* node = tree->template probeNode<NodeT>(ijk);
458 const Index pos = NodeT::coordToOffset(ijk);
459 node->addTile(pos, value, active);
462 auto* node = mTree->template probeConstNode<NodeT>(ijk);
465 assert(this->hasMask());
466 this->
mask()->addTile(NodeT::LEVEL, ijk,
false,
false);
475 template <
typename TreeT>
478 using ChildT =
typename RootT::ChildNodeType;
480 const Index count = mTree.root().childCount();
482 std::vector<std::unique_ptr<ChildT>> children(count);
487 tbb::blocked_range<Index>(0, count),
488 [&](tbb::blocked_range<Index>&
range)
490 for (
Index i = range.begin(); i < range.end(); i++) {
491 children[i] = std::make_unique<ChildT>(
Coord::max(),
true,
true);
499 for (
auto iter = mTree.root().cbeginChildOn(); iter; ++iter) {
500 children[i]->setOrigin(iter->origin());
501 root.addChild(children[i].release());
508 template <
typename TreeT>
509 template <
typename NodeT>
512 using ChildT =
typename NodeT::ChildNodeType;
514 const auto* otherNode = mTree.template probeConstNode<NodeT>(node.origin());
515 if (!otherNode)
return false;
519 if (NodeT::LEVEL == 1) {
520 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
521 node.addTile(iter.pos(),
true,
true);
524 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
525 auto* child =
new ChildT(iter->origin(),
true,
true);
526 node.addChild(child);
538 namespace merge_internal {
541 template <
typename BufferT,
typename ValueT>
542 struct UnallocatedBuffer
544 static void allocateAndFill(BufferT&
buffer,
const ValueT& background)
546 if (buffer.empty()) {
547 if (!buffer.isOutOfCore()) {
549 buffer.fill(background);
554 static bool isPartiallyConstructed(
const BufferT& buffer)
556 return !buffer.isOutOfCore() && buffer.empty();
560 template <
typename BufferT>
561 struct UnallocatedBuffer<BufferT, bool>
564 static void allocateAndFill(BufferT&,
const bool&) { }
565 static bool isPartiallyConstructed(
const BufferT&) {
return false; }
571 template <Index LEVEL>
574 template <
typename NodeT,
typename OpT>
575 static void run(NodeT& node, OpT& op)
577 using ChildT =
typename NodeT::ChildNodeType;
581 Index32 childCount = node.childCount();
582 if (childCount > 0) {
586 std::vector<ChildT*> children;
587 children.reserve(childCount);
588 for (
auto iter = node.beginChildOn(); iter; ++iter) {
589 children.push_back(&(*iter));
594 tbb::blocked_range<Index32>(0, childCount),
595 [&](tbb::blocked_range<Index32>&
range) {
596 for (
Index32 n = range.begin();
n < range.end();
n++) {
611 template <
typename NodeT,
typename OpT>
612 static void run(NodeT& node, OpT& op)
621 template <
typename TreeT>
622 struct ApplyTileToNodeOp
624 using LeafT =
typename TreeT::LeafNodeType;
625 using ValueT =
typename TreeT::ValueType;
627 ApplyTileToNodeOp(
const ValueT&
value,
const bool active):
628 mValue(value), mActive(active) { }
630 template <
typename NodeT>
631 void operator()(NodeT& node,
size_t)
const
637 for (
auto iter = node.beginValueAll(); iter; ++iter) {
638 iter.setValue(mValue + *iter);
640 if (mActive) node.setValuesOn();
643 void operator()(LeafT& leaf,
size_t)
const
645 auto*
data = leaf.buffer().data();
647 if (mValue != zeroVal<ValueT>()) {
652 if (mActive) leaf.setValuesOn();
655 template <
typename NodeT>
656 void run(NodeT& node)
658 Dispatch<NodeT::LEVEL>::run(node, *
this);
675 template <
typename TreeT,
bool Union>
678 const bool Intersect = !Union;
680 if (this->empty())
return false;
683 if (!mBackground) mBackground = &root.background();
686 auto keyExistsInRoot = [&](
const Coord& key) ->
bool
688 return root.getValueDepth(key) > -1;
692 auto keyExistsInAllTrees = [&](
const Coord& key) ->
bool
695 const auto* mergeRoot = mergeTree.rootPtr();
696 if (!mergeRoot)
return false;
697 if (mergeRoot->getValueDepth(key) == -1)
return false;
703 root.eraseBackgroundTiles();
708 std::vector<Coord> toDelete;
709 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
710 const Coord& key = valueIter.getCoord();
711 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
714 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
715 const Coord& key = childIter.getCoord();
716 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
720 for (Coord& key : toDelete) root.addTile(key, *mBackground,
false);
721 root.eraseBackgroundTiles();
727 constexpr uint8_t ACTIVE_TILE = 0x1;
728 constexpr uint8_t INSIDE_TILE = 0x2;
729 constexpr uint8_t OUTSIDE_TILE = 0x4;
731 constexpr uint8_t INSIDE_STATE = Union ? INSIDE_TILE : OUTSIDE_TILE;
732 constexpr uint8_t OUTSIDE_STATE = Union ? OUTSIDE_TILE : INSIDE_TILE;
734 const ValueT insideBackground = Union ? -this->background() : this->background();
735 const ValueT outsideBackground = -insideBackground;
737 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
741 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
742 else if (value > zeroVal<ValueT>()) flag |= OUTSIDE_TILE;
743 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
747 std::unordered_map<Coord, uint8_t> tiles;
749 if (root.getTableSize() > 0) {
750 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
751 const Coord& key = valueIter.getCoord();
752 tiles.insert({key, getTileFlag(valueIter)});
759 const auto* mergeRoot = mergeTree.rootPtr();
760 if (!mergeRoot)
continue;
761 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
762 const Coord& key = valueIter.getCoord();
763 auto it = tiles.find(key);
764 if (it == tiles.end()) {
766 tiles.insert({key, getTileFlag(valueIter)});
769 const uint8_t flag = it->second;
770 if (flag & OUTSIDE_STATE) {
771 const uint8_t newFlag = getTileFlag(valueIter);
772 if (newFlag & INSIDE_STATE) {
773 it->second = newFlag;
782 for (
auto it : tiles) {
783 const uint8_t flag = it.second;
784 if (flag & INSIDE_STATE) {
785 const Coord& key = it.first;
786 const bool state = flag & ACTIVE_TILE;
788 if (Union || keyExistsInRoot(key)) {
789 root.addTile(key, insideBackground, state);
794 std::unordered_set<Coord> children;
796 if (root.getTableSize() > 0) {
797 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
798 const Coord& key = childIter.getCoord();
799 children.insert(key);
803 bool continueRecurse =
false;
809 const auto* mergeRoot = mergeTree.rootPtr();
810 if (!mergeRoot)
continue;
811 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
812 const Coord& key = childIter.getCoord();
815 if (Intersect && !keyExistsInRoot(key))
continue;
818 if (children.count(key)) {
819 continueRecurse =
true;
824 auto it = tiles.find(key);
825 if (it != tiles.end() && it->second == INSIDE_STATE)
continue;
827 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
828 childPtr->resetBackground(mergeRoot->background(), root.background());
829 if (childPtr) root.addChild(childPtr.release());
831 children.insert(key);
837 for (
auto it : tiles) {
838 const uint8_t flag = it.second;
839 if (flag & OUTSIDE_STATE) {
840 const Coord& key = it.first;
841 if (!children.count(key)) {
842 const bool state = flag & ACTIVE_TILE;
844 if (Union || keyExistsInRoot(key)) {
845 root.addTile(key, outsideBackground, state);
852 root.eraseBackgroundTiles();
854 return continueRecurse;
857 template<
typename TreeT,
bool Union>
858 template<
typename NodeT>
863 if (this->empty())
return false;
865 const ValueT insideBackground = Union ? -this->background() : this->background();
866 const ValueT outsideBackground = -insideBackground;
868 using NodeMaskT =
typename NodeT::NodeMaskType;
872 NodeMaskT invalidTile;
881 return Union ?
value > zeroVal<ValueT>() :
value < zeroVal<ValueT>();
884 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
885 if (isValid(iter.getValue())) {
886 validTile.setOn(iter.pos());
887 }
else if (isInvalid(iter.getValue())) {
888 invalidTile.setOn(iter.pos());
892 bool continueRecurse =
false;
896 auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
898 if (!mergeNode)
continue;
902 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
903 Index pos = iter.pos();
905 if (validTile.isOn(pos))
continue;
907 if (isValid(iter.getValue())) {
908 node.addTile(pos, insideBackground, iter.isValueOn());
909 validTile.setOn(pos);
915 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
916 Index pos = iter.pos();
917 const Coord& ijk = iter.getCoord();
919 if (validTile.isOn(pos)) {
920 mergeTree.template addTile<NonConstNodeT>(ijk, outsideBackground,
false);
921 }
else if (invalidTile.isOn(pos)) {
922 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
924 childPtr->resetBackground(mergeTree.rootPtr()->background(), this->background());
925 node.addChild(childPtr.release());
927 invalidTile.setOff(pos);
931 continueRecurse =
true;
936 return continueRecurse;
939 template <
typename TreeT,
bool Union>
942 using LeafT =
typename TreeT::LeafNodeType;
943 using ValueT =
typename LeafT::ValueType;
944 using BufferT =
typename LeafT::Buffer;
946 if (this->empty())
return false;
948 const ValueT background = Union ? this->background() : -this->background();
953 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
954 leaf.buffer(), background);
957 const LeafT* mergeLeaf = mergeTree.template probeConstNode<LeafT>(leaf.origin());
958 if (!mergeLeaf)
continue;
961 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
962 mergeLeaf->buffer())) {
967 const ValueT& newValue = mergeLeaf->getValue(i);
968 const bool doMerge = Union ? newValue < leaf.getValue(i) : newValue > leaf.getValue(i);
970 leaf.setValueOnly(i, newValue);
971 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
979 template <
typename TreeT,
bool Union>
992 template <
typename TreeT>
996 if (!mBackground) mBackground = &root.background();
997 if (!mOtherBackground) mOtherBackground = &mTree.rootPtr()->background();
1002 constexpr uint8_t ACTIVE_TILE = 0x1;
1003 constexpr uint8_t INSIDE_TILE = 0x2;
1004 constexpr uint8_t CHILD = 0x4;
1006 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
1010 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
1011 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
1016 root.eraseBackgroundTiles();
1018 std::unordered_map<Coord, uint8_t>
flags;
1020 if (root.getTableSize() > 0) {
1021 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1022 const Coord& key = valueIter.getCoord();
1023 const uint8_t flag = getTileFlag(valueIter);
1024 if (flag & INSIDE_TILE) {
1025 flags.insert({key, getTileFlag(valueIter)});
1029 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1030 const Coord& key = childIter.getCoord();
1031 flags.insert({key, CHILD});
1035 bool continueRecurse =
false;
1037 const auto* mergeRoot = mTree.rootPtr();
1040 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1041 const Coord& key = valueIter.getCoord();
1042 const uint8_t flag = getTileFlag(valueIter);
1043 if (flag & INSIDE_TILE) {
1044 auto it = flags.find(key);
1045 if (it != flags.end()) {
1046 const bool state = flag & ACTIVE_TILE;
1047 root.addTile(key, this->background(), state);
1052 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1053 const Coord& key = childIter.getCoord();
1054 auto it = flags.find(key);
1055 if (it != flags.end()) {
1056 const uint8_t otherFlag = it->second;
1057 if (otherFlag & CHILD) {
1059 continueRecurse =
true;
1060 }
else if (otherFlag & INSIDE_TILE) {
1061 auto childPtr = mTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
1063 childPtr->resetBackground(this->otherBackground(), this->background());
1065 root.addChild(childPtr.release());
1073 root.eraseBackgroundTiles();
1075 return continueRecurse;
1078 template<
typename TreeT>
1079 template<
typename NodeT>
1084 using NodeMaskT =
typename NodeT::NodeMaskType;
1088 NodeMaskT insideTile;
1089 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
1090 if (iter.getValue() < zeroVal<ValueT>()) {
1091 insideTile.setOn(iter.pos());
1095 bool continueRecurse =
false;
1097 auto* mergeNode = mTree.template probeConstNode<NonConstNodeT>(node.origin());
1099 if (!mergeNode)
return continueRecurse;
1103 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
1104 Index pos = iter.pos();
1105 if (iter.getValue() < zeroVal<ValueT>()) {
1106 if (insideTile.isOn(pos) || node.isChildMaskOn(pos)) {
1107 node.addTile(pos, this->background(), iter.isValueOn());
1114 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
1115 Index pos = iter.pos();
1116 const Coord& ijk = iter.getCoord();
1117 if (insideTile.isOn(pos)) {
1118 auto childPtr = mTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
1120 childPtr->resetBackground(this->otherBackground(), this->background());
1122 node.addChild(childPtr.release());
1124 }
else if (node.isChildMaskOn(pos)) {
1127 continueRecurse =
true;
1131 return continueRecurse;
1134 template <
typename TreeT>
1137 using LeafT =
typename TreeT::LeafNodeType;
1138 using ValueT =
typename LeafT::ValueType;
1139 using BufferT =
typename LeafT::Buffer;
1144 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1145 leaf.buffer(), this->background());
1147 const LeafT* mergeLeaf = mTree.template probeConstNode<LeafT>(leaf.origin());
1148 if (!mergeLeaf)
return false;
1153 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1154 mergeLeaf->buffer())) {
1159 const ValueT& aValue = leaf.getValue(i);
1161 if (aValue < bValue) {
1162 leaf.setValueOnly(i, bValue);
1163 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1170 template <
typename TreeT>
1175 assert(mBackground);
1176 return *mBackground;
1179 template <
typename TreeT>
1180 const typename CsgDifferenceOp<TreeT>::ValueT&
1181 CsgDifferenceOp<TreeT>::otherBackground()
const
1184 assert(mOtherBackground);
1185 return *mOtherBackground;
1192 template <
typename TreeT>
1195 using ValueT =
typename RootT::ValueType;
1196 using ChildT =
typename RootT::ChildNodeType;
1199 if (this->empty())
return false;
1202 if (!mBackground) mBackground = &root.background();
1205 auto keyExistsInRoot = [](
const auto& rootToTest,
const Coord& key) ->
bool
1207 return rootToTest.getValueDepth(key) > -1;
1210 constexpr uint8_t TILE = 0x1;
1211 constexpr uint8_t CHILD = 0x2;
1212 constexpr uint8_t TARGET_CHILD = 0x4;
1214 std::unordered_map<Coord, uint8_t> children;
1218 if (root.getTableSize() > 0) {
1219 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1220 const Coord& key = valueIter.getCoord();
1221 children.insert({key, TILE});
1224 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1225 const Coord& key = childIter.getCoord();
1226 children.insert({key, CHILD | TARGET_CHILD});
1233 const auto* mergeRoot = mergeTree.rootPtr();
1234 if (!mergeRoot)
continue;
1236 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1237 const Coord& key = valueIter.getCoord();
1238 auto it = children.find(key);
1239 if (it == children.end()) {
1241 children.insert({key, TILE});
1248 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1249 const Coord& key = childIter.getCoord();
1250 auto it = children.find(key);
1251 if (it == children.end()) {
1253 children.insert({key, CHILD});
1256 it->second |= CHILD;
1263 for (
const auto& it : children) {
1264 if (!keyExistsInRoot(root, it.first)) {
1265 root.addTile(it.first, root.background(),
false);
1271 for (
const auto& it : children) {
1273 const Coord& key = it.first;
1277 if (it.second & TARGET_CHILD)
continue;
1280 const bool active = root.probeValue(key, value);
1283 const auto* mergeRoot = mergeTree.rootPtr();
1284 if (!mergeRoot)
continue;
1285 if (!keyExistsInRoot(*mergeRoot, key))
continue;
1291 const auto* mergeNode = mergeRoot->template probeConstNode<ChildT>(key);
1293 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(key);
1294 childPtr->resetBackground(mergeRoot->background(), root.background());
1297 merge_internal::ApplyTileToNodeOp<TreeT> applyOp(value, active);
1298 applyOp.run(*childPtr);
1299 root.addChild(childPtr.release());
1305 const bool mergeActive = mergeRoot->probeValue(key, mergeValue);
1307 if (active || mergeActive) {
1308 value += mergeValue;
1309 root.addTile(key, value,
true);
1311 value += mergeValue;
1312 root.addTile(key, value,
false);
1316 mergeTree.template addTile<NonConstChildT>(key, zeroVal<ValueT>(),
false);
1323 template<
typename TreeT>
1324 template<
typename NodeT>
1327 using ChildT =
typename NodeT::ChildNodeType;
1330 if (this->empty())
return false;
1333 const auto* mergeRoot = mergeTree.rootPtr();
1334 if (!mergeRoot)
continue;
1336 const auto* mergeNode = mergeRoot->template probeConstNode<NonConstNodeT>(node.origin());
1340 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1341 if (mergeNode->isChildMaskOn(iter.pos())) {
1343 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(iter.getCoord());
1344 childPtr->resetBackground(mergeRoot->background(), this->background());
1347 merge_internal::ApplyTileToNodeOp<TreeT> applyOp(*iter, iter.isValueOn());
1348 applyOp.run(*childPtr);
1349 node.addChild(childPtr.release());
1353 const bool mergeActive = mergeNode->probeValue(iter.getCoord(), mergeValue);
1354 iter.setValue(*iter + mergeValue);
1355 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1363 const bool mergeActive = mergeRoot->probeValue(node.origin(), mergeValue);
1364 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1365 iter.setValue(*iter + mergeValue);
1366 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1374 template <
typename TreeT>
1377 using RootT =
typename TreeT::RootNodeType;
1378 using RootChildT =
typename RootT::ChildNodeType;
1380 using LeafT =
typename TreeT::LeafNodeType;
1381 using ValueT =
typename LeafT::ValueType;
1382 using BufferT =
typename LeafT::Buffer;
1385 if (this->empty())
return false;
1387 const Coord& ijk = leaf.origin();
1392 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1393 leaf.buffer(), this->background());
1395 auto*
data = leaf.buffer().data();
1398 const RootT* mergeRoot = mergeTree.rootPtr();
1399 if (!mergeRoot)
continue;
1401 const RootChildT* mergeRootChild = mergeRoot->template probeConstNode<NonConstRootChildT>(ijk);
1402 const LeafT* mergeLeaf = mergeRootChild ?
1403 mergeRootChild->template probeConstNode<NonConstLeafT>(ijk) :
nullptr;
1410 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1411 mergeLeaf->buffer())) {
1416 data[i] += mergeLeaf->getValue(i);
1419 leaf.getValueMask() |= mergeLeaf->getValueMask();
1424 bool mergeActive = mergeRootChild ?
1425 mergeRootChild->probeValue(ijk, mergeValue) : mergeRoot->probeValue(ijk, mergeValue);
1427 if (mergeValue != zeroVal<ValueT>()) {
1429 data[i] += mergeValue;
1433 if (mergeActive) leaf.setValuesOn();
1440 template <
typename TreeT>
1445 assert(mBackground);
1446 return *mBackground;
1455 #endif // OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
T negative(const T &val)
Return the unary negation of the given value.
#define OPENVDB_USE_VERSION_NAMESPACE
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Tag dispatch class that distinguishes constructors that steal.
OPENVDB_API void initialize()
Global registration of basic types.
Implementation of a depth-first node visitor.
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
GLsizei const GLfloat * value
Tag dispatch class that distinguishes constructors that deep copy.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
#define OPENVDB_THROW(exception, message)