OpenVDB: openvdb/tree/RootNode.h Source File

OpenVDB 12.0.1 |

Loading...
Searching...
No Matches
RootNode.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3///
4/// @file RootNode.h
5///
6/// @brief The root node of an OpenVDB tree
7
8#ifndef OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
9#define OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
10
11#include <openvdb/Exceptions.h>
12#include <openvdb/Types.h>
13#include <openvdb/io/Compression.h> // for truncateRealToHalf()
14#include <openvdb/math/Math.h> // for isZero(), isExactlyEqual(), etc.
15#include <openvdb/math/BBox.h>
16#include <openvdb/util/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
26namespace openvdb {
27 OPENVDB_USE_VERSION_NAMESPACE
28namespace OPENVDB_VERSION_NAME {
29namespace tree {
30
31// Forward declarations
32template<typename HeadType, int HeadLevel> struct NodeChain;
33template<typename, typename> struct SameRootConfig;
34template<typename, typename, bool> struct RootNodeCopyHelper;
35template<typename, typename, typename, bool> struct RootNodeCombineHelper;
36
37
38template<typename ChildType>
39 class RootNode
40{
41public:
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.
50 using NodeChainType = typename NodeChain<RootNode, LEVEL>::Type;
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 {
58 using Type = RootNode<typename ChildType::template ValueConverter<OtherValueType>::Type>;
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>
65 struct SameConfiguration {
66 static const bool value = SameRootConfig<ChildNodeType, OtherNodeType>::value;
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>
96 RootNode(const RootNode<OtherChildType>& other,
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
126private:
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
361public:
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
959private:
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
1036template<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
1043template<typename HeadT>
1044 struct NodeChain<HeadT, /*HeadLevel=*/1> {
1045 using Type = TypeList<typename HeadT::ChildNodeType, HeadT>;
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)
1055template<typename ChildT1, typename NodeT2>
1056 struct SameRootConfig {
1057 static const bool value = false;
1058};
1059
1060template<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
1070template<typename ChildT>
1071inline
1072 RootNode<ChildT>::RootNode()
1073 : mBackground(zeroVal<ValueType>())
1074 , mOrigin(0, 0, 0)
1075{
1076}
1077
1078
1079template<typename ChildT>
1080inline
1081 RootNode<ChildT>::RootNode(const ValueType& background)
1082 : mBackground(background)
1083 , mOrigin(0, 0, 0)
1084{
1085}
1086
1087
1088template<typename ChildT>
1089template<typename OtherChildType>
1090inline
1091 RootNode<ChildT>::RootNode(const RootNode<OtherChildType>& other,
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
1115template<typename ChildT>
1116template<typename OtherChildType>
1117inline
1118 RootNode<ChildT>::RootNode(const RootNode<OtherChildType>& other,
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.
1149template<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
1167template<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
1209template<typename ChildT>
1210inline RootNode<ChildT>&
1211RootNode<ChildT>::operator=(const RootNode& other)
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
1232template<typename ChildT>
1233template<typename OtherChildType>
1234inline RootNode<ChildT>&
1235 RootNode<ChildT>::operator=(const RootNode<OtherChildType>& other)
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);
1241 RootNodeCopyHelper<RootNode, OtherRootT, compatible>::copyWithValueConversion(*this, other);
1242 return *this;
1243}
1244
1245
1246////////////////////////////////////////
1247
1248template<typename ChildT>
1249inline void
1250RootNode<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
1275template<typename ChildT>
1276inline bool
1277RootNode<ChildT>::isBackgroundTile(const Tile& tile) const
1278{
1279 return !tile.active && math::isApproxEqual(tile.value, mBackground);
1280}
1281
1282template<typename ChildT>
1283inline bool
1284 RootNode<ChildT>::isBackgroundTile(const MapIter& iter) const
1285{
1286 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1287}
1288
1289template<typename ChildT>
1290inline bool
1291 RootNode<ChildT>::isBackgroundTile(const MapCIter& iter) const
1292{
1293 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1294}
1295
1296
1297template<typename ChildT>
1298inline size_t
1299RootNode<ChildT>::numBackgroundTiles() const
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
1309template<typename ChildT>
1310inline size_t
1311RootNode<ChildT>::eraseBackgroundTiles()
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
1327template<typename ChildT>
1328inline void
1329RootNode<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
1337template<typename ChildT>
1338inline typename RootNode<ChildT>::MapIter
1339RootNode<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
1348template<typename ChildT>
1349inline bool
1350RootNode<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
1362template<typename ChildT>
1363inline void
1364RootNode<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
1371template<typename ChildT>
1372inline Coord
1373RootNode<ChildT>::getMinIndex() const
1374{
1375 return mTable.empty() ? Coord(0) : mTable.begin()->first;
1376}
1377
1378template<typename ChildT>
1379inline Coord
1380RootNode<ChildT>::getMaxIndex() const
1381{
1382 return mTable.empty() ? Coord(0) : mTable.rbegin()->first + Coord(ChildT::DIM - 1);
1383}
1384
1385
1386template<typename ChildT>
1387inline void
1388RootNode<ChildT>::getIndexRange(CoordBBox& bbox) const
1389{
1390 bbox.min() = this->getMinIndex();
1391 bbox.max() = this->getMaxIndex();
1392}
1393
1394
1395////////////////////////////////////////
1396
1397
1398template<typename ChildT>
1399template<typename OtherChildType>
1400inline bool
1401RootNode<ChildT>::hasSameTopology(const RootNode<OtherChildType>& other) const
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
1445template<typename ChildT>
1446template<typename OtherChildType>
1447inline bool
1448RootNode<ChildT>::hasSameConfiguration(const RootNode<OtherChildType>&)
1449{
1450 std::vector<Index> thisDims, otherDims;
1451 RootNode::getNodeLog2Dims(thisDims);
1452 RootNode<OtherChildType>::getNodeLog2Dims(otherDims);
1453 return (thisDims == otherDims);
1454}
1455
1456
1457template<typename ChildT>
1458template<typename OtherChildType>
1459inline void
1460RootNode<ChildT>::enforceSameConfiguration(const RootNode<OtherChildType>&)
1461{
1462 std::vector<Index> thisDims, otherDims;
1463 RootNode::getNodeLog2Dims(thisDims);
1464 RootNode<OtherChildType>::getNodeLog2Dims(otherDims);
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
1477template<typename ChildT>
1478template<typename OtherChildType>
1479inline bool
1480RootNode<ChildT>::hasCompatibleValueType(const RootNode<OtherChildType>&)
1481{
1482 using OtherValueType = typename OtherChildType::ValueType;
1483 return CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value;
1484}
1485
1486
1487template<typename ChildT>
1488template<typename OtherChildType>
1489inline void
1490RootNode<ChildT>::enforceCompatibleValueTypes(const RootNode<OtherChildType>&)
1491{
1492 using OtherValueType = typename OtherChildType::ValueType;
1493 if (!CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value) {
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
1505template<typename ChildT>
1506inline Index64
1507RootNode<ChildT>::memUsage() const
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
1519template<typename ChildT>
1520inline void
1521RootNode<ChildT>::clear()
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
1530template<typename ChildT>
1531inline void
1532RootNode<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
1544template<typename ChildT>
1545inline Index64
1546RootNode<ChildT>::leafCount() const
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
1556template<typename ChildT>
1557inline Index64
1558RootNode<ChildT>::nonLeafCount() const
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
1570template<typename ChildT>
1571inline Index32
1572RootNode<ChildT>::childCount() const
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
1582template<typename ChildT>
1583inline Index32
1584RootNode<ChildT>::tileCount() const
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
1594template<typename ChildT>
1595inline Index32
1596RootNode<ChildT>::activeTileCount() const
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
1606template<typename ChildT>
1607inline Index32
1608RootNode<ChildT>::inactiveTileCount() const
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
1618template<typename ChildT>
1619inline Index64
1620RootNode<ChildT>::onVoxelCount() const
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
1634template<typename ChildT>
1635inline Index64
1636RootNode<ChildT>::offVoxelCount() const
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
1650template<typename ChildT>
1651inline Index64
1652RootNode<ChildT>::onLeafVoxelCount() const
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
1662template<typename ChildT>
1663inline Index64
1664RootNode<ChildT>::offLeafVoxelCount() const
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
1673template<typename ChildT>
1674inline Index64
1675RootNode<ChildT>::onTileCount() const
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
1688template<typename ChildT>
1689inline void
1690RootNode<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
1704template<typename ChildT>
1705inline 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;
1713 OPENVDB_NO_DEPRECATION_WARNING_BEGIN
1714 getChild(i).nodeCount(vec);
1715 OPENVDB_NO_DEPRECATION_WARNING_END
1716 }
1717 }
1718 vec[LEVEL] = 1;// one root node
1719 vec[ChildNodeType::LEVEL] = sum;
1720}
1721
1722////////////////////////////////////////
1723
1724
1725template<typename ChildT>
1726inline bool
1727RootNode<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
1734template<typename ChildT>
1735inline bool
1736RootNode<ChildT>::hasActiveTiles() const
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
1744template<typename ChildT>
1745template<typename AccessorT>
1746inline bool
1747RootNode<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
1757template<typename ChildT>
1758inline const typename ChildT::ValueType&
1759RootNode<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
1766template<typename ChildT>
1767template<typename AccessorT>
1768inline 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
1781template<typename ChildT>
1782inline int
1783RootNode<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
1790template<typename ChildT>
1791template<typename AccessorT>
1792inline int
1793RootNode<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
1803template<typename ChildT>
1804inline void
1805RootNode<ChildT>::setValueOff(const Coord& xyz)
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
1817template<typename ChildT>
1818inline void
1819RootNode<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
1840template<typename ChildT>
1841template<typename AccessorT>
1842inline void
1843RootNode<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
1868template<typename ChildT>
1869inline 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
1889template<typename ChildT>
1890template<typename AccessorT>
1891inline void
1892RootNode<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
1915template<typename ChildT>
1916inline void
1917RootNode<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
1934template<typename ChildT>
1935template<typename AccessorT>
1936inline void
1937RootNode<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
1958template<typename ChildT>
1959inline void
1960RootNode<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
1977template<typename ChildT>
1978template<typename AccessorT>
1979inline void
1980RootNode<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
2001template<typename ChildT>
2002template<typename ModifyOp>
2003inline void
2004RootNode<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
2034template<typename ChildT>
2035template<typename ModifyOp, typename AccessorT>
2036inline void
2037RootNode<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
2071template<typename ChildT>
2072template<typename ModifyOp>
2073inline void
2074RootNode<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
2099template<typename ChildT>
2100template<typename ModifyOp, typename AccessorT>
2101inline void
2102RootNode<ChildT>::modifyValueAndActiveStateAndCache(
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
2132template<typename ChildT>
2133inline bool
2134RootNode<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
2147template<typename ChildT>
2148template<typename AccessorT>
2149inline bool
2150RootNode<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
2168template<typename ChildT>
2169inline void
2170RootNode<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
2226template<typename ChildT>
2227inline void
2228RootNode<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
2276template<typename ChildT>
2277inline void
2278RootNode<ChildT>::voxelizeActiveTiles(bool threaded)
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
2301template<typename ChildT>
2302template<typename DenseT>
2303inline void
2304RootNode<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
2346template<typename ChildT>
2347inline bool
2348RootNode<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
2382template<typename ChildT>
2383inline bool
2384RootNode<ChildT>::readTopology(std::istream& is, bool fromHalf)
2385{
2386 // Delete the existing tree.
2387 this->clear();
2388
2389 if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_ROOTNODE_MAP) {
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
2487template<typename ChildT>
2488inline void
2489RootNode<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
2497template<typename ChildT>
2498inline void
2499RootNode<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
2507template<typename ChildT>
2508inline 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
2531template<typename ChildT>
2532inline void
2533RootNode<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
2571template<typename ChildT>
2572inline void
2573RootNode<ChildT>::prune(const ValueType& tolerance)
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
2591template<typename ChildT>
2592template<typename NodeT>
2593inline NodeT*
2594RootNode<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;
2598 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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);
2604 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2605}
2606
2607
2608////////////////////////////////////////
2609
2610
2611template<typename ChildT>
2612inline void
2613RootNode<ChildT>::addLeaf(LeafNodeType* leaf)
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
2646template<typename ChildT>
2647template<typename AccessorT>
2648inline void
2649RootNode<ChildT>::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc)
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
2682template<typename ChildT>
2683inline bool
2684RootNode<ChildT>::addChild(ChildT* child)
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
2698template<typename ChildT>
2699inline void
2700RootNode<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
2708template<typename ChildT>
2709inline void
2710RootNode<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
2721template<typename ChildT>
2722inline 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
2756template<typename ChildT>
2757template<typename AccessorT>
2758inline void
2759RootNode<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
2796template<typename ChildT>
2797inline bool
2798RootNode<ChildT>::deleteChildOrTile(const Coord& xyz)
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
2815template<typename ChildT>
2816inline typename ChildT::LeafNodeType*
2817RootNode<ChildT>::touchLeaf(const Coord& xyz)
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
2835template<typename ChildT>
2836template<typename AccessorT>
2837inline 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
2860template<typename ChildT>
2861template<typename NodeT>
2862inline NodeT*
2863RootNode<ChildT>::probeNode(const Coord& xyz)
2864{
2865 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
2866 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
2867 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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);
2874 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2875}
2876
2877
2878template<typename ChildT>
2879template<typename NodeT>
2880inline const NodeT*
2881 RootNode<ChildT>::probeNode(const Coord& xyz) const
2882{
2883 return this->template probeConstNode<NodeT>(xyz);
2884}
2885
2886
2887template<typename ChildT>
2888template<typename NodeT>
2889inline const NodeT*
2890RootNode<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;
2894 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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);
2901 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2902}
2903
2904
2905template<typename ChildT>
2906inline bool
2907RootNode<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
2925template<typename ChildT>
2926inline bool
2927RootNode<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
2945template<typename ChildT>
2946inline ChildT*
2947RootNode<ChildT>::probeChild(const Coord& xyz)
2948{
2949 return this->template probeNode<ChildT>(xyz);
2950}
2951
2952
2953template<typename ChildT>
2954inline const ChildT*
2955RootNode<ChildT>::probeConstChild(const Coord& xyz) const
2956{
2957 return this->template probeConstNode<ChildT>(xyz);
2958}
2959
2960
2961template<typename ChildT>
2962inline typename ChildT::LeafNodeType*
2963RootNode<ChildT>::probeLeaf(const Coord& xyz)
2964{
2965 return this->template probeNode<LeafNodeType>(xyz);
2966}
2967
2968
2969template<typename ChildT>
2970inline const typename ChildT::LeafNodeType*
2971RootNode<ChildT>::probeConstLeaf(const Coord& xyz) const
2972{
2973 return this->template probeConstNode<LeafNodeType>(xyz);
2974}
2975
2976
2977template<typename ChildT>
2978template<typename AccessorT>
2979inline typename ChildT::LeafNodeType*
2980 RootNode<ChildT>::probeLeafAndCache(const Coord& xyz, AccessorT& acc)
2981{
2982 return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
2983}
2984
2985
2986template<typename ChildT>
2987template<typename AccessorT>
2988inline 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
2995template<typename ChildT>
2996template<typename AccessorT>
2997inline const typename ChildT::LeafNodeType*
2998 RootNode<ChildT>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
2999{
3000 return this->probeConstLeafAndCache(xyz, acc);
3001}
3002
3003
3004template<typename ChildT>
3005template<typename NodeT, typename AccessorT>
3006inline NodeT*
3007RootNode<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;
3011 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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);
3019 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3020}
3021
3022
3023template<typename ChildT>
3024template<typename NodeT,typename AccessorT>
3025inline const NodeT*
3026RootNode<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;
3030 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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);
3038 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3039}
3040
3041
3042////////////////////////////////////////
3043
3044
3045template<typename ChildT>
3046inline const typename ChildT::ValueType&
3047RootNode<ChildT>::getTileValueUnsafe(const Coord& xyz) const
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
3056template<typename ChildT>
3057inline 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
3069template<typename ChildT>
3070inline ChildT*
3071RootNode<ChildT>::getChildUnsafe(const Coord& xyz)
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
3080template<typename ChildT>
3081inline const ChildT*
3082RootNode<ChildT>::getConstChildUnsafe(const Coord& xyz) const
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
3091template<typename ChildT>
3092inline const ChildT*
3093 RootNode<ChildT>::getChildUnsafe(const Coord& xyz) const
3094{
3095 return this->getConstChildUnsafe(xyz);
3096}
3097
3098
3099////////////////////////////////////////
3100
3101
3102template<typename ChildT>
3103template<typename ArrayT>
3104inline void
3105RootNode<ChildT>::getNodes(ArrayT& array)
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) {
3119 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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 }
3125 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3126 }
3127 }
3128}
3129
3130template<typename ChildT>
3131template<typename ArrayT>
3132inline 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) {
3147 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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 }
3153 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3154 }
3155 }
3156}
3157
3158////////////////////////////////////////
3159
3160template<typename ChildT>
3161template<typename ArrayT>
3162inline void
3163RootNode<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) {
3177 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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 }
3183 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3184 }
3185 }
3186}
3187
3188
3189////////////////////////////////////////
3190
3191
3192template<typename ChildT>
3193template<MergePolicy Policy>
3194inline void
3195RootNode<ChildT>::merge(RootNode& other)
3196{
3197 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
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
3251 case MERGE_ACTIVE_STATES_AND_NODES:
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
3297 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3298}
3299
3300
3301////////////////////////////////////////
3302
3303
3304template<typename ChildT>
3305template<typename OtherChildType>
3306inline void
3307RootNode<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
3342template<typename ChildT>
3343template<typename OtherChildType>
3344inline void
3345RootNode<ChildT>::topologyIntersection(const RootNode<OtherChildType>& other)
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
3378template<typename ChildT>
3379template<typename OtherChildType>
3380inline void
3381RootNode<ChildT>::topologyDifference(const RootNode<OtherChildType>& other)
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
3417template<typename ChildT>
3418template<typename CombineOp>
3419inline void
3420RootNode<ChildT>::combine(RootNode& other, CombineOp& op, bool prune)
3421{
3422 CombineArgs<ValueType> args;
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.
3448 SwappedCombineOp<ValueType, CombineOp> swappedOp(op);
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.
3477template<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
3496template<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
3507template<typename ChildT>
3508template<typename CombineOp, typename OtherRootNode>
3509inline void
3510RootNode<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);
3516 RootNodeCombineHelper<CombineOp, RootNode, OtherRootNode, compatible>::combine2(
3517 *this, other0, other1, op, prune);
3518}
3519
3520
3521template<typename ChildT>
3522template<typename CombineOp, typename OtherRootNode>
3523inline void
3524RootNode<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
3534 CombineArgs<ValueType, OtherValueT> args;
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
Assert.h
OPENVDB_ASSERT
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
BBox.h
Compression.h
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
NodeMasks.h
OPENVDB_NO_DEPRECATION_WARNING_END
#define OPENVDB_NO_DEPRECATION_WARNING_END
Definition Platform.h:195
OPENVDB_NO_DEPRECATION_WARNING_BEGIN
#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
OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:141
OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:140
OPENVDB_DEPRECATED_MESSAGE
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition Platform.h:148
openvdb::v12_0::CombineArgs
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition Types.h:569
openvdb::v12_0::CombineArgs::setARef
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition Types.h:621
openvdb::v12_0::CombineArgs::result
const AValueType & result() const
Get the output value.
Definition Types.h:613
openvdb::v12_0::CombineArgs::setBIsActive
CombineArgs & setBIsActive(bool b)
Set the active state of the B value.
Definition Types.h:637
openvdb::v12_0::CombineArgs::setBRef
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition Types.h:623
openvdb::v12_0::CombineArgs::resultIsActive
bool resultIsActive() const
Definition Types.h:632
openvdb::v12_0::CombineArgs::setAIsActive
CombineArgs & setAIsActive(bool b)
Set the active state of the A value.
Definition Types.h:635
openvdb::v12_0::CoordBBox::inf
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition Coord.h:322
openvdb::v12_0::CoordBBox::createCube
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition Coord.h:316
openvdb::v12_0::Coord::minComponent
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition Coord.h:176
openvdb::v12_0::Coord::lessThan
static bool lessThan(const Coord &a, const Coord &b)
Definition Coord.h:209
openvdb::v12_0::PartialCreate
Tag dispatch class that distinguishes constructors during file input.
Definition Types.h:689
openvdb::v12_0::TopologyCopy
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:683
openvdb::v12_0::TypeError
Definition Exceptions.h:64
openvdb::v12_0::ValueError
Definition Exceptions.h:65
openvdb::v12_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
openvdb::v12_0::math::CoordBBox::translate
void translate(const Coord &t)
Translate this bounding box by (tx, ty, tz).
Definition Coord.h:461
openvdb::v12_0::math::CoordBBox::expand
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition Coord.h:421
openvdb::v12_0::math::CoordBBox::empty
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:359
openvdb::v12_0::math::CoordBBox::min
const Coord & min() const
Definition Coord.h:324
openvdb::v12_0::math::CoordBBox::hasOverlap
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition Coord.h:415
openvdb::v12_0::math::CoordBBox::max
const Coord & max() const
Definition Coord.h:325
openvdb::v12_0::math::CoordBBox::isInside
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition Coord.h:403
openvdb::v12_0::math::CoordBBox::intersect
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition Coord.h:447
openvdb::v12_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
openvdb::v12_0::math::Coord::y
Int32 y() const
Definition Coord.h:132
openvdb::v12_0::math::Coord::offsetBy
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition Coord.h:92
openvdb::v12_0::math::Coord::asPointer
const Int32 * asPointer() const
Definition Coord.h:142
openvdb::v12_0::math::Coord::x
Int32 x() const
Definition Coord.h:131
openvdb::v12_0::math::Coord::setZ
Coord & setZ(Int32 z)
Definition Coord.h:82
openvdb::v12_0::math::Coord::setY
Coord & setY(Int32 y)
Definition Coord.h:81
openvdb::v12_0::math::Coord::z
Int32 z() const
Definition Coord.h:133
openvdb::v12_0::math::Coord::setX
Coord & setX(Int32 x)
Definition Coord.h:80
openvdb::v12_0::math::Coord::read
void read(std::istream &is)
Definition Coord.h:220
openvdb::v12_0::tree::RootNode
Definition RootNode.h:40
openvdb::v12_0::tree::RootNode::getNodeBoundingBox
static CoordBBox getNodeBoundingBox()
Return the bounding box of this RootNode, i.e., an infinite bounding box.
Definition RootNode.h:408
openvdb::v12_0::tree::RootNode::setValueAndCache
void setValueAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1937
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildAllIter
DenseIter< RootNode, MapIter, typename SubtreeT::Back, ValueType > ChildAllIter
Definition RootNode.h:366
openvdb::v12_0::tree::RootNode::hasSameConfiguration
static bool hasSameConfiguration(const RootNode< OtherChildType > &other)
Return false if the other node's dimensions don't match this node's.
Definition RootNode.h:1448
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::getValueDepth
int getValueDepth(const Coord &xyz) const
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueOffCIter
ValueIter< const RootNode, MapCIter, ValueOffPred, const ValueType > ValueOffCIter
Definition RootNode.h:372
openvdb::v12_0::tree::RootNode::RootNode
RootNode(const RootNode &other)
Definition RootNode.h:76
openvdb::v12_0::tree::RootNode::cbeginChildOn
ChildOnCIter cbeginChildOn() const
Definition RootNode.h:377
openvdb::v12_0::tree::RootNode::beginChildOn
ChildOnCIter beginChildOn() const
Definition RootNode.h:380
openvdb::v12_0::tree::RootNode::beginChildOn
ChildOnIter beginChildOn()
Definition RootNode.h:383
openvdb::v12_0::tree::RootNode::getDepth
Index getDepth() const
Definition RootNode.h:464
openvdb::v12_0::tree::RootNode::probe
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
openvdb::v12_0::tree::RootNode::RootNode
RootNode(const RootNode< OtherChildType > &other, const ValueType &background, TopologyCopy)
Construct a new tree that reproduces the topology and active states of another tree (which may have a...
Definition RootNode.h:1118
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::isValueOn
bool isValueOn(const Coord &xyz) const
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueOnCIter
ValueIter< const RootNode, MapCIter, ValueOnPred, const ValueType > ValueOnCIter
Definition RootNode.h:370
openvdb::v12_0::tree::RootNode::getIndexRange
void getIndexRange(CoordBBox &bbox) const
Return the current index range. Both min and max are inclusive.
Definition RootNode.h:1388
openvdb::v12_0::tree::RootNode::copyToDense
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
openvdb::v12_0::tree::RootNode::operator=
RootNode & operator=(const RootNode &other)
Copy a root node of the same type as this node.
Definition RootNode.h:1211
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::getMaxIndex
Coord getMaxIndex() const
openvdb::v12_0::tree::RootNode::cbeginValueOff
ValueOffCIter cbeginValueOff() const
Definition RootNode.h:388
openvdb::v12_0::tree::RootNode::probeLeafAndCache
LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as probeLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
openvdb::v12_0::tree::RootNode::transientData
Index32 transientData() const
Return the transient data value.
Definition RootNode.h:411
openvdb::v12_0::tree::RootNode::isBackgroundTile
bool isBackgroundTile(const MapCIter &) const
Definition RootNode.h:1291
openvdb::v12_0::tree::RootNode::addLeafAndCache
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
openvdb::v12_0::tree::RootNode::getChildDim
static Index getChildDim()
Definition RootNode.h:457
openvdb::v12_0::tree::RootNode::getConstChildUnsafe
const ChildNodeType * getConstChildUnsafe(const Coord &xyz) const
Return the child node at the given coordinate.
Definition RootNode.h:3082
openvdb::v12_0::tree::RootNode::operator=
RootNode & operator=(const RootNode< OtherChildType > &other)
Copy a root node of the same tree configuration as this node but a different ValueType.
openvdb::v12_0::tree::RootNode::coordToKey
Coord coordToKey(const Coord &xyz) const
Return a MapType key for the given coordinates, offset by the mOrigin.
Definition RootNode.h:954
openvdb::v12_0::tree::RootNode::combine
void combine(RootNode &other, CombineOp &, bool prune=false)
Definition RootNode.h:3420
openvdb::v12_0::tree::RootNode::addChild
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
openvdb::v12_0::tree::RootNode::getTileValueUnsafe
bool getTileValueUnsafe(const Coord &xyz, ValueType &value) const
Return the tile value and active state at the given coordinate.
Definition RootNode.h:3058
openvdb::v12_0::tree::RootNode::getNodes
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition RootNode.h:3105
openvdb::v12_0::tree::RootNode::getTileValueUnsafe
const ValueType & getTileValueUnsafe(const Coord &xyz) const
Return the tile value at the given coordinate.
Definition RootNode.h:3047
openvdb::v12_0::tree::RootNode::nonLeafCount
Index64 nonLeafCount() const
Definition RootNode.h:1558
openvdb::v12_0::tree::RootNode::stealNode
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
openvdb::v12_0::tree::RootNode::voxelizeActiveTiles
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition RootNode.h:2278
openvdb::v12_0::tree::RootNode::touchLeafAndCache
LeafNodeType * touchLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as touchLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueOffIter
ValueIter< RootNode, MapIter, ValueOffPred, ValueType > ValueOffIter
Definition RootNode.h:371
openvdb::v12_0::tree::RootNode::activeTileCount
Index32 activeTileCount() const
Definition RootNode.h:1596
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueAllIter
ValueIter< RootNode, MapIter, ValueAllPred, ValueType > ValueAllIter
Definition RootNode.h:373
openvdb::v12_0::tree::RootNode::topologyUnion
void topologyUnion(const RootNode< OtherChildType > &other, const bool preserveTiles=false)
Union this tree's set of active values with the active values of the other tree, whose ValueType may ...
Definition RootNode.h:3307
openvdb::v12_0::tree::RootNode::onLeafVoxelCount
Index64 onLeafVoxelCount() const
Definition RootNode.h:1652
openvdb::v12_0::tree::RootNode::probeConstLeafAndCache
const LeafNodeType * probeConstLeafAndCache(const Coord &xyz, AccessorT &acc) const
openvdb::v12_0::tree::RootNode::clip
void clip(const CoordBBox &)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition RootNode.h:2533
openvdb::v12_0::tree::RootNode::probeLeaf
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2963
openvdb::v12_0::tree::RootNode::hasCompatibleValueType
static bool hasCompatibleValueType(const RootNode< OtherChildType > &other)
Definition RootNode.h:1480
openvdb::v12_0::tree::RootNode::cbeginValueAll
ValueAllCIter cbeginValueAll() const
Definition RootNode.h:389
openvdb::v12_0::tree::RootNode::probeNodeAndCache
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
openvdb::v12_0::tree::RootNode::prune
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
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::NodeChainType
typename NodeChain< RootNode, LEVEL >::Type NodeChainType
Definition RootNode.h:50
openvdb::v12_0::tree::RootNode::isBackgroundTile
bool isBackgroundTile(const Tile &) const
Return true if the given tile is inactive and has the background value.
Definition RootNode.h:1277
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::LeafNodeType
typename typename SubtreeT::Back::LeafNodeType LeafNodeType
Definition RootNode.h:43
openvdb::v12_0::tree::RootNode::eraseBackgroundTiles
size_t eraseBackgroundTiles()
Remove all background tiles.
Definition RootNode.h:1311
openvdb::v12_0::tree::RootNode::topologyDifference
void topologyDifference(const RootNode< OtherChildType > &other)
Difference this tree's set of active values with the active values of the other tree,...
Definition RootNode.h:3381
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueOnIter
ValueIter< RootNode, MapIter, ValueOnPred, ValueType > ValueOnIter
Definition RootNode.h:369
openvdb::v12_0::tree::RootNode::beginValueOn
ValueOnCIter beginValueOn() const
Definition RootNode.h:390
openvdb::v12_0::tree::RootNode::merge
void merge(RootNode &other)
Efficiently merge another tree into this tree using one of several schemes.
Definition RootNode.h:3195
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildOnIter
ChildIter< RootNode, MapIter, ChildOnPred, typename SubtreeT::Back > ChildOnIter
Definition RootNode.h:362
openvdb::v12_0::tree::RootNode::offLeafVoxelCount
Index64 offLeafVoxelCount() const
Definition RootNode.h:1664
openvdb::v12_0::tree::RootNode::getWidth
Index getWidth() const
Definition RootNode.h:462
openvdb::v12_0::tree::RootNode::getTableSize
Index getTableSize() const
Return the number of entries in this node's table.
Definition RootNode.h:460
openvdb::v12_0::tree::RootNode::probe
bool probe(const Coord &xyz, const ChildNodeType *&child, ValueType &value, bool &active) const
Definition RootNode.h:750
openvdb::v12_0::tree::RootNode::addTile
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile containing voxel (x, y, z) at the specified tree level, creating a new branch if necessary...
Definition RootNode.h:2723
openvdb::v12_0::tree::RootNode::setOrigin
void setOrigin(const Coord &origin)
change the origin on this root node
Definition RootNode.h:2700
openvdb::v12_0::tree::RootNode::combine2
void combine2(const RootNode &other0, const OtherRootNode &other1, CombineOp &op, bool prune=false)
Definition RootNode.h:3510
openvdb::v12_0::tree::RootNode::origin
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition RootNode.h:945
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::modifyValueAndActiveState
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
openvdb::v12_0::tree::RootNode::setValueOnlyAndCache
void setValueOnlyAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1980
openvdb::v12_0::tree::RootNode::numBackgroundTiles
size_t numBackgroundTiles() const
Return the number of background tiles.
Definition RootNode.h:1299
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildOffCIter
ValueIter< const RootNode, MapCIter, ChildOffPred, ValueType > ChildOffCIter
Definition RootNode.h:365
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::setValueOnly
void setValueOnly(const Coord &xyz, const ValueType &value)
openvdb::v12_0::tree::RootNode::empty
bool empty() const
Return true if this node's table is either empty or contains only background tiles.
Definition RootNode.h:448
openvdb::v12_0::tree::RootNode::probeConstLeaf
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Definition RootNode.h:2971
openvdb::v12_0::tree::RootNode::probeChild
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
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::fill
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
openvdb::v12_0::tree::RootNode::beginValueOff
ValueOffCIter beginValueOff() const
Definition RootNode.h:391
openvdb::v12_0::tree::RootNode::setValueOffAndCache
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition RootNode.h:1892
openvdb::v12_0::tree::RootNode::addLeaf
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
openvdb::v12_0::tree::RootNode::getValueAndCache
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
openvdb::v12_0::tree::RootNode::cbeginChildAll
ChildAllCIter cbeginChildAll() const
Definition RootNode.h:379
openvdb::v12_0::tree::RootNode::leafCount
Index64 leafCount() const
Definition RootNode.h:1546
openvdb::v12_0::tree::RootNode::addTile
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
openvdb::v12_0::tree::RootNode::beginChildAll
ChildAllIter beginChildAll()
Definition RootNode.h:385
openvdb::v12_0::tree::RootNode::probeConst
bool probeConst(const Coord &xyz, const ChildNodeType *&child, ValueType &value, bool &active) const
Definition RootNode.h:2927
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::RootNodeCombineHelper
friend struct RootNodeCombineHelper
Definition RootNode.h:965
openvdb::v12_0::tree::RootNode::getLevel
static Index getLevel()
Definition RootNode.h:455
openvdb::v12_0::tree::RootNode::writeTopology
bool writeTopology(std::ostream &, bool toHalf=false) const
Definition RootNode.h:2348
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueAllCIter
ValueIter< const RootNode, MapCIter, ValueAllPred, const ValueType > ValueAllCIter
Definition RootNode.h:374
openvdb::v12_0::tree::RootNode::getChildUnsafe
const ChildNodeType * getChildUnsafe(const Coord &xyz) const
Return the child node at the given coordinate.
Definition RootNode.h:3093
openvdb::v12_0::tree::RootNode::isValueOnAndCache
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Definition RootNode.h:1747
openvdb::v12_0::tree::RootNode::probeConstNodeAndCache
const NodeT * probeConstNodeAndCache(const Coord &xyz, AccessorT &acc) const
Definition RootNode.h:3026
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::probeValue
bool probeValue(const Coord &xyz, ValueType &value) const
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::setActiveState
void setActiveState(const Coord &xyz, bool on)
openvdb::v12_0::tree::RootNode::beginValueOn
ValueOnIter beginValueOn()
Definition RootNode.h:393
openvdb::v12_0::tree::RootNode::modifyValueAndCache
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition RootNode.h:2037
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::LEVEL
static const Index LEVEL
Definition RootNode.h:47
openvdb::v12_0::tree::RootNode::inactiveTileCount
Index32 inactiveTileCount() const
Definition RootNode.h:1608
openvdb::v12_0::tree::RootNode::cbeginChildOff
ChildOffCIter cbeginChildOff() const
Definition RootNode.h:378
openvdb::v12_0::tree::RootNode::beginChildOff
ChildOffIter beginChildOff()
Definition RootNode.h:384
openvdb::v12_0::tree::RootNode::onVoxelCount
Index64 onVoxelCount() const
Definition RootNode.h:1620
openvdb::v12_0::tree::RootNode::beginChildOff
ChildOffCIter beginChildOff() const
Definition RootNode.h:381
openvdb::v12_0::tree::RootNode::addTileAndCache
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
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ValueType
typename typename SubtreeT::Back::ValueType ValueType
Definition RootNode.h:44
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::setValueOff
void setValueOff(const Coord &xyz)
openvdb::v12_0::tree::RootNode::writeBuffers
void writeBuffers(std::ostream &, bool toHalf=false) const
Definition RootNode.h:2489
openvdb::v12_0::tree::RootNode::nodeCount
void nodeCount(std::vector< Index64 > &vec) const
Definition RootNode.h:1690
openvdb::v12_0::tree::RootNode::cbeginValueOn
ValueOnCIter cbeginValueOn() const
Definition RootNode.h:387
openvdb::v12_0::tree::RootNode::RootNode
RootNode(const ValueType &background)
Construct a new tree with the given background value.
Definition RootNode.h:1081
openvdb::v12_0::tree::RootNode::probeLeaf
const LeafNodeType * probeLeaf(const Coord &xyz) const
Definition RootNode.h:775
openvdb::v12_0::tree::RootNode::tileCount
Index32 tileCount() const
Definition RootNode.h:1584
openvdb::v12_0::tree::RootNode::readBuffers
void readBuffers(std::istream &, const CoordBBox &, bool fromHalf=false)
Definition RootNode.h:2509
openvdb::v12_0::tree::RootNode::childCount
Index32 childCount() const
Definition RootNode.h:1572
openvdb::v12_0::tree::RootNode::onTileCount
Index64 onTileCount() const
Definition RootNode.h:1675
openvdb::v12_0::tree::RootNode::RootNode
RootNode()
Construct a new tree with a background value of 0.
Definition RootNode.h:1072
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::modifyValue
void modifyValue(const Coord &xyz, const ModifyOp &op)
openvdb::v12_0::tree::RootNode::isBackgroundTile
bool isBackgroundTile(const MapIter &) const
Return true if the given iterator points to an inactive tile with the background value.
Definition RootNode.h:1284
openvdb::v12_0::tree::RootNode::~RootNode
~RootNode()
Definition RootNode.h:124
openvdb::v12_0::tree::RootNode::offVoxelCount
Index64 offVoxelCount() const
Definition RootNode.h:1636
openvdb::v12_0::tree::RootNode::touchLeaf
LeafNodeType * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2817
openvdb::v12_0::tree::RootNode::getNodes
void getNodes(ArrayT &array) const
Definition RootNode.h:3133
openvdb::v12_0::tree::RootNode::RootNode
RootNode(const RootNode< OtherChildType > &other, const ValueType &background, const ValueType &foreground, TopologyCopy)
Construct a new tree that reproduces the topology and active states of another tree (which may have a...
Definition RootNode.h:1091
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::BuildType
typename typename SubtreeT::Back::BuildType BuildType
Definition RootNode.h:45
openvdb::v12_0::tree::RootNode::setBackground
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
openvdb::v12_0::tree::RootNode::getChildUnsafe
ChildNodeType * getChildUnsafe(const Coord &xyz)
Return the child node at the given coordinate.
Definition RootNode.h:3071
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildAllCIter
DenseIter< const RootNode, MapCIter, const typename SubtreeT::Back, const ValueType > ChildAllCIter
Definition RootNode.h:367
openvdb::v12_0::tree::RootNode::hasSameTopology
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
openvdb::v12_0::tree::RootNode::denseFill
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
openvdb::v12_0::tree::RootNode::probeNode
const NodeT * probeNode(const Coord &xyz) const
Definition RootNode.h:2881
openvdb::v12_0::tree::RootNode::beginChildAll
ChildAllCIter beginChildAll() const
Definition RootNode.h:382
openvdb::v12_0::tree::RootNode::setActiveStateAndCache
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Definition RootNode.h:1843
openvdb::v12_0::tree::RootNode::topologyIntersection
void topologyIntersection(const RootNode< OtherChildType > &other)
Intersects this tree's set of active values with the active values of the other tree,...
Definition RootNode.h:3345
openvdb::v12_0::tree::RootNode::setTransientData
void setTransientData(Index32 transientData)
Set the transient data value.
Definition RootNode.h:413
openvdb::v12_0::tree::RootNode::stealNodes
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
openvdb::v12_0::tree::RootNode::getHeight
Index getHeight() const
Definition RootNode.h:463
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::clear
void clear()
openvdb::v12_0::tree::RootNode::probeLeafAndCache
const LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc) const
openvdb::v12_0::tree::RootNode::probeValueAndCache
bool probeValueAndCache(const Coord &xyz, ValueType &value, AccessorT &) const
Definition RootNode.h:2150
openvdb::v12_0::tree::RootNode::probeConstNode
const NodeT * probeConstNode(const Coord &xyz) const
Definition RootNode.h:2890
openvdb::v12_0::tree::RootNode::hasKey
bool hasKey(const Coord &key) const
Return true if this node's mTable contains the given key.
Definition RootNode.h:957
openvdb::v12_0::tree::RootNode::evalActiveBoundingBox
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
openvdb::v12_0::tree::RootNode::probeChild
const ChildNodeType * probeChild(const Coord &xyz) const
Definition RootNode.h:767
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::background
const ValueType & background() const
Definition RootNode.h:430
openvdb::v12_0::tree::RootNode::getNodeLog2Dims
static void getNodeLog2Dims(std::vector< Index > &dims)
Definition RootNode.h:1364
openvdb::v12_0::tree::RootNode::RootNode
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
openvdb::v12_0::tree::RootNode::beginValueOff
ValueOffIter beginValueOff()
Definition RootNode.h:394
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildOffIter
ValueIter< RootNode, MapIter, ChildOffPred, const ValueType > ChildOffIter
Definition RootNode.h:364
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::sparseFill
void sparseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Definition RootNode.h:544
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::getMinIndex
Coord getMinIndex() const
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::RootNodeCopyHelper
friend struct RootNodeCopyHelper
Definition RootNode.h:964
openvdb::v12_0::tree::RootNode::probeConstChild
const ChildNodeType * probeConstChild(const Coord &xyz) const
Definition RootNode.h:2955
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildNodeType
typename SubtreeT::Back ChildNodeType
Definition RootNode.h:42
openvdb::v12_0::tree::RootNode::deleteChildOrTile
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
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::hasActiveTiles
bool hasActiveTiles() const
openvdb::v12_0::tree::RootNode::getValueDepthAndCache
int getValueDepthAndCache(const Coord &xyz, AccessorT &) const
Definition RootNode.h:1793
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::getValue
const ValueType & getValue(const Coord &xyz) const
openvdb::v12_0::tree::RootNode::memUsage
Index64 memUsage() const
Return the total amount of memory in bytes occupied by this node and its children.
Definition RootNode.h:1507
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::setValueOn
void setValueOn(const Coord &xyz, const ValueType &value)
openvdb::v12_0::tree::RootNode::stealNodes
void stealNodes(ArrayT &array)
Definition RootNode.h:877
openvdb::v12_0::tree::RootNode::expand
bool expand(const Coord &xyz)
Expand this node's table so that (x, y, z) is included in the index range.
Definition RootNode.h:1350
openvdb::v12_0::tree::RootNode::readBuffers
void readBuffers(std::istream &, bool fromHalf=false)
Definition RootNode.h:2499
openvdb::v12_0::tree::RootNode::modifyValueAndActiveStateAndCache
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition RootNode.h:2102
openvdb::v12_0::tree::RootNode::beginValueAll
ValueAllCIter beginValueAll() const
Definition RootNode.h:392
openvdb::v12_0::tree::RootNode::probeNode
NodeT * probeNode(const Coord &xyz)
Return a pointer to the node that contains voxel (x, y, z). If no such node exists,...
Definition RootNode.h:2863
openvdb::v12_0::tree::RootNode::readTopology
bool readTopology(std::istream &, bool fromHalf=false)
Definition RootNode.h:2384
openvdb::v12_0::tree::RootNode< typename SubtreeT::Back >::ChildOnCIter
ChildIter< const RootNode, MapCIter, ChildOnPred, const typename SubtreeT::Back > ChildOnCIter
Definition RootNode.h:363
openvdb::v12_0::tree::RootNode::beginValueAll
ValueAllIter beginValueAll()
Definition RootNode.h:395
openvdb::v12_0::tree::RootNode::RootNode
friend class RootNode
Definition RootNode.h:962
openvdb::v12_0::util::RootNodeMask
Definition NodeMasks.h:1067
openvdb::v12_0::util::RootNodeMask::isOn
bool isOn(Index32 i) const
Definition NodeMasks.h:1331
openvdb::v12_0::util::RootNodeMask::load
void load(std::istream &is)
Definition NodeMasks.h:1372
openvdb::v12_0::io::setGridBackgroundValuePtr
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...
openvdb::v12_0::io::getFormatVersion
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
openvdb::v12_0::io::truncateRealToHalf
T truncateRealToHalf(const T &val)
Return the given value truncated to 16-bit float precision.
Definition Compression.h:217
openvdb::v12_0::math::operator==
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition Vec3.h:474
openvdb::v12_0::math::operator*
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
openvdb::v12_0::math::isApproxEqual
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
openvdb::v12_0::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition Math.h:128
openvdb::v12_0::math::isExactlyEqual
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition Math.h:443
openvdb::v12_0::math::operator!=
bool operator!=(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Inequality operator, does exact floating point comparisons.
Definition Vec3.h:482
openvdb::v12_0::tools::bool
OutGridT const XformOp bool bool
Definition ValueTransformer.h:610
openvdb::v12_0::tools::op
OutGridT XformOp & op
Definition ValueTransformer.h:140
openvdb::v12_0::tree::iter
Definition TreeIterator.h:30
openvdb::v12_0::util::FindHighestOn
Index32 FindHighestOn(Index32 v)
Return the most significant on bit of the given 32-bit value.
Definition NodeMasks.h:159
openvdb::v12_0::Index
Index32 Index
Definition Types.h:54
openvdb::v12_0::zeroVal
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
openvdb::v12_0::OPENVDB_FILE_VERSION_ROOTNODE_MAP
@ OPENVDB_FILE_VERSION_ROOTNODE_MAP
Definition version.h.in:252
openvdb::v12_0::Index32
uint32_t Index32
Definition Types.h:52
openvdb::v12_0::Int32
int32_t Int32
Definition Types.h:56
openvdb::v12_0::Index64
uint64_t Index64
Definition Types.h:53
openvdb::v12_0::MERGE_ACTIVE_STATES
@ MERGE_ACTIVE_STATES
Definition Types.h:507
openvdb::v12_0::MERGE_NODES
@ MERGE_NODES
Definition Types.h:508
openvdb::v12_0::MERGE_ACTIVE_STATES_AND_NODES
@ MERGE_ACTIVE_STATES_AND_NODES
Definition Types.h:509
openvdb::v12_0::typeNameAsString
const char * typeNameAsString()
Definition Types.h:516
openvdb
Definition Exceptions.h:13
std
Definition Coord.h:590
Exceptions.h
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Types.h
openvdb::v12_0::CanConvertType
CanConvertType<FromType, ToType>::value is true if a value of type ToType can be constructed from a v...
Definition Types.h:403
openvdb::v12_0::CanConvertType::value
@ value
Definition Types.h:403
openvdb::v12_0::SwappedCombineOp
Definition Types.h:660
openvdb::v12_0::TypeList
A list of types (not necessarily unique)
Definition TypeList.h:578
openvdb::v12_0::tree::NodeChain< HeadT, 1 >::Type
TypeList< typename HeadT::ChildNodeType, HeadT > Type
Definition RootNode.h:1045
openvdb::v12_0::tree::NodeChain
NodeChain<RootNodeType, RootNodeType::LEVEL>::Type is a openvdb::TypeList that lists the types of the...
Definition RootNode.h:1037
openvdb::v12_0::tree::NodeChain::SubtreeT
typename NodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition RootNode.h:1038
openvdb::v12_0::tree::NodeChain::Type
typename SubtreeT::template Append< HeadT > Type
Definition RootNode.h:1039
openvdb::v12_0::tree::RootNodeCombineHelper< CombineOp, RootT, OtherRootT, true >::combine2
static void combine2(RootT &self, const RootT &other0, const OtherRootT &other1, CombineOp &op, bool prune)
Definition RootNode.h:3499
openvdb::v12_0::tree::RootNodeCombineHelper
Definition RootNode.h:3479
openvdb::v12_0::tree::RootNodeCombineHelper::combine2
static void combine2(RootT &self, const RootT &, const OtherRootT &other1, CombineOp &, bool)
Definition RootNode.h:3480
openvdb::v12_0::tree::RootNodeCopyHelper< RootT, OtherRootT, true >::copyWithValueConversion
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition RootNode.h:1170
openvdb::v12_0::tree::RootNodeCopyHelper
Definition RootNode.h:1151
openvdb::v12_0::tree::RootNodeCopyHelper::copyWithValueConversion
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition RootNode.h:1152
openvdb::v12_0::tree::RootNode::SameConfiguration
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a RootNod...
Definition RootNode.h:65
openvdb::v12_0::tree::RootNode::SameConfiguration::value
static const bool value
Definition RootNode.h:66
openvdb::v12_0::tree::RootNode::ValueConverter
ValueConverter<T>::Type is the type of a RootNode having the same child hierarchy as this node but a ...
Definition RootNode.h:57
openvdb::v12_0::tree::RootNode::ValueConverter::Type
RootNode< typename ChildType::template ValueConverter< OtherValueType >::Type > Type
Definition RootNode.h:58
openvdb::v12_0::tree::SameRootConfig< ChildT1, RootNode< ChildT2 > >::value
static const bool value
Definition RootNode.h:1062
openvdb::v12_0::tree::SameRootConfig
Definition RootNode.h:1056
openvdb::v12_0::tree::SameRootConfig::value
static const bool value
Definition RootNode.h:1057
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218