OpenVDB  11.0.0
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 
249  using Descriptor = AttributeSet::Descriptor;
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  {
291  assertNonModifiableUnlessZero(value);
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.
325  AttributeSet::UniquePtr stealAttributeSet();
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
417  GroupWriteHandle groupWriteHandle(const Name& 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.
514  CoordBBox getNodeBoundingBox() const;
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(); }
536  void setValueOnly(Index, 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(); }
542  void setValueOff(Index, 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(); }
548  void setValueOn(Index, 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);
568  void fill(const ValueType& value) { assertNonModifiableUnlessZero(value); }
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&) {
576  assertNonmodifiable();
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 
591  void signedFloodFill(const ValueType&) { assertNonmodifiable(); }
592  void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); }
593 
594  void negate() { assertNonmodifiable(); }
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<
632  MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn>;
633  using ValueOffIter = typename BaseLeaf::template ValueIter<
634  MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff>;
635  using ValueOffCIter = typename BaseLeaf::template ValueIter<
636  MaskOffIterator,const PointDataLeafNode,const ValueType,ValueOff>;
637  using ValueAllIter = typename BaseLeaf::template ValueIter<
638  MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll>;
639  using ValueAllCIter = typename BaseLeaf::template ValueIter<
640  MaskDenseIterator,const PointDataLeafNode,const ValueType,ValueAll>;
641  using ChildOnIter = typename BaseLeaf::template ChildIter<
642  MaskOnIterator, PointDataLeafNode, ChildOn>;
643  using ChildOnCIter = typename BaseLeaf::template ChildIter<
644  MaskOnIterator, const PointDataLeafNode, ChildOn>;
645  using ChildOffIter = typename BaseLeaf::template ChildIter<
646  MaskOffIterator, PointDataLeafNode, ChildOff>;
647  using ChildOffCIter = typename BaseLeaf::template ChildIter<
648  MaskOffIterator, const PointDataLeafNode, ChildOff>;
649  using ChildAllIter = typename BaseLeaf::template DenseIter<
650  PointDataLeafNode, ValueType, ChildAll>;
651  using ChildAllCIter = typename BaseLeaf::template DenseIter<
652  const PointDataLeafNode, const ValueType, ChildAll>;
653 
658 
659  /// @brief Leaf index iterator
661  {
662  NullFilter filter;
663  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
664  }
666  {
667  NullFilter filter;
668  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
669  }
671  {
672  NullFilter filter;
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>
686  IndexIter<ValueOnCIter, FilterT> beginIndexOn(const FilterT& filter) const
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>
1001 PointDataLeafNode<T, Log2Dim>::beginIndex(const FilterT& filter) const
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()) {
1341  compression::PagedOutputStream& stream = *(std::any_cast<compression::PagedOutputStream::Ptr>(it->second));
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
1447  io::writeCompressedValuesSize(os, this->buffer().data(), SIZE);
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
1551 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
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 negate()
Definition: PointDataGrid.h:594
ChildOnIter endChildOn()
Definition: PointDataGrid.h:736
Definition: Exceptions.h:65
ValueAllIter endValueAll()
Definition: PointDataGrid.h:722
void setActiveState(const Coord &xyz, bool on)
Definition: PointDataGrid.h:532
ChildOnIter beginChildOn()
Definition: PointDataGrid.h:726
Definition: IndexIterator.h:42
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition: pnanovdb_validate_strides.h:20
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
void setInputStream(std::istream &is)
Definition: StreamCompression.h:221
Attribute Group access and filtering for iteration.
void assertNonModifiableUnlessZero(const ValueType &value)
Definition: PointDataGrid.h:528
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: PointDataGrid.h:458
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition: io.h:124
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
Definition: PointDataGrid.h:280
void setValuesOff()
Definition: PointDataGrid.h:553
ChildAllCIter beginChildAll() const
Definition: PointDataGrid.h:731
Definition: NodeMasks.h:208
Definition: TreeIterator.h:59
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
Definition: PointDataGrid.h:583
void setValueOn(Index offset)
Definition: PointDataGrid.h:545
T ValueType
Definition: PointDataGrid.h:245
PointDataLeafNode()
Default constructor.
Definition: PointDataGrid.h:268
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
Definition: PointDataGrid.h:303
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:70
ChildAllIter beginChildAll()
Definition: PointDataGrid.h:732
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:484
std::map< std::string, std::any > AuxDataMap
Definition: io.h:92
void uninitialize()
Global deregistration of point data-related types.
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:479
typename BaseLeaf::ValueAll ValueAll
Definition: PointDataGrid.h:600
void setValuesOn()
Definition: PointDataGrid.h:552
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: PointDataGrid.h:652
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:572
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Definition: InternalNode.h:33
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
#define VMASK_
Definition: PointDataGrid.h:703
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
Definition: PointDataGrid.h:644
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
void fill(const CoordBBox &, const ValueType &, bool)
Definition: PointDataGrid.h:1551
static index::State state()
Definition: AttributeGroup.h:145
ChildAllCIter cbeginChildAll() const
Definition: PointDataGrid.h:730
std::pair< ValueType, ValueType > ValueTypePair
Definition: PointDataGrid.h:246
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
Definition: PointDataGrid.h:310
typename NodeMaskType::OnIterator MaskOnIterator
Definition: PointDataGrid.h:611
void clip(const CoordBBox &, const ValueType &value)
Definition: PointDataGrid.h:565
IndexOnIter beginIndexOn() const
Definition: PointDataGrid.h:665
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:1619
ValueOffCIter endValueOff() const
Definition: PointDataGrid.h:718
Attribute Array storage templated on type and compression codec.
ValueAllCIter cendValueAll() const
Definition: PointDataGrid.h:720
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:460
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
Definition: PointDataGrid.h:638
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:286
A list of types (not necessarily unique)
Definition: TypeList.h:577
ValueAllCIter cbeginValueAll() const
Definition: PointDataGrid.h:710
Definition: RootNode.h:38
void setValueOff(Index offset)
Definition: PointDataGrid.h:539
Definition: NodeMasks.h:270
Definition: AttributeGroup.h:101
ChildOnCIter cendChildOn() const
Definition: PointDataGrid.h:734
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Definition: PointDataGrid.h:454
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
Definition: PointDataGrid.h:827
ChildAllCIter cendChildAll() const
Definition: PointDataGrid.h:740
std::shared_ptr< PointDataLeafNode > Ptr
Definition: PointDataGrid.h:243
bool operator!=(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:450
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
Definition: PointDataGrid.h:648
typename BaseLeaf::ChildAll ChildAll
Definition: PointDataGrid.h:609
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:314
const PointDataLeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:477
void initialize()
Global registration of point data-related types.
ValueAllCIter endValueAll() const
Definition: PointDataGrid.h:721
void setValueOnly(Index, const ValueType &)
Definition: PointDataGrid.h:536
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:125
ValueOnCIter beginValueOn() const
Definition: PointDataGrid.h:705
typename NodeMaskType::OffIterator MaskOffIterator
Definition: PointDataGrid.h:612
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
Definition: PointDataGrid.h:686
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:38
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:243
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
Base class for storing attribute data.
Definition: AttributeArray.h:92
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
Definition: IndexIterator.h:139
typename PointDataNodeChain< ChildT, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1691
std::vector< ValueType > IndexArray
Definition: PointDataGrid.h:247
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2535
typename BaseLeaf::ValueOn ValueOn
Definition: PointDataGrid.h:598
ValueOnIter beginValueOn()
Definition: PointDataGrid.h:706
uint64_t Index64
Definition: Types.h:53
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
typename BaseLeaf::ValueOff ValueOff
Definition: PointDataGrid.h:599
Convenience wrappers to using Blosc and reading and writing of Paged data.
typename SubtreeT::template Append< InternalNodeT > Type
Definition: PointDataGrid.h:1693
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:683
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
Definition: PointDataGrid.h:646
Base class for storing metadata information in a grid.
Definition: Metadata.h:23
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:37
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:30
typename BaseLeaf::ChildOff ChildOff
Definition: PointDataGrid.h:608
ChildOnCIter beginChildOn() const
Definition: PointDataGrid.h:725
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
Definition: PointDataGrid.h:691
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Definition: PointDataGrid.h:322
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:482
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Definition: PointDataGrid.h:1679
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
void setValueOn(const Coord &xyz)
Definition: PointDataGrid.h:544
void setValueOff(const Coord &, const ValueType &)
Definition: PointDataGrid.h:541
typename SubtreeT::template Append< RootNodeT > Type
Definition: PointDataGrid.h:1683
const char * typeNameAsString< Vec3f >()
Definition: Types.h:535
ValueOnCIter endValueOn() const
Definition: PointDataGrid.h:715
ValueOffCIter beginValueOff() const
Definition: PointDataGrid.h:708
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:472
std::shared_ptr< PagedOutputStream > Ptr
Definition: StreamCompression.h:246
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition: PointAttributeImpl.h:326
Definition: Exceptions.h:13
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
Definition: PointDataGrid.h:139
IndexOffIter beginIndexOff() const
Definition: PointDataGrid.h:670
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:121
void resetBackground(const ValueType &, const ValueType &newBackground)
Definition: PointDataGrid.h:587
Definition: Tree.h:177
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
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:1713
Definition: PointDataGrid.h:170
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
Definition: PointDataGrid.h:650
std::unique_ptr< AttributeSet > UniquePtr
Definition: AttributeSet.h:45
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: PointDataGrid.h:613
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition: PointDataGrid.h:575
Typed class for storing attribute data.
Definition: AttributeArray.h:544
ChildOffCIter cbeginChildOff() const
Definition: PointDataGrid.h:727
ValueOffIter endValueOff()
Definition: PointDataGrid.h:719
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1589
Definition: LeafNode.h:210
ValueAllIter beginValueAll()
Definition: PointDataGrid.h:712
void reset(Index32 begin, Index32 end)
Reset the begining and end of the iterator.
Definition: IndexIterator.h:252
std::string Name
Definition: Name.h:19
void setValueOnly(const Coord &, const ValueType &)
Definition: PointDataGrid.h:535
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.
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:439
AttributeSet::Descriptor Descriptor
Definition: PointDataGrid.h:249
typename TreeType::RootNodeType RootNodeT
Definition: PointDataGrid.h:1714
Index32 Index
Definition: Types.h:54
void setValueOn(const Coord &, const ValueType &)
Definition: PointDataGrid.h:547
Definition: Exceptions.h:57
std::shared_ptr< PagedInputStream > Ptr
Definition: StreamCompression.h:209
ChildOffIter endChildOff()
Definition: PointDataGrid.h:739
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
Definition: PointDataGrid.h:681
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttributeImpl.h:385
ChildOffCIter endChildOff() const
Definition: PointDataGrid.h:738
ChildOnCIter cbeginChildOn() const
Definition: PointDataGrid.h:724
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
Definition: PointDataGrid.h:296
void modifyValue(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:559
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:63
void setValueOff(Index, const ValueType &)
Definition: PointDataGrid.h:542
Index filtering on group membership.
Definition: AttributeGroup.h:134
SharedPtr< StreamMetadata > Ptr
Definition: io.h:33
ValueOnCIter cbeginValueOn() const
Definition: PointDataGrid.h:704
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:463
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
Definition: StreamCompression.h:216
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:106
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:64
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
Definition: PointDataGrid.h:642
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:46
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
Definition: PointDataGrid.h:274
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:481
ValueOnIter endValueOn()
Definition: PointDataGrid.h:716
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
ChildOffCIter beginChildOff() const
Definition: PointDataGrid.h:728
ChildOffIter beginChildOff()
Definition: PointDataGrid.h:729
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:866
ValueOnCIter cendValueOn() const
Definition: PointDataGrid.h:714
void addLeaf(PointDataLeafNode *)
Definition: PointDataGrid.h:452
void setValue(const Coord &, const ValueType &)
Definition: PointDataGrid.h:550
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:580
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:562
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...
void setOutputStream(std::ostream &os)
Definition: StreamCompression.h:258
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
Definition: PointAttributeImpl.h:238
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointDataGrid.h:632
ChildAllCIter endChildAll() const
Definition: PointDataGrid.h:741
Definition: IndexIterator.h:43
bool operator==(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:445
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
void signedFloodFill(const ValueType &, const ValueType &)
Definition: PointDataGrid.h:592
Attribute array storage for string data using Descriptor Metadata.
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
Definition: PointDataGrid.h:634
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: PointDataGrid.h:640
IndexAllIter beginIndexAll() const
Leaf index iterator.
Definition: PointDataGrid.h:660
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:206
Definition: PointIndexGrid.h:53
Definition: AttributeGroup.h:72
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:1606
ChildAllIter endChildAll()
Definition: PointDataGrid.h:742
std::shared_ptr< Descriptor > DescriptorPtr
Definition: AttributeSet.h:49
Definition: Exceptions.h:58
ChildOffCIter cendChildOff() const
Definition: PointDataGrid.h:737
void modifyValue(Index, const ModifyOp &)
Definition: PointDataGrid.h:556
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:248
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
Definition: StreamCompression.h:253
ValueOffCIter cendValueOff() const
Definition: PointDataGrid.h:717
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
ValueOffCIter cbeginValueOff() const
Definition: PointDataGrid.h:707
Definition: NodeMasks.h:239
Definition: PointDataGrid.h:181
ValueOffIter beginValueOff()
Definition: PointDataGrid.h:709
ValueAllCIter beginValueAll() const
Definition: PointDataGrid.h:711
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
Definition: PointDataGrid.h:1715
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: PointDataGrid.h:470
void setActiveState(Index offset, bool on)
Definition: PointDataGrid.h:533
void signedFloodFill(const ValueType &)
Definition: PointDataGrid.h:591
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:102
void setValueOn(Index, const ValueType &)
Definition: PointDataGrid.h:548
ChildOnCIter endChildOn() const
Definition: PointDataGrid.h:735
typename BaseLeaf::ChildOn ChildOn
Definition: PointDataGrid.h:607
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
Definition: IndexIterator.h:314
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
Definition: PointDataGrid.h:630
int32_t Int32
Definition: Types.h:56
Set of Attribute Arrays which tracks metadata about each array.
Definition: LeafNode.h:209
void setValueOff(const Coord &xyz)
Definition: PointDataGrid.h:538
void flush()
Manually flushes the current page to disk if non-zero.
void fill(const ValueType &value)
Definition: PointDataGrid.h:568
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1681
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: PointDataGrid.h:636
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
Integer wrapper, required to distinguish PointIndexGrid and PointDataGrid from Int32Grid and Int64Gri...
Definition: Types.h:156
void assertNonmodifiable()
Definition: PointDataGrid.h:521
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
Definition: Exceptions.h:60