OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
PointDataGrid.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @author Dan Bailey
5///
6/// @file points/PointDataGrid.h
7///
8/// @brief Attribute-owned data structure for points. Point attributes are
9/// stored in leaf nodes and ordered by voxel for fast random and
10/// sequential access.
11
12#ifndef OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
13#define OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
14
15#include <openvdb/version.h>
16#include <openvdb/Grid.h>
17#include <openvdb/tree/Tree.h>
20#include <openvdb/util/Assert.h>
21#include "AttributeArray.h"
23#include "AttributeGroup.h"
24#include "AttributeSet.h"
25#include "StreamCompression.h"
26#include <cstring> // std::memcpy
27#include <iostream>
28#include <limits>
29#include <memory>
30#include <type_traits> // std::is_same
31#include <utility> // std::pair, std::make_pair
32#include <vector>
33
34class TestPointDataLeaf;
35
36namespace openvdb {
38namespace OPENVDB_VERSION_NAME {
39
40namespace io
41{
42
43/// @brief openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to
44/// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
45template<>
46inline void
47readCompressedValues( std::istream& is, PointDataIndex32* destBuf, Index destCount,
48 const util::NodeMask<3>& /*valueMask*/, bool /*fromHalf*/)
49{
51
52 const bool seek = destBuf == nullptr;
53
54 const size_t destBytes = destCount*sizeof(PointDataIndex32);
55 const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
56 if (destBytes >= maximumBytes) {
57 OPENVDB_THROW(openvdb::IoError, "Cannot read more than " <<
58 maximumBytes << " bytes in voxel values.")
59 }
60
61 uint16_t bytes16;
62
64
65 if (seek && meta) {
66 // buffer size temporarily stored in the StreamMetadata pass
67 // to avoid having to perform an expensive disk read for 2-bytes
68 bytes16 = static_cast<uint16_t>(meta->pass());
69 // seek over size of the compressed buffer
70 is.seekg(sizeof(uint16_t), std::ios_base::cur);
71 }
72 else {
73 // otherwise read from disk
74 is.read(reinterpret_cast<char*>(&bytes16), sizeof(uint16_t));
75 }
76
77 if (bytes16 == std::numeric_limits<uint16_t>::max()) {
78 // read or seek uncompressed data
79 if (seek) {
80 is.seekg(destBytes, std::ios_base::cur);
81 }
82 else {
83 is.read(reinterpret_cast<char*>(destBuf), destBytes);
84 }
85 }
86 else {
87 // read or seek uncompressed data
88 if (seek) {
89 is.seekg(int(bytes16), std::ios_base::cur);
90 }
91 else {
92 // decompress into the destination buffer
93 std::unique_ptr<char[]> bloscBuffer(new char[int(bytes16)]);
94 is.read(bloscBuffer.get(), bytes16);
95 std::unique_ptr<char[]> buffer = bloscDecompress( bloscBuffer.get(),
96 destBytes,
97 /*resize=*/false);
98 std::memcpy(destBuf, buffer.get(), destBytes);
99 }
100 }
101}
102
103/// @brief openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to
104/// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
105template<>
106inline void
107writeCompressedValues( std::ostream& os, PointDataIndex32* srcBuf, Index srcCount,
108 const util::NodeMask<3>& /*valueMask*/,
109 const util::NodeMask<3>& /*childMask*/, bool /*toHalf*/)
110{
112
113 const size_t srcBytes = srcCount*sizeof(PointDataIndex32);
114 const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
115 if (srcBytes >= maximumBytes) {
116 OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
117 maximumBytes << " bytes in voxel values.")
118 }
119
120 const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
121
122 size_t compressedBytes;
123 std::unique_ptr<char[]> buffer = bloscCompress( charBuffer, srcBytes,
124 compressedBytes, /*resize=*/false);
125
126 if (compressedBytes > 0) {
127 auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
128 os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
129 os.write(reinterpret_cast<const char*>(buffer.get()), compressedBytes);
130 }
131 else {
132 auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
133 os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
134 os.write(reinterpret_cast<const char*>(srcBuf), srcBytes);
135 }
136}
137
138template <typename T>
139inline void
140writeCompressedValuesSize(std::ostream& os, const T* srcBuf, Index srcCount)
141{
143
144 const size_t srcBytes = srcCount*sizeof(T);
145 const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
146 if (srcBytes >= maximumBytes) {
147 OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
148 maximumBytes << " bytes in voxel values.")
149 }
150
151 const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
152
153 // calculate voxel buffer size after compression
154 size_t compressedBytes = bloscCompressedSize(charBuffer, srcBytes);
155
156 if (compressedBytes > 0) {
157 auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
158 os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
159 }
160 else {
161 auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
162 os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
163 }
164}
165
166} // namespace io
167
168
169// forward declaration
170namespace tree {
171 template<Index, typename> struct SameLeafConfig;
172}
173
174
175////////////////////////////////////////
176
177
178namespace points {
179
180
181// forward declaration
182template<typename T, Index Log2Dim> class PointDataLeafNode;
183
184// these aliases are disabled in one of the unit tests to ensure that
185// they are not used by the Point headers
186
187#ifndef OPENVDB_DISABLE_POINT_DATA_TREE_ALIAS
188
189/// @brief Point index tree configured to match the default VDB configurations.
192
193
194/// @brief Point data grid.
196
197#endif
198
199/// @brief Deep copy the descriptor across all leaf nodes.
200///
201/// @param tree the PointDataTree.
202///
203/// @return the new descriptor.
204///
205/// @note This method will fail if the Descriptors in the tree are not all identical.
206template <typename PointDataTreeT>
208makeDescriptorUnique(PointDataTreeT& tree);
209
210
211/// @brief Toggle the streaming mode on all attributes in the tree to collapse the attributes
212/// after deconstructing a bound AttributeHandle to each array. This results in better
213/// memory efficiency when the data is streamed into another data structure
214/// (typically for rendering).
215///
216/// @param tree the PointDataTree.
217/// @param on @c true to enable streaming
218///
219/// @note Multiple threads cannot safely access the same AttributeArray when using streaming.
220template <typename PointDataTreeT>
221inline void
222setStreamingMode(PointDataTreeT& tree, bool on = true);
223
224
225/// @brief Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order
226/// to accelerate subsequent random access.
227///
228/// @param tree the PointDataTree.
229/// @param position if enabled, prefetch the position attribute (default is on)
230/// @param otherAttributes if enabled, prefetch all other attributes (default is on)
231template <typename PointDataTreeT>
232inline void
233prefetch(PointDataTreeT& tree, bool position = true, bool otherAttributes = true);
234
235
236////////////////////////////////////////
237
238
239template <typename T, Index Log2Dim>
240class PointDataLeafNode : public tree::LeafNode<T, Log2Dim>, io::MultiPass {
241
242public:
244 using Ptr = std::shared_ptr<PointDataLeafNode>;
245
246 using ValueType = T;
247 using ValueTypePair = std::pair<ValueType, ValueType>;
248 using IndexArray = std::vector<ValueType>;
249
251
252 ////////////////////////////////////////
253
254 // The following methods had to be copied from the LeafNode class
255 // to make the derived PointDataLeafNode class compatible with the tree structure.
256
259
260 using BaseLeaf::LOG2DIM;
261 using BaseLeaf::TOTAL;
262 using BaseLeaf::DIM;
265 using BaseLeaf::SIZE;
266 using BaseLeaf::LEVEL;
267
268 /// Default constructor
270 : mAttributeSet(new AttributeSet) { }
271
273
274 /// Construct using deep copy of other PointDataLeafNode
276 : BaseLeaf(other)
277 , mAttributeSet(new AttributeSet(*other.mAttributeSet)) { }
278
279 /// Construct using supplied origin, value and active status
280 explicit
281 PointDataLeafNode(const Coord& coords, const T& value = zeroVal<T>(), bool active = false)
282 : BaseLeaf(coords, zeroVal<T>(), active)
283 , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
284
285 /// Construct using supplied origin, value and active status
286 /// use attribute map from another PointDataLeafNode
287 PointDataLeafNode(const PointDataLeafNode& other, const Coord& coords,
288 const T& value = zeroVal<T>(), bool active = false)
289 : BaseLeaf(coords, zeroVal<T>(), active)
290 , mAttributeSet(new AttributeSet(*other.mAttributeSet))
291 {
293 }
294
295 // Copy-construct from a PointIndexLeafNode with the same configuration but a different ValueType.
296 template<typename OtherValueType>
298 : BaseLeaf(other)
299 , mAttributeSet(new AttributeSet) { }
300
301 // Copy-construct from a LeafNode with the same configuration but a different ValueType.
302 // Used for topology copies - explicitly sets the value (background) to zeroVal
303 template <typename ValueType>
305 : BaseLeaf(other, zeroVal<T>(), TopologyCopy())
306 , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
307
308 // Copy-construct from a LeafNode with the same configuration but a different ValueType.
309 // Used for topology copies - explicitly sets the on and off value (background) to zeroVal
310 template <typename ValueType>
311 PointDataLeafNode(const tree::LeafNode<ValueType, Log2Dim>& other, const T& /*offValue*/, const T& /*onValue*/, TopologyCopy)
312 : BaseLeaf(other, zeroVal<T>(), zeroVal<T>(), TopologyCopy())
313 , mAttributeSet(new AttributeSet) { }
314
316 const T& value = zeroVal<T>(), bool active = false)
317 : BaseLeaf(PartialCreate(), coords, value, active)
318 , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
319
320public:
321
322 /// Retrieve the attribute set.
323 const AttributeSet& attributeSet() const { return *mAttributeSet; }
324
325 /// @brief Steal the attribute set, a new, empty attribute set is inserted in it's place.
327
328 /// @brief Create a new attribute set. Existing attributes will be removed.
329 void initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
330 const AttributeArray::ScopedRegistryLock* lock = nullptr);
331 /// @brief Clear the attribute set.
332 void clearAttributes(const bool updateValueMask = true,
333 const AttributeArray::ScopedRegistryLock* lock = nullptr);
334
335 /// @brief Returns @c true if an attribute with this index exists.
336 /// @param pos Index of the attribute
337 bool hasAttribute(const size_t pos) const;
338 /// @brief Returns @c true if an attribute with this name exists.
339 /// @param attributeName Name of the attribute
340 bool hasAttribute(const Name& attributeName) const;
341
342 /// @brief Append an attribute to the leaf.
343 /// @param expected Existing descriptor is expected to match this parameter.
344 /// @param replacement New descriptor to replace the existing one.
345 /// @param pos Index of the new attribute in the descriptor replacement.
346 /// @param strideOrTotalSize Stride of the attribute array (if constantStride), total size otherwise
347 /// @param constantStride if @c false, stride is interpreted as total size of the array
348 /// @param metadata optional default value metadata
349 /// @param lock an optional scoped registry lock to avoid contention
351 const size_t pos, const Index strideOrTotalSize = 1,
352 const bool constantStride = true,
353 const Metadata* metadata = nullptr,
354 const AttributeArray::ScopedRegistryLock* lock = nullptr);
355
356 /// @brief Drop list of attributes.
357 /// @param pos vector of attribute indices to drop
358 /// @param expected Existing descriptor is expected to match this parameter.
359 /// @param replacement New descriptor to replace the existing one.
360 void dropAttributes(const std::vector<size_t>& pos,
361 const Descriptor& expected, Descriptor::Ptr& replacement);
362 /// @brief Reorder attribute set.
363 /// @param replacement New descriptor to replace the existing one.
364 void reorderAttributes(const Descriptor::Ptr& replacement);
365 /// @brief Rename attributes in attribute set (order must remain the same).
366 /// @param expected Existing descriptor is expected to match this parameter.
367 /// @param replacement New descriptor to replace the existing one.
368 void renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement);
369 /// @brief Compact all attributes in attribute set.
371
372 /// @brief Replace the underlying attribute set with the given @a attributeSet.
373 /// @details This leaf will assume ownership of the given attribute set. The descriptors must
374 /// match and the voxel offsets values will need updating if the point order is different.
375 /// @throws ValueError if @a allowMismatchingDescriptors is @c false and the descriptors
376 /// do not match
377 void replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors = false);
378
379 /// @brief Replace the descriptor with a new one
380 /// The new Descriptor must exactly match the old one
381 void resetDescriptor(const Descriptor::Ptr& replacement);
382
383 /// @brief Sets all of the voxel offset values on this leaf, from the given vector
384 /// of @a offsets. If @a updateValueMask is true, then the active value mask will
385 /// be updated so voxels with points are active and empty voxels are inactive.
386 void setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask = true);
387
388 /// @brief Throws an error if the voxel values on this leaf are not monotonically
389 /// increasing or within the bounds of the attribute arrays
390 void validateOffsets() const;
391
392 /// @brief Read-write attribute array reference from index
393 /// @details Attribute arrays can be shared across leaf nodes, so non-const
394 /// access will deep-copy the array to make it unique. Always prefer
395 /// accessing const arrays where possible to eliminate this copying.
396 /// {
397 AttributeArray& attributeArray(const size_t pos);
398 const AttributeArray& attributeArray(const size_t pos) const;
399 const AttributeArray& constAttributeArray(const size_t pos) const;
400 /// }
401 /// @brief Read-write attribute array reference from name
402 /// @details Attribute arrays can be shared across leaf nodes, so non-const
403 /// access will deep-copy the array to make it unique. Always prefer
404 /// accessing const arrays where possible to eliminate this copying.
405 /// {
406 AttributeArray& attributeArray(const Name& attributeName);
407 const AttributeArray& attributeArray(const Name& attributeName) const;
408 const AttributeArray& constAttributeArray(const Name& attributeName) const;
409 /// }
410
411 /// @brief Read-only group handle from group index
413 /// @brief Read-only group handle from group name
414 GroupHandle groupHandle(const Name& group) const;
415 /// @brief Read-write group handle from group index
417 /// @brief Read-write group handle from group name
419
420 /// @brief Compute the total point count for the leaf
422 /// @brief Compute the total active (on) point count for the leaf
424 /// @brief Compute the total inactive (off) point count for the leaf
426 /// @brief Compute the point count in a specific group for the leaf
427 Index64 groupPointCount(const Name& groupName) const;
428
429 /// @brief Activate voxels with non-zero points, deactivate voxels with zero points.
431
432 ////////////////////////////////////////
433
434 void setOffsetOn(Index offset, const ValueType& val);
435 void setOffsetOnly(Index offset, const ValueType& val);
436
437 /// @brief Return @c true if the given node (which may have a different @c ValueType
438 /// than this node) has the same active value topology as this node.
439 template<typename OtherType, Index OtherLog2Dim>
443
444 /// Check for buffer, state and origin equivalence first.
445 /// If this returns true, do a deeper comparison on the attribute set to check
446 bool operator==(const PointDataLeafNode& other) const {
447 if(BaseLeaf::operator==(other) != true) return false;
448 return (*this->mAttributeSet == *other.mAttributeSet);
449 }
450
451 bool operator!=(const PointDataLeafNode& other) const { return !(other == *this); }
452
454 template<typename AccessorT>
455 void addLeafAndCache(PointDataLeafNode*, AccessorT&) {}
456
457 //@{
458 /// @brief Return a pointer to this node.
459 PointDataLeafNode* touchLeaf(const Coord&) { return this; }
460 template<typename AccessorT>
461 PointDataLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
462
463 template<typename NodeT, typename AccessorT>
464 NodeT* probeNodeAndCache(const Coord&, AccessorT&)
465 {
467 if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
468 return reinterpret_cast<NodeT*>(this);
470 }
471 PointDataLeafNode* probeLeaf(const Coord&) { return this; }
472 template<typename AccessorT>
473 PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
474 //@}
475
476 //@{
477 /// @brief Return a @const pointer to this node.
478 const PointDataLeafNode* probeConstLeaf(const Coord&) const { return this; }
479 template<typename AccessorT>
480 const PointDataLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
481 template<typename AccessorT>
482 const PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
483 const PointDataLeafNode* probeLeaf(const Coord&) const { return this; }
484 template<typename NodeT, typename AccessorT>
485 const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
486 {
488 if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
489 return reinterpret_cast<const NodeT*>(this);
491 }
492 //@}
493
494 // I/O methods
495
496 void readTopology(std::istream& is, bool fromHalf = false);
497 void writeTopology(std::ostream& os, bool toHalf = false) const;
498
499 Index buffers() const;
500
501 void readBuffers(std::istream& is, bool fromHalf = false);
502 void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
503 void writeBuffers(std::ostream& os, bool toHalf = false) const;
504
505
508
509 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
510
511 /// @brief Return the bounding box of this node, i.e., the full index space
512 /// spanned by this leaf node.
514
515 ////////////////////////////////////////
516
517 // Disable all write methods to avoid unintentional changes
518 // to the point-array offsets.
519
521 OPENVDB_ASSERT(false && "Cannot modify voxel values in a PointDataTree.");
522 }
523
524 // some methods silently ignore attempts to modify the
525 // point-array offsets if a zero value is used
526
528 if (value != zeroVal<T>()) this->assertNonmodifiable();
529 }
530
531 void setActiveState(const Coord& xyz, bool on) { BaseLeaf::setActiveState(xyz, on); }
532 void setActiveState(Index offset, bool on) { BaseLeaf::setActiveState(offset, on); }
533
536
537 void setValueOff(const Coord& xyz) { BaseLeaf::setValueOff(xyz); }
538 void setValueOff(Index offset) { BaseLeaf::setValueOff(offset); }
539
540 void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
542
543 void setValueOn(const Coord& xyz) { BaseLeaf::setValueOn(xyz); }
544 void setValueOn(Index offset) { BaseLeaf::setValueOn(offset); }
545
546 void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
548
549 void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
550
553
554 template<typename ModifyOp>
555 void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
556
557 template<typename ModifyOp>
558 void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
559
560 template<typename ModifyOp>
561 void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
562
563 // clipping is not yet supported
564 void clip(const CoordBBox&, const ValueType& value) { assertNonModifiableUnlessZero(value); }
565
566 void fill(const CoordBBox&, const ValueType&, bool);
567 void fill(const ValueType& value) { assertNonModifiableUnlessZero(value); }
568 void fill(const ValueType&, bool);
569
570 template<typename AccessorT>
571 void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
572
573 template<typename ModifyOp, typename AccessorT>
574 void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
576 }
577
578 template<typename AccessorT>
579 void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
580
581 template<typename AccessorT>
582 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& parent) {
583 BaseLeaf::setActiveStateAndCache(xyz, on, parent);
584 }
585
586 void resetBackground(const ValueType&, const ValueType& newBackground) {
587 assertNonModifiableUnlessZero(newBackground);
588 }
589
592
594
595 friend class ::TestPointDataLeaf;
596
597 using ValueOn = typename BaseLeaf::ValueOn;
598 using ValueOff = typename BaseLeaf::ValueOff;
599 using ValueAll = typename BaseLeaf::ValueAll;
600
601private:
602 AttributeSet::UniquePtr mAttributeSet;
603 uint16_t mVoxelBufferSize = 0;
604
605protected:
606 using ChildOn = typename BaseLeaf::ChildOn;
607 using ChildOff = typename BaseLeaf::ChildOff;
608 using ChildAll = typename BaseLeaf::ChildAll;
609
613
614 // During topology-only construction, access is needed
615 // to protected/private members of other template instances.
616 template<typename, Index> friend class PointDataLeafNode;
617
621
622public:
623 /// @brief Leaf value voxel iterator
625
626public:
627
628 using ValueOnIter = typename BaseLeaf::template ValueIter<
630 using ValueOnCIter = typename BaseLeaf::template ValueIter<
632 using ValueOffIter = typename BaseLeaf::template ValueIter<
634 using ValueOffCIter = typename BaseLeaf::template ValueIter<
636 using ValueAllIter = typename BaseLeaf::template ValueIter<
638 using ValueAllCIter = typename BaseLeaf::template ValueIter<
640 using ChildOnIter = typename BaseLeaf::template ChildIter<
642 using ChildOnCIter = typename BaseLeaf::template ChildIter<
644 using ChildOffIter = typename BaseLeaf::template ChildIter<
646 using ChildOffCIter = typename BaseLeaf::template ChildIter<
648 using ChildAllIter = typename BaseLeaf::template DenseIter<
650 using ChildAllCIter = typename BaseLeaf::template DenseIter<
651 const PointDataLeafNode, const ValueType, ChildAll>;
652
657
658 /// @brief Leaf index iterator
660 {
661 NullFilter filter;
662 return this->beginIndex<ValueAllCIter, NullFilter>(filter);
663 }
665 {
666 NullFilter filter;
667 return this->beginIndex<ValueOnCIter, NullFilter>(filter);
668 }
670 {
671 NullFilter filter;
672 return this->beginIndex<ValueOffCIter, NullFilter>(filter);
673 }
674
675 template<typename IterT, typename FilterT>
676 IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
677
678 /// @brief Filtered leaf index iterator
679 template<typename FilterT>
681 {
682 return this->beginIndex<ValueAllCIter, FilterT>(filter);
683 }
684 template<typename FilterT>
686 {
687 return this->beginIndex<ValueOnCIter, FilterT>(filter);
688 }
689 template<typename FilterT>
691 {
692 return this->beginIndex<ValueOffCIter, FilterT>(filter);
693 }
694
695 /// @brief Leaf index iterator from voxel
697
698 /// @brief Filtered leaf index iterator from voxel
699 template<typename FilterT>
700 IndexIter<ValueVoxelCIter, FilterT> beginIndexVoxel(const Coord& ijk, const FilterT& filter) const;
701
702#define VMASK_ this->getValueMask()
703 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
704 ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
705 ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
706 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
707 ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
708 ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
709 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
710 ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
711 ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
712
713 ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
714 ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
715 ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
716 ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
717 ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
718 ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
719 ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
720 ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
721 ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
722
723 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
724 ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
725 ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
726 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
727 ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
728 ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
729 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
730 ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
731 ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
732
733 ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
734 ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
735 ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
736 ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
737 ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
738 ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
739 ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
740 ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
741 ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
742#undef VMASK_
743}; // struct PointDataLeafNode
744
745////////////////////////////////////////
746
747// PointDataLeafNode implementation
748
749template<typename T, Index Log2Dim>
750inline AttributeSet::UniquePtr
752{
753 AttributeSet::UniquePtr ptr = std::make_unique<AttributeSet>();
754 std::swap(ptr, mAttributeSet);
755 return ptr;
756}
757
758template<typename T, Index Log2Dim>
759inline void
762{
763 if (descriptor->size() != 1 ||
764 descriptor->find("P") == AttributeSet::INVALID_POS ||
765 descriptor->valueType(0) != typeNameAsString<Vec3f>())
766 {
767 OPENVDB_THROW(IndexError, "Initializing attributes only allowed with one Vec3f position attribute.");
768 }
769
770 mAttributeSet.reset(new AttributeSet(descriptor, arrayLength, lock));
771}
772
773template<typename T, Index Log2Dim>
774inline void
777{
778 mAttributeSet.reset(new AttributeSet(*mAttributeSet, 0, lock));
779
780 // zero voxel values
781
782 this->buffer().fill(ValueType(0));
783
784 // if updateValueMask, also de-activate all voxels
785
786 if (updateValueMask) this->setValuesOff();
787}
788
789template<typename T, Index Log2Dim>
790inline bool
792{
793 return pos < mAttributeSet->size();
794}
795
796template<typename T, Index Log2Dim>
797inline bool
799{
800 const size_t pos = mAttributeSet->find(attributeName);
801 return pos != AttributeSet::INVALID_POS;
802}
803
804template<typename T, Index Log2Dim>
807 const size_t pos, const Index strideOrTotalSize,
808 const bool constantStride,
809 const Metadata* metadata,
811{
812 return mAttributeSet->appendAttribute(
813 expected, replacement, pos, strideOrTotalSize, constantStride, metadata, lock);
814}
815
816template<typename T, Index Log2Dim>
817inline void
819 const Descriptor& expected, Descriptor::Ptr& replacement)
820{
821 mAttributeSet->dropAttributes(pos, expected, replacement);
822}
823
824template<typename T, Index Log2Dim>
825inline void
827{
828 mAttributeSet->reorderAttributes(replacement);
829}
830
831template<typename T, Index Log2Dim>
832inline void
834{
835 mAttributeSet->renameAttributes(expected, replacement);
836}
837
838template<typename T, Index Log2Dim>
839inline void
841{
842 for (size_t i = 0; i < mAttributeSet->size(); i++) {
843 AttributeArray* array = mAttributeSet->get(i);
844 array->compact();
845 }
846}
847
848template<typename T, Index Log2Dim>
849inline void
851{
852 if (!attributeSet) {
853 OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
854 }
855
856 if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
857 OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
858 }
859
860 mAttributeSet.reset(attributeSet);
861}
862
863template<typename T, Index Log2Dim>
864inline void
866{
867 mAttributeSet->resetDescriptor(replacement);
868}
869
870template<typename T, Index Log2Dim>
871inline void
872PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
873{
874 if (offsets.size() != LeafNodeType::NUM_VALUES) {
875 OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
876 }
877
878 for (Index index = 0; index < offsets.size(); ++index) {
879 setOffsetOnly(index, offsets[index]);
880 }
881
882 if (updateValueMask) this->updateValueMask();
883}
884
885template<typename T, Index Log2Dim>
886inline void
888{
889 // Ensure all of the offset values are monotonically increasing
890 for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
891 if (this->getValue(index-1) > this->getValue(index)) {
892 OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
893 }
894 }
895
896 // Ensure all attribute arrays are of equal length
897 for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
898 if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
899 OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
900 }
901 }
902
903 // Ensure the last voxel's offset value matches the size of each attribute array
904 if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
905 OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
906 }
907}
908
909template<typename T, Index Log2Dim>
910inline AttributeArray&
912{
913 if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
914 return *mAttributeSet->get(pos);
915}
916
917template<typename T, Index Log2Dim>
918inline const AttributeArray&
920{
921 if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
922 return *mAttributeSet->getConst(pos);
923}
924
925template<typename T, Index Log2Dim>
926inline const AttributeArray&
928{
929 return this->attributeArray(pos);
930}
931
932template<typename T, Index Log2Dim>
933inline AttributeArray&
935{
936 const size_t pos = mAttributeSet->find(attributeName);
937 if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
938 return *mAttributeSet->get(pos);
939}
940
941template<typename T, Index Log2Dim>
942inline const AttributeArray&
944{
945 const size_t pos = mAttributeSet->find(attributeName);
946 if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
947 return *mAttributeSet->getConst(pos);
948}
949
950template<typename T, Index Log2Dim>
951inline const AttributeArray&
953{
954 return this->attributeArray(attributeName);
955}
956
957template<typename T, Index Log2Dim>
958inline GroupHandle
960{
961 const AttributeArray& array = this->attributeArray(index.first);
962 OPENVDB_ASSERT(isGroup(array));
963
964 const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
965
966 return GroupHandle(groupArray, index.second);
967}
968
969template<typename T, Index Log2Dim>
970inline GroupHandle
972{
973 const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
974 return this->groupHandle(index);
975}
976
977template<typename T, Index Log2Dim>
978inline GroupWriteHandle
988
989template<typename T, Index Log2Dim>
990inline GroupWriteHandle
992{
993 const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
994 return this->groupWriteHandle(index);
995}
996
997template<typename T, Index Log2Dim>
998template<typename ValueIterT, typename FilterT>
1001{
1002 // generate no-op iterator if filter evaluates no indices
1003
1004 if (filter.state() == index::NONE) {
1005 return IndexIter<ValueIterT, FilterT>(ValueIterT(), filter);
1006 }
1007
1008 // copy filter to ensure thread-safety
1009
1010 FilterT newFilter(filter);
1011 newFilter.reset(*this);
1012
1014
1015 // construct the value iterator and reset the filter to use this leaf
1016
1017 ValueIterT valueIter = IterTraitsT::begin(*this);
1018
1019 return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
1020}
1021
1022template<typename T, Index Log2Dim>
1023inline ValueVoxelCIter
1025{
1028 const ValueType end = this->getValue(index);
1029 const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1030 return ValueVoxelCIter(start, end);
1031}
1032
1033template<typename T, Index Log2Dim>
1036{
1037 ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1038 return IndexVoxelIter(iter, NullFilter());
1039}
1040
1041template<typename T, Index Log2Dim>
1042template<typename FilterT>
1044PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1045{
1046 ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1047 FilterT newFilter(filter);
1048 newFilter.reset(*this);
1049 return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1050}
1051
1052template<typename T, Index Log2Dim>
1053inline Index64
1055{
1056 return this->getLastValue();
1057}
1058
1059template<typename T, Index Log2Dim>
1060inline Index64
1062{
1063 if (this->isEmpty()) return 0;
1064 else if (this->isDense()) return this->pointCount();
1065 return iterCount(this->beginIndexOn());
1066}
1067
1068template<typename T, Index Log2Dim>
1069inline Index64
1071{
1072 if (this->isEmpty()) return this->pointCount();
1073 else if (this->isDense()) return 0;
1074 return iterCount(this->beginIndexOff());
1075}
1076
1077template<typename T, Index Log2Dim>
1078inline Index64
1080{
1081 if (!this->attributeSet().descriptor().hasGroup(groupName)) {
1082 return Index64(0);
1083 }
1084 GroupFilter filter(groupName, this->attributeSet());
1085 if (filter.state() == index::ALL) {
1086 return this->pointCount();
1087 } else {
1088 return iterCount(this->beginIndexAll(filter));
1089 }
1090}
1091
1092template<typename T, Index Log2Dim>
1093inline void
1095{
1096 ValueType start = 0, end = 0;
1097 for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1098 end = this->getValue(n);
1099 this->setValueMask(n, (end - start) > 0);
1100 start = end;
1101 }
1102}
1103
1104template<typename T, Index Log2Dim>
1105inline void
1107{
1108 this->buffer().setValue(offset, val);
1109 this->setValueMaskOn(offset);
1110}
1111
1112template<typename T, Index Log2Dim>
1113inline void
1115{
1116 this->buffer().setValue(offset, val);
1117}
1118
1119template<typename T, Index Log2Dim>
1120inline void
1121PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1122{
1123 BaseLeaf::readTopology(is, fromHalf);
1124}
1125
1126template<typename T, Index Log2Dim>
1127inline void
1128PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1129{
1130 BaseLeaf::writeTopology(os, toHalf);
1131}
1132
1133template<typename T, Index Log2Dim>
1134inline Index
1136{
1137 return Index( /*voxel buffer sizes*/ 1 +
1138 /*voxel buffers*/ 1 +
1139 /*attribute metadata*/ 1 +
1140 /*attribute uniform values*/ mAttributeSet->size() +
1141 /*attribute buffers*/ mAttributeSet->size() +
1142 /*cleanup*/ 1);
1143}
1144
1145template<typename T, Index Log2Dim>
1146inline void
1147PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1148{
1149 this->readBuffers(is, CoordBBox::inf(), fromHalf);
1150}
1151
1152template<typename T, Index Log2Dim>
1153inline void
1154PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1155{
1156 struct Local
1157 {
1158 static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1159 {
1160 // if paged stream exists, delete it
1161 std::string key("paged:" + std::to_string(index));
1162 auto it = auxData.find(key);
1163 if (it != auxData.end()) {
1164 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1165 }
1166 }
1167
1168 static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1169 const Index index)
1170 {
1171 std::string key("paged:" + std::to_string(index));
1172 auto it = auxData.find(key);
1173 if (it != auxData.end()) {
1174 return *(std::any_cast<compression::PagedInputStream::Ptr>(it->second));
1175 }
1176 else {
1177 compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1178 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1179 return *pagedStream;
1180 }
1181 }
1182
1183 static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1184 {
1185 std::string matchingKey("hasMatchingDescriptor");
1186 auto itMatching = auxData.find(matchingKey);
1187 return itMatching != auxData.end();
1188 }
1189
1190 static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1191 {
1192 std::string matchingKey("hasMatchingDescriptor");
1193 std::string descriptorKey("descriptorPtr");
1194 auto itMatching = auxData.find(matchingKey);
1195 auto itDescriptor = auxData.find(descriptorKey);
1196 if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1197 if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1198 }
1199
1200 static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1201 const Descriptor::Ptr descriptor)
1202 {
1203 std::string descriptorKey("descriptorPtr");
1204 std::string matchingKey("hasMatchingDescriptor");
1205 auto itMatching = auxData.find(matchingKey);
1206 if (itMatching == auxData.end()) {
1207 // if matching bool is not found, insert "true" and the descriptor
1208 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1209 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1210 }
1211 }
1212
1213 static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1214 {
1215 std::string descriptorKey("descriptorPtr");
1216 auto itDescriptor = auxData.find(descriptorKey);
1217 OPENVDB_ASSERT(itDescriptor != auxData.end());
1218 const Descriptor::Ptr descriptor = std::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1219 return descriptor;
1220 }
1221 };
1222
1224
1225 if (!meta) {
1226 OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1227 }
1228
1229 const Index pass(static_cast<uint16_t>(meta->pass()));
1230 const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1231
1232 const Index attributes = (maximumPass - 4) / 2;
1233
1234 if (pass == 0) {
1235 // pass 0 - voxel data sizes
1236 is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1237 Local::clearMatchingDescriptor(meta->auxData());
1238 }
1239 else if (pass == 1) {
1240 // pass 1 - descriptor and attribute metadata
1241 if (Local::hasMatchingDescriptor(meta->auxData())) {
1242 AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1243 mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1244 }
1245 else {
1246 uint8_t header;
1247 is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1248 mAttributeSet->readDescriptor(is);
1249 if (header & uint8_t(1)) {
1250 AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1251 Local::insertDescriptor(meta->auxData(), descriptor);
1252 }
1253 // a forwards-compatibility mechanism for future use,
1254 // if a 0x2 bit is set, read and skip over a specific number of bytes
1255 if (header & uint8_t(2)) {
1256 uint64_t bytesToSkip;
1257 is.read(reinterpret_cast<char*>(&bytesToSkip), sizeof(uint64_t));
1258 if (bytesToSkip > uint64_t(0)) {
1259 auto metadata = io::getStreamMetadataPtr(is);
1260 if (metadata && metadata->seekable()) {
1261 is.seekg(bytesToSkip, std::ios_base::cur);
1262 }
1263 else {
1264 std::vector<uint8_t> tempData(bytesToSkip);
1265 is.read(reinterpret_cast<char*>(&tempData[0]), bytesToSkip);
1266 }
1267 }
1268 }
1269 // this reader is only able to read headers with 0x1 and 0x2 bits set
1270 if (header > uint8_t(3)) {
1271 OPENVDB_THROW(IoError, "Unrecognised header flags in PointDataLeafNode");
1272 }
1273 }
1274 mAttributeSet->readMetadata(is);
1275 }
1276 else if (pass < (attributes + 2)) {
1277 // pass 2...n+2 - attribute uniform values
1278 const size_t attributeIndex = pass - 2;
1279 AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1280 mAttributeSet->get(attributeIndex) : nullptr;
1281 if (array) {
1282 compression::PagedInputStream& pagedStream =
1283 Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1284 pagedStream.setInputStream(is);
1285 pagedStream.setSizeOnly(true);
1286 array->readPagedBuffers(pagedStream);
1287 }
1288 }
1289 else if (pass == attributes + 2) {
1290 // pass n+2 - voxel data
1291
1292 const Index passValue(meta->pass());
1293
1294 // StreamMetadata pass variable used to temporarily store voxel buffer size
1295 io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1296 nonConstMeta.setPass(mVoxelBufferSize);
1297
1298 // readBuffers() calls readCompressedValues specialization above
1299 BaseLeaf::readBuffers(is, fromHalf);
1300
1301 // pass now reset to original value
1302 nonConstMeta.setPass(passValue);
1303 }
1304 else if (pass < (attributes*2 + 3)) {
1305 // pass n+2..2n+2 - attribute buffers
1306 const Index attributeIndex = pass - attributes - 3;
1307 AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1308 mAttributeSet->get(attributeIndex) : nullptr;
1309 if (array) {
1310 compression::PagedInputStream& pagedStream =
1311 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1312 pagedStream.setInputStream(is);
1313 pagedStream.setSizeOnly(false);
1314 array->readPagedBuffers(pagedStream);
1315 }
1316 // cleanup paged stream reference in auxiliary metadata
1317 if (pass > attributes + 3) {
1318 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1319 }
1320 }
1321 else if (pass < buffers()) {
1322 // pass 2n+3 - cleanup last paged stream
1323 const Index attributeIndex = pass - attributes - 4;
1324 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1325 }
1326}
1327
1328template<typename T, Index Log2Dim>
1329inline void
1330PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1331{
1332 struct Local
1333 {
1334 static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1335 {
1336 // if paged stream exists, flush and delete it
1337 std::string key("paged:" + std::to_string(index));
1338 auto it = auxData.find(key);
1339 if (it != auxData.end()) {
1340 compression::PagedOutputStream& stream = *(std::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1341 stream.flush();
1342 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1343 }
1344 }
1345
1346 static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1347 const Index index)
1348 {
1349 std::string key("paged:" + std::to_string(index));
1350 auto it = auxData.find(key);
1351 if (it != auxData.end()) {
1352 return *(std::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1353 }
1354 else {
1355 compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1356 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1357 return *pagedStream;
1358 }
1359 }
1360
1361 static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1362 const Descriptor::Ptr descriptor)
1363 {
1364 std::string descriptorKey("descriptorPtr");
1365 std::string matchingKey("hasMatchingDescriptor");
1366 auto itMatching = auxData.find(matchingKey);
1367 auto itDescriptor = auxData.find(descriptorKey);
1368 if (itMatching == auxData.end()) {
1369 // if matching bool is not found, insert "true" and the descriptor
1370 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1371 OPENVDB_ASSERT(itDescriptor == auxData.end());
1372 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1373 }
1374 else {
1375 // if matching bool is found and is false, early exit (a previous descriptor did not match)
1376 bool matching = std::any_cast<bool>(itMatching->second);
1377 if (!matching) return;
1378 OPENVDB_ASSERT(itDescriptor != auxData.end());
1379 // if matching bool is true, check whether the existing descriptor matches the current one and set
1380 // matching bool to false if not
1381 const Descriptor::Ptr existingDescriptor = std::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1382 if (*existingDescriptor != *descriptor) {
1383 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1384 }
1385 }
1386 }
1387
1388 static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1389 {
1390 std::string matchingKey("hasMatchingDescriptor");
1391 auto itMatching = auxData.find(matchingKey);
1392 // if matching key is not found, no matching descriptor
1393 if (itMatching == auxData.end()) return false;
1394 // if matching key is found and is false, no matching descriptor
1395 if (!std::any_cast<bool>(itMatching->second)) return false;
1396 return true;
1397 }
1398
1399 static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1400 {
1401 std::string descriptorKey("descriptorPtr");
1402 auto itDescriptor = auxData.find(descriptorKey);
1403 // if matching key is true, however descriptor is not found, it has already been retrieved
1404 if (itDescriptor == auxData.end()) return nullptr;
1405 // otherwise remove it and return it
1406 const Descriptor::Ptr descriptor = std::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1407 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1408 return descriptor;
1409 }
1410
1411 static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1412 {
1413 std::string matchingKey("hasMatchingDescriptor");
1414 std::string descriptorKey("descriptorPtr");
1415 auto itMatching = auxData.find(matchingKey);
1416 auto itDescriptor = auxData.find(descriptorKey);
1417 if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1418 if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1419 }
1420 };
1421
1423
1424 if (!meta) {
1425 OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1426 }
1427
1428 const Index pass(static_cast<uint16_t>(meta->pass()));
1429
1430 // leaf traversal analysis deduces the number of passes to perform for this leaf
1431 // then updates the leaf traversal value to ensure all passes will be written
1432
1433 if (meta->countingPasses()) {
1434 const Index requiredPasses = this->buffers();
1435 if (requiredPasses > pass) {
1436 meta->setPass(requiredPasses);
1437 }
1438 return;
1439 }
1440
1441 const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1442 const Index attributes = (maximumPass - 4) / 2;
1443
1444 if (pass == 0) {
1445 // pass 0 - voxel data sizes
1446 io::writeCompressedValuesSize(os, this->buffer().data(), SIZE);
1447 // track if descriptor is shared or not
1448 Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1449 }
1450 else if (pass == 1) {
1451 // pass 1 - descriptor and attribute metadata
1452 bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1453 if (matchingDescriptor) {
1454 AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1455 if (descriptor) {
1456 // write a header to indicate a shared descriptor
1457 uint8_t header(1);
1458 os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1459 mAttributeSet->writeDescriptor(os, /*transient=*/false);
1460 }
1461 }
1462 else {
1463 // write a header to indicate a non-shared descriptor
1464 uint8_t header(0);
1465 os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1466 mAttributeSet->writeDescriptor(os, /*transient=*/false);
1467 }
1468 mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1469 }
1470 else if (pass < attributes + 2) {
1471 // pass 2...n+2 - attribute buffer sizes
1472 const Index attributeIndex = pass - 2;
1473 // destroy previous paged stream
1474 if (pass > 2) {
1475 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1476 }
1477 const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1478 mAttributeSet->getConst(attributeIndex) : nullptr;
1479 if (array) {
1480 compression::PagedOutputStream& pagedStream =
1481 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1482 pagedStream.setOutputStream(os);
1483 pagedStream.setSizeOnly(true);
1484 array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1485 }
1486 }
1487 else if (pass == attributes + 2) {
1488 const Index attributeIndex = pass - 3;
1489 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1490 // pass n+2 - voxel data
1491 BaseLeaf::writeBuffers(os, toHalf);
1492 }
1493 else if (pass < (attributes*2 + 3)) {
1494 // pass n+3...2n+3 - attribute buffers
1495 const Index attributeIndex = pass - attributes - 3;
1496 // destroy previous paged stream
1497 if (pass > attributes + 2) {
1498 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1499 }
1500 const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1501 mAttributeSet->getConst(attributeIndex) : nullptr;
1502 if (array) {
1503 compression::PagedOutputStream& pagedStream =
1504 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1505 pagedStream.setOutputStream(os);
1506 pagedStream.setSizeOnly(false);
1507 array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1508 }
1509 }
1510 else if (pass < buffers()) {
1511 Local::clearMatchingDescriptor(meta->auxData());
1512 // pass 2n+3 - cleanup last paged stream
1513 const Index attributeIndex = pass - attributes - 4;
1514 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1515 }
1516}
1517
1518template<typename T, Index Log2Dim>
1519inline Index64
1521{
1522 return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1523}
1524
1525template<typename T, Index Log2Dim>
1526inline Index64
1528{
1529 return BaseLeaf::memUsageIfLoaded() + mAttributeSet->memUsageIfLoaded();
1530}
1531
1532template<typename T, Index Log2Dim>
1533inline void
1535{
1536 BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1537}
1538
1539template<typename T, Index Log2Dim>
1540inline CoordBBox
1545
1546template<typename T, Index Log2Dim>
1547inline void
1548PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1549{
1550 if (!this->allocate()) return;
1551
1552 this->assertNonModifiableUnlessZero(value);
1553
1554 // active state is permitted to be updated
1555
1556 for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1557 const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1558 for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1559 const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1560 for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1561 const Index offset = offsetXY + (z & (DIM-1u));
1562 this->setValueMask(offset, active);
1563 }
1564 }
1565 }
1566}
1567
1568template<typename T, Index Log2Dim>
1569inline void
1571{
1572 this->assertNonModifiableUnlessZero(value);
1573
1574 // active state is permitted to be updated
1575
1576 if (active) this->setValuesOn();
1577 else this->setValuesOff();
1578}
1579
1580
1581////////////////////////////////////////
1582
1583
1584template <typename PointDataTreeT>
1587{
1588 auto leafIter = tree.beginLeaf();
1589 if (!leafIter) return nullptr;
1590
1591 const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1592 auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1593 for (; leafIter; ++leafIter) {
1594 leafIter->resetDescriptor(newDescriptor);
1595 }
1596
1597 return newDescriptor;
1598}
1599
1600
1601template <typename PointDataTreeT>
1602inline void
1603setStreamingMode(PointDataTreeT& tree, bool on)
1604{
1605 auto leafIter = tree.beginLeaf();
1606 for (; leafIter; ++leafIter) {
1607 for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1608 leafIter->attributeArray(i).setStreaming(on);
1609 }
1610 }
1611}
1612
1613
1614template <typename PointDataTreeT>
1615inline void
1616prefetch(PointDataTreeT& tree, bool position, bool otherAttributes)
1617{
1618 // NOTE: the following is intentionally not multi-threaded, as the I/O
1619 // is faster if done in the order in which it is stored in the file
1620
1621 auto leaf = tree.cbeginLeaf();
1622 if (!leaf) return;
1623
1624 const auto& attributeSet = leaf->attributeSet();
1625
1626 // pre-fetch leaf data
1627
1628 for ( ; leaf; ++leaf) {
1629 leaf->buffer().data();
1630 }
1631
1632 // pre-fetch position attribute data (position will typically have index 0)
1633
1634 size_t positionIndex = attributeSet.find("P");
1635
1636 if (position && positionIndex != AttributeSet::INVALID_POS) {
1637 for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1638 OPENVDB_ASSERT(leaf->hasAttribute(positionIndex));
1639 leaf->constAttributeArray(positionIndex).loadData();
1640 }
1641 }
1642
1643 // pre-fetch other attribute data
1644
1645 if (otherAttributes) {
1646 const size_t attributes = attributeSet.size();
1647 for (size_t attributeIndex = 0; attributeIndex < attributes; attributeIndex++) {
1648 if (attributeIndex == positionIndex) continue;
1649 for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1650 OPENVDB_ASSERT(leaf->hasAttribute(attributeIndex));
1651 leaf->constAttributeArray(attributeIndex).loadData();
1652 }
1653 }
1654 }
1655}
1656
1657
1658namespace internal {
1659
1660/// @brief Global registration of point data-related types
1661/// @note This is called from @c openvdb::initialize, so there is
1662/// no need to call it directly.
1664
1665/// @brief Global deregistration of point data-related types
1666/// @note This is called from @c openvdb::uninitialize, so there is
1667/// no need to call it directly.
1669
1670
1671/// @brief Recursive node chain which generates a openvdb::TypeList value
1672/// converted types of nodes to PointDataGrid nodes of the same configuration,
1673/// rooted at RootNodeType in reverse order, from LeafNode to RootNode.
1674/// See also TreeConverter<>.
1675template<typename HeadT, int HeadLevel>
1677{
1678 using SubtreeT = typename PointDataNodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1680 using Type = typename SubtreeT::template Append<RootNodeT>;
1681};
1682
1683// Specialization for internal nodes which require their embedded child type to
1684// be switched
1685template <typename ChildT, Index Log2Dim, int HeadLevel>
1686struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, HeadLevel>
1687{
1688 using SubtreeT = typename PointDataNodeChain<ChildT, HeadLevel-1>::Type;
1690 using Type = typename SubtreeT::template Append<InternalNodeT>;
1691};
1692
1693// Specialization for the last internal node of a node chain, expected
1694// to be templated on a leaf node
1695template <typename ChildT, Index Log2Dim>
1702
1703} // namespace internal
1704
1705
1706/// @brief Similiar to ValueConverter, but allows for tree configuration conversion
1707/// to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a
1708/// PointDataLeafNode is not a specialization of LeafNode
1709template <typename TreeType>
1715
1716
1717} // namespace points
1718
1719
1720////////////////////////////////////////
1721
1722
1723namespace tree
1724{
1725
1726/// Helper metafunction used to implement LeafNode::SameConfiguration
1727/// (which, as an inner class, can't be independently specialized)
1728template<Index Dim1, typename T2>
1729struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1730
1731} // namespace tree
1732} // namespace OPENVDB_VERSION_NAME
1733} // namespace openvdb
1734
1735#endif // OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Attribute array storage for string data using Descriptor Metadata.
Attribute Array storage templated on type and compression codec.
Attribute Group access and filtering for iteration.
Set of Attribute Arrays which tracks metadata about each array.
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:141
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:140
#define VMASK_
Definition PointDataGrid.h:702
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Convenience wrappers to using Blosc and reading and writing of Paged data.
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition Coord.h:322
Container class that associates a tree with a transform and metadata.
Definition Grid.h:571
Definition Exceptions.h:57
Definition Exceptions.h:58
Definition Exceptions.h:60
Base class for storing metadata information in a grid.
Definition Metadata.h:25
Tag dispatch class that distinguishes constructors during file input.
Definition Types.h:689
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:683
Definition Exceptions.h:65
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition StreamCompression.h:208
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
Definition StreamCompression.h:217
void setInputStream(std::istream &is)
Definition StreamCompression.h:222
std::shared_ptr< PagedInputStream > Ptr
Definition StreamCompression.h:210
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition StreamCompression.h:245
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
Definition StreamCompression.h:254
void setOutputStream(std::ostream &os)
Definition StreamCompression.h:259
std::shared_ptr< PagedOutputStream > Ptr
Definition StreamCompression.h:247
void flush()
Manually flushes the current page to disk if non-zero.
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition io.h:31
std::map< std::string, std::any > AuxDataMap
Definition io.h:92
SharedPtr< StreamMetadata > Ptr
Definition io.h:33
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
const Coord & min() const
Definition Coord.h:324
const Coord & max() const
Definition Coord.h:325
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Int32 y() const
Definition Coord.h:132
Int32 x() const
Definition Coord.h:131
Int32 z() const
Definition Coord.h:133
Base class for storing attribute data.
Definition AttributeArray.h:94
std::shared_ptr< AttributeArray > Ptr
Definition AttributeArray.h:126
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
virtual void writePagedBuffers(compression::PagedOutputStream &, bool outputTransient) const =0
An immutable object that stores name, type and AttributeSet position for a constant collection of att...
Definition AttributeSet.h:311
Util::GroupIndex GroupIndex
Definition AttributeSet.h:317
std::shared_ptr< Descriptor > Ptr
Definition AttributeSet.h:313
Ordered collection of uniquely-named attribute arrays.
Definition AttributeSet.h:40
@ INVALID_POS
Definition AttributeSet.h:42
std::unique_ptr< AttributeSet > UniquePtr
Definition AttributeSet.h:46
std::shared_ptr< Descriptor > DescriptorPtr
Definition AttributeSet.h:50
Index filtering on group membership.
Definition AttributeGroup.h:136
static index::State state()
Definition AttributeGroup.h:146
Definition AttributeGroup.h:74
Definition AttributeGroup.h:103
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
Definition IndexIterator.h:141
A no-op filter that can be used when iterating over all indices.
Definition IndexIterator.h:52
Definition PointDataGrid.h:240
ChildOnCIter cbeginChildOn() const
Definition PointDataGrid.h:723
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node.
Definition PointDataGrid.h:1541
IndexIter< ValueAllCIter, NullFilter > IndexAllIter
Definition PointDataGrid.h:654
void setValueOn(Index offset)
Definition PointDataGrid.h:544
void setValueOff(const Coord &, const ValueType &)
Definition PointDataGrid.h:540
ChildOnCIter beginChildOn() const
Definition PointDataGrid.h:724
ChildOnIter beginChildOn()
Definition PointDataGrid.h:725
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
Definition PointDataGrid.h:582
void replaceAttributeSet(AttributeSet *attributeSet, bool allowMismatchingDescriptors=false)
Replace the underlying attribute set with the given attributeSet.
Definition PointDataGrid.h:850
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition PointDataGrid.h:634
GroupWriteHandle groupWriteHandle(const Name &name)
Read-write group handle from group name.
Definition PointDataGrid.h:991
const AttributeArray & constAttributeArray(const Name &attributeName) const
Definition PointDataGrid.h:952
IndexIter< ValueOffCIter, NullFilter > IndexOffIter
Definition PointDataGrid.h:656
ValueOnIter endValueOn()
Definition PointDataGrid.h:715
PointDataLeafNode< T, Log2Dim > LeafNodeType
Definition PointDataGrid.h:243
void writeTopology(std::ostream &os, bool toHalf=false) const
Definition PointDataGrid.h:1128
util::NodeMask< Log2Dim > NodeMaskType
Definition PointDataGrid.h:258
AttributeArray::Ptr appendAttribute(const Descriptor &expected, Descriptor::Ptr &replacement, const size_t pos, const Index strideOrTotalSize=1, const bool constantStride=true, const Metadata *metadata=nullptr, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Append an attribute to the leaf.
Definition PointDataGrid.h:806
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition PointDataGrid.h:459
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
Definition PointDataGrid.h:297
ValueOffCIter cbeginValueOff() const
Definition PointDataGrid.h:706
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Definition PointDataGrid.h:461
void validateOffsets() const
Throws an error if the voxel values on this leaf are not monotonically increasing or within the bound...
Definition PointDataGrid.h:887
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition PointDataGrid.h:287
bool operator==(const PointDataLeafNode &other) const
Definition PointDataGrid.h:446
const AttributeArray & attributeArray(const size_t pos) const
Definition PointDataGrid.h:919
bool hasSameTopology(const PointDataLeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition PointDataGrid.h:440
ChildOnIter endChildOn()
Definition PointDataGrid.h:735
ValueAllIter endValueAll()
Definition PointDataGrid.h:721
GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex &index)
Read-write group handle from group index.
Definition PointDataGrid.h:979
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
Definition PointDataGrid.h:640
void modifyValue(Index, const ModifyOp &)
Definition PointDataGrid.h:555
Index64 groupPointCount(const Name &groupName) const
Compute the point count in a specific group for the leaf.
Definition PointDataGrid.h:1079
void setValueOn(Index, const ValueType &)
Definition PointDataGrid.h:547
void setValuesOff()
Definition PointDataGrid.h:552
ValueAllCIter endValueAll() const
Definition PointDataGrid.h:720
const PointDataLeafNode * probeLeaf(const Coord &) const
Definition PointDataGrid.h:483
ChildOffCIter endChildOff() const
Definition PointDataGrid.h:737
void setValueOff(Index, const ValueType &)
Definition PointDataGrid.h:541
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition PointDataGrid.h:315
ValueAllCIter cbeginValueAll() const
Definition PointDataGrid.h:709
typename BaseLeaf::ChildOff ChildOff
Definition PointDataGrid.h:607
AttributeArray & attributeArray(const size_t pos)
Read-write attribute array reference from index.
Definition PointDataGrid.h:911
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition PointDataGrid.h:630
void readTopology(std::istream &is, bool fromHalf=false)
Definition PointDataGrid.h:1121
const PointDataLeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition PointDataGrid.h:478
void setValueOnly(Index, const ValueType &)
Definition PointDataGrid.h:535
tree::LeafNode< T, Log2Dim > BaseLeaf
Definition PointDataGrid.h:257
GroupHandle groupHandle(const Name &group) const
Read-only group handle from group name.
Definition PointDataGrid.h:971
std::shared_ptr< PointDataLeafNode > Ptr
Definition PointDataGrid.h:244
IndexAllIter beginIndexAll() const
Leaf index iterator.
Definition PointDataGrid.h:659
ValueOnCIter beginValueOn() const
Definition PointDataGrid.h:704
void clearAttributes(const bool updateValueMask=true, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Clear the attribute set.
Definition PointDataGrid.h:775
bool hasAttribute(const Name &attributeName) const
Returns true if an attribute with this name exists.
Definition PointDataGrid.h:798
typename BaseLeaf::ChildOn ChildOn
Definition PointDataGrid.h:606
void signedFloodFill(const ValueType &, const ValueType &)
Definition PointDataGrid.h:591
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
Definition PointDataGrid.h:275
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition PointDataGrid.h:561
typename BaseLeaf::ChildAll ChildAll
Definition PointDataGrid.h:608
IndexIter< IterT, FilterT > beginIndex(const FilterT &filter) const
IndexIter< ValueVoxelCIter, NullFilter > IndexVoxelIter
Definition PointDataGrid.h:653
ValueOnCIter cendValueOn() const
Definition PointDataGrid.h:713
void setOffsetOnly(Index offset, const ValueType &val)
Definition PointDataGrid.h:1114
Index64 pointCount() const
Compute the total point count for the leaf.
Definition PointDataGrid.h:1054
ValueOffCIter beginValueOff() const
Definition PointDataGrid.h:707
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one.
Definition PointDataGrid.h:865
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
Definition PointDataGrid.h:644
IndexOffIter beginIndexOff() const
Definition PointDataGrid.h:669
ChildAllCIter cbeginChildAll() const
Definition PointDataGrid.h:729
ChildOffIter endChildOff()
Definition PointDataGrid.h:738
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition PointDataGrid.h:574
void setValueOnly(const Coord &, const ValueType &)
Definition PointDataGrid.h:534
ChildAllIter beginChildAll()
Definition PointDataGrid.h:731
void renameAttributes(const Descriptor &expected, Descriptor::Ptr &replacement)
Rename attributes in attribute set (order must remain the same).
Definition PointDataGrid.h:833
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Definition PointDataGrid.h:480
static const Index DIM
Definition LeafNode.h:51
void setActiveState(const Coord &xyz, bool on)
Definition PointDataGrid.h:531
ValueOnIter beginValueOn()
Definition PointDataGrid.h:705
void initializeAttributes(const Descriptor::Ptr &descriptor, const Index arrayLength, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Create a new attribute set. Existing attributes will be removed.
Definition PointDataGrid.h:760
ValueVoxelCIter beginValueVoxel(const Coord &ijk) const
Leaf value voxel iterator.
Definition PointDataGrid.h:1024
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Definition PointDataGrid.h:464
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
Definition PointDataGrid.h:680
void assertNonModifiableUnlessZero(const ValueType &value)
Definition PointDataGrid.h:527
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Definition PointDataGrid.h:482
ChildOffCIter cbeginChildOff() const
Definition PointDataGrid.h:726
ChildOffIter beginChildOff()
Definition PointDataGrid.h:728
ChildOffCIter beginChildOff() const
Definition PointDataGrid.h:727
void dropAttributes(const std::vector< size_t > &pos, const Descriptor &expected, Descriptor::Ptr &replacement)
Drop list of attributes.
Definition PointDataGrid.h:818
void compactAttributes()
Compact all attributes in attribute set.
Definition PointDataGrid.h:840
void setValueOff(const Coord &xyz)
Definition PointDataGrid.h:537
bool operator!=(const PointDataLeafNode &other) const
Definition PointDataGrid.h:451
Index buffers() const
Definition PointDataGrid.h:1135
ValueOffIter endValueOff()
Definition PointDataGrid.h:718
void setValueOff(Index offset)
Definition PointDataGrid.h:538
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
Definition PointDataGrid.h:685
ChildAllCIter endChildAll() const
Definition PointDataGrid.h:740
void setOffsets(const std::vector< ValueType > &offsets, const bool updateValueMask=true)
Sets all of the voxel offset values on this leaf, from the given vector of offsets....
Definition PointDataGrid.h:872
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Definition PointDataGrid.h:485
void setOffsetOn(Index offset, const ValueType &val)
Definition PointDataGrid.h:1106
ValueOnCIter cbeginValueOn() const
Definition PointDataGrid.h:703
void writeBuffers(std::ostream &os, bool toHalf=false) const
Definition PointDataGrid.h:1330
IndexIter< ValueOnCIter, NullFilter > IndexOnIter
Definition PointDataGrid.h:655
void clip(const CoordBBox &, const ValueType &value)
Definition PointDataGrid.h:564
ChildOnCIter endChildOn() const
Definition PointDataGrid.h:734
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
Definition PointDataGrid.h:826
ChildOnCIter cendChildOn() const
Definition PointDataGrid.h:733
void fill(const ValueType &, bool)
Definition PointDataGrid.h:1570
ChildAllCIter cendChildAll() const
Definition PointDataGrid.h:739
PointDataLeafNode()
Default constructor.
Definition PointDataGrid.h:269
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Definition PointDataGrid.h:323
void assertNonmodifiable()
Definition PointDataGrid.h:520
Index64 memUsageIfLoaded() const
Definition PointDataGrid.h:1527
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition PointDataGrid.h:579
ChildAllIter endChildAll()
Definition PointDataGrid.h:741
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
Definition PointDataGrid.h:690
bool hasAttribute(const size_t pos) const
Returns true if an attribute with this index exists.
Definition PointDataGrid.h:791
GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex &index) const
}
Definition PointDataGrid.h:959
void resetBackground(const ValueType &, const ValueType &newBackground)
Definition PointDataGrid.h:586
typename NodeMaskType::OffIterator MaskOffIterator
Definition PointDataGrid.h:611
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
Definition PointDataGrid.h:304
AttributeSet::UniquePtr stealAttributeSet()
Steal the attribute set, a new, empty attribute set is inserted in it's place.
Definition PointDataGrid.h:751
void readBuffers(std::istream &is, bool fromHalf=false)
Definition PointDataGrid.h:1147
void setValue(const Coord &, const ValueType &)
Definition PointDataGrid.h:549
ValueAllCIter cendValueAll() const
Definition PointDataGrid.h:719
static const Index NUM_VALUES
Definition LeafNode.h:52
void negate()
Definition PointDataGrid.h:593
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
Definition PointDataGrid.h:628
ChildAllCIter beginChildAll() const
Definition PointDataGrid.h:730
typename BaseLeaf::ValueAll ValueAll
Definition PointDataGrid.h:599
std::pair< ValueType, ValueType > ValueTypePair
Definition PointDataGrid.h:247
void setValuesOn()
Definition PointDataGrid.h:551
AttributeSet::Descriptor Descriptor
Definition PointDataGrid.h:250
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition PointDataGrid.h:650
typename BaseLeaf::ValueOn ValueOn
Definition PointDataGrid.h:597
ChildOffCIter cendChildOff() const
Definition PointDataGrid.h:736
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
Definition PointDataGrid.h:642
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Definition PointDataGrid.h:455
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition PointDataGrid.h:571
IndexIter< ValueVoxelCIter, FilterT > beginIndexVoxel(const Coord &ijk, const FilterT &filter) const
Filtered leaf index iterator from voxel.
Definition PointDataGrid.h:1044
void fill(const ValueType &value)
Definition PointDataGrid.h:567
typename NodeMaskType::OnIterator MaskOnIterator
Definition PointDataGrid.h:610
void addLeaf(PointDataLeafNode *)
Definition PointDataGrid.h:453
static const Index SIZE
Definition LeafNode.h:54
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition PointDataGrid.h:1534
const AttributeArray & constAttributeArray(const size_t pos) const
Definition PointDataGrid.h:927
void signedFloodFill(const ValueType &)
Definition PointDataGrid.h:590
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
Definition PointDataGrid.h:632
ValueOffIter beginValueOff()
Definition PointDataGrid.h:708
void setValueOn(const Coord &xyz)
Definition PointDataGrid.h:543
void setActiveState(Index offset, bool on)
Definition PointDataGrid.h:532
AttributeArray & attributeArray(const Name &attributeName)
Read-write attribute array reference from name.
Definition PointDataGrid.h:934
IndexOnIter beginIndexOn() const
Definition PointDataGrid.h:664
typename BaseLeaf::ValueOff ValueOff
Definition PointDataGrid.h:598
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
Definition PointDataGrid.h:648
IndexVoxelIter beginIndexVoxel(const Coord &ijk) const
Leaf index iterator from voxel.
Definition PointDataGrid.h:1035
Index64 offPointCount() const
Compute the total inactive (off) point count for the leaf.
Definition PointDataGrid.h:1070
void modifyValue(const Coord &, const ModifyOp &)
Definition PointDataGrid.h:558
ValueOffCIter cendValueOff() const
Definition PointDataGrid.h:716
Index64 memUsage() const
Definition PointDataGrid.h:1520
void fill(const CoordBBox &, const ValueType &, bool)
Definition PointDataGrid.h:1548
Index64 onPointCount() const
Compute the total active (on) point count for the leaf.
Definition PointDataGrid.h:1061
ValueOffCIter endValueOff() const
Definition PointDataGrid.h:717
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition PointDataGrid.h:638
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
Definition PointDataGrid.h:646
PointDataLeafNode * probeLeaf(const Coord &)
Definition PointDataGrid.h:471
T ValueType
Definition PointDataGrid.h:246
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Definition PointDataGrid.h:473
ValueOnCIter endValueOn() const
Definition PointDataGrid.h:714
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition PointDataGrid.h:612
ValueAllCIter beginValueAll() const
Definition PointDataGrid.h:710
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
Definition PointDataGrid.h:281
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
Definition PointDataGrid.h:636
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
Definition PointDataGrid.h:311
void readBuffers(std::istream &is, const CoordBBox &, bool fromHalf=false)
Definition PointDataGrid.h:1154
const AttributeArray & attributeArray(const Name &attributeName) const
Definition PointDataGrid.h:943
friend class PointDataLeafNode
Definition PointDataGrid.h:616
void setValueOn(const Coord &, const ValueType &)
Definition PointDataGrid.h:546
ValueAllIter beginValueAll()
Definition PointDataGrid.h:711
std::vector< ValueType > IndexArray
Definition PointDataGrid.h:248
static TypedAttributeArray & cast(AttributeArray &attributeArray)
A forward iterator over array indices in a single voxel.
Definition IndexIterator.h:66
Definition InternalNode.h:35
Base class for iterators over internal and leaf nodes.
Definition Iterator.h:30
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim....
Definition LeafNode.h:39
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node.
Definition LeafNode.h:170
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition LeafNode.h:1306
void setValueMask(const NodeMaskType &mask)
Definition LeafNode.h:887
void setValuesOff()
Mark all voxels as inactive but don't change their values.
Definition LeafNode.h:475
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition LeafNode.h:1298
const Buffer & buffer() const
Definition LeafNode.h:348
void setValueMaskOn(Index n)
Definition LeafNode.h:893
static const Index NUM_VOXELS
Definition LeafNode.h:53
static const Index DIM
Definition LeafNode.h:51
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 LeafNode.h:1125
static const Index LEVEL
Definition LeafNode.h:55
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition LeafNode.h:1040
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition LeafNode.h:410
bool hasSameTopology(const LeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition LeafNode.h:1497
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition LeafNode.h:1432
Index64 memUsageIfLoaded() const
Definition LeafNode.h:1469
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition LeafNode.h:1334
static const Index NUM_VALUES
Definition LeafNode.h:52
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition LeafNode.h:598
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition LeafNode.h:1075
void setValuesOn()
Mark all voxels as active but don't change their values.
Definition LeafNode.h:473
static const Index LOG2DIM
Definition LeafNode.h:49
static const Index SIZE
Definition LeafNode.h:54
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition LeafNode.h:1479
bool isEmpty() const
Return true if this node has no active voxels.
Definition LeafNode.h:151
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition LeafNode.h:420
static const Index TOTAL
Definition LeafNode.h:50
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition LeafNode.h:1459
bool isDense() const
Return true if this node contains only active voxels.
Definition LeafNode.h:153
const ValueType & getLastValue() const
Return a const reference to the last value in the buffer.
Definition LeafNode.h:634
Definition RootNode.h:40
Definition Tree.h:195
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation.
Definition NodeMasks.h:308
DenseMaskIterator< NodeMask > DenseIterator
Definition NodeMasks.h:350
OnMaskIterator< NodeMask > OnIterator
Definition NodeMasks.h:348
OffMaskIterator< NodeMask > OffIterator
Definition NodeMasks.h:349
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
Definition openvdb.h:114
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition Compression.h:646
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition Compression.h:466
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme,...
size_t writeCompressedValuesSize(ValueT *srcBuf, Index srcCount, const MaskT &valueMask, uint8_t maskMetadata, bool toHalf, uint32_t compress)
Definition Compression.h:592
Definition IndexIterator.h:35
@ ALL
Definition IndexIterator.h:44
@ NONE
Definition IndexIterator.h:43
void initialize()
Global registration of point data-related types.
void uninitialize()
Global deregistration of point data-related types.
Definition AttributeArray.h:42
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
Definition PointDataGrid.h:1603
void prefetch(PointDataTreeT &tree, bool position=true, bool otherAttributes=true)
Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order to accelerate sub...
Definition PointDataGrid.h:1616
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointDataLeafNode< PointDataIndex32, 3 >, 4 >, 5 > > > PointDataTree
Point index tree configured to match the default VDB configurations.
Definition PointDataGrid.h:190
bool isGroup(const AttributeArray &array)
Definition AttributeGroup.h:64
TypedAttributeArray< GroupType, GroupCodec > GroupAttributeArray
Definition AttributeGroup.h:41
Grid< PointDataTree > PointDataGrid
Point data grid.
Definition PointDataGrid.h:195
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
Definition IndexIterator.h:315
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition PointDataGrid.h:1586
Definition PointDataGrid.h:170
std::string Name
Definition Name.h:19
Index32 Index
Definition Types.h:54
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
int32_t Int32
Definition Types.h:56
uint64_t Index64
Definition Types.h:53
const char * typeNameAsString()
Definition Types.h:516
PointIndex< Index32, 1 > PointDataIndex32
Definition Types.h:181
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition pnanovdb_validate_strides.h:20
A list of types (not necessarily unique)
Definition TypeList.h:578
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition io.h:124
Similiar to ValueConverter, but allows for tree configuration conversion to a PointDataTree....
Definition PointDataGrid.h:1710
tree::Tree< typename NodeChainT::Back > Type
Definition PointDataGrid.h:1713
typename TreeType::RootNodeType RootNodeT
Definition PointDataGrid.h:1711
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
Definition PointDataGrid.h:1712
typename PointDataNodeChain< ChildT, HeadLevel-1 >::Type SubtreeT
Definition PointDataGrid.h:1688
typename SubtreeT::template Append< InternalNodeT > Type
Definition PointDataGrid.h:1690
tree::InternalNode< typename SubtreeT::Back, Log2Dim > InternalNodeT
Definition PointDataGrid.h:1689
tree::InternalNode< LeafNodeT, Log2Dim > InternalNodeT
Definition PointDataGrid.h:1699
TypeList< LeafNodeT, InternalNodeT > Type
Definition PointDataGrid.h:1700
PointDataLeafNode< PointDataIndex32, ChildT::LOG2DIM > LeafNodeT
Definition PointDataGrid.h:1698
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Definition PointDataGrid.h:1677
tree::RootNode< typename SubtreeT::Back > RootNodeT
Definition PointDataGrid.h:1679
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition PointDataGrid.h:1678
typename SubtreeT::template Append< RootNodeT > Type
Definition PointDataGrid.h:1680
Definition PointIndexGrid.h:1359
Definition TreeIterator.h:61
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition LeafNode.h:253
Definition LeafNode.h:920
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218