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