10 #ifndef OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
11 #define OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
23 #include <unordered_map>
24 #include <unordered_set>
46 template <
typename TreeT>
58 : mTree(&tree), mSteal(true) { }
61 : mTreePtr(treePtr), mTree(mTreePtr.
get()), mSteal(true) { }
69 : mTree(&tree), mSteal(false)
85 void reset(
typename TreeType::Ptr treePtr,
Steal);
97 template<
typename NodeT>
106 template <
typename NodeT>
113 template <
typename NodeT>
118 template <
typename NodeT>
136 typename TreeType::Ptr mTreePtr;
144 template <
typename TreeT>
147 std::unique_ptr<MaskTreeType>
ptr;
157 if (
bool(other.
ptr))
ptr = std::make_unique<MaskTreeType>(*other.
ptr);
165 template <
typename TreeT>
169 using RootT =
typename MaskT::RootNodeType;
170 using LeafT =
typename MaskT::LeafNodeType;
173 bool operator()(RootT& root,
size_t)
const;
174 template<
typename NodeT>
175 bool operator()(NodeT& node,
size_t)
const;
191 template<
typename TreeT,
bool Union>
195 using RootT =
typename TreeT::RootNodeType;
196 using LeafT =
typename TreeT::LeafNodeType;
201 template <
typename TagT>
213 template <
typename TreesT,
typename TagT>
216 for (
auto* tree : trees) {
218 mTreesToMerge.emplace_back(*tree, tag);
227 : mTreesToMerge(trees) { }
233 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
236 bool empty()
const {
return mTreesToMerge.empty(); }
239 size_t size()
const {
return mTreesToMerge.size(); }
248 template<
typename NodeT>
249 bool operator()(NodeT& node,
size_t idx)
const;
257 const ValueT& background()
const;
259 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
260 mutable const ValueT* mBackground =
nullptr;
261 bool mPruneCancelledTiles =
false;
265 template <
typename TreeT>
268 template <
typename TreeT>
278 template<
typename TreeT>
282 using RootT =
typename TreeT::RootNodeType;
283 using LeafT =
typename TreeT::LeafNodeType;
288 template <
typename TagT>
303 size_t size()
const {
return 1; }
309 template<
typename NodeT>
310 bool operator()(NodeT& node,
size_t idx)
const;
318 const ValueT& background()
const;
319 const ValueT& otherBackground()
const;
324 mutable const ValueT* mBackground =
nullptr;
325 mutable const ValueT* mOtherBackground =
nullptr;
326 bool mPruneCancelledTiles =
false;
333 template<
typename TreeT>
337 using RootT =
typename TreeT::RootNodeType;
338 using LeafT =
typename TreeT::LeafNodeType;
342 template <
typename TagT>
343 SumMergeOp(TreeT& tree, TagT tag) { mTreesToMerge.emplace_back(tree, tag); }
352 template <
typename TreesT,
typename TagT>
355 for (
auto* tree : trees) {
357 mTreesToMerge.emplace_back(*tree, tag);
366 : mTreesToMerge(trees) { }
372 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
375 bool empty()
const {
return mTreesToMerge.empty(); }
378 size_t size()
const {
return mTreesToMerge.size(); }
384 template<
typename NodeT>
385 bool operator()(NodeT& node,
size_t idx)
const;
393 const ValueT& background()
const;
395 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
396 mutable const ValueT* mBackground =
nullptr;
403 template<
typename TreeT>
410 manager.foreachTopDown(op);
413 template<
typename TreeT>
416 return bool(mMaskTree.ptr);
419 template<
typename TreeT>
423 OPENVDB_THROW(RuntimeError,
"Cannot reset with empty Tree shared pointer.");
427 mTree = mTreePtr.get();
430 template<
typename TreeT>
434 return &mTree->root();
437 template<
typename TreeT>
438 template<
typename NodeT>
443 if (!mSteal && !this->
mask()->isValueOn(ijk))
return nullptr;
444 return mTree->template probeConstNode<NodeT>(ijk);
447 template<
typename TreeT>
452 assert(this->hasMask());
453 this->
mask()->addTile(level, ijk,
false,
false);
457 template<
typename TreeT>
458 template<
typename NodeT>
459 std::unique_ptr<NodeT>
464 return std::unique_ptr<NodeT>(
465 tree->root().template stealNode<NodeT>(ijk,
value,
false)
468 auto* child = this->probeConstNode<NodeT>(ijk);
470 auto result = std::make_unique<NodeT>(*child);
471 this->pruneMask(NodeT::LEVEL+1, ijk);
475 return std::unique_ptr<NodeT>();
478 template<
typename TreeT>
479 template<
typename NodeT>
480 std::unique_ptr<NodeT>
483 return this->stealOrDeepCopyNode<NodeT>(ijk, mTree->root().background());
486 template<
typename TreeT>
487 template<
typename NodeT>
492 if (NodeT::LEVEL == 0)
return;
496 auto* node = tree->template probeNode<NodeT>(ijk);
498 const Index pos = NodeT::coordToOffset(ijk);
499 node->addTile(pos, value, active);
502 auto* node = mTree->template probeConstNode<NodeT>(ijk);
503 if (node) this->pruneMask(NodeT::LEVEL, ijk);
511 template <
typename TreeT>
514 using ChildT =
typename RootT::ChildNodeType;
516 const Index count = mTree.root().childCount();
518 std::vector<std::unique_ptr<ChildT>> children(count);
523 tbb::blocked_range<Index>(0, count),
524 [&](tbb::blocked_range<Index>&
range)
526 for (
Index i = range.begin(); i < range.end(); i++) {
527 children[i] = std::make_unique<ChildT>(
Coord::max(),
true,
true);
535 for (
auto iter = mTree.root().cbeginChildOn(); iter; ++iter) {
536 children[i]->setOrigin(iter->origin());
537 root.addChild(children[i].release());
544 template <
typename TreeT>
545 template <
typename NodeT>
548 using ChildT =
typename NodeT::ChildNodeType;
550 const auto* otherNode = mTree.template probeConstNode<NodeT>(node.origin());
551 if (!otherNode)
return false;
555 if (NodeT::LEVEL == 1) {
556 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
557 node.addTile(iter.pos(),
true,
true);
560 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
561 auto* child =
new ChildT(iter->origin(),
true,
true);
562 node.addChild(child);
574 namespace merge_internal {
577 template <
typename BufferT,
typename ValueT>
578 struct UnallocatedBuffer
580 static void allocateAndFill(BufferT&
buffer,
const ValueT& background)
582 if (buffer.empty()) {
583 if (!buffer.isOutOfCore()) {
585 buffer.fill(background);
590 static bool isPartiallyConstructed(
const BufferT& buffer)
592 return !buffer.isOutOfCore() && buffer.empty();
596 template <
typename BufferT>
597 struct UnallocatedBuffer<BufferT, bool>
600 static void allocateAndFill(BufferT&,
const bool&) { }
601 static bool isPartiallyConstructed(
const BufferT&) {
return false; }
607 template <Index LEVEL>
610 template <
typename NodeT,
typename OpT>
611 static void run(NodeT& node, OpT& op)
613 using NonConstChildT =
typename NodeT::ChildNodeType;
618 Index32 childCount = node.childCount();
619 if (childCount > 0) {
623 std::vector<ChildT*> children;
624 children.reserve(childCount);
625 for (
auto iter = node.beginChildOn(); iter; ++iter) {
626 children.push_back(&(*iter));
631 tbb::blocked_range<Index32>(0, childCount),
632 [&](tbb::blocked_range<Index32>&
range) {
633 for (
Index32 n = range.begin();
n < range.end();
n++) {
648 template <
typename NodeT,
typename OpT>
649 static void run(NodeT& node, OpT& op)
658 template <
typename TreeT>
659 struct ApplyTileSumToNodeOp
661 using LeafT =
typename TreeT::LeafNodeType;
664 ApplyTileSumToNodeOp(
const ValueT&
value,
const bool active):
665 mValue(value), mActive(active) { }
667 template <
typename NodeT>
668 void operator()(NodeT& node,
size_t)
const
674 for (
auto iter = node.beginValueAll(); iter; ++iter) {
675 iter.setValue(mValue + *iter);
677 if (mActive) node.setValuesOn();
680 void operator()(LeafT& leaf,
size_t)
const
682 auto*
data = leaf.buffer().data();
684 if (mValue != zeroVal<ValueT>()) {
689 if (mActive) leaf.setValuesOn();
692 template <
typename NodeT>
693 void run(NodeT& node)
695 Dispatch<NodeT::LEVEL>::run(node, *
this);
713 template <
typename TreeT,
bool Union>
716 const bool Intersect = !Union;
718 if (this->empty())
return false;
721 if (!mBackground) mBackground = &root.background();
724 auto keyExistsInRoot = [&](
const Coord& key) ->
bool
726 return root.getValueDepth(key) > -1;
730 auto keyExistsInAllTrees = [&](
const Coord& key) ->
bool
733 const auto* mergeRoot = mergeTree.rootPtr();
734 if (!mergeRoot)
return false;
735 if (mergeRoot->getValueDepth(key) == -1)
return false;
741 root.eraseBackgroundTiles();
746 std::vector<Coord> toDelete;
747 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
748 const Coord& key = valueIter.getCoord();
749 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
752 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
753 const Coord& key = childIter.getCoord();
754 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
758 for (Coord& key : toDelete) root.addTile(key, *mBackground,
false);
759 root.eraseBackgroundTiles();
765 constexpr uint8_t ACTIVE_TILE = 0x1;
766 constexpr uint8_t INSIDE_TILE = 0x2;
767 constexpr uint8_t OUTSIDE_TILE = 0x4;
769 constexpr uint8_t INSIDE_STATE = Union ? INSIDE_TILE : OUTSIDE_TILE;
770 constexpr uint8_t OUTSIDE_STATE = Union ? OUTSIDE_TILE : INSIDE_TILE;
772 const ValueT insideBackground = Union ? -this->background() : this->background();
773 const ValueT outsideBackground = -insideBackground;
775 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
779 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
780 else if (value > zeroVal<ValueT>()) flag |= OUTSIDE_TILE;
781 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
785 std::unordered_map<Coord, uint8_t> tiles;
787 if (root.getTableSize() > 0) {
788 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
789 const Coord& key = valueIter.getCoord();
790 tiles.insert({key, getTileFlag(valueIter)});
797 const auto* mergeRoot = mergeTree.rootPtr();
798 if (!mergeRoot)
continue;
799 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
800 const Coord& key = valueIter.getCoord();
801 auto it = tiles.find(key);
802 if (it == tiles.end()) {
804 tiles.insert({key, getTileFlag(valueIter)});
807 const uint8_t flag = it->second;
808 if (flag & OUTSIDE_STATE) {
809 const uint8_t newFlag = getTileFlag(valueIter);
810 if (newFlag & INSIDE_STATE) {
811 it->second = newFlag;
820 for (
auto it : tiles) {
821 const uint8_t flag = it.second;
822 if (flag & INSIDE_STATE) {
823 const Coord& key = it.first;
824 const bool state = flag & ACTIVE_TILE;
826 if (Union || keyExistsInRoot(key)) {
827 root.addTile(key, insideBackground, state);
832 std::unordered_set<Coord> children;
834 if (root.getTableSize() > 0) {
835 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
836 const Coord& key = childIter.getCoord();
837 children.insert(key);
841 bool continueRecurse =
false;
847 const auto* mergeRoot = mergeTree.rootPtr();
848 if (!mergeRoot)
continue;
849 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
850 const Coord& key = childIter.getCoord();
853 if (Intersect && !keyExistsInRoot(key))
continue;
856 if (children.count(key)) {
857 continueRecurse =
true;
862 auto it = tiles.find(key);
863 if (it != tiles.end() && it->second == INSIDE_STATE)
continue;
865 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
866 childPtr->resetBackground(mergeRoot->background(), root.background());
867 if (childPtr) root.addChild(childPtr.release());
869 children.insert(key);
875 for (
auto it : tiles) {
876 const uint8_t flag = it.second;
877 if (flag & OUTSIDE_STATE) {
878 const Coord& key = it.first;
879 if (!children.count(key)) {
880 const bool state = flag & ACTIVE_TILE;
882 if (Union || keyExistsInRoot(key)) {
883 root.addTile(key, outsideBackground, state);
890 root.eraseBackgroundTiles();
892 return continueRecurse;
895 template<
typename TreeT,
bool Union>
896 template<
typename NodeT>
901 if (this->empty())
return false;
903 const ValueT insideBackground = Union ? -this->background() : this->background();
904 const ValueT outsideBackground = -insideBackground;
906 using NodeMaskT =
typename NodeT::NodeMaskType;
910 NodeMaskT invalidTile;
919 return Union ?
value > zeroVal<ValueT>() :
value < zeroVal<ValueT>();
922 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
923 if (isValid(iter.getValue())) {
924 validTile.setOn(iter.pos());
925 }
else if (isInvalid(iter.getValue())) {
926 invalidTile.setOn(iter.pos());
930 bool continueRecurse =
false;
934 auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
936 if (!mergeNode)
continue;
940 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
941 Index pos = iter.pos();
943 if (validTile.isOn(pos))
continue;
945 if (isValid(iter.getValue())) {
946 node.addTile(pos, insideBackground, iter.isValueOn());
947 validTile.setOn(pos);
953 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
954 Index pos = iter.pos();
955 const Coord& ijk = iter.getCoord();
957 if (validTile.isOn(pos)) {
958 mergeTree.template addTile<NonConstNodeT>(ijk, outsideBackground,
false);
959 }
else if (invalidTile.isOn(pos)) {
960 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
962 childPtr->resetBackground(mergeTree.rootPtr()->background(), this->background());
963 node.addChild(childPtr.release());
965 invalidTile.setOff(pos);
969 continueRecurse =
true;
974 return continueRecurse;
977 template <
typename TreeT,
bool Union>
980 using LeafT =
typename TreeT::LeafNodeType;
982 using BufferT =
typename LeafT::Buffer;
984 if (this->empty())
return false;
986 const ValueT background = Union ? this->background() : -this->background();
991 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
992 leaf.buffer(), background);
995 const LeafT* mergeLeaf = mergeTree.template probeConstNode<LeafT>(leaf.origin());
996 if (!mergeLeaf)
continue;
999 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1000 mergeLeaf->buffer())) {
1004 if (mPruneCancelledTiles) {
1005 bool allnegequal =
true;
1007 const ValueT& newValue = mergeLeaf->getValue(i);
1008 const ValueT& oldValue = leaf.getValue(i);
1010 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1012 leaf.setValueOnly(i, newValue);
1013 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1020 if (Union) { leaf.fill(
math::negative(this->background()),
false); }
1021 else { leaf.fill(this->background(),
false); }
1026 const ValueT& newValue = mergeLeaf->getValue(i);
1027 const ValueT& oldValue = leaf.getValue(i);
1028 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1030 leaf.setValueOnly(i, newValue);
1031 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1040 template <
typename TreeT,
bool Union>
1045 assert(mBackground);
1046 return *mBackground;
1053 template <
typename TreeT>
1057 if (!mBackground) mBackground = &root.background();
1058 if (!mOtherBackground) mOtherBackground = &mTree.rootPtr()->background();
1063 constexpr uint8_t ACTIVE_TILE = 0x1;
1064 constexpr uint8_t INSIDE_TILE = 0x2;
1065 constexpr uint8_t CHILD = 0x4;
1067 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
1071 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
1072 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
1077 root.eraseBackgroundTiles();
1079 std::unordered_map<Coord, uint8_t>
flags;
1081 if (root.getTableSize() > 0) {
1082 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1083 const Coord& key = valueIter.getCoord();
1084 const uint8_t flag = getTileFlag(valueIter);
1085 if (flag & INSIDE_TILE) {
1086 flags.insert({key, getTileFlag(valueIter)});
1090 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1091 const Coord& key = childIter.getCoord();
1092 flags.insert({key, CHILD});
1096 bool continueRecurse =
false;
1098 const auto* mergeRoot = mTree.rootPtr();
1101 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1102 const Coord& key = valueIter.getCoord();
1103 const uint8_t flag = getTileFlag(valueIter);
1104 if (flag & INSIDE_TILE) {
1105 auto it = flags.find(key);
1106 if (it != flags.end()) {
1107 const bool state = flag & ACTIVE_TILE;
1108 root.addTile(key, this->background(), state);
1113 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1114 const Coord& key = childIter.getCoord();
1115 auto it = flags.find(key);
1116 if (it != flags.end()) {
1117 const uint8_t otherFlag = it->second;
1118 if (otherFlag & CHILD) {
1120 continueRecurse =
true;
1121 }
else if (otherFlag & INSIDE_TILE) {
1122 auto childPtr = mTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
1124 childPtr->resetBackground(this->otherBackground(), this->background());
1126 root.addChild(childPtr.release());
1134 root.eraseBackgroundTiles();
1136 return continueRecurse;
1139 template<
typename TreeT>
1140 template<
typename NodeT>
1145 using NodeMaskT =
typename NodeT::NodeMaskType;
1149 NodeMaskT insideTile;
1150 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
1151 if (iter.getValue() < zeroVal<ValueT>()) {
1152 insideTile.setOn(iter.pos());
1156 bool continueRecurse =
false;
1158 auto* mergeNode = mTree.template probeConstNode<NonConstNodeT>(node.origin());
1160 if (!mergeNode)
return continueRecurse;
1164 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
1165 Index pos = iter.pos();
1166 if (iter.getValue() < zeroVal<ValueT>()) {
1167 if (insideTile.isOn(pos) || node.isChildMaskOn(pos)) {
1168 node.addTile(pos, this->background(), iter.isValueOn());
1175 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
1176 Index pos = iter.pos();
1177 const Coord& ijk = iter.getCoord();
1178 if (insideTile.isOn(pos)) {
1179 auto childPtr = mTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
1181 childPtr->resetBackground(this->otherBackground(), this->background());
1183 node.addChild(childPtr.release());
1185 }
else if (node.isChildMaskOn(pos)) {
1188 continueRecurse =
true;
1192 return continueRecurse;
1195 template <
typename TreeT>
1198 using LeafT =
typename TreeT::LeafNodeType;
1200 using BufferT =
typename LeafT::Buffer;
1205 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1206 leaf.buffer(), this->background());
1208 const LeafT* mergeLeaf = mTree.template probeConstNode<LeafT>(leaf.origin());
1209 if (!mergeLeaf)
return false;
1214 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1215 mergeLeaf->buffer())) {
1219 if (mPruneCancelledTiles) {
1220 bool allequal =
true;
1222 const ValueT& aValue = leaf.getValue(i);
1223 ValueT bValue = mergeLeaf->getValue(i);
1224 allequal &= aValue == bValue;
1226 if (aValue < bValue) {
1227 leaf.setValueOnly(i, bValue);
1228 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1235 leaf.fill(background(),
false);
1239 const ValueT& aValue = leaf.getValue(i);
1240 ValueT bValue = mergeLeaf->getValue(i);
1242 if (aValue < bValue) {
1243 leaf.setValueOnly(i, bValue);
1244 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1252 template <
typename TreeT>
1257 assert(mBackground);
1258 return *mBackground;
1261 template <
typename TreeT>
1262 const typename CsgDifferenceOp<TreeT>::ValueT&
1263 CsgDifferenceOp<TreeT>::otherBackground()
const
1266 assert(mOtherBackground);
1267 return *mOtherBackground;
1274 template <
typename TreeT>
1278 using ChildT =
typename RootT::ChildNodeType;
1281 if (this->empty())
return false;
1284 if (!mBackground) mBackground = &root.background();
1287 auto keyExistsInRoot = [](
const auto& rootToTest,
const Coord& key) ->
bool
1289 return rootToTest.getValueDepth(key) > -1;
1292 constexpr uint8_t TILE = 0x1;
1293 constexpr uint8_t CHILD = 0x2;
1294 constexpr uint8_t TARGET_CHILD = 0x4;
1296 std::unordered_map<Coord, uint8_t> children;
1300 if (root.getTableSize() > 0) {
1301 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1302 const Coord& key = valueIter.getCoord();
1303 children.insert({key, TILE});
1306 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1307 const Coord& key = childIter.getCoord();
1308 children.insert({key, CHILD | TARGET_CHILD});
1315 const auto* mergeRoot = mergeTree.rootPtr();
1316 if (!mergeRoot)
continue;
1318 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1319 const Coord& key = valueIter.getCoord();
1320 auto it = children.find(key);
1321 if (it == children.end()) {
1323 children.insert({key, TILE});
1330 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1331 const Coord& key = childIter.getCoord();
1332 auto it = children.find(key);
1333 if (it == children.end()) {
1335 children.insert({key, CHILD});
1338 it->second |= CHILD;
1345 for (
const auto& it : children) {
1346 if (!keyExistsInRoot(root, it.first)) {
1347 root.addTile(it.first, root.background(),
false);
1353 for (
const auto& it : children) {
1355 const Coord& key = it.first;
1359 if (it.second & TARGET_CHILD)
continue;
1362 const bool active = root.probeValue(key, value);
1365 const auto* mergeRoot = mergeTree.rootPtr();
1366 if (!mergeRoot)
continue;
1372 const auto* mergeNode = mergeRoot->template probeConstNode<ChildT>(key);
1374 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(key);
1377 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(value, active);
1378 applyOp.run(*childPtr);
1379 root.addChild(childPtr.release());
1385 const bool mergeActive = mergeRoot->probeValue(key, mergeValue);
1387 if (active || mergeActive) {
1388 value += mergeValue;
1389 root.addTile(key, value,
true);
1391 value += mergeValue;
1392 root.addTile(key, value,
false);
1396 mergeTree.template addTile<NonConstChildT>(key, zeroVal<ValueT>(),
false);
1402 ValueT background = root.background();
1405 const auto* mergeRoot = mergeTree.rootPtr();
1406 if (!mergeRoot)
continue;
1407 background += mergeRoot->background();
1410 root.setBackground(background,
false);
1415 template<
typename TreeT>
1416 template<
typename NodeT>
1419 using ChildT =
typename NodeT::ChildNodeType;
1422 if (this->empty())
return false;
1425 const auto* mergeRoot = mergeTree.rootPtr();
1426 if (!mergeRoot)
continue;
1428 const auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
1432 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1433 if (mergeNode->isChildMaskOn(iter.pos())) {
1435 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(iter.getCoord());
1438 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(*iter, iter.isValueOn());
1439 applyOp.run(*childPtr);
1440 node.addChild(childPtr.release());
1444 const bool mergeActive = mergeNode->probeValue(iter.getCoord(), mergeValue);
1445 iter.setValue(*iter + mergeValue);
1446 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1453 if (mergeTree.hasMask()) {
1456 const ChildT* originalMergeNode = mergeRoot->template probeConstNode<ChildT>(node.origin());
1457 if (originalMergeNode)
continue;
1461 const bool mergeActive = mergeRoot->probeValue(node.origin(), mergeValue);
1462 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1463 iter.setValue(*iter + mergeValue);
1464 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1472 template <
typename TreeT>
1475 using RootT =
typename TreeT::RootNodeType;
1476 using RootChildT =
typename RootT::ChildNodeType;
1478 using LeafT =
typename TreeT::LeafNodeType;
1480 using BufferT =
typename LeafT::Buffer;
1483 if (this->empty())
return false;
1485 const Coord& ijk = leaf.origin();
1490 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1491 leaf.buffer(), this->background());
1493 auto*
data = leaf.buffer().data();
1496 const RootT* mergeRoot = mergeTree.rootPtr();
1497 if (!mergeRoot)
continue;
1499 const LeafT* mergeLeaf = mergeTree.template probeConstNode<NonConstLeafT>(ijk);
1506 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1507 mergeLeaf->buffer())) {
1512 data[i] += mergeLeaf->getValue(i);
1515 leaf.getValueMask() |= mergeLeaf->getValueMask();
1519 if (mergeTree.hasMask()) {
1522 const LeafT* originalMergeLeaf = mergeRoot->template probeConstNode<NonConstLeafT>(ijk);
1523 if (originalMergeLeaf)
continue;
1526 const RootChildT* mergeRootChild = mergeRoot->template probeConstNode<NonConstRootChildT>(ijk);
1529 bool mergeActive = mergeRootChild ?
1530 mergeRootChild->probeValue(ijk, mergeValue) : mergeRoot->probeValue(ijk, mergeValue);
1532 if (mergeValue != zeroVal<ValueT>()) {
1534 data[i] += mergeValue;
1538 if (mergeActive) leaf.setValuesOn();
1545 template <
typename TreeT>
1550 assert(mBackground);
1551 return *mBackground;
1559 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1561 #ifdef OPENVDB_INSTANTIATE_MERGE
1594 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1601 #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.
GLsizei const GLfloat * value
#define OPENVDB_USE_VERSION_NAMESPACE
**But if you need a result
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
#define OPENVDB_INSTANTIATE_STRUCT
auto get(const UT_ARTIterator< T > &it) -> decltype(it.key())
Tag dispatch class that distinguishes constructors that steal.
OPENVDB_API void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
Implementation of a depth-first node visitor.
LeafData & operator=(const LeafData &)=delete
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
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)