HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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>
18 #include <openvdb/tree/LeafNode.h>
20 #include <openvdb/util/Assert.h>
21 #include "AttributeArray.h"
22 #include "AttributeArrayString.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 
34 class TestPointDataLeaf;
35 
36 namespace openvdb {
38 namespace OPENVDB_VERSION_NAME {
39 
40 namespace 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
45 template<>
46 inline void
47 readCompressedValues( 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
105 template<>
106 inline void
107 writeCompressedValues( 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 
138 template <typename T>
139 inline void
140 writeCompressedValuesSize(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
170 namespace tree {
171  template<Index, typename> struct SameLeafConfig;
172 }
173 
174 
175 ////////////////////////////////////////
176 
177 
178 namespace points {
179 
180 
181 // forward declaration
182 template<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.
206 template <typename PointDataTreeT>
207 inline AttributeSet::Descriptor::Ptr
208 makeDescriptorUnique(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.
220 template <typename PointDataTreeT>
221 inline void
222 setStreamingMode(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)
231 template <typename PointDataTreeT>
232 inline void
233 prefetch(PointDataTreeT& tree, bool position = true, bool otherAttributes = true);
234 
235 
236 ////////////////////////////////////////
237 
238 
239 template <typename T, Index Log2Dim>
240 class PointDataLeafNode : public tree::LeafNode<T, Log2Dim>, io::MultiPass {
241 
242 public:
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;
263  using BaseLeaf::NUM_VALUES;
264  using BaseLeaf::NUM_VOXELS;
265  using BaseLeaf::SIZE;
266  using BaseLeaf::LEVEL;
267 
268  /// Default constructor
270  : mAttributeSet(new AttributeSet) { }
271 
272  ~PointDataLeafNode() = default;
273 
274  /// Construct using deep copy of other PointDataLeafNode
275  explicit PointDataLeafNode(const PointDataLeafNode& other)
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 
315  PointDataLeafNode(PartialCreate, const Coord& coords,
316  const T& value = zeroVal<T>(), bool active = false)
317  : BaseLeaf(PartialCreate(), coords, value, active)
318  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
319 
320 public:
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
350  AttributeArray::Ptr appendAttribute(const Descriptor& expected, Descriptor::Ptr& replacement,
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.
370  void compactAttributes();
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
412  GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const;
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
416  GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index);
417  /// @brief Read-write group handle from group name
419 
420  /// @brief Compute the total point count for the leaf
421  Index64 pointCount() const;
422  /// @brief Compute the total active (on) point count for the leaf
423  Index64 onPointCount() const;
424  /// @brief Compute the total inactive (off) point count for the leaf
425  Index64 offPointCount() const;
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.
430  void updateValueMask();
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>
441  return BaseLeaf::hasSameTopology(other);
442  }
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 
506  Index64 memUsage() const;
507  Index64 memUsageIfLoaded() const;
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 
534  void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
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 
551  void setValuesOn() { BaseLeaf::setValuesOn(); }
552  void setValuesOff() { BaseLeaf::setValuesOff(); }
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);
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 
601 private:
602  AttributeSet::UniquePtr mAttributeSet;
603  uint16_t mVoxelBufferSize = 0;
604 
605 protected:
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 
622 public:
623  /// @brief Leaf value voxel iterator
624  ValueVoxelCIter beginValueVoxel(const Coord& ijk) const;
625 
626 public:
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<
652 
657 
658  /// @brief Leaf index iterator
660  {
662  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
663  }
665  {
667  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
668  }
670  {
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
696  IndexVoxelIter beginIndexVoxel(const Coord& ijk) const;
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 
749 template<typename T, Index Log2Dim>
752 {
753  AttributeSet::UniquePtr ptr = std::make_unique<AttributeSet>();
754  std::swap(ptr, mAttributeSet);
755  return ptr;
756 }
757 
758 template<typename T, Index Log2Dim>
759 inline void
760 PointDataLeafNode<T, Log2Dim>::initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
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 
773 template<typename T, Index Log2Dim>
774 inline 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 
789 template<typename T, Index Log2Dim>
790 inline bool
792 {
793  return pos < mAttributeSet->size();
794 }
795 
796 template<typename T, Index Log2Dim>
797 inline bool
799 {
800  const size_t pos = mAttributeSet->find(attributeName);
801  return pos != AttributeSet::INVALID_POS;
802 }
803 
804 template<typename T, Index Log2Dim>
805 inline AttributeArray::Ptr
806 PointDataLeafNode<T, Log2Dim>::appendAttribute( const Descriptor& expected, Descriptor::Ptr& replacement,
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 
816 template<typename T, Index Log2Dim>
817 inline void
818 PointDataLeafNode<T, Log2Dim>::dropAttributes(const std::vector<size_t>& pos,
819  const Descriptor& expected, Descriptor::Ptr& replacement)
820 {
821  mAttributeSet->dropAttributes(pos, expected, replacement);
822 }
823 
824 template<typename T, Index Log2Dim>
825 inline void
826 PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
827 {
828  mAttributeSet->reorderAttributes(replacement);
829 }
830 
831 template<typename T, Index Log2Dim>
832 inline void
833 PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
834 {
835  mAttributeSet->renameAttributes(expected, replacement);
836 }
837 
838 template<typename T, Index Log2Dim>
839 inline void
841 {
842  for (size_t i = 0; i < mAttributeSet->size(); i++) {
843  AttributeArray* array = mAttributeSet->get(i);
844  array->compact();
845  }
846 }
847 
848 template<typename T, Index Log2Dim>
849 inline void
850 PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
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 
863 template<typename T, Index Log2Dim>
864 inline void
865 PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
866 {
867  mAttributeSet->resetDescriptor(replacement);
868 }
869 
870 template<typename T, Index Log2Dim>
871 inline void
872 PointDataLeafNode<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 
885 template<typename T, Index Log2Dim>
886 inline 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 
909 template<typename T, Index Log2Dim>
910 inline AttributeArray&
912 {
913  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
914  return *mAttributeSet->get(pos);
915 }
916 
917 template<typename T, Index Log2Dim>
918 inline const AttributeArray&
920 {
921  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
922  return *mAttributeSet->getConst(pos);
923 }
924 
925 template<typename T, Index Log2Dim>
926 inline const AttributeArray&
928 {
929  return this->attributeArray(pos);
930 }
931 
932 template<typename T, Index Log2Dim>
933 inline 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 
941 template<typename T, Index Log2Dim>
942 inline 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 
950 template<typename T, Index Log2Dim>
951 inline const AttributeArray&
953 {
954  return this->attributeArray(attributeName);
955 }
956 
957 template<typename T, Index Log2Dim>
958 inline GroupHandle
959 PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
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 
969 template<typename T, Index Log2Dim>
970 inline GroupHandle
972 {
973  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
974  return this->groupHandle(index);
975 }
976 
977 template<typename T, Index Log2Dim>
978 inline GroupWriteHandle
979 PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
980 {
981  AttributeArray& array = this->attributeArray(index.first);
982  OPENVDB_ASSERT(isGroup(array));
983 
984  GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
985 
986  return GroupWriteHandle(groupArray, index.second);
987 }
988 
989 template<typename T, Index Log2Dim>
990 inline GroupWriteHandle
992 {
993  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
994  return this->groupWriteHandle(index);
995 }
996 
997 template<typename T, Index Log2Dim>
998 template<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 
1013  using IterTraitsT = tree::IterTraits<LeafNodeType, ValueIterT>;
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 
1022 template<typename T, Index Log2Dim>
1023 inline ValueVoxelCIter
1025 {
1026  const Index index = LeafNodeType::coordToOffset(ijk);
1027  OPENVDB_ASSERT(index < BaseLeaf::SIZE);
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 
1033 template<typename T, Index Log2Dim>
1036 {
1037  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1038  return IndexVoxelIter(iter, NullFilter());
1039 }
1040 
1041 template<typename T, Index Log2Dim>
1042 template<typename FilterT>
1044 PointDataLeafNode<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 
1052 template<typename T, Index Log2Dim>
1053 inline Index64
1055 {
1056  return this->getLastValue();
1057 }
1058 
1059 template<typename T, Index Log2Dim>
1060 inline Index64
1062 {
1063  if (this->isEmpty()) return 0;
1064  else if (this->isDense()) return this->pointCount();
1065  return iterCount(this->beginIndexOn());
1066 }
1067 
1068 template<typename T, Index Log2Dim>
1069 inline Index64
1071 {
1072  if (this->isEmpty()) return this->pointCount();
1073  else if (this->isDense()) return 0;
1074  return iterCount(this->beginIndexOff());
1075 }
1076 
1077 template<typename T, Index Log2Dim>
1078 inline 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 
1092 template<typename T, Index Log2Dim>
1093 inline 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 
1104 template<typename T, Index Log2Dim>
1105 inline void
1107 {
1108  this->buffer().setValue(offset, val);
1109  this->setValueMaskOn(offset);
1110 }
1111 
1112 template<typename T, Index Log2Dim>
1113 inline void
1115 {
1116  this->buffer().setValue(offset, val);
1117 }
1118 
1119 template<typename T, Index Log2Dim>
1120 inline void
1121 PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1122 {
1123  BaseLeaf::readTopology(is, fromHalf);
1124 }
1125 
1126 template<typename T, Index Log2Dim>
1127 inline void
1128 PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1129 {
1130  BaseLeaf::writeTopology(os, toHalf);
1131 }
1132 
1133 template<typename T, Index Log2Dim>
1134 inline 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 
1145 template<typename T, Index Log2Dim>
1146 inline void
1147 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1148 {
1149  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1150 }
1151 
1152 template<typename T, Index Log2Dim>
1153 inline void
1154 PointDataLeafNode<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 
1328 template<typename T, Index Log2Dim>
1329 inline void
1330 PointDataLeafNode<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()) {
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
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 
1518 template<typename T, Index Log2Dim>
1519 inline Index64
1521 {
1522  return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1523 }
1524 
1525 template<typename T, Index Log2Dim>
1526 inline Index64
1528 {
1529  return BaseLeaf::memUsageIfLoaded() + mAttributeSet->memUsageIfLoaded();
1530 }
1531 
1532 template<typename T, Index Log2Dim>
1533 inline void
1535 {
1536  BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1537 }
1538 
1539 template<typename T, Index Log2Dim>
1540 inline CoordBBox
1542 {
1543  return BaseLeaf::getNodeBoundingBox();
1544 }
1545 
1546 template<typename T, Index Log2Dim>
1547 inline void
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 
1568 template<typename T, Index Log2Dim>
1569 inline 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 
1584 template <typename PointDataTreeT>
1585 inline AttributeSet::Descriptor::Ptr
1586 makeDescriptorUnique(PointDataTreeT& tree)
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 
1601 template <typename PointDataTreeT>
1602 inline void
1603 setStreamingMode(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 
1614 template <typename PointDataTreeT>
1615 inline void
1616 prefetch(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 
1658 namespace 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.
1663 void initialize();
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.
1668 void uninitialize();
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<>.
1675 template<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
1685 template <typename ChildT, Index Log2Dim, int HeadLevel>
1686 struct 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
1695 template <typename ChildT, Index Log2Dim>
1696 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, /*HeadLevel=*/1>
1697 {
1701 };
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
1709 template <typename TreeType>
1711  using RootNodeT = typename TreeType::RootNodeType;
1714 };
1715 
1716 
1717 } // namespace points
1718 
1719 
1720 ////////////////////////////////////////
1721 
1722 
1723 namespace tree
1724 {
1725 
1726 /// Helper metafunction used to implement LeafNode::SameConfiguration
1727 /// (which, as an inner class, can't be independently specialized)
1728 template<Index Dim1, typename T2>
1729 struct 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
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
GLuint GLuint stream
Definition: glcorearb.h:1832
void initializeAttributes(const Descriptor::Ptr &descriptor, const Index arrayLength, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Create a new attribute set. Existing attributes will be removed.
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
Index64 onPointCount() const
Compute the total active (on) point count for the leaf.
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
AttributeSet::UniquePtr stealAttributeSet()
Steal the attribute set, a new, empty attribute set is inserted in it's place.
void setValue(const Coord &, const ValueType &)
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:276
Definition: ImfName.h:28
Descriptor & descriptor()
Return a reference to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:103
bool operator!=(const PointDataLeafNode &other) const
auto to_string(const T &value) -> std::string
Definition: format.h:4527
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
IndexVoxelIter beginIndexVoxel(const Coord &ijk) const
Leaf index iterator from voxel.
std::map< std::string, std::any > AuxDataMap
Definition: io.h:92
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
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. If updateValueMask is true, then the active value mask will be updated so voxels with points are active and empty voxels are inactive.
void modifyValue(const Coord &, const ModifyOp &)
GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex &index)
Read-write group handle from group index.
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...
GLboolean * data
Definition: glcorearb.h:131
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
void setValueOff(const Coord &, const ValueType &)
GLuint start
Definition: glcorearb.h:475
GLsizei const GLfloat * value
Definition: glcorearb.h:824
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:646
void renameAttributes(const Descriptor &expected, Descriptor::Ptr &replacement)
Rename attributes in attribute set (order must remain the same).
void writeTopology(std::ostream &os, bool toHalf=false) const
void dropAttributes(const std::vector< size_t > &pos, const Descriptor &expected, Descriptor::Ptr &replacement)
Drop list of attributes.
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...
SharedPtr< StreamMetadata > Ptr
Definition: io.h:33
bool hasAttribute(const size_t pos) const
Returns true if an attribute with this index exists.
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
void validateOffsets() const
Throws an error if the voxel values on this leaf are not monotonically increasing or within the bound...
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition: io.h:124
void updateValueMask()
Activate voxels with non-zero points, deactivate voxels with zero points.
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:245
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
IndexIter< IterT, FilterT > beginIndex(const FilterT &filter) const
void readBuffers(std::istream &is, bool fromHalf=false)
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
GLint y
Definition: glcorearb.h:103
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a pointer to this node.
void signedFloodFill(const ValueType &, const ValueType &)
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
void initialize()
Global registration of point data-related types.
Definition: logging.h:294
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:51
GLuint buffer
Definition: glcorearb.h:660
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
virtual void writePagedBuffers(compression::PagedOutputStream &, bool outputTransient) const =0
void readTopology(std::istream &is, bool fromHalf=false)
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
typename SubtreeT::template Append< RootNodeT > Type
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
bool isGroup(const AttributeArray &array)
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:5578
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2621
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:466
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
const PointDataLeafNode * probeConstLeaf(const Coord &) const
Return a pointer to this node.
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
void compactAttributes()
Compact all attributes in attribute set.
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:70
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
const char * typeNameAsString< Vec3f >()
Definition: Types.h:535
GLdouble n
Definition: glcorearb.h:2008
Base class for storing attribute data.
GLintptr offset
Definition: glcorearb.h:665
typename NodeMaskType::OffIterator MaskOffIterator
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
SYS_FORCE_INLINE const X * cast(const InstancablePtr *o)
IndexIter< ValueVoxelCIter, NullFilter > IndexVoxelIter
size_t writeCompressedValuesSize(ValueT *srcBuf, Index srcCount, const MaskT &valueMask, uint8_t maskMetadata, bool toHalf, uint32_t compress)
Definition: Compression.h:592
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:65
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2516
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
void uninitialize()
Global deregistration of point data-related types.
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:38
IndexAllIter beginIndexAll() const
Leaf index iterator.
void clearAttributes(const bool updateValueMask=true, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Clear the attribute set.
GLuint GLuint end
Definition: glcorearb.h:475
bool operator==(const PointDataLeafNode &other) const
Attribute array storage for string data using Descriptor Metadata.
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
const GLuint * buffers
Definition: glcorearb.h:661
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...
GLuint coords
Definition: glad.h:4091
Index64 memUsageIfLoaded(const TreeT &tree, bool threaded=true)
Return the deserialized memory usage of this tree. This is not necessarily equal to the current memor...
Definition: Count.h:502
void clip(const CoordBBox &, const ValueType &value)
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
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.
void setValueOnly(const Coord &, const ValueType &)
void setOffsetOn(Index offset, const ValueType &val)
Convenience wrappers to using Blosc and reading and writing of Paged data.
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter, const bool inCoreOnly, const bool threaded)
Count the total number of points in a PointDataTree.
GLuint const GLchar * name
Definition: glcorearb.h:786
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
Index64 offPointCount() const
Compute the total inactive (off) point count for the leaf.
GLint GLenum GLint x
Definition: glcorearb.h:409
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Index filtering on group membership.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
const AttributeArray & constAttributeArray(const size_t pos) const
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
void flush()
Manually flushes the current page to disk if non-zero.
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
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.
std::unique_ptr< AttributeSet > UniquePtr
Definition: AttributeSet.h:46
void fill(const CoordBBox &, const ValueType &, bool)
Library and file format version numbers.
ValueVoxelCIter beginValueVoxel(const Coord &ijk) const
Leaf value voxel iterator.
GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex &index) const
}
void setOffsetOnly(Index offset, const ValueType &val)
Typed class for storing attribute data.
Set of Attribute Arrays which tracks metadata about each array.
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Attribute Group access and filtering for iteration.
GLuint index
Definition: glcorearb.h:786
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
SIM_API const UT_StringHolder position
void resetBackground(const ValueType &, const ValueType &newBackground)
Base class for storing metadata information in a grid.
Definition: Metadata.h:24
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:39
#define VMASK_
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
void replaceAttributeSet(AttributeSet *attributeSet, bool allowMismatchingDescriptors=false)
Replace the underlying attribute set with the given attributeSet.
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
Integer wrapper, required to distinguish PointIndexGrid and PointDataGrid from Int32Grid and Int64Gri...
Definition: Types.h:156
#define SIZE
Definition: simple.C:41
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
void writeBuffers(std::ostream &os, bool toHalf=false) const
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:683
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:30
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Index64 groupPointCount(const Name &groupName) const
Compute the point count in a specific group for the leaf.
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Attribute Array storage templated on type and compression codec.
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Similiar to ValueConverter, but allows for tree configuration conversion to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a PointDataLeafNode is not a specialization of LeafNode.
typename NodeMaskType::DenseIterator MaskDenseIterator
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
AttributeArray & attributeArray(const size_t pos)
Read-write attribute array reference from index.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
void setValueOn(const Coord &, const ValueType &)
bool ValueType
Definition: NanoVDB.h:5729
A list of types (not necessarily unique)
Definition: TypeList.h:577
Index64 pointCount() const
Compute the total point count for the leaf.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566