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)
98 template<
typename NodeT>
107 template <
typename NodeT>
114 template <
typename NodeT>
119 template <
typename NodeT>
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()) {
584 if (!buffer.isOutOfCore()) {
586 buffer.fill(background);
591 static bool isPartiallyConstructed(
const BufferT& buffer)
593 return !buffer.isOutOfCore() && buffer.empty();
597template <
typename BufferT>
598struct UnallocatedBuffer<BufferT,
bool>
601 static void allocateAndFill(BufferT&,
const bool&) { }
602 static bool isPartiallyConstructed(
const BufferT&) {
return false; }
608template <Index LEVEL>
611 template <
typename NodeT,
typename OpT>
612 static void run(NodeT& node, OpT& op)
614 using NonConstChildT =
typename NodeT::ChildNodeType;
615 using ChildT =
typename CopyConstness<NodeT, NonConstChildT>::Type;
619 Index32 childCount = node.childCount();
620 if (childCount > 0) {
624 std::vector<ChildT*> children;
625 children.reserve(childCount);
626 for (
auto iter = node.beginChildOn(); iter; ++iter) {
627 children.push_back(&(*iter));
632 tbb::blocked_range<Index32>(0, childCount),
633 [&](tbb::blocked_range<Index32>& range) {
634 for (Index32 n = range.begin(); n < range.end(); n++) {
635 DepthFirstNodeVisitor<ChildT>::visit(*children[n], op);
640 DepthFirstNodeVisitor<NodeT>::visit(node, op);
649 template <
typename NodeT,
typename OpT>
650 static void run(NodeT& node, OpT& op)
652 DepthFirstNodeVisitor<NodeT>::visit(node, op);
659template <
typename TreeT>
660struct ApplyTileSumToNodeOp
662 using LeafT =
typename TreeT::LeafNodeType;
663 using ValueT =
typename TreeT::ValueType;
665 ApplyTileSumToNodeOp(
const ValueT& value,
const bool active):
666 mValue(value), mActive(active) { }
668 template <
typename NodeT>
669 void operator()(NodeT& node,
size_t)
const
675 for (
auto iter = node.beginValueAll(); iter; ++iter) {
676 iter.setValue(mValue + *iter);
678 if (mActive) node.setValuesOn();
681 void operator()(LeafT& leaf,
size_t)
const
683 auto* data = leaf.buffer().data();
685 if (mValue != zeroVal<ValueT>()) {
686 for (Index i = 0; i < LeafT::SIZE; ++i) {
690 if (mActive) leaf.setValuesOn();
693 template <
typename NodeT>
694 void run(NodeT& node)
696 Dispatch<NodeT::LEVEL>::run(node, *
this);
714template <
typename TreeT,
bool Union>
717 const bool Intersect = !Union;
719 if (this->
empty())
return false;
722 if (!mBackground) mBackground = &root.background();
725 auto keyExistsInRoot = [&](
const Coord& key) ->
bool
727 return root.getValueDepth(key) > -1;
731 auto keyExistsInAllTrees = [&](
const Coord& key) ->
bool
734 const auto* mergeRoot = mergeTree.rootPtr();
735 if (!mergeRoot)
return false;
736 if (mergeRoot->getValueDepth(key) == -1)
return false;
742 root.eraseBackgroundTiles();
747 std::vector<Coord> toDelete;
748 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
749 const Coord& key = valueIter.getCoord();
750 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
753 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
754 const Coord& key = childIter.getCoord();
755 if (!keyExistsInAllTrees(key)) toDelete.push_back(key);
759 for (
Coord& key : toDelete) root.addTile(key, *mBackground,
false);
760 root.eraseBackgroundTiles();
766 constexpr uint8_t ACTIVE_TILE = 0x1;
767 constexpr uint8_t INSIDE_TILE = 0x2;
768 constexpr uint8_t OUTSIDE_TILE = 0x4;
770 constexpr uint8_t INSIDE_STATE = Union ? INSIDE_TILE : OUTSIDE_TILE;
771 constexpr uint8_t OUTSIDE_STATE = Union ? OUTSIDE_TILE : INSIDE_TILE;
773 const ValueT insideBackground = Union ? -this->background() : this->background();
774 const ValueT outsideBackground = -insideBackground;
776 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
779 const ValueT& value = valueIter.getValue();
782 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
786 std::unordered_map<
Coord, uint8_t> tiles;
788 if (root.getTableSize() > 0) {
789 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
790 const Coord& key = valueIter.getCoord();
791 tiles.insert({key, getTileFlag(valueIter)});
798 const auto* mergeRoot = mergeTree.rootPtr();
799 if (!mergeRoot)
continue;
800 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
801 const Coord& key = valueIter.getCoord();
802 auto it = tiles.find(key);
803 if (it == tiles.end()) {
805 tiles.insert({key, getTileFlag(valueIter)});
808 const uint8_t flag = it->second;
809 if (flag & OUTSIDE_STATE) {
810 const uint8_t newFlag = getTileFlag(valueIter);
811 if (newFlag & INSIDE_STATE) {
812 it->second = newFlag;
821 for (
auto it : tiles) {
822 const uint8_t flag = it.second;
823 if (flag & INSIDE_STATE) {
824 const Coord& key = it.first;
825 const bool state = flag & ACTIVE_TILE;
827 if (Union || keyExistsInRoot(key)) {
828 root.addTile(key, insideBackground, state);
833 std::unordered_set<Coord> children;
835 if (root.getTableSize() > 0) {
836 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
837 const Coord& key = childIter.getCoord();
838 children.insert(key);
842 bool continueRecurse =
false;
848 const auto* mergeRoot = mergeTree.rootPtr();
849 if (!mergeRoot)
continue;
850 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
851 const Coord& key = childIter.getCoord();
854 if (Intersect && !keyExistsInRoot(key))
continue;
857 if (children.count(key)) {
858 continueRecurse =
true;
863 auto it = tiles.find(key);
864 if (it != tiles.end() && it->second == INSIDE_STATE)
continue;
866 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
867 childPtr->resetBackground(mergeRoot->background(), root.background());
868 if (childPtr) root.addChild(childPtr.release());
870 children.insert(key);
876 for (
auto it : tiles) {
877 const uint8_t flag = it.second;
878 if (flag & OUTSIDE_STATE) {
879 const Coord& key = it.first;
880 if (!children.count(key)) {
881 const bool state = flag & ACTIVE_TILE;
883 if (Union || keyExistsInRoot(key)) {
884 root.addTile(key, outsideBackground, state);
891 root.eraseBackgroundTiles();
893 return continueRecurse;
896template<
typename TreeT,
bool Union>
897template<
typename NodeT>
900 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
902 if (this->
empty())
return false;
904 const ValueT insideBackground = Union ? -this->background() : this->background();
905 const ValueT outsideBackground = -insideBackground;
907 using NodeMaskT =
typename NodeT::NodeMaskType;
911 NodeMaskT invalidTile;
913 auto isValid = [](
const ValueT& value)
918 auto isInvalid = [](
const ValueT& value)
923 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
924 if (isValid(iter.getValue())) {
925 validTile.setOn(iter.pos());
926 }
else if (isInvalid(iter.getValue())) {
927 invalidTile.setOn(iter.pos());
931 bool continueRecurse =
false;
935 auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
937 if (!mergeNode)
continue;
941 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
942 Index pos = iter.pos();
944 if (validTile.isOn(pos))
continue;
946 if (isValid(iter.getValue())) {
947 node.addTile(pos, insideBackground, iter.isValueOn());
948 validTile.setOn(pos);
954 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
955 Index pos = iter.pos();
956 const Coord& ijk = iter.getCoord();
958 if (validTile.isOn(pos)) {
959 mergeTree.template addTile<NonConstNodeT>(ijk, outsideBackground,
false);
960 }
else if (invalidTile.isOn(pos)) {
961 auto childPtr = mergeTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
963 childPtr->resetBackground(mergeTree.rootPtr()->background(), this->background());
964 node.addChild(childPtr.release());
966 invalidTile.setOff(pos);
970 continueRecurse =
true;
975 return continueRecurse;
978template <
typename TreeT,
bool Union>
981 using LeafT =
typename TreeT::LeafNodeType;
982 using ValueT =
typename LeafT::ValueType;
983 using BufferT =
typename LeafT::Buffer;
985 if (this->
empty())
return false;
987 const ValueT background = Union ? this->background() : -this->background();
992 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
993 leaf.buffer(), background);
996 const LeafT* mergeLeaf = mergeTree.template probeConstNode<LeafT>(leaf.origin());
997 if (!mergeLeaf)
continue;
1000 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1001 mergeLeaf->buffer())) {
1005 if (mPruneCancelledTiles) {
1006 bool allnegequal =
true;
1007 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1008 const ValueT& newValue = mergeLeaf->getValue(i);
1009 const ValueT& oldValue = leaf.getValue(i);
1011 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1013 leaf.setValueOnly(i, newValue);
1014 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1021 if (Union) { leaf.fill(
math::negative(this->background()),
false); }
1022 else { leaf.fill(this->background(),
false); }
1026 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1027 const ValueT& newValue = mergeLeaf->getValue(i);
1028 const ValueT& oldValue = leaf.getValue(i);
1029 const bool doMerge = Union ? newValue < oldValue : newValue > oldValue;
1031 leaf.setValueOnly(i, newValue);
1032 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1041template <
typename TreeT,
bool Union>
1043CsgUnionOrIntersectionOp<TreeT, Union>::background()
const
1047 return *mBackground;
1054template <
typename TreeT>
1058 if (!mBackground) mBackground = &root.background();
1059 if (!mOtherBackground) mOtherBackground = &mTree.rootPtr()->background();
1064 constexpr uint8_t ACTIVE_TILE = 0x1;
1065 constexpr uint8_t INSIDE_TILE = 0x2;
1066 constexpr uint8_t CHILD = 0x4;
1068 auto getTileFlag = [&](
auto& valueIter) -> uint8_t
1071 const ValueT& value = valueIter.getValue();
1073 if (valueIter.isValueOn()) flag |= ACTIVE_TILE;
1078 root.eraseBackgroundTiles();
1080 std::unordered_map<
Coord, uint8_t> flags;
1082 if (root.getTableSize() > 0) {
1083 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1084 const Coord& key = valueIter.getCoord();
1085 const uint8_t flag = getTileFlag(valueIter);
1086 if (flag & INSIDE_TILE) {
1087 flags.insert({key, getTileFlag(valueIter)});
1091 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1092 const Coord& key = childIter.getCoord();
1093 flags.insert({key, CHILD});
1097 bool continueRecurse =
false;
1099 const auto* mergeRoot = mTree.rootPtr();
1102 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1103 const Coord& key = valueIter.getCoord();
1104 const uint8_t flag = getTileFlag(valueIter);
1105 if (flag & INSIDE_TILE) {
1106 auto it = flags.find(key);
1107 if (it != flags.end()) {
1108 const bool state = flag & ACTIVE_TILE;
1109 root.addTile(key, this->background(), state);
1114 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1115 const Coord& key = childIter.getCoord();
1116 auto it = flags.find(key);
1117 if (it != flags.end()) {
1118 const uint8_t otherFlag = it->second;
1119 if (otherFlag & CHILD) {
1121 continueRecurse =
true;
1122 }
else if (otherFlag & INSIDE_TILE) {
1123 auto childPtr = mTree.template stealOrDeepCopyNode<typename RootT::ChildNodeType>(key);
1125 childPtr->resetBackground(this->otherBackground(), this->background());
1127 root.addChild(childPtr.release());
1135 root.eraseBackgroundTiles();
1137 return continueRecurse;
1140template<
typename TreeT>
1141template<
typename NodeT>
1144 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
1146 using NodeMaskT =
typename NodeT::NodeMaskType;
1150 NodeMaskT insideTile;
1151 for (
auto iter = node.cbeginValueAll(); iter; ++iter) {
1153 insideTile.setOn(iter.pos());
1157 bool continueRecurse =
false;
1159 auto* mergeNode = mTree.template probeConstNode<NonConstNodeT>(node.origin());
1161 if (!mergeNode)
return continueRecurse;
1165 for (
auto iter = mergeNode->cbeginValueAll(); iter; ++iter) {
1166 Index pos = iter.pos();
1168 if (insideTile.isOn(pos) || node.isChildMaskOn(pos)) {
1169 node.addTile(pos, this->background(), iter.isValueOn());
1176 for (
auto iter = mergeNode->cbeginChildOn(); iter; ++iter) {
1177 Index pos = iter.pos();
1178 const Coord& ijk = iter.getCoord();
1179 if (insideTile.isOn(pos)) {
1180 auto childPtr = mTree.template stealOrDeepCopyNode<typename NodeT::ChildNodeType>(ijk);
1182 childPtr->resetBackground(this->otherBackground(), this->background());
1184 node.addChild(childPtr.release());
1186 }
else if (node.isChildMaskOn(pos)) {
1189 continueRecurse =
true;
1193 return continueRecurse;
1196template <
typename TreeT>
1199 using LeafT =
typename TreeT::LeafNodeType;
1200 using ValueT =
typename LeafT::ValueType;
1201 using BufferT =
typename LeafT::Buffer;
1206 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1207 leaf.buffer(), this->background());
1209 const LeafT* mergeLeaf = mTree.template probeConstNode<LeafT>(leaf.origin());
1210 if (!mergeLeaf)
return false;
1215 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1216 mergeLeaf->buffer())) {
1220 if (mPruneCancelledTiles) {
1221 bool allequal =
true;
1222 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1223 const ValueT& aValue = leaf.getValue(i);
1224 ValueT bValue = mergeLeaf->getValue(i);
1225 allequal &= aValue == bValue;
1227 if (aValue < bValue) {
1228 leaf.setValueOnly(i, bValue);
1229 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1236 leaf.fill(background(),
false);
1239 for (
Index i = 0 ; i < LeafT::SIZE; i++) {
1240 const ValueT& aValue = leaf.getValue(i);
1241 ValueT bValue = mergeLeaf->getValue(i);
1243 if (aValue < bValue) {
1244 leaf.setValueOnly(i, bValue);
1245 leaf.setActiveState(i, mergeLeaf->isValueOn(i));
1253template <
typename TreeT>
1255CsgDifferenceOp<TreeT>::background()
const
1259 return *mBackground;
1262template <
typename TreeT>
1263const typename CsgDifferenceOp<TreeT>::ValueT&
1264CsgDifferenceOp<TreeT>::otherBackground()
const
1268 return *mOtherBackground;
1275template <
typename TreeT>
1278 using ValueT =
typename RootT::ValueType;
1279 using ChildT =
typename RootT::ChildNodeType;
1280 using NonConstChildT =
typename std::remove_const<ChildT>::type;
1282 if (this->
empty())
return false;
1285 if (!mBackground) mBackground = &root.background();
1288 auto keyExistsInRoot = [](
const auto& rootToTest,
const Coord& key) ->
bool
1290 return rootToTest.getValueDepth(key) > -1;
1293 constexpr uint8_t TILE = 0x1;
1294 constexpr uint8_t CHILD = 0x2;
1295 constexpr uint8_t TARGET_CHILD = 0x4;
1297 std::unordered_map<
Coord, uint8_t> children;
1301 if (root.getTableSize() > 0) {
1302 for (
auto valueIter = root.cbeginValueAll(); valueIter; ++valueIter) {
1303 const Coord& key = valueIter.getCoord();
1304 children.insert({key, TILE});
1307 for (
auto childIter = root.cbeginChildOn(); childIter; ++childIter) {
1308 const Coord& key = childIter.getCoord();
1309 children.insert({key, CHILD | TARGET_CHILD});
1316 const auto* mergeRoot = mergeTree.rootPtr();
1317 if (!mergeRoot)
continue;
1319 for (
auto valueIter = mergeRoot->cbeginValueAll(); valueIter; ++valueIter) {
1320 const Coord& key = valueIter.getCoord();
1321 auto it = children.find(key);
1322 if (it == children.end()) {
1324 children.insert({key, TILE});
1331 for (
auto childIter = mergeRoot->cbeginChildOn(); childIter; ++childIter) {
1332 const Coord& key = childIter.getCoord();
1333 auto it = children.find(key);
1334 if (it == children.end()) {
1336 children.insert({key, CHILD});
1339 it->second |= CHILD;
1346 for (
const auto& it : children) {
1347 if (!keyExistsInRoot(root, it.first)) {
1348 root.addTile(it.first, root.background(),
false);
1354 for (
const auto& it : children) {
1356 const Coord& key = it.first;
1360 if (it.second & TARGET_CHILD)
continue;
1363 const bool active = root.probeValue(key, value);
1366 const auto* mergeRoot = mergeTree.rootPtr();
1367 if (!mergeRoot)
continue;
1373 const auto* mergeNode = mergeRoot->template probeConstNode<ChildT>(key);
1375 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(key);
1378 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(value, active);
1379 applyOp.run(*childPtr);
1380 root.addChild(childPtr.release());
1386 const bool mergeActive = mergeRoot->probeValue(key, mergeValue);
1388 if (active || mergeActive) {
1389 value += mergeValue;
1390 root.addTile(key, value,
true);
1392 value += mergeValue;
1393 root.addTile(key, value,
false);
1397 mergeTree.template addTile<NonConstChildT>(key,
zeroVal<ValueT>(),
false);
1403 ValueT background = root.background();
1406 const auto* mergeRoot = mergeTree.rootPtr();
1407 if (!mergeRoot)
continue;
1408 background += mergeRoot->background();
1411 root.setBackground(background,
false);
1416template<
typename TreeT>
1417template<
typename NodeT>
1420 using ChildT =
typename NodeT::ChildNodeType;
1421 using NonConstNodeT =
typename std::remove_const<NodeT>::type;
1423 if (this->
empty())
return false;
1426 const auto* mergeRoot = mergeTree.rootPtr();
1427 if (!mergeRoot)
continue;
1429 const auto* mergeNode = mergeTree.template probeConstNode<NonConstNodeT>(node.origin());
1433 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1434 if (mergeNode->isChildMaskOn(iter.pos())) {
1436 auto childPtr = mergeTree.template stealOrDeepCopyNode<ChildT>(iter.getCoord());
1439 merge_internal::ApplyTileSumToNodeOp<TreeT> applyOp(*iter, iter.isValueOn());
1440 applyOp.run(*childPtr);
1441 node.addChild(childPtr.release());
1445 const bool mergeActive = mergeNode->probeValue(iter.getCoord(), mergeValue);
1446 iter.setValue(*iter + mergeValue);
1447 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1454 if (mergeTree.hasMask()) {
1457 const ChildT* originalMergeNode = mergeRoot->template probeConstNode<ChildT>(node.origin());
1458 if (originalMergeNode)
continue;
1462 const bool mergeActive = mergeRoot->probeValue(node.origin(), mergeValue);
1463 for (
auto iter = node.beginValueAll(); iter; ++iter) {
1464 iter.setValue(*iter + mergeValue);
1465 if (mergeActive && !iter.isValueOn()) iter.setValueOn();
1473template <
typename TreeT>
1476 using RootT =
typename TreeT::RootNodeType;
1477 using RootChildT =
typename RootT::ChildNodeType;
1478 using NonConstRootChildT =
typename std::remove_const<RootChildT>::type;
1479 using LeafT =
typename TreeT::LeafNodeType;
1480 using ValueT =
typename LeafT::ValueType;
1481 using BufferT =
typename LeafT::Buffer;
1482 using NonConstLeafT =
typename std::remove_const<LeafT>::type;
1484 if (this->
empty())
return false;
1486 const Coord& ijk = leaf.origin();
1491 merge_internal::UnallocatedBuffer<BufferT, ValueT>::allocateAndFill(
1492 leaf.buffer(), this->background());
1494 auto* data = leaf.buffer().data();
1497 const RootT* mergeRoot = mergeTree.rootPtr();
1498 if (!mergeRoot)
continue;
1500 const LeafT* mergeLeaf = mergeTree.template probeConstNode<NonConstLeafT>(ijk);
1507 if (merge_internal::UnallocatedBuffer<BufferT, ValueT>::isPartiallyConstructed(
1508 mergeLeaf->buffer())) {
1512 for (
Index i = 0; i < LeafT::SIZE; ++i) {
1513 data[i] += mergeLeaf->getValue(i);
1516 leaf.getValueMask() |= mergeLeaf->getValueMask();
1520 if (mergeTree.hasMask()) {
1523 const LeafT* originalMergeLeaf = mergeRoot->template probeConstNode<NonConstLeafT>(ijk);
1524 if (originalMergeLeaf)
continue;
1527 const RootChildT* mergeRootChild = mergeRoot->template probeConstNode<NonConstRootChildT>(ijk);
1530 bool mergeActive = mergeRootChild ?
1531 mergeRootChild->probeValue(ijk, mergeValue) : mergeRoot->probeValue(ijk, mergeValue);
1534 for (
Index i = 0; i < LeafT::SIZE; ++i) {
1535 data[i] += mergeValue;
1539 if (mergeActive) leaf.setValuesOn();
1546template <
typename TreeT>
1548SumMergeOp<TreeT>::background()
const
1552 return *mBackground;
1560#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1562#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:685
Definition Exceptions.h:63
Tag dispatch class that distinguishes constructors that steal.
Definition Types.h:687
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:128
Definition PointDataGrid.h:170
Index32 Index
Definition Types.h:54
OPENVDB_IMPORT 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:70
uint32_t Index32
Definition Types.h:52
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:159
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218