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