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