OpenVDB  12.0.0
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 
250  using Descriptor = AttributeSet::Descriptor;
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  {
292  assertNonModifiableUnlessZero(value);
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.
326  AttributeSet::UniquePtr stealAttributeSet();
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
418  GroupWriteHandle groupWriteHandle(const Name& 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.
513  CoordBBox getNodeBoundingBox() const;
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(); }
535  void setValueOnly(Index, 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(); }
541  void setValueOff(Index, 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(); }
547  void setValueOn(Index, 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);
567  void fill(const ValueType& value) { assertNonModifiableUnlessZero(value); }
568  void fill(const ValueType&, bool);
569 
570  template<typename AccessorT>
571  void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
572 
573  template<typename ModifyOp, typename AccessorT>
574  void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
575  assertNonmodifiable();
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 
590  void signedFloodFill(const ValueType&) { assertNonmodifiable(); }
591  void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); }
592 
593  void negate() { assertNonmodifiable(); }
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<
631  MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn>;
632  using ValueOffIter = typename BaseLeaf::template ValueIter<
633  MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff>;
634  using ValueOffCIter = typename BaseLeaf::template ValueIter<
635  MaskOffIterator,const PointDataLeafNode,const ValueType,ValueOff>;
636  using ValueAllIter = typename BaseLeaf::template ValueIter<
637  MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll>;
638  using ValueAllCIter = typename BaseLeaf::template ValueIter<
639  MaskDenseIterator,const PointDataLeafNode,const ValueType,ValueAll>;
640  using ChildOnIter = typename BaseLeaf::template ChildIter<
641  MaskOnIterator, PointDataLeafNode, ChildOn>;
642  using ChildOnCIter = typename BaseLeaf::template ChildIter<
643  MaskOnIterator, const PointDataLeafNode, ChildOn>;
644  using ChildOffIter = typename BaseLeaf::template ChildIter<
645  MaskOffIterator, PointDataLeafNode, ChildOff>;
646  using ChildOffCIter = typename BaseLeaf::template ChildIter<
647  MaskOffIterator, const PointDataLeafNode, ChildOff>;
648  using ChildAllIter = typename BaseLeaf::template DenseIter<
649  PointDataLeafNode, ValueType, ChildAll>;
650  using ChildAllCIter = typename BaseLeaf::template DenseIter<
651  const PointDataLeafNode, const ValueType, ChildAll>;
652 
657 
658  /// @brief Leaf index iterator
660  {
661  NullFilter filter;
662  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
663  }
665  {
666  NullFilter filter;
667  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
668  }
670  {
671  NullFilter filter;
672  return this->beginIndex<ValueOffCIter, NullFilter>(filter);
673  }
674 
675  template<typename IterT, typename FilterT>
676  IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
677 
678  /// @brief Filtered leaf index iterator
679  template<typename FilterT>
681  {
682  return this->beginIndex<ValueAllCIter, FilterT>(filter);
683  }
684  template<typename FilterT>
685  IndexIter<ValueOnCIter, FilterT> beginIndexOn(const FilterT& filter) const
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>
1000 PointDataLeafNode<T, Log2Dim>::beginIndex(const FilterT& filter) const
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()) {
1340  compression::PagedOutputStream& stream = *(std::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1341  stream.flush();
1342  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1343  }
1344  }
1345 
1346  static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1347  const Index index)
1348  {
1349  std::string key("paged:" + std::to_string(index));
1350  auto it = auxData.find(key);
1351  if (it != auxData.end()) {
1352  return *(std::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1353  }
1354  else {
1355  compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1356  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1357  return *pagedStream;
1358  }
1359  }
1360 
1361  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1362  const Descriptor::Ptr descriptor)
1363  {
1364  std::string descriptorKey("descriptorPtr");
1365  std::string matchingKey("hasMatchingDescriptor");
1366  auto itMatching = auxData.find(matchingKey);
1367  auto itDescriptor = auxData.find(descriptorKey);
1368  if (itMatching == auxData.end()) {
1369  // if matching bool is not found, insert "true" and the descriptor
1370  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1371  OPENVDB_ASSERT(itDescriptor == auxData.end());
1372  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1373  }
1374  else {
1375  // if matching bool is found and is false, early exit (a previous descriptor did not match)
1376  bool matching = std::any_cast<bool>(itMatching->second);
1377  if (!matching) return;
1378  OPENVDB_ASSERT(itDescriptor != auxData.end());
1379  // if matching bool is true, check whether the existing descriptor matches the current one and set
1380  // matching bool to false if not
1381  const Descriptor::Ptr existingDescriptor = std::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1382  if (*existingDescriptor != *descriptor) {
1383  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1384  }
1385  }
1386  }
1387 
1388  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1389  {
1390  std::string matchingKey("hasMatchingDescriptor");
1391  auto itMatching = auxData.find(matchingKey);
1392  // if matching key is not found, no matching descriptor
1393  if (itMatching == auxData.end()) return false;
1394  // if matching key is found and is false, no matching descriptor
1395  if (!std::any_cast<bool>(itMatching->second)) return false;
1396  return true;
1397  }
1398 
1399  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1400  {
1401  std::string descriptorKey("descriptorPtr");
1402  auto itDescriptor = auxData.find(descriptorKey);
1403  // if matching key is true, however descriptor is not found, it has already been retrieved
1404  if (itDescriptor == auxData.end()) return nullptr;
1405  // otherwise remove it and return it
1406  const Descriptor::Ptr descriptor = std::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1407  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1408  return descriptor;
1409  }
1410 
1411  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1412  {
1413  std::string matchingKey("hasMatchingDescriptor");
1414  std::string descriptorKey("descriptorPtr");
1415  auto itMatching = auxData.find(matchingKey);
1416  auto itDescriptor = auxData.find(descriptorKey);
1417  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1418  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1419  }
1420  };
1421 
1423 
1424  if (!meta) {
1425  OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1426  }
1427 
1428  const Index pass(static_cast<uint16_t>(meta->pass()));
1429 
1430  // leaf traversal analysis deduces the number of passes to perform for this leaf
1431  // then updates the leaf traversal value to ensure all passes will be written
1432 
1433  if (meta->countingPasses()) {
1434  const Index requiredPasses = this->buffers();
1435  if (requiredPasses > pass) {
1436  meta->setPass(requiredPasses);
1437  }
1438  return;
1439  }
1440 
1441  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1442  const Index attributes = (maximumPass - 4) / 2;
1443 
1444  if (pass == 0) {
1445  // pass 0 - voxel data sizes
1446  io::writeCompressedValuesSize(os, this->buffer().data(), SIZE);
1447  // track if descriptor is shared or not
1448  Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1449  }
1450  else if (pass == 1) {
1451  // pass 1 - descriptor and attribute metadata
1452  bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1453  if (matchingDescriptor) {
1454  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1455  if (descriptor) {
1456  // write a header to indicate a shared descriptor
1457  uint8_t header(1);
1458  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1459  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1460  }
1461  }
1462  else {
1463  // write a header to indicate a non-shared descriptor
1464  uint8_t header(0);
1465  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1466  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1467  }
1468  mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1469  }
1470  else if (pass < attributes + 2) {
1471  // pass 2...n+2 - attribute buffer sizes
1472  const Index attributeIndex = pass - 2;
1473  // destroy previous paged stream
1474  if (pass > 2) {
1475  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1476  }
1477  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1478  mAttributeSet->getConst(attributeIndex) : nullptr;
1479  if (array) {
1480  compression::PagedOutputStream& pagedStream =
1481  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1482  pagedStream.setOutputStream(os);
1483  pagedStream.setSizeOnly(true);
1484  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1485  }
1486  }
1487  else if (pass == attributes + 2) {
1488  const Index attributeIndex = pass - 3;
1489  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1490  // pass n+2 - voxel data
1491  BaseLeaf::writeBuffers(os, toHalf);
1492  }
1493  else if (pass < (attributes*2 + 3)) {
1494  // pass n+3...2n+3 - attribute buffers
1495  const Index attributeIndex = pass - attributes - 3;
1496  // destroy previous paged stream
1497  if (pass > attributes + 2) {
1498  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1499  }
1500  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1501  mAttributeSet->getConst(attributeIndex) : nullptr;
1502  if (array) {
1503  compression::PagedOutputStream& pagedStream =
1504  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1505  pagedStream.setOutputStream(os);
1506  pagedStream.setSizeOnly(false);
1507  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1508  }
1509  }
1510  else if (pass < buffers()) {
1511  Local::clearMatchingDescriptor(meta->auxData());
1512  // pass 2n+3 - cleanup last paged stream
1513  const Index attributeIndex = pass - attributes - 4;
1514  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1515  }
1516 }
1517 
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
1534 PointDataLeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
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
1548 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1549 {
1550  if (!this->allocate()) return;
1551 
1552  this->assertNonModifiableUnlessZero(value);
1553 
1554  // active state is permitted to be updated
1555 
1556  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1557  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1558  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1559  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1560  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1561  const Index offset = offsetXY + (z & (DIM-1u));
1562  this->setValueMask(offset, active);
1563  }
1564  }
1565  }
1566 }
1567 
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 negate()
Definition: PointDataGrid.h:593
ChildOnIter endChildOn()
Definition: PointDataGrid.h:735
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:38
void setActiveState(const Coord &xyz, bool on)
Definition: PointDataGrid.h:531
ValueAllIter endValueAll()
Definition: PointDataGrid.h:721
ChildOnIter beginChildOn()
Definition: PointDataGrid.h:725
Definition: Tree.h:194
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition: pnanovdb_validate_strides.h:20
typename TreeType::RootNodeType RootNodeT
Definition: PointDataGrid.h:1711
Attribute Group access and filtering for iteration.
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: PointDataGrid.h:459
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
Definition: PointDataGrid.h:281
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
Definition: StreamCompression.h:217
Definition: Exceptions.h:60
void assertNonModifiableUnlessZero(const ValueType &value)
Definition: PointDataGrid.h:527
void setValuesOff()
Definition: PointDataGrid.h:552
Definition: PointIndexGrid.h:54
ChildAllCIter beginChildAll() const
Definition: PointDataGrid.h:730
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
Definition: PointDataGrid.h:582
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition: PointAttributeImpl.h:326
T ValueType
Definition: PointDataGrid.h:246
void setValueOn(Index offset)
Definition: PointDataGrid.h:544
PointDataLeafNode()
Default constructor.
Definition: PointDataGrid.h:269
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
Definition: PointDataGrid.h:304
ChildAllIter beginChildAll()
Definition: PointDataGrid.h:731
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:485
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:64
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
Definition: Exceptions.h:57
typename BaseLeaf::ValueAll ValueAll
Definition: PointDataGrid.h:599
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:480
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
void setValuesOn()
Definition: PointDataGrid.h:551
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: PointDataGrid.h:651
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:571
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttributeImpl.h:385
uint64_t Index64
Definition: Types.h:53
#define VMASK_
Definition: PointDataGrid.h:702
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
Definition: PointDataGrid.h:643
ChildAllCIter cbeginChildAll() const
Definition: PointDataGrid.h:729
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1586
static index::State state()
Definition: AttributeGroup.h:146
std::pair< ValueType, ValueType > ValueTypePair
Definition: PointDataGrid.h:247
void fill(const CoordBBox &, const ValueType &, bool)
Definition: PointDataGrid.h:1548
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
Definition: PointDataGrid.h:311
typename NodeMaskType::OnIterator MaskOnIterator
Definition: PointDataGrid.h:610
std::shared_ptr< PagedInputStream > Ptr
Definition: StreamCompression.h:210
IndexOnIter beginIndexOn() const
Definition: PointDataGrid.h:664
ValueOffCIter endValueOff() const
Definition: PointDataGrid.h:717
void clip(const CoordBBox &, const ValueType &value)
Definition: PointDataGrid.h:564
A list of types (not necessarily unique)
Definition: TypeList.h:577
Attribute Array storage templated on type and compression codec.
typename PointDataNodeChain< ChildT, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1688
ValueAllCIter cendValueAll() const
Definition: PointDataGrid.h:719
Definition: AttributeGroup.h:102
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:461
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
Definition: PointDataGrid.h:637
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:287
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:244
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
ValueAllCIter cbeginValueAll() const
Definition: PointDataGrid.h:709
void setValueOff(Index offset)
Definition: PointDataGrid.h:538
Definition: NodeMasks.h:270
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
Definition: IndexIterator.h:140
ChildOnCIter cendChildOn() const
Definition: PointDataGrid.h:733
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
Definition: PointDataGrid.h:826
Definition: NodeMasks.h:239
ChildAllCIter cendChildAll() const
Definition: PointDataGrid.h:739
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Definition: PointDataGrid.h:455
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
Definition: PointDataGrid.h:647
typename BaseLeaf::ChildAll ChildAll
Definition: PointDataGrid.h:608
std::shared_ptr< PointDataLeafNode > Ptr
Definition: PointDataGrid.h:244
bool operator!=(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:451
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
Definition: PointAttributeImpl.h:238
void uninitialize()
Global deregistration of point data-related types.
void appendAttribute(PointDataTreeT &tree, const Name &name, const NamePair &type, const Index strideOrTotalSize=1, const bool constantStride=true, const Metadata *defaultValue=nullptr, const bool hidden=false, const bool transient=false)
Appends a new attribute to the VDB tree (this method does not require a templated AttributeType) ...
Definition: PointAttributeImpl.h:103
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:315
const PointDataLeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:478
ValueAllCIter endValueAll() const
Definition: PointDataGrid.h:720
int32_t Int32
Definition: Types.h:56
Index filtering on group membership.
Definition: AttributeGroup.h:135
Definition: PointDataGrid.h:182
void setValueOnly(Index, const ValueType &)
Definition: PointDataGrid.h:535
Index32 Index
Definition: Types.h:54
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
Definition: PointDataGrid.h:1603
ValueOnCIter beginValueOn() const
Definition: PointDataGrid.h:704
typename NodeMaskType::OffIterator MaskOffIterator
Definition: PointDataGrid.h:611
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1678
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
Definition: PointDataGrid.h:685
void readCompressedValues(std::istream &is, PointDataIndex32 *destBuf, Index destCount, const util::NodeMask< 3 > &, bool)
openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask...
Definition: PointDataGrid.h:47
std::shared_ptr< PagedOutputStream > Ptr
Definition: StreamCompression.h:247
Definition: Exceptions.h:65
std::vector< ValueType > IndexArray
Definition: PointDataGrid.h:248
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
Definition: PointDataGrid.h:140
Definition: LeafNode.h:213
Definition: IndexIterator.h:44
Base class for storing metadata information in a grid.
Definition: Metadata.h:24
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
Definition: IndexIterator.h:315
ValueOnIter beginValueOn()
Definition: PointDataGrid.h:705
typename BaseLeaf::ValueOn ValueOn
Definition: PointDataGrid.h:597
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Definition: PointDataGrid.h:1676
Convenience wrappers to using Blosc and reading and writing of Paged data.
typename BaseLeaf::ValueOff ValueOff
Definition: PointDataGrid.h:598
Definition: IndexIterator.h:43
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
Definition: PointDataGrid.h:645
Definition: NodeMasks.h:208
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
Definition: AttributeGroup.h:73
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:30
Definition: InternalNode.h:34
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
ChildOnCIter beginChildOn() const
Definition: PointDataGrid.h:724
typename BaseLeaf::ChildOff ChildOff
Definition: PointDataGrid.h:607
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Definition: PointDataGrid.h:323
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
Definition: PointDataGrid.h:690
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
Definition: PointDataGrid.h:1712
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:483
void setValueOn(const Coord &xyz)
Definition: PointDataGrid.h:543
void setValueOff(const Coord &, const ValueType &)
Definition: PointDataGrid.h:540
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCountImpl.h:18
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:251
ValueOnCIter endValueOn() const
Definition: PointDataGrid.h:714
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:473
ValueOffCIter beginValueOff() const
Definition: PointDataGrid.h:707
SharedPtr< StreamMetadata > Ptr
Definition: io.h:33
Integer wrapper, required to distinguish PointIndexGrid and PointDataGrid from Int32Grid and Int64Gri...
Definition: Types.h:156
void setInputStream(std::istream &is)
Definition: StreamCompression.h:222
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...
Definition: Exceptions.h:13
IndexOffIter beginIndexOff() const
Definition: PointDataGrid.h:669
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
void resetBackground(const ValueType &, const ValueType &newBackground)
Definition: PointDataGrid.h:586
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
Definition: PointDataGrid.h:649
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: PointDataGrid.h:612
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:70
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition: PointDataGrid.h:574
ValueOffIter endValueOff()
Definition: PointDataGrid.h:718
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:122
ChildOffCIter cbeginChildOff() const
Definition: PointDataGrid.h:726
ValueAllIter beginValueAll()
Definition: PointDataGrid.h:711
void writeCompressedValues(std::ostream &os, PointDataIndex32 *srcBuf, Index srcCount, const util::NodeMask< 3 > &, const util::NodeMask< 3 > &, bool)
openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask...
Definition: PointDataGrid.h:107
typename SubtreeT::template Append< RootNodeT > Type
Definition: PointDataGrid.h:1680
void setValueOnly(const Coord &, const ValueType &)
Definition: PointDataGrid.h:534
std::unique_ptr< AttributeSet > UniquePtr
Definition: AttributeSet.h:46
void prefetch(PointDataTreeT &tree, bool position=true, bool otherAttributes=true)
Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order to accelerate sub...
Definition: PointDataGrid.h:1616
AttributeSet::Descriptor Descriptor
Definition: PointDataGrid.h:250
bool hasSameTopology(const PointDataLeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition: PointDataGrid.h:440
Definition: TreeIterator.h:60
Definition: RootNode.h:39
void setValueOn(const Coord &, const ValueType &)
Definition: PointDataGrid.h:546
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
Definition: PointDataGrid.h:680
ChildOffIter endChildOff()
Definition: PointDataGrid.h:738
ChildOffCIter endChildOff() const
Definition: PointDataGrid.h:737
ChildOnCIter cbeginChildOn() const
Definition: PointDataGrid.h:723
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
Definition: PointDataGrid.h:297
void modifyValue(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:558
void setValueOff(Index, const ValueType &)
Definition: PointDataGrid.h:541
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
ValueOnCIter cbeginValueOn() const
Definition: PointDataGrid.h:703
Definition: LeafNode.h:212
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:464
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
void setOutputStream(std::ostream &os)
Definition: StreamCompression.h:259
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
Definition: PointDataGrid.h:641
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:65
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.
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
Definition: PointDataGrid.h:275
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:482
ValueOnIter endValueOn()
Definition: PointDataGrid.h:715
ChildOffCIter beginChildOff() const
Definition: PointDataGrid.h:727
std::map< std::string, std::any > AuxDataMap
Definition: io.h:92
ChildOffIter beginChildOff()
Definition: PointDataGrid.h:728
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...
Definition: PointDataGrid.h:865
void addLeaf(PointDataLeafNode *)
Definition: PointDataGrid.h:453
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:579
ValueOnCIter cendValueOn() const
Definition: PointDataGrid.h:713
void setValue(const Coord &, const ValueType &)
Definition: PointDataGrid.h:549
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:561
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.
Definition: PointDataGrid.h:1710
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointDataGrid.h:631
ChildAllCIter endChildAll() const
Definition: PointDataGrid.h:740
bool operator==(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:446
void signedFloodFill(const ValueType &, const ValueType &)
Definition: PointDataGrid.h:591
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
Definition: PointDataGrid.h:633
Attribute array storage for string data using Descriptor Metadata.
std::shared_ptr< Descriptor > DescriptorPtr
Definition: AttributeSet.h:50
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:103
IndexAllIter beginIndexAll() const
Leaf index iterator.
Definition: PointDataGrid.h:659
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: PointDataGrid.h:639
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
Definition: StreamCompression.h:254
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:126
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition: io.h:124
Definition: Exceptions.h:58
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
ChildAllIter endChildAll()
Definition: PointDataGrid.h:741
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:207
void modifyValue(Index, const ModifyOp &)
Definition: PointDataGrid.h:555
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:683
ChildOffCIter cendChildOff() const
Definition: PointDataGrid.h:736
std::string Name
Definition: Name.h:19
ValueOffCIter cendValueOff() const
Definition: PointDataGrid.h:716
ValueOffCIter cbeginValueOff() const
Definition: PointDataGrid.h:706
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:39
void initialize()
Global registration of point data-related types.
ValueOffIter beginValueOff()
Definition: PointDataGrid.h:708
ValueAllCIter beginValueAll() const
Definition: PointDataGrid.h:710
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: PointDataGrid.h:471
typename SubtreeT::template Append< InternalNodeT > Type
Definition: PointDataGrid.h:1690
void reset(Index32 begin, Index32 end)
Reset the begining and end of the iterator.
Definition: IndexIterator.h:253
void signedFloodFill(const ValueType &)
Definition: PointDataGrid.h:590
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
void setActiveState(Index offset, bool on)
Definition: PointDataGrid.h:532
void setValueOn(Index, const ValueType &)
Definition: PointDataGrid.h:547
void flush()
Manually flushes the current page to disk if non-zero.
ChildOnCIter endChildOn() const
Definition: PointDataGrid.h:734
typename BaseLeaf::ChildOn ChildOn
Definition: PointDataGrid.h:606
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
Definition: PointDataGrid.h:629
Definition: PointDataGrid.h:171
Set of Attribute Arrays which tracks metadata about each array.
const char * typeNameAsString< Vec3f >()
Definition: Types.h:535
void fill(const ValueType &value)
Definition: PointDataGrid.h:567
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
void setValueOff(const Coord &xyz)
Definition: PointDataGrid.h:537
Typed class for storing attribute data.
Definition: AttributeArray.h:511
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: PointDataGrid.h:635
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:51
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
void assertNonmodifiable()
Definition: PointDataGrid.h:520
Base class for storing attribute data.
Definition: AttributeArray.h:93