10 #ifndef OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED 11 #define OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED 24 #include <unordered_map> 25 #include <unordered_set> 47 template <
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)
72 if (mTree &&
initialize) this->initializeMask();
86 void reset(
typename TreeType::Ptr treePtr,
Steal);
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;
145 template <
typename TreeT>
148 std::unique_ptr<MaskTreeType>
ptr;
158 if (
bool(other.
ptr)) ptr = std::make_unique<MaskTreeType>(*other.
ptr);
166 template <
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;
192 template<
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(); }
246 bool operator()(
RootT& root,
size_t idx)
const;
249 template<
typename NodeT>
250 bool operator()(NodeT& node,
size_t idx)
const;
253 bool operator()(
LeafT& leaf,
size_t idx)
const;
258 const ValueT& background()
const;
260 mutable std::vector<TreeToMerge<TreeT>> mTreesToMerge;
261 mutable const ValueT* mBackground =
nullptr;
262 bool mPruneCancelledTiles =
false;
266 template <
typename TreeT>
269 template <
typename TreeT>
279 template<
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;
334 template<
typename TreeT>
337 using ValueT =
typename TreeT::ValueType;
338 using RootT =
typename TreeT::RootNodeType;
339 using LeafT =
typename TreeT::LeafNodeType;
343 template <
typename TagT>
344 SumMergeOp(TreeT& tree, TagT tag) { mTreesToMerge.emplace_back(tree, tag); }
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;
404 template<
typename TreeT>
411 manager.foreachTopDown(op);
414 template<
typename TreeT>
417 return bool(mMaskTree.ptr);
420 template<
typename TreeT>
428 mTree = mTreePtr.get();
431 template<
typename TreeT>
435 return &mTree->root();
438 template<
typename TreeT>
439 template<
typename NodeT>
444 if (!mSteal && !this->mask()->isValueOn(ijk))
return nullptr;
445 return mTree->template probeConstNode<NodeT>(ijk);
448 template<
typename TreeT>
454 this->mask()->addTile(level, ijk,
false,
false);
458 template<
typename TreeT>
459 template<
typename NodeT>
460 std::unique_ptr<NodeT>
465 return std::unique_ptr<NodeT>(
466 tree->root().template stealNode<NodeT>(ijk, value,
false)
469 auto* child = this->probeConstNode<NodeT>(ijk);
471 auto result = std::make_unique<NodeT>(*child);
472 this->pruneMask(NodeT::LEVEL+1, ijk);
476 return std::unique_ptr<NodeT>();
479 template<
typename TreeT>
480 template<
typename NodeT>
481 std::unique_ptr<NodeT>
484 return this->stealOrDeepCopyNode<NodeT>(ijk, mTree->root().background());
487 template<
typename TreeT>
488 template<
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);
503 auto* node = mTree->template probeConstNode<NodeT>(ijk);
504 if (node) this->pruneMask(NodeT::LEVEL, ijk);
512 template <
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());
545 template <
typename TreeT>
546 template <
typename NodeT>
549 using ChildT =
typename NodeT::ChildNodeType;
551 const auto* otherNode = mTree.template probeConstNode<NodeT>(node.origin());
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);
575 namespace merge_internal {
578 template <
typename BufferT,
typename ValueT>
579 struct 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();
597 template <
typename BufferT>
598 struct UnallocatedBuffer<BufferT, bool>
601 static void allocateAndFill(BufferT&,
const bool&) { }
602 static bool isPartiallyConstructed(
const BufferT&) {
return false; }
608 template <Index LEVEL>
611 template <
typename NodeT,
typename OpT>
612 static void run(NodeT& node, OpT&
op)
614 using NonConstChildT =
typename NodeT::ChildNodeType;
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++) {
649 template <
typename NodeT,
typename OpT>
650 static void run(NodeT& node, OpT&
op)
659 template <
typename TreeT>
660 struct 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)
714 template <
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();
780 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
781 else if (value > zeroVal<ValueT>()) flag |= OUTSIDE_TILE;
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;
896 template<
typename TreeT,
bool Union>
897 template<
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;
915 return Union ? value < zeroVal<ValueT>() : value > zeroVal<ValueT>();
918 auto isInvalid = [](
const ValueT& value)
920 return Union ? value > zeroVal<ValueT>() : value < zeroVal<ValueT>();
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;
978 template <
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));
1041 template <
typename TreeT,
bool Union>
1047 return *mBackground;
1054 template <
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();
1072 if (value < zeroVal<ValueT>()) flag |= INSIDE_TILE;
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;
1140 template<
typename TreeT>
1141 template<
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) {
1152 if (iter.getValue() < zeroVal<ValueT>()) {
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();
1167 if (iter.getValue() < zeroVal<ValueT>()) {
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;
1196 template <
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));
1253 template <
typename TreeT>
1259 return *mBackground;
1262 template <
typename TreeT>
1268 return *mOtherBackground;
1275 template <
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);
1416 template<
typename TreeT>
1417 template<
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();
1473 template <
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);
1533 if (mergeValue != zeroVal<ValueT>()) {
1534 for (
Index i = 0; i < LeafT::SIZE; ++i) {
1535 data[i] += mergeValue;
1539 if (mergeActive) leaf.setValuesOn();
1546 template <
typename TreeT>
1552 return *mBackground;
1560 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 1562 #ifdef OPENVDB_INSTANTIATE_MERGE 1595 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION 1602 #endif // OPENVDB_TOOLS_MERGE_HAS_BEEN_INCLUDED
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
#define OPENVDB_INSTANTIATE_STRUCT
Definition: version.h.in:159
__hostdev__ bool isValid(GridType gridType, GridClass gridClass)
return true if the combination of GridType and GridClass is valid.
Definition: NanoVDB.h:613
Definition: NodeManager.h:37
Implementation of a depth-first node visitor.
Tag dispatch class that distinguishes constructors that deep copy.
Definition: Types.h:685
typename std::remove_const< ToType >::type Type
Definition: Types.h:439
Index32 Index
Definition: Types.h:54
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
OPENVDB_IMPORT void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:687
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is '\0'
Definition: Util.h:144
Definition: Exceptions.h:13
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.
uint32_t Index32
Definition: Types.h:52
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_USE_VERSION_NAMESPACE
Definition: version.h.in:218
Definition: Exceptions.h:63