OpenVDB 14.0.0
Loading...
Searching...
No Matches
RootNode.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3///
4/// @file RootNode.h
5///
6/// @brief The root node of an OpenVDB tree
7
8#ifndef OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
9#define OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
10
11#include <openvdb/Exceptions.h>
12#include <openvdb/Types.h>
13#include <openvdb/io/Compression.h> // for truncateRealToHalf()
14#include <openvdb/math/Math.h> // for isZero(), isExactlyEqual(), etc.
15#include <openvdb/math/BBox.h>
16#include <openvdb/util/Assert.h>
17#include <openvdb/version.h>
18#include <tbb/parallel_for.h>
19#include <map>
20#include <set>
21#include <sstream>
22#include <vector>
23
24
25namespace openvdb {
27namespace OPENVDB_VERSION_NAME {
28namespace tree {
29
30// Forward declarations
31template<typename HeadType, int HeadLevel> struct NodeChain;
32template<typename, typename> struct SameRootConfig;
33template<typename, typename, bool> struct RootNodeCopyHelper;
34template<typename, typename, typename, bool> struct RootNodeCombineHelper;
35
36
37template<typename ChildType>
39{
40public:
41 using ChildNodeType = ChildType;
42 using LeafNodeType = typename ChildType::LeafNodeType;
43 using ValueType = typename ChildType::ValueType;
44 using BuildType = typename ChildType::BuildType;
45
46 static const Index LEVEL = 1 + ChildType::LEVEL; // level 0 = leaf
47
48 /// NodeChainType is a list of this tree's node types, from LeafNodeType to RootNode.
50 static_assert(NodeChainType::Size == LEVEL + 1,
51 "wrong number of entries in RootNode node chain");
52
53 /// @brief ValueConverter<T>::Type is the type of a RootNode having the same
54 /// child hierarchy as this node but a different value type, T.
55 template<typename OtherValueType>
59
60 /// @brief SameConfiguration<OtherNodeType>::value is @c true if and only if
61 /// OtherNodeType is the type of a RootNode whose ChildNodeType has the same
62 /// configuration as this node's ChildNodeType.
63 template<typename OtherNodeType>
67
68
69 /// Construct a new tree with a background value of 0.
71
72 /// Construct a new tree with the given background value.
73 explicit RootNode(const ValueType& background);
74
75 RootNode(const RootNode& other) { *this = other; }
76
77 /// @brief Construct a new tree that reproduces the topology and active states
78 /// of a tree of a different ValueType but the same configuration (levels,
79 /// node dimensions and branching factors). Cast the other tree's values to
80 /// this tree's ValueType.
81 /// @throw TypeError if the other tree's configuration doesn't match this tree's
82 /// or if this tree's ValueType is not constructible from the other tree's ValueType.
83 template<typename OtherChildType>
84 explicit RootNode(const RootNode<OtherChildType>& other) { *this = other; }
85
86 /// @brief Construct a new tree that reproduces the topology and active states of
87 /// another tree (which may have a different ValueType), but not the other tree's values.
88 /// @details All tiles and voxels that are active in the other tree are set to
89 /// @a foreground in the new tree, and all inactive tiles and voxels are set to @a background.
90 /// @param other the root node of a tree having (possibly) a different ValueType
91 /// @param background the value to which inactive tiles and voxels are initialized
92 /// @param foreground the value to which active tiles and voxels are initialized
93 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
94 template<typename OtherChildType>
96 const ValueType& background, const ValueType& foreground, TopologyCopy);
97
98 /// @brief Construct a new tree that reproduces the topology and active states of
99 /// another tree (which may have a different ValueType), but not the other tree's values.
100 /// All tiles and voxels in the new tree are set to @a background regardless of
101 /// their active states in the other tree.
102 /// @param other the root node of a tree having (possibly) a different ValueType
103 /// @param background the value to which inactive tiles and voxels are initialized
104 /// @note This copy constructor is generally faster than the one that takes both
105 /// a foreground and a background value. Its main application is in multithreaded
106 /// operations where the topology of the output tree exactly matches the input tree.
107 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
108 template<typename OtherChildType>
110
111 /// @brief Copy a root node of the same type as this node.
113 /// @brief Copy a root node of the same tree configuration as this node
114 /// but a different ValueType.
115 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
116 /// @note This node's ValueType must be constructible from the other node's ValueType.
117 /// For example, a root node with values of type float can be assigned to a root node
118 /// with values of type Vec3s, because a Vec3s can be constructed from a float.
119 /// But a Vec3s root node cannot be assigned to a float root node.
120 template<typename OtherChildType>
122
123 ~RootNode() { this->clear(); }
124
125private:
126 struct Tile {
127 Tile(): value(zeroVal<ValueType>()), active(false) {}
128 Tile(const ValueType& v, bool b): value(v), active(b) {}
129 ValueType value;
130 bool active;
131 };
132
133 // This lightweight struct pairs child pointers and tiles.
134 struct NodeStruct {
135 ChildType* child;
136 Tile tile;
137
138 NodeStruct(): child(nullptr) {}
139 NodeStruct(ChildType& c): child(&c) {}
140 NodeStruct(const Tile& t): child(nullptr), tile(t) {}
141 NodeStruct(const NodeStruct&) = default;
142 NodeStruct(NodeStruct&&) noexcept = default;
143 NodeStruct& operator=(const NodeStruct&) = default;
144 ~NodeStruct() {} ///< @note doesn't delete child
145
146 bool isChild() const { return child != nullptr; }
147 bool isTile() const { return child == nullptr; }
148 bool isTileOff() const { return isTile() && !tile.active; }
149 bool isTileOn() const { return isTile() && tile.active; }
150
151 void set(ChildType& c) { delete child; child = &c; }
152 void set(const Tile& t) { delete child; child = nullptr; tile = t; }
153 ChildType& steal(const Tile& t) { ChildType* c=child; child=nullptr; tile=t; return *c; }
154 };
155
156 using MapType = std::map<Coord, NodeStruct>;
157 using MapIter = typename MapType::iterator;
158 using MapCIter = typename MapType::const_iterator;
159
160 using CoordSet = std::set<Coord>;
161 using CoordSetIter = typename CoordSet::iterator;
162 using CoordSetCIter = typename CoordSet::const_iterator;
163
164 static void setTile(const MapIter& i, const Tile& t) { i->second.set(t); }
165 static void setChild(const MapIter& i, ChildType& c) { i->second.set(c); }
166 static Tile& getTile(const MapIter& i) { return i->second.tile; }
167 static const Tile& getTile(const MapCIter& i) { return i->second.tile; }
168 static ChildType& getChild(const MapIter& i) { return *(i->second.child); }
169 static const ChildType& getChild(const MapCIter& i) { return *(i->second.child); }
170 static ChildType& stealChild(const MapIter& i, const Tile& t) {return i->second.steal(t);}
171 static const ChildType& stealChild(const MapCIter& i,const Tile& t) {return i->second.steal(t);}
172
173 static bool isChild(const MapCIter& i) { return i->second.isChild(); }
174 static bool isChild(const MapIter& i) { return i->second.isChild(); }
175 static bool isTile(const MapCIter& i) { return i->second.isTile(); }
176 static bool isTile(const MapIter& i) { return i->second.isTile(); }
177 static bool isTileOff(const MapCIter& i) { return i->second.isTileOff(); }
178 static bool isTileOff(const MapIter& i) { return i->second.isTileOff(); }
179 static bool isTileOn(const MapCIter& i) { return i->second.isTileOn(); }
180 static bool isTileOn(const MapIter& i) { return i->second.isTileOn(); }
181
182 struct NullPred {
183 static inline bool test(const MapIter&) { return true; }
184 static inline bool test(const MapCIter&) { return true; }
185 };
186 struct ValueOnPred {
187 static inline bool test(const MapIter& i) { return isTileOn(i); }
188 static inline bool test(const MapCIter& i) { return isTileOn(i); }
189 };
190 struct ValueOffPred {
191 static inline bool test(const MapIter& i) { return isTileOff(i); }
192 static inline bool test(const MapCIter& i) { return isTileOff(i); }
193 };
194 struct ValueAllPred {
195 static inline bool test(const MapIter& i) { return isTile(i); }
196 static inline bool test(const MapCIter& i) { return isTile(i); }
197 };
198 struct ChildOnPred {
199 static inline bool test(const MapIter& i) { return isChild(i); }
200 static inline bool test(const MapCIter& i) { return isChild(i); }
201 };
202 struct ChildOffPred {
203 static inline bool test(const MapIter& i) { return isTile(i); }
204 static inline bool test(const MapCIter& i) { return isTile(i); }
205 };
206
207 template<typename _RootNodeT, typename _MapIterT, typename FilterPredT>
208 class BaseIter
209 {
210 public:
211 using RootNodeT = _RootNodeT;
212 using MapIterT = _MapIterT; // either MapIter or MapCIter
213
214 bool operator==(const BaseIter& other) const
215 {
216 return (mParentNode == other.mParentNode) && (mIter == other.mIter);
217 }
218 bool operator!=(const BaseIter& other) const { return !(*this == other); }
219
220 RootNodeT* getParentNode() const { return mParentNode; }
221 /// Return a reference to the node over which this iterator iterates.
222 RootNodeT& parent() const
223 {
224 if (!mParentNode) OPENVDB_THROW(ValueError, "iterator references a null parent node");
225 return *mParentNode;
226 }
227
228 bool test() const { OPENVDB_ASSERT(mParentNode); return mIter != mParentNode->mTable.end(); }
229 operator bool() const { return this->test(); }
230
231 void increment() { if (this->test()) { ++mIter; } this->skip(); }
232 bool next() { this->increment(); return this->test(); }
233 void increment(Index n) { for (Index i = 0; i < n && this->next(); ++i) {} }
234
235 /// @brief Return this iterator's position as an offset from
236 /// the beginning of the parent node's map.
237 Index pos() const
238 {
239 return !mParentNode ? 0U : Index(std::distance(mParentNode->mTable.begin(), mIter));
240 }
241
242 bool isValueOn() const { return RootNodeT::isTileOn(mIter); }
243 bool isValueOff() const { return RootNodeT::isTileOff(mIter); }
244 void setValueOn(bool on = true) const { mIter->second.tile.active = on; }
245 void setValueOff() const { mIter->second.tile.active = false; }
246
247 /// Return the coordinates of the item to which this iterator is pointing.
248 Coord getCoord() const { return mIter->first; }
249 /// Return in @a xyz the coordinates of the item to which this iterator is pointing.
250 void getCoord(Coord& xyz) const { xyz = this->getCoord(); }
251
252 protected:
253 BaseIter(): mParentNode(nullptr) {}
254 BaseIter(RootNodeT& parent, const MapIterT& iter): mParentNode(&parent), mIter(iter) {}
255
256 void skip() { while (this->test() && !FilterPredT::test(mIter)) ++mIter; }
257
258 RootNodeT* mParentNode;
259 MapIterT mIter;
260 }; // BaseIter
261
262 template<typename RootNodeT, typename MapIterT, typename FilterPredT, typename ChildNodeT>
263 class ChildIter: public BaseIter<RootNodeT, MapIterT, FilterPredT>
264 {
265 public:
266 using BaseT = BaseIter<RootNodeT, MapIterT, FilterPredT>;
267 using NodeType = RootNodeT;
268 using ValueType = NodeType;
269 using ChildNodeType = ChildNodeT;
270 using NonConstNodeType = typename std::remove_const<NodeType>::type;
271 using NonConstValueType = typename std::remove_const<ValueType>::type;
272 using NonConstChildNodeType = typename std::remove_const<ChildNodeType>::type;
273 using BaseT::mIter;
274
275 ChildIter() {}
276 ChildIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); }
277
278 ChildIter& operator++() { BaseT::increment(); return *this; }
279
280 ChildNodeT& getValue() const { return getChild(mIter); }
281 ChildNodeT& operator*() const { return this->getValue(); }
282 ChildNodeT* operator->() const { return &this->getValue(); }
283 }; // ChildIter
284
285 template<typename RootNodeT, typename MapIterT, typename FilterPredT, typename ValueT>
286 class ValueIter: public BaseIter<RootNodeT, MapIterT, FilterPredT>
287 {
288 public:
289 using BaseT = BaseIter<RootNodeT, MapIterT, FilterPredT>;
290 using NodeType = RootNodeT;
291 using ValueType = ValueT;
292 using NonConstNodeType = typename std::remove_const<NodeType>::type;
293 using NonConstValueType = typename std::remove_const<ValueT>::type;
294 using BaseT::mIter;
295
296 ValueIter() {}
297 ValueIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); }
298
299 ValueIter& operator++() { BaseT::increment(); return *this; }
300
301 ValueT& getValue() const { return getTile(mIter).value; }
302 ValueT& operator*() const { return this->getValue(); }
303 ValueT* operator->() const { return &(this->getValue()); }
304
305 void setValue(const ValueT& v) const { OPENVDB_ASSERT(isTile(mIter)); getTile(mIter).value = v; }
306
307 template<typename ModifyOp>
308 void modifyValue(const ModifyOp& op) const
309 {
310 OPENVDB_ASSERT(isTile(mIter));
311 op(getTile(mIter).value);
312 }
313 }; // ValueIter
314
315 template<typename RootNodeT, typename MapIterT, typename ChildNodeT, typename ValueT>
316 class DenseIter: public BaseIter<RootNodeT, MapIterT, NullPred>
317 {
318 public:
319 using BaseT = BaseIter<RootNodeT, MapIterT, NullPred>;
320 using NodeType = RootNodeT;
321 using ValueType = ValueT;
322 using ChildNodeType = ChildNodeT;
323 using NonConstNodeType = typename std::remove_const<NodeType>::type;
324 using NonConstValueType = typename std::remove_const<ValueT>::type;
325 using NonConstChildNodeType = typename std::remove_const<ChildNodeT>::type;
326 using BaseT::mIter;
327
328 DenseIter() {}
329 DenseIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) {}
330
331 DenseIter& operator++() { BaseT::increment(); return *this; }
332
333 bool isChildNode() const { return isChild(mIter); }
334
335 ChildNodeT* probeChild(NonConstValueType& value) const
336 {
337 if (isChild(mIter)) return &getChild(mIter);
338 value = getTile(mIter).value;
339 return nullptr;
340 }
341 bool probeChild(ChildNodeT*& child, NonConstValueType& value) const
342 {
343 child = this->probeChild(value);
344 return child != nullptr;
345 }
346 bool probeValue(NonConstValueType& value) const { return !this->probeChild(value); }
347
348 void setChild(ChildNodeT& c) const { RootNodeT::setChild(mIter, c); }
349 void setChild(ChildNodeT* c) const { OPENVDB_ASSERT(c != nullptr); RootNodeT::setChild(mIter, *c); }
350 void setValue(const ValueT& v) const
351 {
352 if (isTile(mIter)) getTile(mIter).value = v;
353 /// @internal For consistency with iterators for other node types
354 /// (see, e.g., InternalNode::DenseIter::unsetItem()), we don't call
355 /// setTile() here, because that would also delete the child.
356 else stealChild(mIter, Tile(v, /*active=*/true));
357 }
358 }; // DenseIter
359
360public:
361 using ChildOnIter = ChildIter<RootNode, MapIter, ChildOnPred, ChildType>;
362 using ChildOnCIter = ChildIter<const RootNode, MapCIter, ChildOnPred, const ChildType>;
363 using ChildOffIter = ValueIter<RootNode, MapIter, ChildOffPred, const ValueType>;
364 using ChildOffCIter = ValueIter<const RootNode, MapCIter, ChildOffPred, ValueType>;
365 using ChildAllIter = DenseIter<RootNode, MapIter, ChildType, ValueType>;
366 using ChildAllCIter = DenseIter<const RootNode, MapCIter, const ChildType, const ValueType>;
367
368 using ValueOnIter = ValueIter<RootNode, MapIter, ValueOnPred, ValueType>;
369 using ValueOnCIter = ValueIter<const RootNode, MapCIter, ValueOnPred, const ValueType>;
370 using ValueOffIter = ValueIter<RootNode, MapIter, ValueOffPred, ValueType>;
371 using ValueOffCIter = ValueIter<const RootNode, MapCIter, ValueOffPred, const ValueType>;
372 using ValueAllIter = ValueIter<RootNode, MapIter, ValueAllPred, ValueType>;
373 using ValueAllCIter = ValueIter<const RootNode, MapCIter, ValueAllPred, const ValueType>;
374
375
376 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(*this, mTable.begin()); }
377 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(*this, mTable.begin()); }
378 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(*this, mTable.begin()); }
382 ChildOnIter beginChildOn() { return ChildOnIter(*this, mTable.begin()); }
383 ChildOffIter beginChildOff() { return ChildOffIter(*this, mTable.begin()); }
384 ChildAllIter beginChildAll() { return ChildAllIter(*this, mTable.begin()); }
385
386 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this, mTable.begin()); }
387 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this, mTable.begin()); }
388 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this, mTable.begin()); }
392 ValueOnIter beginValueOn() { return ValueOnIter(*this, mTable.begin()); }
393 ValueOffIter beginValueOff() { return ValueOffIter(*this, mTable.begin()); }
394 ValueAllIter beginValueAll() { return ValueAllIter(*this, mTable.begin()); }
395
396 /// Return the total amount of memory in bytes occupied by this node and its children.
398
399 /// @brief Expand the specified bbox so it includes the active tiles of
400 /// this root node as well as all the active values in its child
401 /// nodes. If visitVoxels is false LeafNodes will be approximated
402 /// as dense, i.e. with all voxels active. Else the individual
403 /// active voxels are visited to produce a tight bbox.
404 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
405
406 /// Return the bounding box of this RootNode, i.e., an infinite bounding box.
408
409 /// Return the transient data value.
410 Index32 transientData() const { return mTransientData; }
411 /// Set the transient data value.
413
414 /// @brief Change inactive tiles or voxels with a value equal to +/- the
415 /// old background to the specified value (with the same sign). Active values
416 /// are unchanged.
417 ///
418 /// @param value The new background value
419 /// @param updateChildNodes If true the background values of the
420 /// child nodes is also updated. Else only the background value
421 /// stored in the RootNode itself is changed.
422 ///
423 /// @note Instead of setting @a updateChildNodes to true, consider
424 /// using tools::changeBackground or
425 /// tools::changeLevelSetBackground which are multi-threaded!
426 void setBackground(const ValueType& value, bool updateChildNodes);
427
428 /// Return this node's background value.
429 const ValueType& background() const { return mBackground; }
430
431 /// Return @c true if the given tile is inactive and has the background value.
432 bool isBackgroundTile(const Tile&) const;
433 //@{
434 /// Return @c true if the given iterator points to an inactive tile with the background value.
435 bool isBackgroundTile(const MapIter&) const;
436 bool isBackgroundTile(const MapCIter&) const;
437 //@}
438
439 /// Return the number of background tiles.
440 size_t numBackgroundTiles() const;
441 /// @brief Remove all background tiles.
442 /// @return the number of tiles removed.
444 inline void clear();
445
446 /// Return @c true if this node's table is either empty or contains only background tiles.
447 bool empty() const { return mTable.size() == numBackgroundTiles(); }
448
449 /// @brief Expand this node's table so that (x, y, z) is included in the index range.
450 /// @return @c true if an expansion was performed (i.e., if (x, y, z) was not already
451 /// included in the index range).
452 bool expand(const Coord& xyz);
453
454 static Index getLevel() { return LEVEL; }
455 static void getNodeLog2Dims(std::vector<Index>& dims);
456 static Index getChildDim() { return ChildType::DIM; }
457
458 /// Return the number of entries in this node's table.
459 Index getTableSize() const { return static_cast<Index>(mTable.size()); }
460
461 Index getWidth() const { return this->getMaxIndex()[0] - this->getMinIndex()[0]; }
462 Index getHeight() const { return this->getMaxIndex()[1] - this->getMinIndex()[1]; }
463 Index getDepth() const { return this->getMaxIndex()[2] - this->getMinIndex()[2]; }
464
465 /// Return the smallest index of the current tree.
467 /// Return the largest index of the current tree.
469 /// Return the current index range. Both min and max are inclusive.
470 void getIndexRange(CoordBBox& bbox) const;
471
472 /// @brief Return @c true if the given tree has the same node and active value
473 /// topology as this tree (but possibly a different @c ValueType).
474 template<typename OtherChildType>
476
477 /// Return @c false if the other node's dimensions don't match this node's.
478 template<typename OtherChildType>
480
481 /// Return @c true if values of the other node's ValueType can be converted
482 /// to values of this node's ValueType.
483 template<typename OtherChildType>
485
497 void nodeCount(std::vector<Index64> &vec) const;
498
499 bool isValueOn(const Coord& xyz) const;
500
501 /// Return @c true if this root node, or any of its child nodes, have active tiles.
502 bool hasActiveTiles() const;
503
504 const ValueType& getValue(const Coord& xyz) const;
505 bool probeValue(const Coord& xyz, ValueType& value) const;
506
507 /// @brief Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
508 /// @details If (x, y, z) isn't explicitly represented in the tree (i.e.,
509 /// it is implicitly a background voxel), return -1.
510 int getValueDepth(const Coord& xyz) const;
511
512 /// Set the active state of the voxel at the given coordinates but don't change its value.
513 void setActiveState(const Coord& xyz, bool on);
514 /// Set the value of the voxel at the given coordinates but don't change its active state.
515 void setValueOnly(const Coord& xyz, const ValueType& value);
516 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
517 void setValueOn(const Coord& xyz, const ValueType& value);
518 /// Mark the voxel at the given coordinates as inactive but don't change its value.
519 void setValueOff(const Coord& xyz);
520 /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
521 void setValueOff(const Coord& xyz, const ValueType& value);
522
523 /// @brief Apply a functor to the value of the voxel at the given coordinates
524 /// and mark the voxel as active.
525 template<typename ModifyOp>
526 void modifyValue(const Coord& xyz, const ModifyOp& op);
527 /// Apply a functor to the voxel at the given coordinates.
528 template<typename ModifyOp>
529 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
530
531 //@{
532 /// @brief Set all voxels within a given axis-aligned box to a constant value.
533 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box
534 /// @param value the value to which to set voxels within the box
535 /// @param active if true, mark voxels within the box as active,
536 /// otherwise mark them as inactive
537 /// @note This operation generates a sparse, but not always optimally sparse,
538 /// representation of the filled box. Follow fill operations with a prune()
539 /// operation for optimal sparseness.
540 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
541 void sparseFill(const CoordBBox& bbox, const ValueType& value, bool active = true)
542 {
543 this->fill(bbox, value, active);
544 }
545 //@}
546
547 /// @brief Set all voxels within a given axis-aligned box to a constant value
548 /// and ensure that those voxels are all represented at the leaf level.
549 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box.
550 /// @param value the value to which to set voxels within the box.
551 /// @param active if true, mark voxels within the box as active,
552 /// otherwise mark them as inactive.
553 /// @sa voxelizeActiveTiles()
554 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
555
556 /// @brief Densify active tiles, i.e., replace them with leaf-level active voxels.
557 ///
558 /// @param threaded if true, this operation is multi-threaded (over the internal nodes).
559 ///
560 /// @warning This method can explode the tree's memory footprint, especially if it
561 /// contains active tiles at the upper levels (in particular the root level)!
562 ///
563 /// @sa denseFill()
564 void voxelizeActiveTiles(bool threaded = true);
565
566 /// @brief Copy into a dense grid the values of all voxels, both active and inactive,
567 /// that intersect a given bounding box.
568 /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
569 /// @param dense dense grid with a stride in @e z of one (see tools::Dense
570 /// in tools/Dense.h for the required API)
571 template<typename DenseT>
572 void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
573
574
575#if OPENVDB_ABI_VERSION_NUMBER < 14
576 //
577 // I/O
578 //
579 bool writeTopology(std::ostream&, bool toHalf = false) const;
580 bool readTopology(std::istream&, bool fromHalf = false);
581
582 void writeBuffers(std::ostream&, bool toHalf = false) const;
583 void readBuffers(std::istream&, bool fromHalf = false);
584 void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false);
585#endif // OPENVDB_ABI_VERSION_NUMBER < 14
586
587
588 //
589 // Voxel access
590 //
591 /// Return the value of the voxel at the given coordinates and, if necessary, update
592 /// the accessor with pointers to the nodes along the path from the root node to
593 /// the node containing the voxel.
594 /// @note Used internally by ValueAccessor.
595 template<typename AccessorT>
596 const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const;
597 /// Return @c true if the voxel at the given coordinates is active and, if necessary,
598 /// update the accessor with pointers to the nodes along the path from the root node
599 /// to the node containing the voxel.
600 /// @note Used internally by ValueAccessor.
601 template<typename AccessorT>
602 bool isValueOnAndCache(const Coord& xyz, AccessorT&) const;
603
604 /// Change the value of the voxel at the given coordinates and mark it as active.
605 /// If necessary, update the accessor with pointers to the nodes along the path
606 /// from the root node to the node containing the voxel.
607 /// @note Used internally by ValueAccessor.
608 template<typename AccessorT>
609 void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
610
611 /// Set the value of the voxel at the given coordinates without changing its active state.
612 /// If necessary, update the accessor with pointers to the nodes along the path
613 /// from the root node to the node containing the voxel.
614 /// @note Used internally by ValueAccessor.
615 template<typename AccessorT>
616 void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
617
618 /// Apply a functor to the value of the voxel at the given coordinates
619 /// and mark the voxel as active.
620 /// If necessary, update the accessor with pointers to the nodes along the path
621 /// from the root node to the node containing the voxel.
622 /// @note Used internally by ValueAccessor.
623 template<typename ModifyOp, typename AccessorT>
624 void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
625
626 /// Apply a functor to the voxel at the given coordinates.
627 /// If necessary, update the accessor with pointers to the nodes along the path
628 /// from the root node to the node containing the voxel.
629 /// @note Used internally by ValueAccessor.
630 template<typename ModifyOp, typename AccessorT>
631 void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
632
633 /// Change the value of the voxel at the given coordinates and mark it as inactive.
634 /// If necessary, update the accessor with pointers to the nodes along the path
635 /// from the root node to the node containing the voxel.
636 /// @note Used internally by ValueAccessor.
637 template<typename AccessorT>
638 void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
639
640 /// Set the active state of the voxel at the given coordinates without changing its value.
641 /// If necessary, update the accessor with pointers to the nodes along the path
642 /// from the root node to the node containing the voxel.
643 /// @note Used internally by ValueAccessor.
644 template<typename AccessorT>
645 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&);
646
647 /// Return, in @a value, the value of the voxel at the given coordinates and,
648 /// if necessary, update the accessor with pointers to the nodes along
649 /// the path from the root node to the node containing the voxel.
650 /// @return @c true if the voxel at the given coordinates is active
651 /// @note Used internally by ValueAccessor.
652 template<typename AccessorT>
653 bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const;
654
655 /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
656 /// If (x, y, z) isn't explicitly represented in the tree (i.e., it is implicitly
657 /// a background voxel), return -1. If necessary, update the accessor with pointers
658 /// to the nodes along the path from the root node to the node containing the voxel.
659 /// @note Used internally by ValueAccessor.
660 template<typename AccessorT>
661 int getValueDepthAndCache(const Coord& xyz, AccessorT&) const;
662
663 /// Set all voxels that lie outside the given axis-aligned box to the background.
664 void clip(const CoordBBox&);
665
666 /// @brief Reduce the memory footprint of this tree by replacing with tiles
667 /// any nodes whose values are all the same (optionally to within a tolerance)
668 /// and have the same active state.
669 ///
670 /// @note Consider instead using tools::prune which is multi-threaded!
671 void prune(const ValueType& tolerance = zeroVal<ValueType>());
672
673 /// @brief Add the given leaf node to this tree, creating a new branch if necessary.
674 /// If a leaf node with the same origin already exists, replace it.
676
677 /// @brief Same as addLeaf() but, if necessary, update the given accessor with pointers
678 /// to the nodes along the path from the root node to the node containing the coordinate.
679 template<typename AccessorT>
680 void addLeafAndCache(LeafNodeType* leaf, AccessorT&);
681
682 /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z)
683 /// and replace it with a tile of the specified value and state.
684 /// If no such node exists, leave the tree unchanged and return @c nullptr.
685 ///
686 /// @note The caller takes ownership of the node and is responsible for deleting it.
687 ///
688 /// @warning Since this method potentially removes nodes and branches of the tree,
689 /// it is important to clear the caches of all ValueAccessors associated with this tree.
690 template<typename NodeT>
691 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state);
692
693 /// @brief Add the given child node at the root level.
694 /// If a child node with the same origin already exists, delete the old node and add
695 /// the new node in its place (i.e. ownership of the new child node is transferred
696 /// to this RootNode).
697 /// @return @c true (for consistency with InternalNode::addChild)
699
700 /// @brief Add a tile containing voxel (x, y, z) at the root level,
701 /// deleting the existing branch if necessary.
702 void addTile(const Coord& xyz, const ValueType& value, bool state);
703
704 /// @brief Add a tile containing voxel (x, y, z) at the specified tree level,
705 /// creating a new branch if necessary. Delete any existing lower-level nodes
706 /// that contain (x, y, z).
707 void addTile(Index level, const Coord& xyz, const ValueType& value, bool state);
708
709 /// @brief Same as addTile() but, if necessary, update the given accessor with pointers
710 /// to the nodes along the path from the root node to the node containing the coordinate.
711 template<typename AccessorT>
712 void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&);
713
714 /// @brief Delete any child or tile containing voxel (x, y, z) at the root level.
715 /// Do nothing if no child or tile was found.
716 /// @warning This method will invalidate any existing RootNode iterators.
717 /// @return @c true if child or tile was deleted
718 bool deleteChildOrTile(const Coord& xyz);
719
720 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
721 /// If no such node exists, create one that preserves the values and
722 /// active states of all voxels.
723 /// @details Use this method to preallocate a static tree topology
724 /// over which to safely perform multithreaded processing.
726
727 /// @brief Same as touchLeaf() but, if necessary, update the given accessor with pointers
728 /// to the nodes along the path from the root node to the node containing the coordinate.
729 template<typename AccessorT>
730 LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT& acc);
731
732 //@{
733 /// @brief Return a pointer to the node that contains voxel (x, y, z).
734 /// If no such node exists, return @c nullptr.
735 template <typename NodeT>
736 NodeT* probeNode(const Coord& xyz);
737 template <typename NodeT>
738 const NodeT* probeNode(const Coord& xyz) const;
739 template <typename NodeT>
740 const NodeT* probeConstNode(const Coord& xyz) const;
741 //@}
742
743 //@{
744 /// @brief Return a pointer to the root child node that contains voxel (x, y, z).
745 /// If no such node exists, query and set the tile value and active status and
746 /// return @c nullptr.
747 bool probe(const Coord& xyz, ChildNodeType*& child, ValueType& value, bool& active);
748 bool probeConst(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const;
749 bool probe(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const { return this->probeConst(xyz, child, value, active); }
750 //}
751
752 //@{
753 /// @brief Same as probeNode() but, if necessary, update the given accessor with pointers
754 /// to the nodes along the path from the root node to the node containing the coordinate.
755 template<typename NodeT, typename AccessorT>
756 NodeT* probeNodeAndCache(const Coord& xyz, AccessorT& acc);
757 template<typename NodeT, typename AccessorT>
758 const NodeT* probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const;
759 //@}
760
761 //@{
762 /// @brief Return a pointer to the root child node that contains voxel (x, y, z).
763 /// If no such node exists, return @c nullptr.
765 const ChildNodeType* probeConstChild(const Coord& xyz) const;
766 const ChildNodeType* probeChild(const Coord& xyz) const { return this->probeConstChild(xyz); }
767 //@}
768
769 //@{
770 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
771 /// If no such node exists, return @c nullptr.
773 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
774 const LeafNodeType* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
775 //@}
776
777 //@{
778 /// @brief Same as probeLeaf() but, if necessary, update the given accessor with pointers
779 /// to the nodes along the path from the root node to the node containing the coordinate.
780 template<typename AccessorT>
781 LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc);
782 template<typename AccessorT>
783 const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const;
784 template<typename AccessorT>
785 const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const;
786 //@}
787
788 //
789 // Unsafe methods
790 //
791 // WARNING: For improved performance, these unsafe methods assume that the tile
792 // or child exists. If used incorrectly, this can cause the application to crash.
793 // Always use the safer alternative method(s) unless you really know what you're doing.
794 // Enabling OpenVDB asserts will catch where assumptions are incorrectly invalidated.
795
796 /// @brief Return the tile value at the given coordinate.
797 /// @note Use cbeginValueAll() for a safer alternative.
798 /// @warning This method should only be used by experts seeking low-level optimizations.
799 const ValueType& getTileValueUnsafe(const Coord& xyz) const;
800 /// @brief Return the tile value and active state at the given coordinate.
801 /// @note Use cbeginValueAll() for a safer alternative.
802 /// @warning This method should only be used by experts seeking low-level optimizations.
803 bool getTileValueUnsafe(const Coord& xyz, ValueType& value) const;
804 /// @brief Return the child node at the given coordinate.
805 /// @note Use beginChildAll() for a safer alternative.
806 /// @warning This method should only be used by experts seeking low-level optimizations.
808 /// @brief Return the child node at the given coordinate.
809 /// @note Use cbeginChildAll() for a safer alternative.
810 /// @warning This method should only be used by experts seeking low-level optimizations.
811 const ChildNodeType* getConstChildUnsafe(const Coord& xyz) const;
812 /// @brief Return the child node at the given coordinate.
813 /// @note Use cbeginChildAll() for a safer alternative.
814 /// @warning This method should only be used by experts seeking low-level optimizations.
815 const ChildNodeType* getChildUnsafe(const Coord& xyz) const;
816
817
818 //
819 // Aux methods
820 //
821
822 //@{
823 /// @brief Adds all nodes of a certain type to a container with the following API:
824 /// @code
825 /// struct ArrayT {
826 /// using value_type = ...;// defines the type of nodes to be added to the array
827 /// void push_back(value_type nodePtr);// method that add nodes to the array
828 /// };
829 /// @endcode
830 /// @details An example of a wrapper around a c-style array is:
831 /// @code
832 /// struct MyArray {
833 /// using value_type = LeafType*;
834 /// value_type* ptr;
835 /// MyArray(value_type* array) : ptr(array) {}
836 /// void push_back(value_type leaf) { *ptr++ = leaf; }
837 ///};
838 /// @endcode
839 /// @details An example that constructs a list of pointer to all leaf nodes is:
840 /// @code
841 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
842 /// array.reserve(tree.leafCount());//this is a fast preallocation.
843 /// tree.getNodes(array);
844 /// @endcode
845 template<typename ArrayT> void getNodes(ArrayT& array);
846 template<typename ArrayT> void getNodes(ArrayT& array) const;
847 //@}
848
849 //@{
850 /// @brief Steals all nodes of a certain type from the tree and
851 /// adds them to a container with the following API:
852 /// @code
853 /// struct ArrayT {
854 /// using value_type = ...;// defines the type of nodes to be added to the array
855 /// void push_back(value_type nodePtr);// method that add nodes to the array
856 /// };
857 /// @endcode
858 /// @details An example of a wrapper around a c-style array is:
859 /// @code
860 /// struct MyArray {
861 /// using value_type = LeafType*;
862 /// value_type* ptr;
863 /// MyArray(value_type* array) : ptr(array) {}
864 /// void push_back(value_type leaf) { *ptr++ = leaf; }
865 ///};
866 /// @endcode
867 /// @details An example that constructs a list of pointer to all leaf nodes is:
868 /// @code
869 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
870 /// array.reserve(tree.leafCount());//this is a fast preallocation.
871 /// tree.stealNodes(array);
872 /// @endcode
873 template<typename ArrayT>
874 void stealNodes(ArrayT& array, const ValueType& value, bool state);
875 template<typename ArrayT>
876 void stealNodes(ArrayT& array) { this->stealNodes(array, mBackground, false); }
877 //@}
878
879 /// @brief Efficiently merge another tree into this tree using one of several schemes.
880 /// @details This operation is primarily intended to combine trees that are mostly
881 /// non-overlapping (for example, intermediate trees from computations that are
882 /// parallelized across disjoint regions of space).
883 /// @note This operation is not guaranteed to produce an optimally sparse tree.
884 /// Follow merge() with prune() for optimal sparseness.
885 /// @warning This operation always empties the other tree.
886 template<MergePolicy Policy> void merge(RootNode& other);
887
888 /// @brief Union this tree's set of active values with the active values
889 /// of the other tree, whose @c ValueType may be different.
890 /// @details The resulting state of a value is active if the corresponding value
891 /// was already active OR if it is active in the other tree. Also, a resulting
892 /// value maps to a voxel if the corresponding value already mapped to a voxel
893 /// OR if it is a voxel in the other tree. Thus, a resulting value can only
894 /// map to a tile if the corresponding value already mapped to a tile
895 /// AND if it is a tile value in other tree.
896 ///
897 /// @note This operation modifies only active states, not values.
898 /// Specifically, active tiles and voxels in this tree are not changed, and
899 /// tiles or voxels that were inactive in this tree but active in the other tree
900 /// are marked as active in this tree but left with their original values.
901 ///
902 /// @note If preserveTiles is true, any active tile in this topology
903 /// will not be densified by overlapping child topology.
904 template<typename OtherChildType>
905 void topologyUnion(const RootNode<OtherChildType>& other, const bool preserveTiles = false);
906
907 /// @brief Intersects this tree's set of active values with the active values
908 /// of the other tree, whose @c ValueType may be different.
909 /// @details The resulting state of a value is active only if the corresponding
910 /// value was already active AND if it is active in the other tree. Also, a
911 /// resulting value maps to a voxel if the corresponding value
912 /// already mapped to an active voxel in either of the two grids
913 /// and it maps to an active tile or voxel in the other grid.
914 ///
915 /// @note This operation can delete branches in this grid if they
916 /// overlap with inactive tiles in the other grid. Likewise active
917 /// voxels can be turned into inactive voxels resulting in leaf
918 /// nodes with no active values. Thus, it is recommended to
919 /// subsequently call prune.
920 template<typename OtherChildType>
922
923 /// @brief Difference this tree's set of active values with the active values
924 /// of the other tree, whose @c ValueType may be different. So a
925 /// resulting voxel will be active only if the original voxel is
926 /// active in this tree and inactive in the other tree.
927 ///
928 /// @note This operation can delete branches in this grid if they
929 /// overlap with active tiles in the other grid. Likewise active
930 /// voxels can be turned into inactive voxels resulting in leaf
931 /// nodes with no active values. Thus, it is recommended to
932 /// subsequently call prune.
933 template<typename OtherChildType>
935
936 template<typename CombineOp>
937 void combine(RootNode& other, CombineOp&, bool prune = false);
938
939 template<typename CombineOp, typename OtherRootNode /*= RootNode*/>
940 void combine2(const RootNode& other0, const OtherRootNode& other1,
941 CombineOp& op, bool prune = false);
942
943 /// Return the grid index coordinates of this node's local origin.
944 const Coord& origin() const { return mOrigin; }
945 /// @brief change the origin on this root node
946 /// @param origin the index coordinates of the new alignment
947 ///
948 /// @warning This method will throw if the origin is non-zero, since
949 /// other tools do not yet support variable offsets.
950 void setOrigin(const Coord &origin);
951
952 /// Return a MapType key for the given coordinates, offset by the mOrigin.
953 Coord coordToKey(const Coord& xyz) const { return (xyz - mOrigin) & ~(ChildType::DIM - 1); }
954
955 /// Return @c true if this node's mTable contains the given key.
956 bool hasKey(const Coord& key) const { return mTable.find(key) != mTable.end(); }
957
958private:
959 /// During topology-only construction, access is needed
960 /// to protected/private members of other template instances.
961 template<typename> friend class RootNode;
962
963 template<typename, typename, bool> friend struct RootNodeCopyHelper;
964 template<typename, typename, typename, bool> friend struct RootNodeCombineHelper;
965
966 /// Insert this node's mTable keys into the given set.
967 void insertKeys(CoordSet&) const;
968
969 //@{
970 /// @brief Look up the given key in this node's mTable.
971 /// @return an iterator pointing to the matching mTable entry or to mTable.end().
972 MapIter findKey(const Coord& key) { return mTable.find(key); }
973 MapCIter findKey(const Coord& key) const { return mTable.find(key); }
974 //@}
975 //@{
976 /// @brief Convert the given coordinates to a key and look the key up in this node's mTable.
977 /// @return an iterator pointing to the matching mTable entry or to mTable.end().
978 MapIter findCoord(const Coord& xyz) { return mTable.find(coordToKey(xyz)); }
979 MapCIter findCoord(const Coord& xyz) const { return mTable.find(coordToKey(xyz)); }
980 //@}
981 /// @brief Convert the given coordinates to a key and look the key up in this node's mTable.
982 /// @details If the key is not found, insert a background tile with that key.
983 /// @return an iterator pointing to the matching mTable entry.
984 MapIter findOrAddCoord(const Coord& xyz);
985
986 /// @brief Verify that the tree rooted at @a other has the same configuration
987 /// (levels, branching factors and node dimensions) as this tree, but allow
988 /// their ValueTypes to differ.
989 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
990 template<typename OtherChildType>
991 static void enforceSameConfiguration(const RootNode<OtherChildType>& other);
992
993 /// @brief Verify that @a other has values of a type that can be converted
994 /// to this node's ValueType.
995 /// @details For example, values of type float are compatible with values of type Vec3s,
996 /// because a Vec3s can be constructed from a float. But the reverse is not true.
997 /// @throw TypeError if the other node's ValueType is not convertible into this node's.
998 template<typename OtherChildType>
999 static void enforceCompatibleValueTypes(const RootNode<OtherChildType>& other);
1000
1001 template<typename CombineOp, typename OtherRootNode /*= RootNode*/>
1002 void doCombine2(const RootNode&, const OtherRootNode&, CombineOp&, bool prune);
1003
1004 MapType mTable;
1005 ValueType mBackground;
1006 Coord mOrigin;
1007 /// Transient Data (not serialized)
1008 Index32 mTransientData = 0;
1009}; // end of RootNode class
1010
1011
1012////////////////////////////////////////
1013
1014
1015/// @brief NodeChain<RootNodeType, RootNodeType::LEVEL>::Type is a openvdb::TypeList
1016/// that lists the types of the nodes of the tree rooted at RootNodeType in reverse order,
1017/// from LeafNode to RootNode.
1018/// @details For example, if RootNodeType is
1019/// @code
1020/// RootNode<InternalNode<InternalNode<LeafNode> > >
1021/// @endcode
1022/// then NodeChain::Type is
1023/// @code
1024/// openvdb::TypeList<
1025/// LeafNode,
1026/// InternalNode<LeafNode>,
1027/// InternalNode<InternalNode<LeafNode> >,
1028/// RootNode<InternalNode<InternalNode<LeafNode> > > >
1029/// @endcode
1030///
1031/// @note Use the following to get the Nth node type, where N=0 is the LeafNodeType:
1032/// @code
1033/// NodeChainType::Get<N>;
1034/// @endcode
1035template<typename HeadT, int HeadLevel>
1037 using SubtreeT = typename NodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1038 using Type = typename SubtreeT::template Append<HeadT>;
1039};
1040
1041/// Specialization to terminate NodeChain
1042template<typename HeadT>
1043struct NodeChain<HeadT, /*HeadLevel=*/1> {
1045};
1046
1047
1048////////////////////////////////////////
1049
1050
1051//@{
1052/// Helper metafunction used to implement RootNode::SameConfiguration
1053/// (which, as an inner class, can't be independently specialized)
1054template<typename ChildT1, typename NodeT2>
1056 static const bool value = false;
1057};
1058
1059template<typename ChildT1, typename ChildT2>
1060struct SameRootConfig<ChildT1, RootNode<ChildT2> > {
1061 static const bool value = ChildT1::template SameConfiguration<ChildT2>::value;
1062};
1063//@}
1064
1065
1066////////////////////////////////////////
1067
1068
1069template<typename ChildT>
1070inline
1072 : mBackground(zeroVal<ValueType>())
1073 , mOrigin(0, 0, 0)
1074{
1075}
1076
1077
1078template<typename ChildT>
1079inline
1081 : mBackground(background)
1082 , mOrigin(0, 0, 0)
1083{
1084}
1085
1086
1087template<typename ChildT>
1088template<typename OtherChildType>
1089inline
1091 const ValueType& backgd, const ValueType& foregd, TopologyCopy)
1092 : mBackground(backgd)
1093 , mOrigin(other.mOrigin)
1094 , mTransientData(other.mTransientData)
1095{
1096 using OtherRootT = RootNode<OtherChildType>;
1097
1098 if (mOrigin != Coord(0,0,0)) {
1099 OPENVDB_THROW(ValueError, "RootNode::RootNode: non-zero offsets are currently not supported");
1100 }
1101
1102 enforceSameConfiguration(other);
1103
1104 const Tile bgTile(backgd, /*active=*/false), fgTile(foregd, true);
1105
1106 for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) {
1107 mTable.emplace(i->first, OtherRootT::isTile(i)
1108 ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile)
1109 : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, foregd, TopologyCopy()))));
1110 }
1111}
1112
1113
1114template<typename ChildT>
1115template<typename OtherChildType>
1116inline
1118 const ValueType& backgd, TopologyCopy)
1119 : mBackground(backgd)
1120 , mOrigin(other.mOrigin)
1121 , mTransientData(other.mTransientData)
1122{
1123 using OtherRootT = RootNode<OtherChildType>;
1124
1125 if (mOrigin != Coord(0,0,0)) {
1126 OPENVDB_THROW(ValueError, "RootNode::RootNode: non-zero offsets are currently not supported");
1127 }
1128
1129 enforceSameConfiguration(other);
1130
1131 const Tile bgTile(backgd, /*active=*/false), fgTile(backgd, true);
1132
1133 for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) {
1134 mTable.emplace(i->first,
1135 OtherRootT::isTile(i)
1136 ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile)
1137 : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, TopologyCopy()))));
1138 }
1139}
1140
1141
1142////////////////////////////////////////
1143
1144
1145// This helper class is a friend of RootNode and is needed so that assignment
1146// with value conversion can be specialized for compatible and incompatible
1147// pairs of RootNode types.
1148template<typename RootT, typename OtherRootT, bool Compatible = false>
1150{
1151 static inline void copyWithValueConversion(RootT& self, const OtherRootT& other)
1152 {
1153 // If the two root nodes have different configurations or incompatible ValueTypes,
1154 // throw an exception.
1155 self.enforceSameConfiguration(other);
1156 self.enforceCompatibleValueTypes(other);
1157 // One of the above two tests should throw, so we should never get here:
1158 std::ostringstream ostr;
1159 ostr << "cannot convert a " << typeid(OtherRootT).name()
1160 << " to a " << typeid(RootT).name();
1161 OPENVDB_THROW(TypeError, ostr.str());
1162 }
1163};
1164
1165// Specialization for root nodes of compatible types
1166template<typename RootT, typename OtherRootT>
1167struct RootNodeCopyHelper<RootT, OtherRootT, /*Compatible=*/true>
1168{
1169 static inline void copyWithValueConversion(RootT& self, const OtherRootT& other)
1170 {
1171 using ValueT = typename RootT::ValueType;
1172 using ChildT = typename RootT::ChildNodeType;
1173 using Tile = typename RootT::Tile;
1174 using OtherValueT = typename OtherRootT::ValueType;
1175 using OtherMapCIter = typename OtherRootT::MapCIter;
1176 using OtherTile = typename OtherRootT::Tile;
1177
1178 struct Local {
1179 /// @todo Consider using a value conversion functor passed as an argument instead.
1180 static inline ValueT convertValue(const OtherValueT& val) {
1182 return ValueT(val);
1184 }
1185 };
1186
1187 self.mBackground = Local::convertValue(other.mBackground);
1188 if (other.mOrigin != Coord(0,0,0)) {
1189 OPENVDB_THROW(ValueError, "RootNodeCopyHelper::copyWithValueConversion: non-zero offsets are currently not supported");
1190 }
1191 self.mOrigin = other.mOrigin;
1192 self.mTransientData = other.mTransientData;
1193
1194 self.clear();
1195
1196 for (OtherMapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
1197 if (other.isTile(i)) {
1198 // Copy the other node's tile, but convert its value to this node's ValueType.
1199 const OtherTile& otherTile = other.getTile(i);
1200 self.mTable.emplace(i->first,
1201 Tile(Local::convertValue(otherTile.value), otherTile.active));
1202 } else {
1203 // Copy the other node's child, but convert its values to this node's ValueType.
1204 self.mTable.emplace(i->first, *(new ChildT(other.getChild(i))));
1205 }
1206 }
1207 }
1208};
1209
1210
1211// Overload for root nodes of the same type as this node
1212template<typename ChildT>
1213inline RootNode<ChildT>&
1215{
1216 if (&other != this) {
1217 mBackground = other.mBackground;
1218 mOrigin = other.mOrigin;
1219 if (mOrigin != Coord(0,0,0)) {
1220 OPENVDB_THROW(ValueError, "RootNode::operator=: non-zero offsets are currently not supported");
1221 }
1222 mTransientData = other.mTransientData;
1223
1224 this->clear();
1225
1226 for (MapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
1227 mTable.emplace(i->first,
1228 isTile(i) ? NodeStruct(getTile(i)) : NodeStruct(*(new ChildT(getChild(i)))));
1229 }
1230 }
1231 return *this;
1232}
1233
1234// Overload for root nodes of different types
1235template<typename ChildT>
1236template<typename OtherChildType>
1237inline RootNode<ChildT>&
1239{
1240 using OtherRootT = RootNode<OtherChildType>;
1241 using OtherValueT = typename OtherRootT::ValueType;
1242 static const bool compatible = (SameConfiguration<OtherRootT>::value
1243 && CanConvertType</*from=*/OtherValueT, /*to=*/ValueType>::value);
1245 return *this;
1246}
1247
1248
1249////////////////////////////////////////
1250
1251template<typename ChildT>
1252inline void
1254{
1255 if (math::isExactlyEqual(background, mBackground)) return;
1256
1257 if (updateChildNodes) {
1258 // Traverse the tree, replacing occurrences of mBackground with background
1259 // and -mBackground with -background.
1260 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1261 ChildT *child = iter->second.child;
1262 if (child) {
1263 child->resetBackground(/*old=*/mBackground, /*new=*/background);
1264 } else {
1265 Tile& tile = getTile(iter);
1266 if (tile.active) continue;//only change inactive tiles
1267 if (math::isApproxEqual(tile.value, mBackground)) {
1268 tile.value = background;
1269 } else if (math::isApproxEqual(tile.value, math::negative(mBackground))) {
1270 tile.value = math::negative(background);
1271 }
1272 }
1273 }
1274 }
1275 mBackground = background;
1276}
1277
1278template<typename ChildT>
1279inline bool
1281{
1282 return !tile.active && math::isApproxEqual(tile.value, mBackground);
1283}
1284
1285template<typename ChildT>
1286inline bool
1288{
1289 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1290}
1291
1292template<typename ChildT>
1293inline bool
1295{
1296 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1297}
1298
1299
1300template<typename ChildT>
1301inline size_t
1303{
1304 size_t count = 0;
1305 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1306 if (this->isBackgroundTile(i)) ++count;
1307 }
1308 return count;
1309}
1310
1311
1312template<typename ChildT>
1313inline size_t
1315{
1316 std::set<Coord> keysToErase;
1317 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1318 if (this->isBackgroundTile(i)) keysToErase.insert(i->first);
1319 }
1320 for (std::set<Coord>::iterator i = keysToErase.begin(), e = keysToErase.end(); i != e; ++i) {
1321 mTable.erase(*i);
1322 }
1323 return keysToErase.size();
1324}
1325
1326
1327////////////////////////////////////////
1328
1329
1330template<typename ChildT>
1331inline void
1332RootNode<ChildT>::insertKeys(CoordSet& keys) const
1333{
1334 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1335 keys.insert(i->first);
1336 }
1337}
1338
1339
1340template<typename ChildT>
1341inline typename RootNode<ChildT>::MapIter
1342RootNode<ChildT>::findOrAddCoord(const Coord& xyz)
1343{
1344 const Coord key = coordToKey(xyz);
1345 std::pair<MapIter, bool> result = mTable.try_emplace(key,
1346 Tile(mBackground, /*active=*/false));
1347 return result.first;
1348}
1349
1350
1351template<typename ChildT>
1352inline bool
1354{
1355 const Coord key = coordToKey(xyz);
1356 std::pair<MapIter, bool> result = mTable.try_emplace(key,
1357 Tile(mBackground, /*active=*/false));
1358 return result.second; // return true if the key did not already exist
1359}
1360
1361
1362////////////////////////////////////////
1363
1364
1365template<typename ChildT>
1366inline void
1367RootNode<ChildT>::getNodeLog2Dims(std::vector<Index>& dims)
1368{
1369 dims.push_back(0); // magic number; RootNode has no Log2Dim
1370 ChildT::getNodeLog2Dims(dims);
1371}
1372
1373
1374template<typename ChildT>
1375inline Coord
1377{
1378 return mTable.empty() ? Coord(0) : mTable.begin()->first;
1379}
1380
1381template<typename ChildT>
1382inline Coord
1384{
1385 return mTable.empty() ? Coord(0) : mTable.rbegin()->first + Coord(ChildT::DIM - 1);
1386}
1387
1388
1389template<typename ChildT>
1390inline void
1392{
1393 bbox.min() = this->getMinIndex();
1394 bbox.max() = this->getMaxIndex();
1395}
1396
1397
1398////////////////////////////////////////
1399
1400
1401template<typename ChildT>
1402template<typename OtherChildType>
1403inline bool
1405{
1406 using OtherRootT = RootNode<OtherChildType>;
1407 using OtherMapT = typename OtherRootT::MapType;
1408 using OtherIterT = typename OtherRootT::MapIter;
1409 using OtherCIterT = typename OtherRootT::MapCIter;
1410
1411 if (!hasSameConfiguration(other)) return false;
1412
1413 // Create a local copy of the other node's table.
1414 OtherMapT copyOfOtherTable = other.mTable;
1415
1416 // For each entry in this node's table...
1417 for (MapCIter thisIter = mTable.begin(); thisIter != mTable.end(); ++thisIter) {
1418 if (this->isBackgroundTile(thisIter)) continue; // ignore background tiles
1419
1420 // Fail if there is no corresponding entry in the other node's table.
1421 OtherCIterT otherIter = other.findKey(thisIter->first);
1422 if (otherIter == other.mTable.end()) return false;
1423
1424 // Fail if this entry is a tile and the other is a child or vice-versa.
1425 if (isChild(thisIter)) {//thisIter points to a child
1426 if (OtherRootT::isTile(otherIter)) return false;
1427 // Fail if both entries are children, but the children have different topology.
1428 if (!getChild(thisIter).hasSameTopology(&OtherRootT::getChild(otherIter))) return false;
1429 } else {//thisIter points to a tile
1430 if (OtherRootT::isChild(otherIter)) return false;
1431 if (getTile(thisIter).active != OtherRootT::getTile(otherIter).active) return false;
1432 }
1433
1434 // Remove tiles and child nodes with matching topology from
1435 // the copy of the other node's table. This is required since
1436 // the two root tables can include an arbitrary number of
1437 // background tiles and still have the same topology!
1438 copyOfOtherTable.erase(otherIter->first);
1439 }
1440 // Fail if the remaining entries in copyOfOtherTable are not all background tiles.
1441 for (OtherIterT i = copyOfOtherTable.begin(), e = copyOfOtherTable.end(); i != e; ++i) {
1442 if (!other.isBackgroundTile(i)) return false;
1443 }
1444 return true;
1445}
1446
1447
1448template<typename ChildT>
1449template<typename OtherChildType>
1450inline bool
1452{
1453 std::vector<Index> thisDims, otherDims;
1454 RootNode::getNodeLog2Dims(thisDims);
1456 return (thisDims == otherDims);
1457}
1458
1459
1460template<typename ChildT>
1461template<typename OtherChildType>
1462inline void
1463RootNode<ChildT>::enforceSameConfiguration(const RootNode<OtherChildType>&)
1464{
1465 std::vector<Index> thisDims, otherDims;
1466 RootNode::getNodeLog2Dims(thisDims);
1468 if (thisDims != otherDims) {
1469 std::ostringstream ostr;
1470 ostr << "grids have incompatible configurations (" << thisDims[0];
1471 for (size_t i = 1, N = thisDims.size(); i < N; ++i) ostr << " x " << thisDims[i];
1472 ostr << " vs. " << otherDims[0];
1473 for (size_t i = 1, N = otherDims.size(); i < N; ++i) ostr << " x " << otherDims[i];
1474 ostr << ")";
1475 OPENVDB_THROW(TypeError, ostr.str());
1476 }
1477}
1478
1479
1480template<typename ChildT>
1481template<typename OtherChildType>
1482inline bool
1484{
1485 using OtherValueType = typename OtherChildType::ValueType;
1486 return CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value;
1487}
1488
1489
1490template<typename ChildT>
1491template<typename OtherChildType>
1492inline void
1493RootNode<ChildT>::enforceCompatibleValueTypes(const RootNode<OtherChildType>&)
1494{
1495 using OtherValueType = typename OtherChildType::ValueType;
1497 std::ostringstream ostr;
1498 ostr << "values of type " << typeNameAsString<OtherValueType>()
1499 << " cannot be converted to type " << typeNameAsString<ValueType>();
1500 OPENVDB_THROW(TypeError, ostr.str());
1501 }
1502}
1503
1504
1505////////////////////////////////////////
1506
1507
1508template<typename ChildT>
1509inline Index64
1511{
1512 Index64 sum = sizeof(*this);
1513 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1514 if (const ChildT *child = iter->second.child) {
1515 sum += child->memUsage();
1516 }
1517 }
1518 return sum;
1519}
1520
1521
1522template<typename ChildT>
1523inline void
1525{
1526 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1527 delete i->second.child;
1528 }
1529 mTable.clear();
1530}
1531
1532
1533template<typename ChildT>
1534inline void
1536{
1537 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1538 if (const ChildT *child = iter->second.child) {
1539 child->evalActiveBoundingBox(bbox, visitVoxels);
1540 } else if (isTileOn(iter)) {
1541 bbox.expand(iter->first, ChildT::DIM);
1542 }
1543 }
1544}
1545
1546
1547template<typename ChildT>
1548inline Index64
1550{
1551 Index64 sum = 0;
1552 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1553 if (isChild(i)) sum += getChild(i).leafCount();
1554 }
1555 return sum;
1556}
1557
1558
1559template<typename ChildT>
1560inline Index64
1562{
1563 Index64 sum = 1;
1564 if (ChildT::LEVEL != 0) {
1565 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1566 if (isChild(i)) sum += getChild(i).nonLeafCount();
1567 }
1568 }
1569 return sum;
1570}
1571
1572
1573template<typename ChildT>
1574inline Index32
1576{
1577 Index sum = 0;
1578 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1579 if (isChild(i)) ++sum;
1580 }
1581 return sum;
1582}
1583
1584
1585template<typename ChildT>
1586inline Index32
1588{
1589 Index32 sum = 0;
1590 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1591 if (isTile(i)) ++sum;
1592 }
1593 return sum;
1594}
1595
1596
1597template<typename ChildT>
1598inline Index32
1600{
1601 Index32 sum = 0;
1602 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1603 if (isTileOn(i)) ++sum;
1604 }
1605 return sum;
1606}
1607
1608
1609template<typename ChildT>
1610inline Index32
1612{
1613 Index32 sum = 0;
1614 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1615 if (isTileOff(i)) ++sum;
1616 }
1617 return sum;
1618}
1619
1620
1621template<typename ChildT>
1622inline Index64
1624{
1625 Index64 sum = 0;
1626 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1627 if (isChild(i)) {
1628 sum += getChild(i).onVoxelCount();
1629 } else if (isTileOn(i)) {
1630 sum += ChildT::NUM_VOXELS;
1631 }
1632 }
1633 return sum;
1634}
1635
1636
1637template<typename ChildT>
1638inline Index64
1640{
1641 Index64 sum = 0;
1642 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1643 if (isChild(i)) {
1644 sum += getChild(i).offVoxelCount();
1645 } else if (isTileOff(i) && !this->isBackgroundTile(i)) {
1646 sum += ChildT::NUM_VOXELS;
1647 }
1648 }
1649 return sum;
1650}
1651
1652
1653template<typename ChildT>
1654inline Index64
1656{
1657 Index64 sum = 0;
1658 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1659 if (isChild(i)) sum += getChild(i).onLeafVoxelCount();
1660 }
1661 return sum;
1662}
1663
1664
1665template<typename ChildT>
1666inline Index64
1668{
1669 Index64 sum = 0;
1670 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1671 if (isChild(i)) sum += getChild(i).offLeafVoxelCount();
1672 }
1673 return sum;
1674}
1675
1676template<typename ChildT>
1677inline Index64
1679{
1680 Index64 sum = 0;
1681 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1682 if (isChild(i)) {
1683 sum += getChild(i).onTileCount();
1684 } else if (isTileOn(i)) {
1685 sum += 1;
1686 }
1687 }
1688 return sum;
1689}
1690
1691template<typename ChildT>
1692inline void
1693RootNode<ChildT>::nodeCount(std::vector<Index64> &vec) const
1694{
1695 OPENVDB_ASSERT(vec.size() > LEVEL);
1696 Index64 sum = 0;
1697 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1698 if (isChild(i)) {
1699 ++sum;
1700 getChild(i).nodeCount(vec);
1701 }
1702 }
1703 vec[LEVEL] = 1;// one root node
1704 vec[ChildNodeType::LEVEL] = sum;
1705}
1706
1707////////////////////////////////////////
1708
1709
1710template<typename ChildT>
1711inline bool
1713{
1714 MapCIter iter = this->findCoord(xyz);
1715 if (iter == mTable.end() || isTileOff(iter)) return false;
1716 return isTileOn(iter) ? true : getChild(iter).isValueOn(xyz);
1717}
1718
1719template<typename ChildT>
1720inline bool
1722{
1723 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1724 if (isChild(i) ? getChild(i).hasActiveTiles() : getTile(i).active) return true;
1725 }
1726 return false;
1727}
1728
1729template<typename ChildT>
1730template<typename AccessorT>
1731inline bool
1732RootNode<ChildT>::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const
1733{
1734 MapCIter iter = this->findCoord(xyz);
1735 if (iter == mTable.end() || isTileOff(iter)) return false;
1736 if (isTileOn(iter)) return true;
1737 acc.insert(xyz, &getChild(iter));
1738 return getChild(iter).isValueOnAndCache(xyz, acc);
1739}
1740
1741
1742template<typename ChildT>
1743inline const typename ChildT::ValueType&
1745{
1746 MapCIter iter = this->findCoord(xyz);
1747 return iter == mTable.end() ? mBackground
1748 : (isTile(iter) ? getTile(iter).value : getChild(iter).getValue(xyz));
1749}
1750
1751template<typename ChildT>
1752template<typename AccessorT>
1753inline const typename ChildT::ValueType&
1754RootNode<ChildT>::getValueAndCache(const Coord& xyz, AccessorT& acc) const
1755{
1756 MapCIter iter = this->findCoord(xyz);
1757 if (iter == mTable.end()) return mBackground;
1758 if (isChild(iter)) {
1759 acc.insert(xyz, &getChild(iter));
1760 return getChild(iter).getValueAndCache(xyz, acc);
1761 }
1762 return getTile(iter).value;
1763}
1764
1765
1766template<typename ChildT>
1767inline int
1769{
1770 MapCIter iter = this->findCoord(xyz);
1771 return iter == mTable.end() ? -1
1772 : (isTile(iter) ? 0 : int(LEVEL) - int(getChild(iter).getValueLevel(xyz)));
1773}
1774
1775template<typename ChildT>
1776template<typename AccessorT>
1777inline int
1778RootNode<ChildT>::getValueDepthAndCache(const Coord& xyz, AccessorT& acc) const
1779{
1780 MapCIter iter = this->findCoord(xyz);
1781 if (iter == mTable.end()) return -1;
1782 if (isTile(iter)) return 0;
1783 acc.insert(xyz, &getChild(iter));
1784 return int(LEVEL) - int(getChild(iter).getValueLevelAndCache(xyz, acc));
1785}
1786
1787
1788template<typename ChildT>
1789inline void
1791{
1792 MapIter iter = this->findCoord(xyz);
1793 if (iter != mTable.end() && !isTileOff(iter)) {
1794 if (isTileOn(iter)) {
1795 setChild(iter, *new ChildT(xyz, getTile(iter).value, /*active=*/true));
1796 }
1797 getChild(iter).setValueOff(xyz);
1798 }
1799}
1800
1801
1802template<typename ChildT>
1803inline void
1805{
1806 ChildT* child = nullptr;
1807 const Coord key = this->coordToKey(xyz);
1808 MapIter iter = this->findKey(key);
1809 if (iter == mTable.end()) {
1810 if (on) {
1811 child = new ChildT(xyz, mBackground);
1812 mTable.emplace(key, *child);
1813 } else {
1814 // Nothing to do; (x, y, z) is background and therefore already inactive.
1815 }
1816 } else if (isChild(iter)) {
1817 child = &getChild(iter);
1818 } else if (on != getTile(iter).active) {
1819 child = new ChildT(xyz, getTile(iter).value, !on);
1820 setChild(iter, *child);
1821 }
1822 if (child) child->setActiveState(xyz, on);
1823}
1824
1825template<typename ChildT>
1826template<typename AccessorT>
1827inline void
1828RootNode<ChildT>::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc)
1829{
1830 ChildT* child = nullptr;
1831 const Coord key = this->coordToKey(xyz);
1832 MapIter iter = this->findKey(key);
1833 if (iter == mTable.end()) {
1834 if (on) {
1835 child = new ChildT(xyz, mBackground);
1836 mTable.emplace(key, *child);
1837 } else {
1838 // Nothing to do; (x, y, z) is background and therefore already inactive.
1839 }
1840 } else if (isChild(iter)) {
1841 child = &getChild(iter);
1842 } else if (on != getTile(iter).active) {
1843 child = new ChildT(xyz, getTile(iter).value, !on);
1844 setChild(iter, *child);
1845 }
1846 if (child) {
1847 acc.insert(xyz, child);
1848 child->setActiveStateAndCache(xyz, on, acc);
1849 }
1850}
1851
1852
1853template<typename ChildT>
1854inline void
1856{
1857 ChildT* child = nullptr;
1858 const Coord key = this->coordToKey(xyz);
1859 MapIter iter = this->findKey(key);
1860 if (iter == mTable.end()) {
1861 if (!math::isExactlyEqual(mBackground, value)) {
1862 child = new ChildT(xyz, mBackground);
1863 mTable.emplace(key, *child);
1864 }
1865 } else if (isChild(iter)) {
1866 child = &getChild(iter);
1867 } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1868 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1869 setChild(iter, *child);
1870 }
1871 if (child) child->setValueOff(xyz, value);
1872}
1873
1874template<typename ChildT>
1875template<typename AccessorT>
1876inline void
1877RootNode<ChildT>::setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1878{
1879 ChildT* child = nullptr;
1880 const Coord key = this->coordToKey(xyz);
1881 MapIter iter = this->findKey(key);
1882 if (iter == mTable.end()) {
1883 if (!math::isExactlyEqual(mBackground, value)) {
1884 child = new ChildT(xyz, mBackground);
1885 mTable.emplace(key, *child);
1886 }
1887 } else if (isChild(iter)) {
1888 child = &getChild(iter);
1889 } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1890 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1891 setChild(iter, *child);
1892 }
1893 if (child) {
1894 acc.insert(xyz, child);
1895 child->setValueOffAndCache(xyz, value, acc);
1896 }
1897}
1898
1899
1900template<typename ChildT>
1901inline void
1903{
1904 ChildT* child = nullptr;
1905 const Coord key = this->coordToKey(xyz);
1906 MapIter iter = this->findKey(key);
1907 if (iter == mTable.end()) {
1908 child = new ChildT(xyz, mBackground);
1909 mTable.emplace(key, *child);
1910 } else if (isChild(iter)) {
1911 child = &getChild(iter);
1912 } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1913 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1914 setChild(iter, *child);
1915 }
1916 if (child) child->setValueOn(xyz, value);
1917}
1918
1919template<typename ChildT>
1920template<typename AccessorT>
1921inline void
1922RootNode<ChildT>::setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1923{
1924 ChildT* child = nullptr;
1925 const Coord key = this->coordToKey(xyz);
1926 MapIter iter = this->findKey(key);
1927 if (iter == mTable.end()) {
1928 child = new ChildT(xyz, mBackground);
1929 mTable.emplace(key, *child);
1930 } else if (isChild(iter)) {
1931 child = &getChild(iter);
1932 } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1933 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1934 setChild(iter, *child);
1935 }
1936 if (child) {
1937 acc.insert(xyz, child);
1938 child->setValueAndCache(xyz, value, acc);
1939 }
1940}
1941
1942
1943template<typename ChildT>
1944inline void
1946{
1947 ChildT* child = nullptr;
1948 const Coord key = this->coordToKey(xyz);
1949 MapIter iter = this->findKey(key);
1950 if (iter == mTable.end()) {
1951 child = new ChildT(xyz, mBackground);
1952 mTable.emplace(key, *child);
1953 } else if (isChild(iter)) {
1954 child = &getChild(iter);
1955 } else if (!math::isExactlyEqual(getTile(iter).value, value)) {
1956 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1957 setChild(iter, *child);
1958 }
1959 if (child) child->setValueOnly(xyz, value);
1960}
1961
1962template<typename ChildT>
1963template<typename AccessorT>
1964inline void
1965RootNode<ChildT>::setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1966{
1967 ChildT* child = nullptr;
1968 const Coord key = this->coordToKey(xyz);
1969 MapIter iter = this->findKey(key);
1970 if (iter == mTable.end()) {
1971 child = new ChildT(xyz, mBackground);
1972 mTable.emplace(key, *child);
1973 } else if (isChild(iter)) {
1974 child = &getChild(iter);
1975 } else if (!math::isExactlyEqual(getTile(iter).value, value)) {
1976 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1977 setChild(iter, *child);
1978 }
1979 if (child) {
1980 acc.insert(xyz, child);
1981 child->setValueOnlyAndCache(xyz, value, acc);
1982 }
1983}
1984
1985
1986template<typename ChildT>
1987template<typename ModifyOp>
1988inline void
1989RootNode<ChildT>::modifyValue(const Coord& xyz, const ModifyOp& op)
1990{
1991 ChildT* child = nullptr;
1992 const Coord key = this->coordToKey(xyz);
1993 MapIter iter = this->findKey(key);
1994 if (iter == mTable.end()) {
1995 child = new ChildT(xyz, mBackground);
1996 mTable.emplace(key, *child);
1997 } else if (isChild(iter)) {
1998 child = &getChild(iter);
1999 } else {
2000 // Need to create a child if the tile is inactive,
2001 // in order to activate voxel (x, y, z).
2002 bool createChild = isTileOff(iter);
2003 if (!createChild) {
2004 // Need to create a child if applying the functor
2005 // to the tile value produces a different value.
2006 const ValueType& tileVal = getTile(iter).value;
2007 ValueType modifiedVal = tileVal;
2008 op(modifiedVal);
2009 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
2010 }
2011 if (createChild) {
2012 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2013 setChild(iter, *child);
2014 }
2015 }
2016 if (child) child->modifyValue(xyz, op);
2017}
2018
2019template<typename ChildT>
2020template<typename ModifyOp, typename AccessorT>
2021inline void
2022RootNode<ChildT>::modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT& acc)
2023{
2024 ChildT* child = nullptr;
2025 const Coord key = this->coordToKey(xyz);
2026 MapIter iter = this->findKey(key);
2027 if (iter == mTable.end()) {
2028 child = new ChildT(xyz, mBackground);
2029 mTable.emplace(key, *child);
2030 } else if (isChild(iter)) {
2031 child = &getChild(iter);
2032 } else {
2033 // Need to create a child if the tile is inactive,
2034 // in order to activate voxel (x, y, z).
2035 bool createChild = isTileOff(iter);
2036 if (!createChild) {
2037 // Need to create a child if applying the functor
2038 // to the tile value produces a different value.
2039 const ValueType& tileVal = getTile(iter).value;
2040 ValueType modifiedVal = tileVal;
2041 op(modifiedVal);
2042 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
2043 }
2044 if (createChild) {
2045 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2046 setChild(iter, *child);
2047 }
2048 }
2049 if (child) {
2050 acc.insert(xyz, child);
2051 child->modifyValueAndCache(xyz, op, acc);
2052 }
2053}
2054
2055
2056template<typename ChildT>
2057template<typename ModifyOp>
2058inline void
2060{
2061 ChildT* child = nullptr;
2062 const Coord key = this->coordToKey(xyz);
2063 MapIter iter = this->findKey(key);
2064 if (iter == mTable.end()) {
2065 child = new ChildT(xyz, mBackground);
2066 mTable.emplace(key, *child);
2067 } else if (isChild(iter)) {
2068 child = &getChild(iter);
2069 } else {
2070 const Tile& tile = getTile(iter);
2071 bool modifiedState = tile.active;
2072 ValueType modifiedVal = tile.value;
2073 op(modifiedVal, modifiedState);
2074 // Need to create a child if applying the functor to the tile
2075 // produces a different value or active state.
2076 if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) {
2077 child = new ChildT(xyz, tile.value, tile.active);
2078 setChild(iter, *child);
2079 }
2080 }
2081 if (child) child->modifyValueAndActiveState(xyz, op);
2082}
2083
2084template<typename ChildT>
2085template<typename ModifyOp, typename AccessorT>
2086inline void
2088 const Coord& xyz, const ModifyOp& op, AccessorT& acc)
2089{
2090 ChildT* child = nullptr;
2091 const Coord key = this->coordToKey(xyz);
2092 MapIter iter = this->findKey(key);
2093 if (iter == mTable.end()) {
2094 child = new ChildT(xyz, mBackground);
2095 mTable.emplace(key, *child);
2096 } else if (isChild(iter)) {
2097 child = &getChild(iter);
2098 } else {
2099 const Tile& tile = getTile(iter);
2100 bool modifiedState = tile.active;
2101 ValueType modifiedVal = tile.value;
2102 op(modifiedVal, modifiedState);
2103 // Need to create a child if applying the functor to the tile
2104 // produces a different value or active state.
2105 if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) {
2106 child = new ChildT(xyz, tile.value, tile.active);
2107 setChild(iter, *child);
2108 }
2109 }
2110 if (child) {
2111 acc.insert(xyz, child);
2112 child->modifyValueAndActiveStateAndCache(xyz, op, acc);
2113 }
2114}
2115
2116
2117template<typename ChildT>
2118inline bool
2120{
2121 MapCIter iter = this->findCoord(xyz);
2122 if (iter == mTable.end()) {
2123 value = mBackground;
2124 return false;
2125 } else if (isChild(iter)) {
2126 return getChild(iter).probeValue(xyz, value);
2127 }
2128 value = getTile(iter).value;
2129 return isTileOn(iter);
2130}
2131
2132template<typename ChildT>
2133template<typename AccessorT>
2134inline bool
2135RootNode<ChildT>::probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT& acc) const
2136{
2137 MapCIter iter = this->findCoord(xyz);
2138 if (iter == mTable.end()) {
2139 value = mBackground;
2140 return false;
2141 } else if (isChild(iter)) {
2142 acc.insert(xyz, &getChild(iter));
2143 return getChild(iter).probeValueAndCache(xyz, value, acc);
2144 }
2145 value = getTile(iter).value;
2146 return isTileOn(iter);
2147}
2148
2149
2150////////////////////////////////////////
2151
2152
2153template<typename ChildT>
2154inline void
2155RootNode<ChildT>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
2156{
2157 if (bbox.empty()) return;
2158
2159 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2160 // (The first and last chunks along each axis might be smaller than a tile.)
2161 Coord xyz, tileMax;
2162 for (int x = bbox.min().x(); x <= bbox.max().x(); x = tileMax.x() + 1) {
2163 xyz.setX(x);
2164 for (int y = bbox.min().y(); y <= bbox.max().y(); y = tileMax.y() + 1) {
2165 xyz.setY(y);
2166 for (int z = bbox.min().z(); z <= bbox.max().z(); z = tileMax.z() + 1) {
2167 xyz.setZ(z);
2168
2169 // Get the bounds of the tile that contains voxel (x, y, z).
2170 Coord tileMin = coordToKey(xyz);
2171 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2172
2173 if (xyz != tileMin || Coord::lessThan(bbox.max(), tileMax)) {
2174 // If the box defined by (xyz, bbox.max()) doesn't completely enclose
2175 // the tile to which xyz belongs, create a child node (or retrieve
2176 // the existing one).
2177 ChildT* child = nullptr;
2178 MapIter iter = this->findKey(tileMin);
2179 if (iter == mTable.end()) {
2180 // No child or tile exists. Create a child and initialize it
2181 // with the background value.
2182 child = new ChildT(xyz, mBackground);
2183 mTable.emplace(tileMin, *child);
2184 } else if (isTile(iter)) {
2185 // Replace the tile with a newly-created child that is filled
2186 // with the tile's value and active state.
2187 const Tile& tile = getTile(iter);
2188 child = new ChildT(xyz, tile.value, tile.active);
2189 setChild(iter, *child);
2190 } else if (isChild(iter)) {
2191 child = &getChild(iter);
2192 }
2193 // Forward the fill request to the child.
2194 if (child) {
2195 const Coord tmp = Coord::minComponent(bbox.max(), tileMax);
2196 child->fill(CoordBBox(xyz, tmp), value, active);
2197 }
2198 } else {
2199 // If the box given by (xyz, bbox.max()) completely encloses
2200 // the tile to which xyz belongs, create the tile (if it
2201 // doesn't already exist) and give it the fill value.
2202 MapIter iter = this->findOrAddCoord(tileMin);
2203 setTile(iter, Tile(value, active));
2204 }
2205 }
2206 }
2207 }
2208}
2209
2210
2211template<typename ChildT>
2212inline void
2213RootNode<ChildT>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
2214{
2215 if (bbox.empty()) return;
2216
2217 if (active && mTable.empty()) {
2218 // If this tree is empty, then a sparse fill followed by (threaded)
2219 // densification of active tiles is the more efficient approach.
2220 sparseFill(bbox, value, active);
2221 voxelizeActiveTiles(/*threaded=*/true);
2222 return;
2223 }
2224
2225 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2226 // (The first and last chunks along each axis might be smaller than a tile.)
2227 Coord xyz, tileMin, tileMax;
2228 for (int x = bbox.min().x(); x <= bbox.max().x(); x = tileMax.x() + 1) {
2229 xyz.setX(x);
2230 for (int y = bbox.min().y(); y <= bbox.max().y(); y = tileMax.y() + 1) {
2231 xyz.setY(y);
2232 for (int z = bbox.min().z(); z <= bbox.max().z(); z = tileMax.z() + 1) {
2233 xyz.setZ(z);
2234
2235 // Get the bounds of the tile that contains voxel (x, y, z).
2236 tileMin = coordToKey(xyz);
2237 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2238
2239 // Retrieve the table entry for the tile that contains xyz,
2240 // or, if there is no table entry, add a background tile.
2241 const auto iter = findOrAddCoord(tileMin);
2242
2243 if (isTile(iter)) {
2244 // If the table entry is a tile, replace it with a child node
2245 // that is filled with the tile's value and active state.
2246 const auto& tile = getTile(iter);
2247 auto* child = new ChildT{tileMin, tile.value, tile.active};
2248 setChild(iter, *child);
2249 }
2250 // Forward the fill request to the child.
2251 getChild(iter).denseFill(bbox, value, active);
2252 }
2253 }
2254 }
2255}
2256
2257
2258////////////////////////////////////////
2259
2260
2261template<typename ChildT>
2262inline void
2264{
2265 // There is little point in threading over the root table since each tile
2266 // spans a huge index space (by default 4096^3) and hence we expect few
2267 // active tiles if any at all. In fact, you're very likely to run out of
2268 // memory if this method is called on a tree with root-level active tiles!
2269 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2270 if (this->isTileOff(i)) continue;
2271 ChildT* child = i->second.child;
2272 if (child == nullptr) {
2273 // If this table entry is an active tile (i.e., not off and not a child node),
2274 // replace it with a child node filled with active tiles of the same value.
2275 child = new ChildT{i->first, this->getTile(i).value, true};
2276 i->second.child = child;
2277 }
2278 child->voxelizeActiveTiles(threaded);
2279 }
2280}
2281
2282
2283////////////////////////////////////////
2284
2285
2286template<typename ChildT>
2287template<typename DenseT>
2288inline void
2289RootNode<ChildT>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
2290{
2291 using DenseValueType = typename DenseT::ValueType;
2292
2293 const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
2294 const Coord& min = dense.bbox().min();
2295 CoordBBox nodeBBox;
2296 for (Coord xyz = bbox.min(); xyz[0] <= bbox.max()[0]; xyz[0] = nodeBBox.max()[0] + 1) {
2297 for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = nodeBBox.max()[1] + 1) {
2298 for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = nodeBBox.max()[2] + 1) {
2299
2300 // Get the coordinate bbox of the child node that contains voxel xyz.
2301 nodeBBox = CoordBBox::createCube(coordToKey(xyz), ChildT::DIM);
2302
2303 // Get the coordinate bbox of the interection of inBBox and nodeBBox
2304 CoordBBox sub(xyz, Coord::minComponent(bbox.max(), nodeBBox.max()));
2305
2306 MapCIter iter = this->findKey(nodeBBox.min());
2307 if (iter != mTable.end() && isChild(iter)) {//is a child
2308 getChild(iter).copyToDense(sub, dense);
2309 } else {//is background or a tile value
2310 const ValueType value = iter==mTable.end() ? mBackground : getTile(iter).value;
2311 sub.translate(-min);
2312 DenseValueType* a0 = dense.data() + zStride*sub.min()[2];
2313 for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x<ex; ++x) {
2314 DenseValueType* a1 = a0 + x*xStride;
2315 for (Int32 y=sub.min()[1], ey=sub.max()[1]+1; y<ey; ++y) {
2316 DenseValueType* a2 = a1 + y*yStride;
2317 for (Int32 z=sub.min()[2], ez=sub.max()[2]+1; z<ez; ++z, a2 += zStride) {
2318 *a2 = DenseValueType(value);
2319 }
2320 }
2321 }
2322 }
2323 }
2324 }
2325 }
2326}
2327
2328////////////////////////////////////////
2329
2330
2331#if OPENVDB_ABI_VERSION_NUMBER < 14
2332
2333template<typename ChildT>
2334inline bool
2335RootNode<ChildT>::writeTopology(std::ostream& os, bool toHalf) const
2336{
2337 if (!toHalf) {
2338 os.write(reinterpret_cast<const char*>(&mBackground), sizeof(ValueType));
2339 } else {
2340 ValueType truncatedVal = io::truncateRealToHalf(mBackground);
2341 os.write(reinterpret_cast<const char*>(&truncatedVal), sizeof(ValueType));
2342 }
2343 io::setGridBackgroundValuePtr(os, &mBackground);
2344
2345 const Index numTiles = this->tileCount(), numChildren = this->childCount();
2346 os.write(reinterpret_cast<const char*>(&numTiles), sizeof(Index));
2347 os.write(reinterpret_cast<const char*>(&numChildren), sizeof(Index));
2348
2349 if (numTiles == 0 && numChildren == 0) return false;
2350
2351 // Write tiles.
2352 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2353 if (isChild(i)) continue;
2354 os.write(reinterpret_cast<const char*>(i->first.asPointer()), 3 * sizeof(Int32));
2355 os.write(reinterpret_cast<const char*>(&getTile(i).value), sizeof(ValueType));
2356 os.write(reinterpret_cast<const char*>(&getTile(i).active), sizeof(bool));
2357 }
2358 // Write child nodes.
2359 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2360 if (isTile(i)) continue;
2361 os.write(reinterpret_cast<const char*>(i->first.asPointer()), 3 * sizeof(Int32));
2362 getChild(i).writeTopology(os, toHalf);
2363 }
2364
2365 return true; // not empty
2366}
2367
2368
2369template<typename ChildT>
2370inline bool
2371RootNode<ChildT>::readTopology(std::istream& is, bool fromHalf)
2372{
2374
2375 // Delete the existing tree.
2376 this->clear();
2377
2378 // Read a RootNode that was stored in the current format.
2379
2380 is.read(reinterpret_cast<char*>(&mBackground), sizeof(ValueType));
2381 io::setGridBackgroundValuePtr(is, &mBackground);
2382
2383 Index numTiles = 0, numChildren = 0;
2384 is.read(reinterpret_cast<char*>(&numTiles), sizeof(Index));
2385 is.read(reinterpret_cast<char*>(&numChildren), sizeof(Index));
2386
2387 if (numTiles == 0 && numChildren == 0) return false;
2388
2389 Int32 vec[3];
2390 ValueType value;
2391 bool active;
2392
2393 // Read tiles.
2394 for (Index n = 0; n < numTiles; ++n) {
2395 is.read(reinterpret_cast<char*>(vec), 3 * sizeof(Int32));
2396 is.read(reinterpret_cast<char*>(&value), sizeof(ValueType));
2397 is.read(reinterpret_cast<char*>(&active), sizeof(bool));
2398 mTable.emplace(Coord(vec), Tile(value, active));
2399 }
2400
2401 // Read child nodes.
2402 for (Index n = 0; n < numChildren; ++n) {
2403 is.read(reinterpret_cast<char*>(vec), 3 * sizeof(Int32));
2404 Coord origin(vec);
2405 ChildT* child = new ChildT(PartialCreate(), origin, mBackground);
2406 child->readTopology(is, fromHalf);
2407 mTable.emplace(Coord(vec), *child);
2408 }
2409
2410 return true; // not empty
2411}
2412
2413
2414template<typename ChildT>
2415inline void
2416RootNode<ChildT>::writeBuffers(std::ostream& os, bool toHalf) const
2417{
2418 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2419 if (isChild(i)) getChild(i).writeBuffers(os, toHalf);
2420 }
2421}
2422
2423
2424template<typename ChildT>
2425inline void
2426RootNode<ChildT>::readBuffers(std::istream& is, bool fromHalf)
2427{
2428 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2429 if (isChild(i)) getChild(i).readBuffers(is, fromHalf);
2430 }
2431}
2432
2433
2434template<typename ChildT>
2435inline void
2436RootNode<ChildT>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
2437{
2438 const Tile bgTile(mBackground, /*active=*/false);
2439
2440 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2441 if (isChild(i)) {
2442 // Stream in and clip the branch rooted at this child.
2443 // (We can't skip over children that lie outside the clipping region,
2444 // because buffers are serialized in depth-first order and need to be
2445 // unserialized in the same order.)
2446 ChildT& child = getChild(i);
2447 child.readBuffers(is, clipBBox, fromHalf);
2448 }
2449 }
2450 // Clip root-level tiles and prune children that were clipped.
2451 this->clip(clipBBox);
2452}
2453
2454#endif // OPENVDB_ABI_VERSION_NUMBER < 14
2455
2456
2457////////////////////////////////////////
2458
2459
2460template<typename ChildT>
2461inline void
2463{
2464 const Tile bgTile(mBackground, /*active=*/false);
2465
2466 // Iterate over a copy of this node's table so that we can modify the original.
2467 // (Copying the table copies child node pointers, not the nodes themselves.)
2468 MapType copyOfTable(mTable);
2469 for (MapIter i = copyOfTable.begin(), e = copyOfTable.end(); i != e; ++i) {
2470 const Coord& xyz = i->first; // tile or child origin
2471 CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds
2472 if (!clipBBox.hasOverlap(tileBBox)) {
2473 // This table entry lies completely outside the clipping region. Delete it.
2474 setTile(this->findCoord(xyz), bgTile); // delete any existing child node first
2475 mTable.erase(xyz);
2476 } else if (!clipBBox.isInside(tileBBox)) {
2477 // This table entry does not lie completely inside the clipping region
2478 // and must be clipped.
2479 if (isChild(i)) {
2480 getChild(i).clip(clipBBox, mBackground);
2481 } else {
2482 // Replace this tile with a background tile, then fill the clip region
2483 // with the tile's original value. (This might create a child branch.)
2484 tileBBox.intersect(clipBBox);
2485 const Tile& origTile = getTile(i);
2486 setTile(this->findCoord(xyz), bgTile);
2487 this->sparseFill(tileBBox, origTile.value, origTile.active);
2488 }
2489 } else {
2490 // This table entry lies completely inside the clipping region. Leave it intact.
2491 }
2492 }
2493 this->prune(); // also erases root-level background tiles
2494}
2495
2496
2497////////////////////////////////////////
2498
2499
2500template<typename ChildT>
2501inline void
2503{
2504 bool state = false;
2505 ValueType value = zeroVal<ValueType>();
2506 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2507 if (this->isTile(i)) continue;
2508 this->getChild(i).prune(tolerance);
2509 if (this->getChild(i).isConstant(value, state, tolerance)) {
2510 this->setTile(i, Tile(value, state));
2511 }
2512 }
2513 this->eraseBackgroundTiles();
2514}
2515
2516
2517////////////////////////////////////////
2518
2519
2520template<typename ChildT>
2521template<typename NodeT>
2522inline NodeT*
2523RootNode<ChildT>::stealNode(const Coord& xyz, const ValueType& value, bool state)
2524{
2525 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2526 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2528 MapIter iter = this->findCoord(xyz);
2529 if (iter == mTable.end() || isTile(iter)) return nullptr;
2530 return (std::is_same<NodeT, ChildT>::value)
2531 ? reinterpret_cast<NodeT*>(&stealChild(iter, Tile(value, state)))
2532 : getChild(iter).template stealNode<NodeT>(xyz, value, state);
2534}
2535
2536
2537////////////////////////////////////////
2538
2539
2540template<typename ChildT>
2541inline void
2543{
2544 if (leaf == nullptr) return;
2545 ChildT* child = nullptr;
2546 const Coord& xyz = leaf->origin();
2547 const Coord key = this->coordToKey(xyz);
2548 MapIter iter = this->findKey(key);
2549 if (iter == mTable.end()) {
2550 if (ChildT::LEVEL>0) {
2551 child = new ChildT(xyz, mBackground, false);
2552 } else {
2553 child = reinterpret_cast<ChildT*>(leaf);
2554 }
2555 mTable.emplace(key, *child);
2556 } else if (isChild(iter)) {
2557 if (ChildT::LEVEL>0) {
2558 child = &getChild(iter);
2559 } else {
2560 child = reinterpret_cast<ChildT*>(leaf);
2561 setChild(iter, *child);//this also deletes the existing child node
2562 }
2563 } else {//tile
2564 if (ChildT::LEVEL>0) {
2565 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2566 } else {
2567 child = reinterpret_cast<ChildT*>(leaf);
2568 }
2569 setChild(iter, *child);
2570 }
2571 child->addLeaf(leaf);
2572}
2573
2574
2575template<typename ChildT>
2576template<typename AccessorT>
2577inline void
2579{
2580 if (leaf == nullptr) return;
2581 ChildT* child = nullptr;
2582 const Coord& xyz = leaf->origin();
2583 const Coord key = this->coordToKey(xyz);
2584 MapIter iter = this->findKey(key);
2585 if (iter == mTable.end()) {
2586 if (ChildT::LEVEL>0) {
2587 child = new ChildT(xyz, mBackground, false);
2588 } else {
2589 child = reinterpret_cast<ChildT*>(leaf);
2590 }
2591 mTable.emplace(key, *child);
2592 } else if (isChild(iter)) {
2593 if (ChildT::LEVEL>0) {
2594 child = &getChild(iter);
2595 } else {
2596 child = reinterpret_cast<ChildT*>(leaf);
2597 setChild(iter, *child);//this also deletes the existing child node
2598 }
2599 } else {//tile
2600 if (ChildT::LEVEL>0) {
2601 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2602 } else {
2603 child = reinterpret_cast<ChildT*>(leaf);
2604 }
2605 setChild(iter, *child);
2606 }
2607 acc.insert(xyz, child);
2608 child->addLeafAndCache(leaf, acc);
2609}
2610
2611template<typename ChildT>
2612inline bool
2614{
2615 if (!child) return false;
2616 const Coord& xyz = child->origin();
2617 const Coord key = this->coordToKey(xyz);
2618 MapIter iter = this->findKey(key);
2619 if (iter == mTable.end()) {//background
2620 mTable.emplace(key, *child);
2621 } else {//child or tile
2622 setChild(iter, *child);//this also deletes the existing child node
2623 }
2624 return true;
2625}
2626
2627template<typename ChildT>
2628inline void
2630{
2631 if (origin != Coord(0,0,0)) {
2632 OPENVDB_THROW(ValueError, "RootNode::setOrigin: non-zero offsets are currently not supported");
2633 }
2634 mOrigin = origin;
2635}
2636
2637template<typename ChildT>
2638inline void
2639RootNode<ChildT>::addTile(const Coord& xyz, const ValueType& value, bool state)
2640{
2641 const Coord key = this->coordToKey(xyz);
2642 MapIter iter = this->findKey(key);
2643 if (iter == mTable.end()) {//background
2644 mTable.emplace(key, Tile(value, state));
2645 } else {//child or tile
2646 setTile(iter, Tile(value, state));//this also deletes the existing child node
2647 }
2648}
2649
2650template<typename ChildT>
2651inline void
2653 const ValueType& value, bool state)
2654{
2655 if (LEVEL >= level) {
2656 const Coord key = this->coordToKey(xyz);
2657 MapIter iter = this->findKey(key);
2658 if (iter == mTable.end()) {//background
2659 if (LEVEL > level) {
2660 ChildT* child = new ChildT(xyz, mBackground, false);
2661 mTable.emplace(key, *child);
2662 child->addTile(level, xyz, value, state);
2663 } else {
2664 mTable.emplace(key, Tile(value, state));
2665 }
2666 } else if (isChild(iter)) {//child
2667 if (LEVEL > level) {
2668 getChild(iter).addTile(level, xyz, value, state);
2669 } else {
2670 setTile(iter, Tile(value, state));//this also deletes the existing child node
2671 }
2672 } else {//tile
2673 if (LEVEL > level) {
2674 ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2675 setChild(iter, *child);
2676 child->addTile(level, xyz, value, state);
2677 } else {
2678 setTile(iter, Tile(value, state));
2679 }
2680 }
2681 }
2682}
2683
2684
2685template<typename ChildT>
2686template<typename AccessorT>
2687inline void
2689 bool state, AccessorT& acc)
2690{
2691 if (LEVEL >= level) {
2692 const Coord key = this->coordToKey(xyz);
2693 MapIter iter = this->findKey(key);
2694 if (iter == mTable.end()) {//background
2695 if (LEVEL > level) {
2696 ChildT* child = new ChildT(xyz, mBackground, false);
2697 acc.insert(xyz, child);
2698 mTable.emplace(key, *child);
2699 child->addTileAndCache(level, xyz, value, state, acc);
2700 } else {
2701 mTable.emplace(key, Tile(value, state));
2702 }
2703 } else if (isChild(iter)) {//child
2704 if (LEVEL > level) {
2705 ChildT* child = &getChild(iter);
2706 acc.insert(xyz, child);
2707 child->addTileAndCache(level, xyz, value, state, acc);
2708 } else {
2709 setTile(iter, Tile(value, state));//this also deletes the existing child node
2710 }
2711 } else {//tile
2712 if (LEVEL > level) {
2713 ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2714 acc.insert(xyz, child);
2715 setChild(iter, *child);
2716 child->addTileAndCache(level, xyz, value, state, acc);
2717 } else {
2718 setTile(iter, Tile(value, state));
2719 }
2720 }
2721 }
2722}
2723
2724
2725template<typename ChildT>
2726inline bool
2728{
2729 Coord key = this->coordToKey(xyz);
2730 MapIter iter = this->findKey(key);
2731 if (iter != mTable.end()) {
2732 // the child must be deleted to prevent a memory leak
2733 if (isChild(iter)) delete iter->second.child;
2734 mTable.erase(iter);
2735 return true;
2736 }
2737 return false;
2738}
2739
2740
2741////////////////////////////////////////
2742
2743
2744template<typename ChildT>
2745inline typename ChildT::LeafNodeType*
2747{
2748 ChildT* child = nullptr;
2749 const Coord key = this->coordToKey(xyz);
2750 MapIter iter = this->findKey(key);
2751 if (iter == mTable.end()) {
2752 child = new ChildT(xyz, mBackground, false);
2753 mTable.emplace(key, *child);
2754 } else if (isChild(iter)) {
2755 child = &getChild(iter);
2756 } else {
2757 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2758 setChild(iter, *child);
2759 }
2760 return child->touchLeaf(xyz);
2761}
2762
2763
2764template<typename ChildT>
2765template<typename AccessorT>
2766inline typename ChildT::LeafNodeType*
2768{
2769 ChildT* child = nullptr;
2770 const Coord key = this->coordToKey(xyz);
2771 MapIter iter = this->findKey(key);
2772 if (iter == mTable.end()) {
2773 child = new ChildT(xyz, mBackground, false);
2774 mTable.emplace(key, *child);
2775 } else if (isChild(iter)) {
2776 child = &getChild(iter);
2777 } else {
2778 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2779 setChild(iter, *child);
2780 }
2781 acc.insert(xyz, child);
2782 return child->touchLeafAndCache(xyz, acc);
2783}
2784
2785
2786////////////////////////////////////////
2787
2788
2789template<typename ChildT>
2790template<typename NodeT>
2791inline NodeT*
2793{
2794 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2795 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2797 MapIter iter = this->findCoord(xyz);
2798 if (iter == mTable.end() || isTile(iter)) return nullptr;
2799 ChildT* child = &getChild(iter);
2800 return (std::is_same<NodeT, ChildT>::value)
2801 ? reinterpret_cast<NodeT*>(child)
2802 : child->template probeNode<NodeT>(xyz);
2804}
2805
2806
2807template<typename ChildT>
2808template<typename NodeT>
2809inline const NodeT*
2811{
2812 return this->template probeConstNode<NodeT>(xyz);
2813}
2814
2815
2816template<typename ChildT>
2817template<typename NodeT>
2818inline const NodeT*
2820{
2821 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2822 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2824 MapCIter iter = this->findCoord(xyz);
2825 if (iter == mTable.end() || isTile(iter)) return nullptr;
2826 const ChildT* child = &getChild(iter);
2827 return (std::is_same<NodeT, ChildT>::value)
2828 ? reinterpret_cast<const NodeT*>(child)
2829 : child->template probeConstNode<NodeT>(xyz);
2831}
2832
2833
2834template<typename ChildT>
2835inline bool
2836RootNode<ChildT>::probe(const Coord& xyz, ChildNodeType*& child, ValueType& value, bool& active)
2837{
2838 MapIter iter = this->findCoord(xyz);
2839 if (iter == mTable.end()) {
2840 child = nullptr;
2841 return false;
2842 } else if (isChild(iter)) {
2843 child = &getChild(iter);
2844 return true;
2845 }
2846 const Tile& tile = getTile(iter);
2847 child = nullptr;
2848 value = tile.value;
2849 active = tile.active;
2850 return true;
2851}
2852
2853
2854template<typename ChildT>
2855inline bool
2856RootNode<ChildT>::probeConst(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const
2857{
2858 MapCIter iter = this->findCoord(xyz);
2859 if (iter == mTable.end()) {
2860 child = nullptr;
2861 return false;
2862 } else if (isChild(iter)) {
2863 child = &getChild(iter);
2864 return true;
2865 }
2866 const Tile& tile = getTile(iter);
2867 child = nullptr;
2868 value = tile.value;
2869 active = tile.active;
2870 return true;
2871}
2872
2873
2874template<typename ChildT>
2875inline ChildT*
2877{
2878 return this->template probeNode<ChildT>(xyz);
2879}
2880
2881
2882template<typename ChildT>
2883inline const ChildT*
2885{
2886 return this->template probeConstNode<ChildT>(xyz);
2887}
2888
2889
2890template<typename ChildT>
2891inline typename ChildT::LeafNodeType*
2893{
2894 return this->template probeNode<LeafNodeType>(xyz);
2895}
2896
2897
2898template<typename ChildT>
2899inline const typename ChildT::LeafNodeType*
2901{
2902 return this->template probeConstNode<LeafNodeType>(xyz);
2903}
2904
2905
2906template<typename ChildT>
2907template<typename AccessorT>
2908inline typename ChildT::LeafNodeType*
2910{
2911 return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
2912}
2913
2914
2915template<typename ChildT>
2916template<typename AccessorT>
2917inline const typename ChildT::LeafNodeType*
2918RootNode<ChildT>::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const
2919{
2920 return this->template probeConstNodeAndCache<LeafNodeType>(xyz, acc);
2921}
2922
2923
2924template<typename ChildT>
2925template<typename AccessorT>
2926inline const typename ChildT::LeafNodeType*
2927RootNode<ChildT>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
2928{
2929 return this->probeConstLeafAndCache(xyz, acc);
2930}
2931
2932
2933template<typename ChildT>
2934template<typename NodeT, typename AccessorT>
2935inline NodeT*
2937{
2938 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2939 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2941 MapIter iter = this->findCoord(xyz);
2942 if (iter == mTable.end() || isTile(iter)) return nullptr;
2943 ChildT* child = &getChild(iter);
2944 acc.insert(xyz, child);
2945 return (std::is_same<NodeT, ChildT>::value)
2946 ? reinterpret_cast<NodeT*>(child)
2947 : child->template probeNodeAndCache<NodeT>(xyz, acc);
2949}
2950
2951
2952template<typename ChildT>
2953template<typename NodeT,typename AccessorT>
2954inline const NodeT*
2955RootNode<ChildT>::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const
2956{
2957 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2958 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2960 MapCIter iter = this->findCoord(xyz);
2961 if (iter == mTable.end() || isTile(iter)) return nullptr;
2962 const ChildT* child = &getChild(iter);
2963 acc.insert(xyz, child);
2964 return (std::is_same<NodeT, ChildT>::value)
2965 ? reinterpret_cast<const NodeT*>(child)
2966 : child->template probeConstNodeAndCache<NodeT>(xyz, acc);
2968}
2969
2970
2971////////////////////////////////////////
2972
2973
2974template<typename ChildT>
2975inline const typename ChildT::ValueType&
2977{
2978 MapCIter iter = this->findCoord(xyz);
2979 OPENVDB_ASSERT(iter != mTable.end());
2980 OPENVDB_ASSERT(isTile(iter));
2981 return getTile(iter).value;
2982}
2983
2984
2985template<typename ChildT>
2986inline bool
2988{
2989 MapCIter iter = this->findCoord(xyz);
2990 OPENVDB_ASSERT(iter != mTable.end());
2991 OPENVDB_ASSERT(isTile(iter));
2992 const Tile& tile = getTile(iter);
2993 value = tile.value;
2994 return tile.active;
2995}
2996
2997
2998template<typename ChildT>
2999inline ChildT*
3001{
3002 MapIter iter = this->findCoord(xyz);
3003 OPENVDB_ASSERT(iter != mTable.end());
3004 OPENVDB_ASSERT(isChild(iter));
3005 return &getChild(iter);
3006}
3007
3008
3009template<typename ChildT>
3010inline const ChildT*
3012{
3013 MapCIter iter = this->findCoord(xyz);
3014 OPENVDB_ASSERT(iter != mTable.end());
3015 OPENVDB_ASSERT(isChild(iter));
3016 return &getChild(iter);
3017}
3018
3019
3020template<typename ChildT>
3021inline const ChildT*
3023{
3024 return this->getConstChildUnsafe(xyz);
3025}
3026
3027
3028////////////////////////////////////////
3029
3030
3031template<typename ChildT>
3032template<typename ArrayT>
3033inline void
3035{
3036 using NodePtr = typename ArrayT::value_type;
3037 static_assert(std::is_pointer<NodePtr>::value,
3038 "argument to getNodes() must be a pointer array");
3039 using NodeType = typename std::remove_pointer<NodePtr>::type;
3040 using NonConstNodeType = typename std::remove_const<NodeType>::type;
3041 static_assert(NodeChainType::template Contains<NonConstNodeType>,
3042 "can't extract non-const nodes from a const tree");
3043 using ArrayChildT = typename std::conditional<
3044 std::is_const<NodeType>::value, const ChildT, ChildT>::type;
3045
3046 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
3047 if (ChildT* child = iter->second.child) {
3049 if (std::is_same<NodePtr, ArrayChildT*>::value) {
3050 array.push_back(reinterpret_cast<NodePtr>(iter->second.child));
3051 } else {
3052 child->getNodes(array);//descent
3053 }
3055 }
3056 }
3057}
3058
3059template<typename ChildT>
3060template<typename ArrayT>
3061inline void
3062RootNode<ChildT>::getNodes(ArrayT& array) const
3063{
3064 using NodePtr = typename ArrayT::value_type;
3065 static_assert(std::is_pointer<NodePtr>::value,
3066 "argument to getNodes() must be a pointer array");
3067 using NodeType = typename std::remove_pointer<NodePtr>::type;
3068 static_assert(std::is_const<NodeType>::value,
3069 "argument to getNodes() must be an array of const node pointers");
3070 using NonConstNodeType = typename std::remove_const<NodeType>::type;
3071 static_assert(NodeChainType::template Contains<NonConstNodeType>,
3072 "can't extract non-const nodes from a const tree");
3073
3074 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
3075 if (const ChildNodeType *child = iter->second.child) {
3077 if (std::is_same<NodePtr, const ChildT*>::value) {
3078 array.push_back(reinterpret_cast<NodePtr>(iter->second.child));
3079 } else {
3080 child->getNodes(array);//descent
3081 }
3083 }
3084 }
3085}
3086
3087////////////////////////////////////////
3088
3089template<typename ChildT>
3090template<typename ArrayT>
3091inline void
3092RootNode<ChildT>::stealNodes(ArrayT& array, const ValueType& value, bool state)
3093{
3094 using NodePtr = typename ArrayT::value_type;
3095 static_assert(std::is_pointer<NodePtr>::value,
3096 "argument to stealNodes() must be a pointer array");
3097 using NodeType = typename std::remove_pointer<NodePtr>::type;
3098 using NonConstNodeType = typename std::remove_const<NodeType>::type;
3099 static_assert(NodeChainType::template Contains<NonConstNodeType>,
3100 "can't extract non-const nodes from a const tree");
3101 using ArrayChildT = typename std::conditional<
3102 std::is_const<NodeType>::value, const ChildT, ChildT>::type;
3103
3104 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
3105 if (ChildT* child = iter->second.child) {
3107 if (std::is_same<NodePtr, ArrayChildT*>::value) {
3108 array.push_back(reinterpret_cast<NodePtr>(&stealChild(iter, Tile(value, state))));
3109 } else {
3110 child->stealNodes(array, value, state);//descent
3111 }
3113 }
3114 }
3115}
3116
3117
3118////////////////////////////////////////
3119
3120
3121template<typename ChildT>
3122template<MergePolicy Policy>
3123inline void
3125{
3127
3128 switch (Policy) {
3129
3130 default:
3132 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3133 MapIter j = mTable.find(i->first);
3134 if (other.isChild(i)) {
3135 if (j == mTable.end()) { // insert other node's child
3136 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3137 child.resetBackground(other.mBackground, mBackground);
3138 mTable.emplace(i->first, child);
3139 } else if (isTile(j)) {
3140 if (isTileOff(j)) { // replace inactive tile with other node's child
3141 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3142 child.resetBackground(other.mBackground, mBackground);
3143 setChild(j, child);
3144 }
3145 } else { // merge both child nodes
3146 getChild(j).template merge<MERGE_ACTIVE_STATES>(getChild(i),
3147 other.mBackground, mBackground);
3148 }
3149 } else if (other.isTileOn(i)) {
3150 if (j == mTable.end()) { // insert other node's active tile
3151 mTable.emplace(i->first, i->second);
3152 } else if (!isTileOn(j)) {
3153 // Replace anything except an active tile with the other node's active tile.
3154 setTile(j, Tile(other.getTile(i).value, true));
3155 }
3156 }
3157 }
3158 break;
3159
3160 case MERGE_NODES:
3161 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3162 MapIter j = mTable.find(i->first);
3163 if (other.isChild(i)) {
3164 if (j == mTable.end()) { // insert other node's child
3165 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3166 child.resetBackground(other.mBackground, mBackground);
3167 mTable.emplace(i->first, child);
3168 } else if (isTile(j)) { // replace tile with other node's child
3169 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3170 child.resetBackground(other.mBackground, mBackground);
3171 setChild(j, child);
3172 } else { // merge both child nodes
3173 getChild(j).template merge<MERGE_NODES>(
3174 getChild(i), other.mBackground, mBackground);
3175 }
3176 }
3177 }
3178 break;
3179
3181 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3182 MapIter j = mTable.find(i->first);
3183 if (other.isChild(i)) {
3184 if (j == mTable.end()) {
3185 // Steal and insert the other node's child.
3186 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3187 child.resetBackground(other.mBackground, mBackground);
3188 mTable.emplace(i->first, child);
3189 } else if (isTile(j)) {
3190 // Replace this node's tile with the other node's child.
3191 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
3192 child.resetBackground(other.mBackground, mBackground);
3193 const Tile tile = getTile(j);
3194 setChild(j, child);
3195 if (tile.active) {
3196 // Merge the other node's child with this node's active tile.
3198 tile.value, tile.active);
3199 }
3200 } else /*if (isChild(j))*/ {
3201 // Merge the other node's child into this node's child.
3202 getChild(j).template merge<MERGE_ACTIVE_STATES_AND_NODES>(getChild(i),
3203 other.mBackground, mBackground);
3204 }
3205 } else if (other.isTileOn(i)) {
3206 if (j == mTable.end()) {
3207 // Insert a copy of the other node's active tile.
3208 mTable.emplace(i->first, i->second);
3209 } else if (isTileOff(j)) {
3210 // Replace this node's inactive tile with a copy of the other's active tile.
3211 setTile(j, Tile(other.getTile(i).value, true));
3212 } else if (isChild(j)) {
3213 // Merge the other node's active tile into this node's child.
3214 const Tile& tile = getTile(i);
3215 getChild(j).template merge<MERGE_ACTIVE_STATES_AND_NODES>(
3216 tile.value, tile.active);
3217 }
3218 } // else if (other.isTileOff(i)) {} // ignore the other node's inactive tiles
3219 }
3220 break;
3221 }
3222
3223 // Empty the other tree so as not to leave it in a partially cannibalized state.
3224 other.clear();
3225
3227}
3228
3229
3230////////////////////////////////////////
3231
3232
3233template<typename ChildT>
3234template<typename OtherChildType>
3235inline void
3236RootNode<ChildT>::topologyUnion(const RootNode<OtherChildType>& other, const bool preserveTiles)
3237{
3238 using OtherRootT = RootNode<OtherChildType>;
3239 using OtherCIterT = typename OtherRootT::MapCIter;
3240
3241 enforceSameConfiguration(other);
3242
3243 for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3244 MapIter j = mTable.find(i->first);
3245 if (other.isChild(i)) {
3246 if (j == mTable.end()) { // create child branch with identical topology
3247 mTable.emplace(i->first,
3248 *(new ChildT(other.getChild(i), mBackground, TopologyCopy())));
3249 } else if (this->isChild(j)) { // union with child branch
3250 this->getChild(j).topologyUnion(other.getChild(i), preserveTiles);
3251 } else {// this is a tile so replace it with a child branch with identical topology
3252 if (!preserveTiles || this->isTileOff(j)) { // force child topology
3253 ChildT* child = new ChildT(
3254 other.getChild(i), this->getTile(j).value, TopologyCopy());
3255 if (this->isTileOn(j)) child->setValuesOn();//this is an active tile
3256 this->setChild(j, *child);
3257 }
3258 }
3259 } else if (other.isTileOn(i)) { // other is an active tile
3260 if (j == mTable.end()) { // insert an active tile
3261 mTable.emplace(i->first, Tile(mBackground, true));
3262 } else if (this->isChild(j)) {
3263 this->getChild(j).setValuesOn();
3264 } else if (this->isTileOff(j)) {
3265 this->setTile(j, Tile(this->getTile(j).value, true));
3266 }
3267 }
3268 }
3269}
3270
3271template<typename ChildT>
3272template<typename OtherChildType>
3273inline void
3275{
3276 using OtherRootT = RootNode<OtherChildType>;
3277 using OtherCIterT = typename OtherRootT::MapCIter;
3278
3279 enforceSameConfiguration(other);
3280
3281 std::set<Coord> tmp;//keys to erase
3282 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
3283 OtherCIterT j = other.mTable.find(i->first);
3284 if (this->isChild(i)) {
3285 if (j == other.mTable.end() || other.isTileOff(j)) {
3286 tmp.insert(i->first);//delete child branch
3287 } else if (other.isChild(j)) { // intersect with child branch
3288 this->getChild(i).topologyIntersection(other.getChild(j), mBackground);
3289 }
3290 } else if (this->isTileOn(i)) {
3291 if (j == other.mTable.end() || other.isTileOff(j)) {
3292 this->setTile(i, Tile(this->getTile(i).value, false));//turn inactive
3293 } else if (other.isChild(j)) { //replace with a child branch with identical topology
3294 ChildT* child =
3295 new ChildT(other.getChild(j), this->getTile(i).value, TopologyCopy());
3296 this->setChild(i, *child);
3297 }
3298 }
3299 }
3300 for (std::set<Coord>::iterator i = tmp.begin(), e = tmp.end(); i != e; ++i) {
3301 MapIter it = this->findCoord(*i);
3302 setTile(it, Tile()); // delete any existing child node first
3303 mTable.erase(it);
3304 }
3305}
3306
3307template<typename ChildT>
3308template<typename OtherChildType>
3309inline void
3311{
3312 using OtherRootT = RootNode<OtherChildType>;
3313 using OtherCIterT = typename OtherRootT::MapCIter;
3314
3315 enforceSameConfiguration(other);
3316
3317 for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3318 MapIter j = mTable.find(i->first);
3319 if (other.isChild(i)) {
3320 if (j == mTable.end() || this->isTileOff(j)) {
3321 //do nothing
3322 } else if (this->isChild(j)) { // difference with child branch
3323 this->getChild(j).topologyDifference(other.getChild(i), mBackground);
3324 } else if (this->isTileOn(j)) {
3325 // this is an active tile so create a child node and descent
3326 ChildT* child = new ChildT(j->first, this->getTile(j).value, true);
3327 child->topologyDifference(other.getChild(i), mBackground);
3328 this->setChild(j, *child);
3329 }
3330 } else if (other.isTileOn(i)) { // other is an active tile
3331 if (j == mTable.end() || this->isTileOff(j)) {
3332 // do nothing
3333 } else if (this->isChild(j)) {
3334 setTile(j, Tile()); // delete any existing child node first
3335 mTable.erase(j);
3336 } else if (this->isTileOn(j)) {
3337 this->setTile(j, Tile(this->getTile(j).value, false));
3338 }
3339 }
3340 }
3341}
3342
3343////////////////////////////////////////
3344
3345
3346template<typename ChildT>
3347template<typename CombineOp>
3348inline void
3349RootNode<ChildT>::combine(RootNode& other, CombineOp& op, bool prune)
3350{
3352
3353 CoordSet keys;
3354 this->insertKeys(keys);
3355 other.insertKeys(keys);
3356
3357 for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) {
3358 MapIter iter = findOrAddCoord(*i), otherIter = other.findOrAddCoord(*i);
3359 if (isTile(iter) && isTile(otherIter)) {
3360 // Both this node and the other node have constant values (tiles).
3361 // Combine the two values and store the result as this node's new tile value.
3362 op(args.setARef(getTile(iter).value)
3363 .setAIsActive(isTileOn(iter))
3364 .setBRef(getTile(otherIter).value)
3365 .setBIsActive(isTileOn(otherIter)));
3366 setTile(iter, Tile(args.result(), args.resultIsActive()));
3367
3368 } else if (isChild(iter) && isTile(otherIter)) {
3369 // Combine this node's child with the other node's constant value.
3370 ChildT& child = getChild(iter);
3371 child.combine(getTile(otherIter).value, isTileOn(otherIter), op);
3372
3373 } else if (isTile(iter) && isChild(otherIter)) {
3374 // Combine this node's constant value with the other node's child,
3375 // but use a new functor in which the A and B values are swapped,
3376 // since the constant value is the A value, not the B value.
3378 ChildT& child = getChild(otherIter);
3379 child.combine(getTile(iter).value, isTileOn(iter), swappedOp);
3380
3381 // Steal the other node's child.
3382 setChild(iter, stealChild(otherIter, Tile()));
3383
3384 } else /*if (isChild(iter) && isChild(otherIter))*/ {
3385 // Combine this node's child with the other node's child.
3386 ChildT &child = getChild(iter), &otherChild = getChild(otherIter);
3387 child.combine(otherChild, op);
3388 }
3389 if (prune && isChild(iter)) getChild(iter).prune();
3390 }
3391
3392 // Combine background values.
3393 op(args.setARef(mBackground).setBRef(other.mBackground));
3394 mBackground = args.result();
3395
3396 // Empty the other tree so as not to leave it in a partially cannibalized state.
3397 other.clear();
3398}
3399
3400
3401////////////////////////////////////////
3402
3403
3404// This helper class is a friend of RootNode and is needed so that combine2
3405// can be specialized for compatible and incompatible pairs of RootNode types.
3406template<typename CombineOp, typename RootT, typename OtherRootT, bool Compatible = false>
3408{
3409 static inline void combine2(RootT& self, const RootT&, const OtherRootT& other1,
3410 CombineOp&, bool)
3411 {
3412 // If the two root nodes have different configurations or incompatible ValueTypes,
3413 // throw an exception.
3414 self.enforceSameConfiguration(other1);
3415 self.enforceCompatibleValueTypes(other1);
3416 // One of the above two tests should throw, so we should never get here:
3417 std::ostringstream ostr;
3418 ostr << "cannot combine a " << typeid(OtherRootT).name()
3419 << " into a " << typeid(RootT).name();
3420 OPENVDB_THROW(TypeError, ostr.str());
3421 }
3422};
3423
3424// Specialization for root nodes of compatible types
3425template<typename CombineOp, typename RootT, typename OtherRootT>
3426struct RootNodeCombineHelper<CombineOp, RootT, OtherRootT, /*Compatible=*/true>
3427{
3428 static inline void combine2(RootT& self, const RootT& other0, const OtherRootT& other1,
3429 CombineOp& op, bool prune)
3430 {
3431 self.doCombine2(other0, other1, op, prune);
3432 }
3433};
3434
3435
3436template<typename ChildT>
3437template<typename CombineOp, typename OtherRootNode>
3438inline void
3439RootNode<ChildT>::combine2(const RootNode& other0, const OtherRootNode& other1,
3440 CombineOp& op, bool prune)
3441{
3442 using OtherValueType = typename OtherRootNode::ValueType;
3443 static const bool compatible = (SameConfiguration<OtherRootNode>::value
3444 && CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value);
3446 *this, other0, other1, op, prune);
3447}
3448
3449
3450template<typename ChildT>
3451template<typename CombineOp, typename OtherRootNode>
3452inline void
3453RootNode<ChildT>::doCombine2(const RootNode& other0, const OtherRootNode& other1,
3454 CombineOp& op, bool prune)
3455{
3456 enforceSameConfiguration(other1);
3457
3458 using OtherValueT = typename OtherRootNode::ValueType;
3459 using OtherTileT = typename OtherRootNode::Tile;
3460 using OtherNodeStructT = typename OtherRootNode::NodeStruct;
3461 using OtherMapCIterT = typename OtherRootNode::MapCIter;
3462
3464
3465 CoordSet keys;
3466 other0.insertKeys(keys);
3467 other1.insertKeys(keys);
3468
3469 const NodeStruct bg0(Tile(other0.mBackground, /*active=*/false));
3470 const OtherNodeStructT bg1(OtherTileT(other1.mBackground, /*active=*/false));
3471
3472 for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) {
3473 MapIter thisIter = this->findOrAddCoord(*i);
3474 MapCIter iter0 = other0.findKey(*i);
3475 OtherMapCIterT iter1 = other1.findKey(*i);
3476 const NodeStruct& ns0 = (iter0 != other0.mTable.end()) ? iter0->second : bg0;
3477 const OtherNodeStructT& ns1 = (iter1 != other1.mTable.end()) ? iter1->second : bg1;
3478 if (ns0.isTile() && ns1.isTile()) {
3479 // Both input nodes have constant values (tiles).
3480 // Combine the two values and add a new tile to this node with the result.
3481 op(args.setARef(ns0.tile.value)
3482 .setAIsActive(ns0.isTileOn())
3483 .setBRef(ns1.tile.value)
3484 .setBIsActive(ns1.isTileOn()));
3485 setTile(thisIter, Tile(args.result(), args.resultIsActive()));
3486 } else {
3487 if (!isChild(thisIter)) {
3488 // Add a new child with the same coordinates, etc. as the other node's child.
3489 const Coord& childOrigin =
3490 ns0.isChild() ? ns0.child->origin() : ns1.child->origin();
3491 setChild(thisIter, *(new ChildT(childOrigin, getTile(thisIter).value)));
3492 }
3493 ChildT& child = getChild(thisIter);
3494
3495 if (ns0.isTile()) {
3496 // Combine node1's child with node0's constant value
3497 // and write the result into this node's child.
3498 child.combine2(ns0.tile.value, *ns1.child, ns0.isTileOn(), op);
3499 } else if (ns1.isTile()) {
3500 // Combine node0's child with node1's constant value
3501 // and write the result into this node's child.
3502 child.combine2(*ns0.child, ns1.tile.value, ns1.isTileOn(), op);
3503 } else {
3504 // Combine node0's child with node1's child
3505 // and write the result into this node's child.
3506 child.combine2(*ns0.child, *ns1.child, op);
3507 }
3508 }
3509 if (prune && isChild(thisIter)) getChild(thisIter).prune();
3510 }
3511
3512 // Combine background values.
3513 op(args.setARef(other0.mBackground).setBRef(other1.mBackground));
3514 mBackground = args.result();
3515}
3516
3517
3518} // namespace tree
3519} // namespace OPENVDB_VERSION_NAME
3520} // namespace openvdb
3521
3522#endif // OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
Bracket code with OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN/_END, to inhibit warnings about type conve...
Definition Platform.h:239
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:151
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition Platform.h:240
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:150
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition Types.h:640
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition Types.h:692
const AValueType & result() const
Get the output value.
Definition Types.h:684
CombineArgs & setBIsActive(bool b)
Set the active state of the B value.
Definition Types.h:708
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition Types.h:694
bool resultIsActive() const
Definition Types.h:703
CombineArgs & setAIsActive(bool b)
Set the active state of the A value.
Definition Types.h:706
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition Coord.h:322
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition Coord.h:316
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition Coord.h:176
static bool lessThan(const Coord &a, const Coord &b)
Definition Coord.h:209
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
Definition Exceptions.h:64
Definition Exceptions.h:65
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
void translate(const Coord &t)
Translate this bounding box by (tx, ty, tz).
Definition Coord.h:461
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition Coord.h:421
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:359
const Coord & min() const
Definition Coord.h:324
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition Coord.h:415
const Coord & max() const
Definition Coord.h:325
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition Coord.h:403
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition Coord.h:447
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Int32 y() const
Definition Coord.h:132
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition Coord.h:92
Int32 x() const
Definition Coord.h:131
Coord & setZ(Int32 z)
Definition Coord.h:82
Coord & setY(Int32 y)
Definition Coord.h:81
Int32 z() const
Definition Coord.h:133
Coord & setX(Int32 x)
Definition Coord.h:80
Definition RootNode.h:39
static CoordBBox getNodeBoundingBox()
Return the bounding box of this RootNode, i.e., an infinite bounding box.
Definition RootNode.h:407
void setValueAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1922
DenseIter< RootNode, MapIter, typename SubtreeT::Back, ValueType > ChildAllIter
Definition RootNode.h:365
static bool hasSameConfiguration(const RootNode< OtherChildType > &other)
Return false if the other node's dimensions don't match this node's.
Definition RootNode.h:1451
int getValueDepth(const Coord &xyz) const
Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
Definition RootNode.h:1768
ValueIter< const RootNode, MapCIter, ValueOffPred, const ValueType > ValueOffCIter
Definition RootNode.h:371
RootNode(const RootNode &other)
Definition RootNode.h:75
ChildOnCIter cbeginChildOn() const
Definition RootNode.h:376
ChildOnCIter beginChildOn() const
Definition RootNode.h:379
ChildOnIter beginChildOn()
Definition RootNode.h:382
Index getDepth() const
Definition RootNode.h:463
bool probe(const Coord &xyz, ChildNodeType *&child, ValueType &value, bool &active)
Return a pointer to the root child node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2836
RootNode(const RootNode< OtherChildType > &other, const ValueType &background, TopologyCopy)
Construct a new tree that reproduces the topology and active states of another tree (which may have a...
Definition RootNode.h:1117
bool isValueOn(const Coord &xyz) const
Definition RootNode.h:1712
ValueIter< const RootNode, MapCIter, ValueOnPred, const ValueType > ValueOnCIter
Definition RootNode.h:369
void getIndexRange(CoordBBox &bbox) const
Return the current index range. Both min and max are inclusive.
Definition RootNode.h:1391
void copyToDense(const CoordBBox &bbox, DenseT &dense) const
Copy into a dense grid the values of all voxels, both active and inactive, that intersect a given bou...
Definition RootNode.h:2289
RootNode & operator=(const RootNode &other)
Copy a root node of the same type as this node.
Definition RootNode.h:1214
ValueOffCIter cbeginValueOff() const
Definition RootNode.h:387
LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as probeLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
Index32 transientData() const
Return the transient data value.
Definition RootNode.h:410
bool isBackgroundTile(const MapCIter &) const
Definition RootNode.h:1294
void addLeafAndCache(LeafNodeType *leaf, AccessorT &)
Same as addLeaf() but, if necessary, update the given accessor with pointers to the nodes along the p...
Definition RootNode.h:2578
static Index getChildDim()
Definition RootNode.h:456
const ChildNodeType * getConstChildUnsafe(const Coord &xyz) const
Return the child node at the given coordinate.
Definition RootNode.h:3011
RootNode & operator=(const RootNode< OtherChildType > &other)
Copy a root node of the same tree configuration as this node but a different ValueType.
Coord coordToKey(const Coord &xyz) const
Return a MapType key for the given coordinates, offset by the mOrigin.
Definition RootNode.h:953
void combine(RootNode &other, CombineOp &, bool prune=false)
Definition RootNode.h:3349
bool getTileValueUnsafe(const Coord &xyz, ValueType &value) const
Return the tile value and active state at the given coordinate.
Definition RootNode.h:2987
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition RootNode.h:3034
const ValueType & getTileValueUnsafe(const Coord &xyz) const
Return the tile value at the given coordinate.
Definition RootNode.h:2976
Index64 nonLeafCount() const
Definition RootNode.h:1561
NodeT * stealNode(const Coord &xyz, const ValueType &value, bool state)
Return a pointer to the node of type NodeT that contains voxel (x, y, z) and replace it with a tile o...
Definition RootNode.h:2523
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition RootNode.h:2263
LeafNodeType * touchLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as touchLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
ValueIter< RootNode, MapIter, ValueOffPred, ValueType > ValueOffIter
Definition RootNode.h:370
Index32 activeTileCount() const
Definition RootNode.h:1599
ValueIter< RootNode, MapIter, ValueAllPred, ValueType > ValueAllIter
Definition RootNode.h:372
void topologyUnion(const RootNode< OtherChildType > &other, const bool preserveTiles=false)
Union this tree's set of active values with the active values of the other tree, whose ValueType may ...
Definition RootNode.h:3236
Index64 onLeafVoxelCount() const
Definition RootNode.h:1655
const LeafNodeType * probeConstLeafAndCache(const Coord &xyz, AccessorT &acc) const
void clip(const CoordBBox &)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition RootNode.h:2462
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2892
static bool hasCompatibleValueType(const RootNode< OtherChildType > &other)
Definition RootNode.h:1483
ValueAllCIter cbeginValueAll() const
Definition RootNode.h:388
NodeT * probeNodeAndCache(const Coord &xyz, AccessorT &acc)
Same as probeNode() but, if necessary, update the given accessor with pointers to the nodes along the...
Definition RootNode.h:2936
void prune(const ValueType &tolerance=zeroVal< ValueType >())
Reduce the memory footprint of this tree by replacing with tiles any nodes whose values are all the s...
Definition RootNode.h:2502
typename NodeChain< RootNode, LEVEL >::Type NodeChainType
Definition RootNode.h:49
bool isBackgroundTile(const Tile &) const
Return true if the given tile is inactive and has the background value.
Definition RootNode.h:1280
typename typename SubtreeT::Back::LeafNodeType LeafNodeType
Definition RootNode.h:42
size_t eraseBackgroundTiles()
Remove all background tiles.
Definition RootNode.h:1314
void topologyDifference(const RootNode< OtherChildType > &other)
Difference this tree's set of active values with the active values of the other tree,...
Definition RootNode.h:3310
ValueIter< RootNode, MapIter, ValueOnPred, ValueType > ValueOnIter
Definition RootNode.h:368
ValueOnCIter beginValueOn() const
Definition RootNode.h:389
void merge(RootNode &other)
Efficiently merge another tree into this tree using one of several schemes.
Definition RootNode.h:3124
ChildIter< RootNode, MapIter, ChildOnPred, typename SubtreeT::Back > ChildOnIter
Definition RootNode.h:361
Index64 offLeafVoxelCount() const
Definition RootNode.h:1667
Index getWidth() const
Definition RootNode.h:461
Index getTableSize() const
Return the number of entries in this node's table.
Definition RootNode.h:459
bool probe(const Coord &xyz, const ChildNodeType *&child, ValueType &value, bool &active) const
Definition RootNode.h:749
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile containing voxel (x, y, z) at the specified tree level, creating a new branch if necessary...
Definition RootNode.h:2652
void setOrigin(const Coord &origin)
change the origin on this root node
Definition RootNode.h:2629
void combine2(const RootNode &other0, const OtherRootNode &other1, CombineOp &op, bool prune=false)
Definition RootNode.h:3439
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition RootNode.h:944
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition RootNode.h:2059
void setValueOnlyAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1965
size_t numBackgroundTiles() const
Return the number of background tiles.
Definition RootNode.h:1302
ValueIter< const RootNode, MapCIter, ChildOffPred, ValueType > ChildOffCIter
Definition RootNode.h:364
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates but don't change its active state.
Definition RootNode.h:1945
bool empty() const
Return true if this node's table is either empty or contains only background tiles.
Definition RootNode.h:447
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Definition RootNode.h:2900
ChildNodeType * probeChild(const Coord &xyz)
Return a pointer to the root child node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2876
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition RootNode.h:2155
ValueOffCIter beginValueOff() const
Definition RootNode.h:390
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1877
void addLeaf(LeafNodeType *leaf)
Add the given leaf node to this tree, creating a new branch if necessary. If a leaf node with the sam...
Definition RootNode.h:2542
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
ChildAllCIter cbeginChildAll() const
Definition RootNode.h:378
Index64 leafCount() const
Definition RootNode.h:1549
void addTile(const Coord &xyz, const ValueType &value, bool state)
Add a tile containing voxel (x, y, z) at the root level, deleting the existing branch if necessary.
Definition RootNode.h:2639
ChildAllIter beginChildAll()
Definition RootNode.h:384
bool probeConst(const Coord &xyz, const ChildNodeType *&child, ValueType &value, bool &active) const
Definition RootNode.h:2856
friend struct RootNodeCombineHelper
Definition RootNode.h:964
static Index getLevel()
Definition RootNode.h:454
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition RootNode.h:1855
ValueIter< const RootNode, MapCIter, ValueAllPred, const ValueType > ValueAllCIter
Definition RootNode.h:373
const ChildNodeType * getChildUnsafe(const Coord &xyz) const
Return the child node at the given coordinate.
Definition RootNode.h:3022
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Definition RootNode.h:1732
const NodeT * probeConstNodeAndCache(const Coord &xyz, AccessorT &acc) const
Definition RootNode.h:2955
bool probeValue(const Coord &xyz, ValueType &value) const
Definition RootNode.h:2119
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don't change its value.
Definition RootNode.h:1804
ValueOnIter beginValueOn()
Definition RootNode.h:392
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition RootNode.h:2022
static const Index LEVEL
Definition RootNode.h:46
Index32 inactiveTileCount() const
Definition RootNode.h:1611
ChildOffCIter cbeginChildOff() const
Definition RootNode.h:377
ChildOffIter beginChildOff()
Definition RootNode.h:383
Index64 onVoxelCount() const
Definition RootNode.h:1623
ChildOffCIter beginChildOff() const
Definition RootNode.h:380
void addTileAndCache(Index level, const Coord &xyz, const ValueType &, bool state, AccessorT &)
Same as addTile() but, if necessary, update the given accessor with pointers to the nodes along the p...
Definition RootNode.h:2688
typename typename SubtreeT::Back::ValueType ValueType
Definition RootNode.h:43
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition RootNode.h:1790
void nodeCount(std::vector< Index64 > &vec) const
Definition RootNode.h:1693
ValueOnCIter cbeginValueOn() const
Definition RootNode.h:386
RootNode(const ValueType &background)
Construct a new tree with the given background value.
Definition RootNode.h:1080
const LeafNodeType * probeLeaf(const Coord &xyz) const
Definition RootNode.h:774
Index32 tileCount() const
Definition RootNode.h:1587
Index32 childCount() const
Definition RootNode.h:1575
Index64 onTileCount() const
Definition RootNode.h:1678
RootNode()
Construct a new tree with a background value of 0.
Definition RootNode.h:1071
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active.
Definition RootNode.h:1989
bool isBackgroundTile(const MapIter &) const
Return true if the given iterator points to an inactive tile with the background value.
Definition RootNode.h:1287
~RootNode()
Definition RootNode.h:123
Index64 offVoxelCount() const
Definition RootNode.h:1639
LeafNodeType * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2746
void getNodes(ArrayT &array) const
Definition RootNode.h:3062
RootNode(const RootNode< OtherChildType > &other, const ValueType &background, const ValueType &foreground, TopologyCopy)
Construct a new tree that reproduces the topology and active states of another tree (which may have a...
Definition RootNode.h:1090
typename typename SubtreeT::Back::BuildType BuildType
Definition RootNode.h:44
void setBackground(const ValueType &value, bool updateChildNodes)
Change inactive tiles or voxels with a value equal to +/- the old background to the specified value (...
Definition RootNode.h:1253
ChildNodeType * getChildUnsafe(const Coord &xyz)
Return the child node at the given coordinate.
Definition RootNode.h:3000
DenseIter< const RootNode, MapCIter, const typename SubtreeT::Back, const ValueType > ChildAllCIter
Definition RootNode.h:366
bool hasSameTopology(const RootNode< OtherChildType > &other) const
Return true if the given tree has the same node and active value topology as this tree (but possibly ...
Definition RootNode.h:1404
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value and ensure that those voxels are a...
Definition RootNode.h:2213
const NodeT * probeNode(const Coord &xyz) const
Definition RootNode.h:2810
ChildAllCIter beginChildAll() const
Definition RootNode.h:381
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Definition RootNode.h:1828
void topologyIntersection(const RootNode< OtherChildType > &other)
Intersects this tree's set of active values with the active values of the other tree,...
Definition RootNode.h:3274
void setTransientData(Index32 transientData)
Set the transient data value.
Definition RootNode.h:412
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:
Definition RootNode.h:3092
Index getHeight() const
Definition RootNode.h:462
const LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc) const
bool probeValueAndCache(const Coord &xyz, ValueType &value, AccessorT &) const
Definition RootNode.h:2135
bool addChild(ChildNodeType *child)
Add the given child node at the root level. If a child node with the same origin already exists,...
Definition RootNode.h:2613
const NodeT * probeConstNode(const Coord &xyz) const
Definition RootNode.h:2819
bool hasKey(const Coord &key) const
Return true if this node's mTable contains the given key.
Definition RootNode.h:956
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Expand the specified bbox so it includes the active tiles of this root node as well as all the active...
Definition RootNode.h:1535
const ChildNodeType * probeChild(const Coord &xyz) const
Definition RootNode.h:766
const ValueType & background() const
Definition RootNode.h:429
static void getNodeLog2Dims(std::vector< Index > &dims)
Definition RootNode.h:1367
RootNode(const RootNode< OtherChildType > &other)
Construct a new tree that reproduces the topology and active states of a tree of a different ValueTyp...
Definition RootNode.h:84
ValueOffIter beginValueOff()
Definition RootNode.h:393
ValueIter< RootNode, MapIter, ChildOffPred, const ValueType > ChildOffIter
Definition RootNode.h:363
void sparseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Definition RootNode.h:541
friend struct RootNodeCopyHelper
Definition RootNode.h:963
const ChildNodeType * probeConstChild(const Coord &xyz) const
Definition RootNode.h:2884
typename SubtreeT::Back ChildNodeType
Definition RootNode.h:41
bool deleteChildOrTile(const Coord &xyz)
Delete any child or tile containing voxel (x, y, z) at the root level. Do nothing if no child or tile...
Definition RootNode.h:2727
bool hasActiveTiles() const
Return true if this root node, or any of its child nodes, have active tiles.
Definition RootNode.h:1721
int getValueDepthAndCache(const Coord &xyz, AccessorT &) const
Definition RootNode.h:1778
const ValueType & getValue(const Coord &xyz) const
Definition RootNode.h:1744
Index64 memUsage() const
Return the total amount of memory in bytes occupied by this node and its children.
Definition RootNode.h:1510
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active.
Definition RootNode.h:1902
void stealNodes(ArrayT &array)
Definition RootNode.h:876
bool expand(const Coord &xyz)
Expand this node's table so that (x, y, z) is included in the index range.
Definition RootNode.h:1353
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition RootNode.h:2087
ValueAllCIter beginValueAll() const
Definition RootNode.h:391
NodeT * probeNode(const Coord &xyz)
Return a pointer to the node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2792
ChildIter< const RootNode, MapCIter, ChildOnPred, const typename SubtreeT::Back > ChildOnCIter
Definition RootNode.h:362
ValueAllIter beginValueAll()
Definition RootNode.h:394
friend class RootNode
Definition RootNode.h:961
T truncateRealToHalf(const T &val)
Return the given value truncated to 16-bit float precision.
Definition Compression.h:216
void checkFormatVersion(std::ios_base &)
Throws an IoError if the file format version number is not supported.
void setGridBackgroundValuePtr(std::ios_base &, const void *background)
Specify (a pointer to) the background value of the grid currently being read from or written to the g...
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition Vec3.h:474
Mat3< typename promote< T0, T1 >::type > operator*(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Multiply m0 by m1 and return the resulting matrix.
Definition Mat3.h:597
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
Definition Math.h:428
T negative(const T &val)
Return the unary negation of the given value.
Definition Math.h:139
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition Math.h:465
bool operator!=(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Inequality operator, does exact floating point comparisons.
Definition Vec3.h:482
GridType::Ptr clip(const GridType &grid, const BBoxd &bbox, bool keepInterior=true)
Clip the given grid against a world-space bounding box and return a new grid containing the result.
Definition Clip.h:352
Definition TreeIterator.h:30
Index32 Index
Definition Types.h:34
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
uint32_t Index32
Definition Types.h:32
int32_t Int32
Definition Types.h:36
uint64_t Index64
Definition Types.h:33
@ MERGE_ACTIVE_STATES
Definition Types.h:578
@ MERGE_NODES
Definition Types.h:579
@ MERGE_ACTIVE_STATES_AND_NODES
Definition Types.h:580
const char * typeNameAsString()
Definition Types.h:587
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
CanConvertType<FromType, ToType>::value is true if a value of type ToType can be constructed from a v...
Definition Types.h:459
@ value
Definition Types.h:459
Definition Types.h:731
A list of types (not necessarily unique)
Definition TypeList.h:576
TypeList< typename HeadT::ChildNodeType, HeadT > Type
Definition RootNode.h:1044
NodeChain<RootNodeType, RootNodeType::LEVEL>::Type is a openvdb::TypeList that lists the types of the...
Definition RootNode.h:1036
typename NodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition RootNode.h:1037
typename SubtreeT::template Append< HeadT > Type
Definition RootNode.h:1038
static void combine2(RootT &self, const RootT &other0, const OtherRootT &other1, CombineOp &op, bool prune)
Definition RootNode.h:3428
static void combine2(RootT &self, const RootT &, const OtherRootT &other1, CombineOp &, bool)
Definition RootNode.h:3409
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition RootNode.h:1169
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition RootNode.h:1151
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a RootNod...
Definition RootNode.h:64
static const bool value
Definition RootNode.h:65
ValueConverter<T>::Type is the type of a RootNode having the same child hierarchy as this node but a ...
Definition RootNode.h:56
RootNode< typename ChildType::template ValueConverter< OtherValueType >::Type > Type
Definition RootNode.h:57
Definition RootNode.h:1055
static const bool value
Definition RootNode.h:1056
#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:291