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