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