10#ifndef OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
11#define OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
24#include <unordered_map>
25#include <unordered_set>
47template <
typename TreeT>
53 using MaskTreeType =
typename TreeT::template ValueConverter<ValueMask>::Type;
59 : mTree(&
tree), mSteal(true) { }
62 : mTreePtr(treePtr), mTree(mTreePtr.get()), mSteal(true) { }
70 : mTree(&
tree), mSteal(false)
86 void reset(
typename TreeType::Ptr treePtr,
Steal);
94 const RootNodeType* rootPtr()
const;
98 template<
typename NodeT>
99 const NodeT* probeConstNode(
const Coord& ijk)
const;
102 void pruneMask(
Index level,
const Coord& ijk);
107 template <
typename NodeT>
108 std::unique_ptr<NodeT> stealOrDeepCopyNode(
const Coord& ijk,
const ValueType& value);
114 template <
typename NodeT>
115 std::unique_ptr<NodeT> stealOrDeepCopyNode(
const Coord& ijk);
119 template <
typename NodeT>
120 void addTile(
const Coord& ijk,
const ValueType& value,
bool active);
124 void initializeMask();
127 bool hasMask()
const;
137 typename TreeType::Ptr mTreePtr;
138 const TreeType* mTree;
145template <
typename TreeT>
148 std::unique_ptr<MaskTreeType>
ptr;
158 if (
bool(other.
ptr))
ptr = std::make_unique<MaskTreeType>(*other.
ptr);
166template <
typename TreeT>
170 using RootT =
typename MaskT::RootNodeType;
171 using LeafT =
typename MaskT::LeafNodeType;
174 bool operator()(RootT& root,
size_t)
const;
175 template<
typename NodeT>
176 bool operator()(NodeT& node,
size_t)
const;
192template<
typename TreeT,
bool Union>
195 using ValueT =
typename TreeT::ValueType;
196 using RootT =
typename TreeT::RootNodeType;
197 using LeafT =
typename TreeT::LeafNodeType;
202 template <
typename TagT>
214 template <
typename TreesT,
typename TagT>
217 for (
auto*
tree : trees) {
219 mTreesToMerge.emplace_back(*
tree, tag);
228 : mTreesToMerge(trees) { }
234 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
237 bool empty()
const {
return mTreesToMerge.empty(); }
240 size_t size()
const {
return mTreesToMerge.size(); }
249 template<
typename NodeT>
258 const ValueT& background()
const;
260 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
261 mutable const ValueT* mBackground =
nullptr;
262 bool mPruneCancelledTiles =
false;
266template <
typename TreeT>
269template <
typename TreeT>
279template<
typename TreeT>
282 using ValueT =
typename TreeT::ValueType;
283 using RootT =
typename TreeT::RootNodeType;
284 using LeafT =
typename TreeT::LeafNodeType;
289 template <
typename TagT>
304 size_t size()
const {
return 1; }
307 bool operator()(RootT& root,
size_t idx)
const;
310 template<
typename NodeT>
311 bool operator()(NodeT& node,
size_t idx)
const;
314 bool operator()(LeafT& leaf,
size_t idx)
const;
319 const ValueT& background()
const;
320 const ValueT& otherBackground()
const;
325 mutable const ValueT* mBackground =
nullptr;
326 mutable const ValueT* mOtherBackground =
nullptr;
327 bool mPruneCancelledTiles =
false;
334template<
typename TreeT>
337 using ValueT =
typename TreeT::ValueType;
338 using RootT =
typename TreeT::RootNodeType;
339 using LeafT =
typename TreeT::LeafNodeType;
343 template <
typename TagT>
353 template <
typename TreesT,
typename TagT>
356 for (
auto*
tree : trees) {
358 mTreesToMerge.emplace_back(*
tree, tag);
367 : mTreesToMerge(trees) { }
373 : mTreesToMerge(trees.cbegin(), trees.cend()) { }
376 bool empty()
const {
return mTreesToMerge.empty(); }
379 size_t size()
const {
return mTreesToMerge.size(); }
382 bool operator()(RootT& root,
size_t idx)
const;
385 template<
typename NodeT>
386 bool operator()(NodeT& node,
size_t idx)
const;
389 bool operator()(LeafT& leaf,
size_t idx)
const;
394 const ValueT& background()
const;
396 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
397 mutable const ValueT* mBackground =
nullptr;
404template<
typename TreeT>
411 manager.foreachTopDown(op);
414template<
typename TreeT>
417 return bool(mMaskTree.ptr);
420template<
typename TreeT>
428 mTree = mTreePtr.get();
431template<
typename TreeT>
435 return &mTree->root();
438template<
typename TreeT>
439template<
typename NodeT>
444 if (!mSteal && !this->
mask()->isValueOn(ijk))
return nullptr;
448template<
typename TreeT>
454 this->
mask()->addTile(level, ijk,
false,
false);
458template<
typename TreeT>
459template<
typename NodeT>
460std::unique_ptr<NodeT>
465 return std::unique_ptr<NodeT>(
466 tree->root().template stealNode<NodeT>(ijk, value,
false)
471 auto result = std::make_unique<NodeT>(*child);
476 return std::unique_ptr<NodeT>();
479template<
typename TreeT>
480template<
typename NodeT>
481std::unique_ptr<NodeT>
487template<
typename TreeT>
488template<
typename NodeT>
493 if (NodeT::LEVEL == 0)
return;
497 auto* node =
tree->template probeNode<NodeT>(ijk);
499 const Index pos = NodeT::coordToOffset(ijk);
500 node->addTile(pos, value, active);
504 if (node) this->
pruneMask(NodeT::LEVEL, ijk);
512template <
typename TreeT>
515 using ChildT =
typename RootT::ChildNodeType;
517 const Index count = mTree.root().childCount();
519 std::vector<std::unique_ptr<ChildT>> children(count);
524 tbb::blocked_range<Index>(0, count),
525 [&](tbb::blocked_range<Index>& range)
527 for (
Index i = range.begin(); i < range.end(); i++) {
528 children[i] = std::make_unique<ChildT>(
Coord::max(),
true,
true);
536 for (
auto iter = mTree.root().cbeginChildOn(); iter; ++iter) {
537 children[i]->setOrigin(iter->origin());
538 root.addChild(children[i].release());
545template <
typename TreeT>
546template <
typename NodeT>
549 using ChildT =
typename NodeT::ChildNodeType;
552 if (!otherNode)
return false;
556 if (NodeT::LEVEL == 1) {
557 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
558 node.addTile(iter.pos(),
true,
true);
561 for (
auto iter = otherNode->cbeginChildOn(); iter; ++iter) {
562 auto* child =
new ChildT(iter->origin(),
true,
true);
563 node.addChild(child);
575namespace merge_internal {
578template <
typename BufferT,
typename ValueT>
579struct UnallocatedBuffer
581 static void allocateAndFill(BufferT& buffer,
const ValueT& background)
583 if (buffer.empty()) {
585 buffer.fill(background);
589 static bool isPartiallyConstructed(
const BufferT& buffer)
591 return buffer.empty();
595template <
typename BufferT>
596struct UnallocatedBuffer<BufferT, bool>
599 static void allocateAndFill(BufferT&,
const bool&) { }
600 static bool isPartiallyConstructed(
const BufferT&) {
return false; }
606template <Index LEVEL>
609 template <
typename NodeT,
typename OpT>
610 static void run(NodeT& node, OpT& op)
612 using NonConstChildT =
typename NodeT::ChildNodeType;
613 using ChildT =
typename CopyConstness<NodeT, NonConstChildT>::Type;
617 Index32 childCount = node.childCount();
618 if (childCount > 0) {
622 std::vector<ChildT*> children;
623 children.reserve(childCount);
624 for (
auto iter = node.beginChildOn(); iter; ++iter) {
625 children.push_back(&(*iter));
630 tbb::blocked_range<Index32>(0, childCount),
631 [&](tbb::blocked_range<Index32>& range) {
632 for (Index32 n = range.begin(); n < range.end(); n++) {
633 DepthFirstNodeVisitor<ChildT>::visit(*children[n], op);
638 DepthFirstNodeVisitor<NodeT>::visit(node, op);
647 template <
typename NodeT,
typename OpT>
648 static void run(NodeT& node, OpT& op)
650 DepthFirstNodeVisitor<NodeT>::visit(node, op);
657template <
typename TreeT>
658struct ApplyTileSumToNodeOp
660 using LeafT =
typename TreeT::LeafNodeType;
661 using ValueT =
typename TreeT::ValueType;
663 ApplyTileSumToNodeOp(
const ValueT& value,
const bool active):
664 mValue(value), mActive(active) { }
666 template <
typename NodeT>
667 void operator()(NodeT& node,
size_t)
const
673 for (
auto iter = node.beginValueAll(); iter; ++iter) {
674 iter.setValue(mValue + *iter);
676 if (mActive) node.setValuesOn();
679 void operator()(LeafT& leaf,
size_t)
const
681 auto* data = leaf.buffer().data();
683 if (mValue != zeroVal<ValueT>()) {
684 for (Index i = 0; i < LeafT::SIZE; ++i) {
688 if (mActive) leaf.setValuesOn();
691 template <
typename NodeT>
692 void run(NodeT& node)
694 Dispatch<NodeT::LEVEL>::run(node, *
this);
712template <
typename TreeT,
bool Union>
715 const bool Intersect = !Union;
717 if (this->
empty())
return false;
720 if (!mBackground) mBackground = &root.background();
723 auto keyExistsInRoot = [&](
const Coord& key) ->
bool
725 return root.getValueDepth(key) > -1;
729 auto keyExistsInAllTrees = [&](
const Coord& key) ->
bool
732 const auto* mergeRoot = mergeTree.rootPtr();
733 if (!mergeRoot)
return false;
734 if (mergeRoot->getValueDepth(key) == -1)
return false;
740 root.eraseBackgroundTiles();
745 std::vector<Coord> toDelete;
746 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
747 const Coord& key = valueIter.getCoord();
748 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
751 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
752 const Coord& key = childIter.getCoord();
753 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
757 for (
Coord& key : toDelete) root.addTile(key, *mBackground,
false);
758 root.eraseBackgroundTiles();
764 constexpr uint8_t ACTIVE_TILE = 0x1;
765 constexpr uint8_t INSIDE_TILE = 0x2;
766 constexpr uint8_t OUTSIDE_TILE = 0x4;
768 constexpr uint8_t INSIDE_STATE = Union ? INSIDE_TILE : OUTSIDE_TILE;
769 constexpr uint8_t OUTSIDE_STATE = Union ? OUTSIDE_TILE : INSIDE_TILE;
771 const ValueT insideBackground = Union ? -this->background() : this->background();
772 const ValueT outsideBackground = -insideBackground;
774 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
777 const ValueT& value = valueIter.getValue();
780 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
784 std::unordered_map<
Coord, uint8_t> tiles;
786 if (root.getTableSize() > 0) {
787 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
788 const Coord& key = valueIter.getCoord();
789 tiles.insert({key, getTileFlag(valueIter)});
796 const auto* mergeRoot = mergeTree.rootPtr();
797 if (!mergeRoot)
continue;
798 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
799 const Coord& key = valueIter.getCoord();
800 auto it = tiles.find(key);
801 if (it == tiles.end()) {
803 tiles.insert({key, getTileFlag(valueIter)});
806 const uint8_t flag = it->second;
807 if (flag & OUTSIDE_STATE) {
808 const uint8_t newFlag = getTileFlag(valueIter);
809 if (newFlag & INSIDE_STATE) {
810 it->second = newFlag;
819 for (
auto it : tiles) {
820 const uint8_t flag = it.second;
821 if (flag & INSIDE_STATE) {
822 const Coord& key = it.first;
823 const bool state = flag & ACTIVE_TILE;
825 if (Union || keyExistsInRoot(key)) {
826 root.addTile(key, insideBackground, state);
831 std::unordered_set<Coord> children;
833 if (root.getTableSize() > 0) {
834 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
835 const Coord& key = childIter.getCoord();
836 children.insert(key);
840 bool continueRecurse =
false;
846 const auto* mergeRoot = mergeTree.rootPtr();
847 if (!mergeRoot)
continue;
848 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
849 const Coord& key = childIter.getCoord();
852 if (Intersect && !keyExistsInRoot(key))
continue;
855 if (children.count(key)) {
856 continueRecurse =
true;
861 auto it = tiles.find(key);
862 if (it != tiles.end() && it->second == INSIDE_STATE)
continue;
864 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
865 childPtr->resetBackground(mergeRoot->background(), root.background());
866 if (childPtr) root.addChild(childPtr.release());
868 children.insert(key);
874 for (
auto it : tiles) {
875 const uint8_t flag = it.second;
876 if (flag & OUTSIDE_STATE) {
877 const Coord& key = it.first;
878 if (!children.count(key)) {
879 const bool state = flag & ACTIVE_TILE;
881 if (Union || keyExistsInRoot(key)) {
882 root.addTile(key, outsideBackground, state);
889 root.eraseBackgroundTiles();
891 return continueRecurse;
894template<
typename TreeT,
bool Union>
895template<
typename NodeT>
898 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
900 if (this->
empty())
return false;
902 const ValueT insideBackground = Union ? -this->background() : this->background();
903 const ValueT outsideBackground = -insideBackground;
905 using NodeMaskT =
typename NodeT::NodeMaskType;
909 NodeMaskT invalidTile;
911 auto isValid = [](
const ValueT& value)
916 auto isInvalid = [](
const ValueT& value)
921 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
922 if (isValid(iter.getValue())) {
923 validTile.setOn(iter.pos());
924 }
else if (isInvalid(iter.getValue())) {
925 invalidTile.setOn(iter.pos());
929 bool continueRecurse =
false;
933 auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
935 if (!mergeNode)
continue;
939 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
940 Index pos = iter.pos();
942 if (validTile.isOn(pos))
continue;
944 if (isValid(iter.getValue())) {
945 node.addTile(pos, insideBackground, iter.isValueOn());
946 validTile.setOn(pos);
952 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
953 Index pos = iter.pos();
954 const Coord& ijk = iter.getCoord();
956 if (validTile.isOn(pos)) {
957 mergeTree.template addTile<NonConstNodeT>(ijk, outsideBackground,
false);
958 }
else if (invalidTile.isOn(pos)) {
959 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
961 childPtr->resetBackground(mergeTree.rootPtr()->background(), this->background());
962 node.addChild(childPtr.release());
964 invalidTile.setOff(pos);
968 continueRecurse =
true;
973 return continueRecurse;
976template <
typename TreeT,
bool Union>
979 using LeafT =
typename TreeT::LeafNodeType;
980 using ValueT =
typename LeafT::ValueType;
981 using BufferT =
typename LeafT::Buffer;
983 if (this->
empty())
return false;
985 const ValueT background = Union ? this->background() : -this->background();
990 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
991 leaf.buffer(), background);
994 const LeafT* mergeLeaf = mergeTree.template probeConstNode<LeafT>(leaf.origin());
995 if (!mergeLeaf)
continue;
998 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
999 mergeLeaf->buffer())) {
1003 if (mPruneCancelledTiles) {
1004 bool allnegequal =
true;
1005 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1006 const ValueT& newValue = mergeLeaf->getValue(i);
1007 const ValueT& oldValue = leaf.getValue(i);
1009 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1011 leaf.setValueOnly(i, newValue);
1012 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1019 if (Union) { leaf.fill(
math::negative(this->background()),
false); }
1020 else { leaf.fill(this->background(),
false); }
1024 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1025 const ValueT& newValue = mergeLeaf->getValue(i);
1026 const ValueT& oldValue = leaf.getValue(i);
1027 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1029 leaf.setValueOnly(i, newValue);
1030 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1039template <
typename TreeT,
bool Union>
1041CsgUnionOrIntersectionOp<TreeT, Union>::background()
const
1045 return *mBackground;
1052template <
typename TreeT>
1056 if (!mBackground) mBackground = &root.background();
1057 if (!mOtherBackground) mOtherBackground = &mTree.rootPtr()->background();
1062 constexpr uint8_t ACTIVE_TILE = 0x1;
1063 constexpr uint8_t INSIDE_TILE = 0x2;
1064 constexpr uint8_t CHILD = 0x4;
1066 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
1069 const ValueT& value = valueIter.getValue();
1071 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
1076 root.eraseBackgroundTiles();
1078 std::unordered_map<
Coord, uint8_t> flags;
1080 if (root.getTableSize() > 0) {
1081 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1082 const Coord& key = valueIter.getCoord();
1083 const uint8_t flag = getTileFlag(valueIter);
1084 if (flag & INSIDE_TILE) {
1085 flags.insert({key, getTileFlag(valueIter)});
1089 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1090 const Coord& key = childIter.getCoord();
1091 flags.insert({key, CHILD});
1095 bool continueRecurse =
false;
1097 const auto* mergeRoot = mTree.rootPtr();
1100 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1101 const Coord& key = valueIter.getCoord();
1102 const uint8_t flag = getTileFlag(valueIter);
1103 if (flag & INSIDE_TILE) {
1104 auto it = flags.find(key);
1105 if (it != flags.end()) {
1106 const bool state = flag & ACTIVE_TILE;
1107 root.addTile(key, this->background(), state);
1112 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1113 const Coord& key = childIter.getCoord();
1114 auto it = flags.find(key);
1115 if (it != flags.end()) {
1116 const uint8_t otherFlag = it->second;
1117 if (otherFlag & CHILD) {
1119 continueRecurse =
true;
1120 }
else if (otherFlag & INSIDE_TILE) {
1121 auto childPtr = mTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
1123 childPtr->resetBackground(this->otherBackground(), this->background());
1125 root.addChild(childPtr.release());
1133 root.eraseBackgroundTiles();
1135 return continueRecurse;
1138template<
typename TreeT>
1139template<
typename NodeT>
1142 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
1144 using NodeMaskT =
typename NodeT::NodeMaskType;
1148 NodeMaskT insideTile;
1149 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
1151 insideTile.setOn(iter.pos());
1155 bool continueRecurse =
false;
1157 auto* mergeNode = mTree.template probeConstNode<NonConstNodeT>(node.origin());
1159 if (!mergeNode)
return continueRecurse;
1163 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
1164 Index pos = iter.pos();
1166 if (insideTile.isOn(pos) || node.isChildMaskOn(pos)) {
1167 node.addTile(pos, this->background(), iter.isValueOn());
1174 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
1175 Index pos = iter.pos();
1176 const Coord& ijk = iter.getCoord();
1177 if (insideTile.isOn(pos)) {
1178 auto childPtr = mTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
1180 childPtr->resetBackground(this->otherBackground(), this->background());
1182 node.addChild(childPtr.release());
1184 }
else if (node.isChildMaskOn(pos)) {
1187 continueRecurse =
true;
1191 return continueRecurse;
1194template <
typename TreeT>
1197 using LeafT =
typename TreeT::LeafNodeType;
1198 using ValueT =
typename LeafT::ValueType;
1199 using BufferT =
typename LeafT::Buffer;
1204 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1205 leaf.buffer(), this->background());
1207 const LeafT* mergeLeaf = mTree.template probeConstNode<LeafT>(leaf.origin());
1208 if (!mergeLeaf)
return false;
1213 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1214 mergeLeaf->buffer())) {
1218 if (mPruneCancelledTiles) {
1219 bool allequal =
true;
1220 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1221 const ValueT& aValue = leaf.getValue(i);
1222 ValueT bValue = mergeLeaf->getValue(i);
1223 allequal &= aValue == bValue;
1225 if (aValue < bValue) {
1226 leaf.setValueOnly(i, bValue);
1227 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1234 leaf.fill(background(),
false);
1237 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1238 const ValueT& aValue = leaf.getValue(i);
1239 ValueT bValue = mergeLeaf->getValue(i);
1241 if (aValue < bValue) {
1242 leaf.setValueOnly(i, bValue);
1243 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1251template <
typename TreeT>
1253CsgDifferenceOp<TreeT>::background()
const
1257 return *mBackground;
1260template <
typename TreeT>
1261const typename CsgDifferenceOp<TreeT>::ValueT&
1262CsgDifferenceOp<TreeT>::otherBackground()
const
1266 return *mOtherBackground;
1273template <
typename TreeT>
1276 using ValueT =
typename RootT::ValueType;
1277 using ChildT =
typename RootT::ChildNodeType;
1278 using NonConstChildT =
typename std::remove_const<ChildT>::type;
1280 if (this->
empty())
return false;
1283 if (!mBackground) mBackground = &root.background();
1286 auto keyExistsInRoot = [](
const auto& rootToTest,
const Coord& key) ->
bool
1288 return rootToTest.getValueDepth(key) > -1;
1291 constexpr uint8_t TILE = 0x1;
1292 constexpr uint8_t CHILD = 0x2;
1293 constexpr uint8_t TARGET_CHILD = 0x4;
1295 std::unordered_map<
Coord, uint8_t> children;
1299 if (root.getTableSize() > 0) {
1300 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1301 const Coord& key = valueIter.getCoord();
1302 children.insert({key, TILE});
1305 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1306 const Coord& key = childIter.getCoord();
1307 children.insert({key, CHILD | TARGET_CHILD});
1314 const auto* mergeRoot = mergeTree.rootPtr();
1315 if (!mergeRoot)
continue;
1317 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1318 const Coord& key = valueIter.getCoord();
1319 auto it = children.find(key);
1320 if (it == children.end()) {
1322 children.insert({key, TILE});
1329 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1330 const Coord& key = childIter.getCoord();
1331 auto it = children.find(key);
1332 if (it == children.end()) {
1334 children.insert({key, CHILD});
1337 it->second |= CHILD;
1344 for (
const auto& it : children) {
1345 if (!keyExistsInRoot(root, it.first)) {
1346 root.addTile(it.first, root.background(),
false);
1352 for (
const auto& it : children) {
1354 const Coord& key = it.first;
1358 if (it.second & TARGET_CHILD)
continue;
1361 const bool active = root.probeValue(key, value);
1364 const auto* mergeRoot = mergeTree.rootPtr();
1365 if (!mergeRoot)
continue;
1371 const auto* mergeNode = mergeRoot->template probeConstNode<ChildT>(key);
1373 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(key);
1376 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(value, active);
1377 applyOp.run(*childPtr);
1378 root.addChild(childPtr.release());
1384 const bool mergeActive = mergeRoot->probeValue(key, mergeValue);
1386 if (active || mergeActive) {
1387 value += mergeValue;
1388 root.addTile(key, value,
true);
1390 value += mergeValue;
1391 root.addTile(key, value,
false);
1395 mergeTree.template addTile<NonConstChildT>(key,
zeroVal<ValueT>(),
false);
1401 ValueT background = root.background();
1404 const auto* mergeRoot = mergeTree.rootPtr();
1405 if (!mergeRoot)
continue;
1406 background += mergeRoot->background();
1409 root.setBackground(background,
false);
1414template<
typename TreeT>
1415template<
typename NodeT>
1418 using ChildT =
typename NodeT::ChildNodeType;
1419 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
1421 if (this->
empty())
return false;
1424 const auto* mergeRoot = mergeTree.rootPtr();
1425 if (!mergeRoot)
continue;
1427 const auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
1431 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1432 if (mergeNode->isChildMaskOn(iter.pos())) {
1434 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(iter.getCoord());
1437 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(*iter, iter.isValueOn());
1438 applyOp.run(*childPtr);
1439 node.addChild(childPtr.release());
1443 const bool mergeActive = mergeNode->probeValue(iter.getCoord(), mergeValue);
1444 iter.setValue(*iter + mergeValue);
1445 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1452 if (mergeTree.hasMask()) {
1455 const ChildT* originalMergeNode = mergeRoot->template probeConstNode<ChildT>(node.origin());
1456 if (originalMergeNode)
continue;
1460 const bool mergeActive = mergeRoot->probeValue(node.origin(), mergeValue);
1461 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1462 iter.setValue(*iter + mergeValue);
1463 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1471template <
typename TreeT>
1474 using RootT =
typename TreeT::RootNodeType;
1475 using RootChildT =
typename RootT::ChildNodeType;
1476 using NonConstRootChildT =
typename std::remove_const<RootChildT>::type;
1477 using LeafT =
typename TreeT::LeafNodeType;
1478 using ValueT =
typename LeafT::ValueType;
1479 using BufferT =
typename LeafT::Buffer;
1480 using NonConstLeafT =
typename std::remove_const<LeafT>::type;
1482 if (this->
empty())
return false;
1484 const Coord& ijk = leaf.origin();
1489 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1490 leaf.buffer(), this->background());
1492 auto* data = leaf.buffer().data();
1495 const RootT* mergeRoot = mergeTree.rootPtr();
1496 if (!mergeRoot)
continue;
1498 const LeafT* mergeLeaf = mergeTree.template probeConstNode<NonConstLeafT>(ijk);
1505 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1506 mergeLeaf->buffer())) {
1510 for (
Index i = 0; i < LeafT::SIZE; ++i) {
1511 data[i] += mergeLeaf->getValue(i);
1514 leaf.getValueMask() |= mergeLeaf->getValueMask();
1518 if (mergeTree.hasMask()) {
1521 const LeafT* originalMergeLeaf = mergeRoot->template probeConstNode<NonConstLeafT>(ijk);
1522 if (originalMergeLeaf)
continue;
1525 const RootChildT* mergeRootChild = mergeRoot->template probeConstNode<NonConstRootChildT>(ijk);
1528 bool mergeActive = mergeRootChild ?
1529 mergeRootChild->probeValue(ijk, mergeValue) : mergeRoot->probeValue(ijk, mergeValue);
1532 for (
Index i = 0; i < LeafT::SIZE; ++i) {
1533 data[i] += mergeValue;
1537 if (mergeActive) leaf.setValuesOn();
1544template <
typename TreeT>
1546SumMergeOp<TreeT>::background()
const
1550 return *mBackground;
1558#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1560#ifdef OPENVDB_INSTANTIATE_MERGE
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Implementation of a depth-first node visitor.
static Coord max()
Return the largest possible coordinate.
Definition Coord.h:47
Tag dispatch class that distinguishes constructors that deep copy.
Definition Types.h:756
Definition Exceptions.h:63
Tag dispatch class that distinguishes constructors that steal.
Definition Types.h:758
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Definition NodeManager.h:891
OPENVDB_AX_API void run(const char *ax, openvdb::GridBase &grid, const AttributeBindings &bindings={})
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
T negative(const T &val)
Return the unary negation of the given value.
Definition Math.h:139
Definition PointDataGrid.h:48
Index32 Index
Definition Types.h:34
void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types.
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
uint32_t Index32
Definition Types.h:32
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_INSTANTIATE_STRUCT
Definition version.h.in:232
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:291