HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointDataGrid.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @author Dan Bailey
5 ///
6 /// @file points/PointDataGrid.h
7 ///
8 /// @brief Attribute-owned data structure for points. Point attributes are
9 /// stored in leaf nodes and ordered by voxel for fast random and
10 /// sequential access.
11 
12 #ifndef OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
13 #define OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
14 
15 #include <openvdb/version.h>
16 #include <openvdb/Grid.h>
17 #include <openvdb/tree/Tree.h>
18 #include <openvdb/tree/LeafNode.h>
20 #include "AttributeArray.h"
21 #include "AttributeArrayString.h"
22 #include "AttributeGroup.h"
23 #include "AttributeSet.h"
24 #include "StreamCompression.h"
25 #include <cstring> // std::memcpy
26 #include <iostream>
27 #include <limits>
28 #include <memory>
29 #include <type_traits> // std::is_same
30 #include <utility> // std::pair, std::make_pair
31 #include <vector>
32 
33 class TestPointDataLeaf;
34 
35 namespace openvdb {
37 namespace OPENVDB_VERSION_NAME {
38 
39 namespace io
40 {
41 
42 /// @brief openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to
43 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
44 template<>
45 inline void
46 readCompressedValues( std::istream& is, PointDataIndex32* destBuf, Index destCount,
47  const util::NodeMask<3>& /*valueMask*/, bool /*fromHalf*/)
48 {
50 
51  const bool seek = destBuf == nullptr;
52 
53  const size_t destBytes = destCount*sizeof(PointDataIndex32);
54  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
55  if (destBytes >= maximumBytes) {
56  OPENVDB_THROW(openvdb::IoError, "Cannot read more than " <<
57  maximumBytes << " bytes in voxel values.")
58  }
59 
60  uint16_t bytes16;
61 
63 
64  if (seek && meta) {
65  // buffer size temporarily stored in the StreamMetadata pass
66  // to avoid having to perform an expensive disk read for 2-bytes
67  bytes16 = static_cast<uint16_t>(meta->pass());
68  // seek over size of the compressed buffer
69  is.seekg(sizeof(uint16_t), std::ios_base::cur);
70  }
71  else {
72  // otherwise read from disk
73  is.read(reinterpret_cast<char*>(&bytes16), sizeof(uint16_t));
74  }
75 
76  if (bytes16 == std::numeric_limits<uint16_t>::max()) {
77  // read or seek uncompressed data
78  if (seek) {
79  is.seekg(destBytes, std::ios_base::cur);
80  }
81  else {
82  is.read(reinterpret_cast<char*>(destBuf), destBytes);
83  }
84  }
85  else {
86  // read or seek uncompressed data
87  if (seek) {
88  is.seekg(int(bytes16), std::ios_base::cur);
89  }
90  else {
91  // decompress into the destination buffer
92  std::unique_ptr<char[]> bloscBuffer(new char[int(bytes16)]);
93  is.read(bloscBuffer.get(), bytes16);
94  std::unique_ptr<char[]> buffer = bloscDecompress( bloscBuffer.get(),
95  destBytes,
96  /*resize=*/false);
97  std::memcpy(destBuf, buffer.get(), destBytes);
98  }
99  }
100 }
101 
102 /// @brief openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to
103 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
104 template<>
105 inline void
106 writeCompressedValues( std::ostream& os, PointDataIndex32* srcBuf, Index srcCount,
107  const util::NodeMask<3>& /*valueMask*/,
108  const util::NodeMask<3>& /*childMask*/, bool /*toHalf*/)
109 {
111 
112  const size_t srcBytes = srcCount*sizeof(PointDataIndex32);
113  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
114  if (srcBytes >= maximumBytes) {
115  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
116  maximumBytes << " bytes in voxel values.")
117  }
118 
119  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
120 
121  size_t compressedBytes;
122  std::unique_ptr<char[]> buffer = bloscCompress( charBuffer, srcBytes,
123  compressedBytes, /*resize=*/false);
124 
125  if (compressedBytes > 0) {
126  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
127  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
128  os.write(reinterpret_cast<const char*>(buffer.get()), compressedBytes);
129  }
130  else {
131  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
132  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
133  os.write(reinterpret_cast<const char*>(srcBuf), srcBytes);
134  }
135 }
136 
137 template <typename T>
138 inline void
139 writeCompressedValuesSize(std::ostream& os, const T* srcBuf, Index srcCount)
140 {
142 
143  const size_t srcBytes = srcCount*sizeof(T);
144  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
145  if (srcBytes >= maximumBytes) {
146  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
147  maximumBytes << " bytes in voxel values.")
148  }
149 
150  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
151 
152  // calculate voxel buffer size after compression
153  size_t compressedBytes = bloscCompressedSize(charBuffer, srcBytes);
154 
155  if (compressedBytes > 0) {
156  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
157  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
158  }
159  else {
160  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
161  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
162  }
163 }
164 
165 } // namespace io
166 
167 
168 // forward declaration
169 namespace tree {
170  template<Index, typename> struct SameLeafConfig;
171 }
172 
173 
174 ////////////////////////////////////////
175 
176 
177 namespace points {
178 
179 
180 // forward declaration
181 template<typename T, Index Log2Dim> class PointDataLeafNode;
182 
183 // these aliases are disabled in one of the unit tests to ensure that
184 // they are not used by the Point headers
185 
186 #ifndef OPENVDB_DISABLE_POINT_DATA_TREE_ALIAS
187 
188 /// @brief Point index tree configured to match the default VDB configurations.
191 
192 
193 /// @brief Point data grid.
195 
196 #endif
197 
198 /// @brief Deep copy the descriptor across all leaf nodes.
199 ///
200 /// @param tree the PointDataTree.
201 ///
202 /// @return the new descriptor.
203 ///
204 /// @note This method will fail if the Descriptors in the tree are not all identical.
205 template <typename PointDataTreeT>
206 inline AttributeSet::Descriptor::Ptr
207 makeDescriptorUnique(PointDataTreeT& tree);
208 
209 
210 /// @brief Toggle the streaming mode on all attributes in the tree to collapse the attributes
211 /// after deconstructing a bound AttributeHandle to each array. This results in better
212 /// memory efficiency when the data is streamed into another data structure
213 /// (typically for rendering).
214 ///
215 /// @param tree the PointDataTree.
216 /// @param on @c true to enable streaming
217 ///
218 /// @note Multiple threads cannot safely access the same AttributeArray when using streaming.
219 template <typename PointDataTreeT>
220 inline void
221 setStreamingMode(PointDataTreeT& tree, bool on = true);
222 
223 
224 /// @brief Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order
225 /// to accelerate subsequent random access.
226 ///
227 /// @param tree the PointDataTree.
228 /// @param position if enabled, prefetch the position attribute (default is on)
229 /// @param otherAttributes if enabled, prefetch all other attributes (default is on)
230 template <typename PointDataTreeT>
231 inline void
232 prefetch(PointDataTreeT& tree, bool position = true, bool otherAttributes = true);
233 
234 
235 ////////////////////////////////////////
236 
237 
238 template <typename T, Index Log2Dim>
239 class PointDataLeafNode : public tree::LeafNode<T, Log2Dim>, io::MultiPass {
240 
241 public:
243  using Ptr = std::shared_ptr<PointDataLeafNode>;
244 
245  using ValueType = T;
246  using ValueTypePair = std::pair<ValueType, ValueType>;
247  using IndexArray = std::vector<ValueType>;
248 
250 
251  ////////////////////////////////////////
252 
253  // The following methods had to be copied from the LeafNode class
254  // to make the derived PointDataLeafNode class compatible with the tree structure.
255 
258 
259  using BaseLeaf::LOG2DIM;
260  using BaseLeaf::TOTAL;
261  using BaseLeaf::DIM;
262  using BaseLeaf::NUM_VALUES;
263  using BaseLeaf::NUM_VOXELS;
264  using BaseLeaf::SIZE;
265  using BaseLeaf::LEVEL;
266 
267  /// Default constructor
269  : mAttributeSet(new AttributeSet) { }
270 
271  ~PointDataLeafNode() = default;
272 
273  /// Construct using deep copy of other PointDataLeafNode
274  explicit PointDataLeafNode(const PointDataLeafNode& other)
275  : BaseLeaf(other)
276  , mAttributeSet(new AttributeSet(*other.mAttributeSet)) { }
277 
278  /// Construct using supplied origin, value and active status
279  explicit
280  PointDataLeafNode(const Coord& coords, const T& value = zeroVal<T>(), bool active = false)
281  : BaseLeaf(coords, zeroVal<T>(), active)
282  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
283 
284  /// Construct using supplied origin, value and active status
285  /// use attribute map from another PointDataLeafNode
286  PointDataLeafNode(const PointDataLeafNode& other, const Coord& coords,
287  const T& value = zeroVal<T>(), bool active = false)
288  : BaseLeaf(coords, zeroVal<T>(), active)
289  , mAttributeSet(new AttributeSet(*other.mAttributeSet))
290  {
292  }
293 
294  // Copy-construct from a PointIndexLeafNode with the same configuration but a different ValueType.
295  template<typename OtherValueType>
297  : BaseLeaf(other)
298  , mAttributeSet(new AttributeSet) { }
299 
300  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
301  // Used for topology copies - explicitly sets the value (background) to zeroVal
302  template <typename ValueType>
304  : BaseLeaf(other, zeroVal<T>(), TopologyCopy())
305  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
306 
307  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
308  // Used for topology copies - explicitly sets the on and off value (background) to zeroVal
309  template <typename ValueType>
310  PointDataLeafNode(const tree::LeafNode<ValueType, Log2Dim>& other, const T& /*offValue*/, const T& /*onValue*/, TopologyCopy)
311  : BaseLeaf(other, zeroVal<T>(), zeroVal<T>(), TopologyCopy())
312  , mAttributeSet(new AttributeSet) { }
313 
314  PointDataLeafNode(PartialCreate, const Coord& coords,
315  const T& value = zeroVal<T>(), bool active = false)
316  : BaseLeaf(PartialCreate(), coords, value, active)
317  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
318 
319 public:
320 
321  /// Retrieve the attribute set.
322  const AttributeSet& attributeSet() const { return *mAttributeSet; }
323 
324  /// @brief Steal the attribute set, a new, empty attribute set is inserted in it's place.
326 
327  /// @brief Create a new attribute set. Existing attributes will be removed.
328  void initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
329  const AttributeArray::ScopedRegistryLock* lock = nullptr);
330  /// @brief Clear the attribute set.
331  void clearAttributes(const bool updateValueMask = true,
332  const AttributeArray::ScopedRegistryLock* lock = nullptr);
333 
334  /// @brief Returns @c true if an attribute with this index exists.
335  /// @param pos Index of the attribute
336  bool hasAttribute(const size_t pos) const;
337  /// @brief Returns @c true if an attribute with this name exists.
338  /// @param attributeName Name of the attribute
339  bool hasAttribute(const Name& attributeName) const;
340 
341  /// @brief Append an attribute to the leaf.
342  /// @param expected Existing descriptor is expected to match this parameter.
343  /// @param replacement New descriptor to replace the existing one.
344  /// @param pos Index of the new attribute in the descriptor replacement.
345  /// @param strideOrTotalSize Stride of the attribute array (if constantStride), total size otherwise
346  /// @param constantStride if @c false, stride is interpreted as total size of the array
347  /// @param metadata optional default value metadata
348  /// @param lock an optional scoped registry lock to avoid contention
349  AttributeArray::Ptr appendAttribute(const Descriptor& expected, Descriptor::Ptr& replacement,
350  const size_t pos, const Index strideOrTotalSize = 1,
351  const bool constantStride = true,
352  const Metadata* metadata = nullptr,
353  const AttributeArray::ScopedRegistryLock* lock = nullptr);
354 
355  /// @brief Drop list of attributes.
356  /// @param pos vector of attribute indices to drop
357  /// @param expected Existing descriptor is expected to match this parameter.
358  /// @param replacement New descriptor to replace the existing one.
359  void dropAttributes(const std::vector<size_t>& pos,
360  const Descriptor& expected, Descriptor::Ptr& replacement);
361  /// @brief Reorder attribute set.
362  /// @param replacement New descriptor to replace the existing one.
363  void reorderAttributes(const Descriptor::Ptr& replacement);
364  /// @brief Rename attributes in attribute set (order must remain the same).
365  /// @param expected Existing descriptor is expected to match this parameter.
366  /// @param replacement New descriptor to replace the existing one.
367  void renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement);
368  /// @brief Compact all attributes in attribute set.
369  void compactAttributes();
370 
371  /// @brief Replace the underlying attribute set with the given @a attributeSet.
372  /// @details This leaf will assume ownership of the given attribute set. The descriptors must
373  /// match and the voxel offsets values will need updating if the point order is different.
374  /// @throws ValueError if @a allowMismatchingDescriptors is @c false and the descriptors
375  /// do not match
376  void replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors = false);
377 
378  /// @brief Replace the descriptor with a new one
379  /// The new Descriptor must exactly match the old one
380  void resetDescriptor(const Descriptor::Ptr& replacement);
381 
382  /// @brief Sets all of the voxel offset values on this leaf, from the given vector
383  /// of @a offsets. If @a updateValueMask is true, then the active value mask will
384  /// be updated so voxels with points are active and empty voxels are inactive.
385  void setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask = true);
386 
387  /// @brief Throws an error if the voxel values on this leaf are not monotonically
388  /// increasing or within the bounds of the attribute arrays
389  void validateOffsets() const;
390 
391  /// @brief Read-write attribute array reference from index
392  /// @details Attribute arrays can be shared across leaf nodes, so non-const
393  /// access will deep-copy the array to make it unique. Always prefer
394  /// accessing const arrays where possible to eliminate this copying.
395  /// {
396  AttributeArray& attributeArray(const size_t pos);
397  const AttributeArray& attributeArray(const size_t pos) const;
398  const AttributeArray& constAttributeArray(const size_t pos) const;
399  /// }
400  /// @brief Read-write attribute array reference from name
401  /// @details Attribute arrays can be shared across leaf nodes, so non-const
402  /// access will deep-copy the array to make it unique. Always prefer
403  /// accessing const arrays where possible to eliminate this copying.
404  /// {
405  AttributeArray& attributeArray(const Name& attributeName);
406  const AttributeArray& attributeArray(const Name& attributeName) const;
407  const AttributeArray& constAttributeArray(const Name& attributeName) const;
408  /// }
409 
410  /// @brief Read-only group handle from group index
411  GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const;
412  /// @brief Read-only group handle from group name
413  GroupHandle groupHandle(const Name& group) const;
414  /// @brief Read-write group handle from group index
415  GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index);
416  /// @brief Read-write group handle from group name
418 
419  /// @brief Compute the total point count for the leaf
420  Index64 pointCount() const;
421  /// @brief Compute the total active (on) point count for the leaf
422  Index64 onPointCount() const;
423  /// @brief Compute the total inactive (off) point count for the leaf
424  Index64 offPointCount() const;
425  /// @brief Compute the point count in a specific group for the leaf
426  Index64 groupPointCount(const Name& groupName) const;
427 
428  /// @brief Activate voxels with non-zero points, deactivate voxels with zero points.
429  void updateValueMask();
430 
431  ////////////////////////////////////////
432 
433  void setOffsetOn(Index offset, const ValueType& val);
434  void setOffsetOnly(Index offset, const ValueType& val);
435 
436  /// @brief Return @c true if the given node (which may have a different @c ValueType
437  /// than this node) has the same active value topology as this node.
438  template<typename OtherType, Index OtherLog2Dim>
440  return BaseLeaf::hasSameTopology(other);
441  }
442 
443  /// Check for buffer, state and origin equivalence first.
444  /// If this returns true, do a deeper comparison on the attribute set to check
445  bool operator==(const PointDataLeafNode& other) const {
446  if(BaseLeaf::operator==(other) != true) return false;
447  return (*this->mAttributeSet == *other.mAttributeSet);
448  }
449 
450  bool operator!=(const PointDataLeafNode& other) const { return !(other == *this); }
451 
453  template<typename AccessorT>
454  void addLeafAndCache(PointDataLeafNode*, AccessorT&) {}
455 
456  //@{
457  /// @brief Return a pointer to this node.
458  PointDataLeafNode* touchLeaf(const Coord&) { return this; }
459  template<typename AccessorT>
460  PointDataLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
461 
462  template<typename NodeT, typename AccessorT>
463  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
464  {
466  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
467  return reinterpret_cast<NodeT*>(this);
469  }
470  PointDataLeafNode* probeLeaf(const Coord&) { return this; }
471  template<typename AccessorT>
472  PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
473  //@}
474 
475  //@{
476  /// @brief Return a @const pointer to this node.
477  const PointDataLeafNode* probeConstLeaf(const Coord&) const { return this; }
478  template<typename AccessorT>
479  const PointDataLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
480  template<typename AccessorT>
481  const PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
482  const PointDataLeafNode* probeLeaf(const Coord&) const { return this; }
483  template<typename NodeT, typename AccessorT>
484  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
485  {
487  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
488  return reinterpret_cast<const NodeT*>(this);
490  }
491  //@}
492 
493  // I/O methods
494 
495  void readTopology(std::istream& is, bool fromHalf = false);
496  void writeTopology(std::ostream& os, bool toHalf = false) const;
497 
498  Index buffers() const;
499 
500  void readBuffers(std::istream& is, bool fromHalf = false);
501  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
502  void writeBuffers(std::ostream& os, bool toHalf = false) const;
503 
504 
505  Index64 memUsage() const;
506 
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 template<typename T, Index Log2Dim>
815 inline void
816 PointDataLeafNode<T, Log2Dim>::dropAttributes(const std::vector<size_t>& pos,
817  const Descriptor& expected, Descriptor::Ptr& replacement)
818 {
819  mAttributeSet->dropAttributes(pos, expected, replacement);
820 }
821 
822 template<typename T, Index Log2Dim>
823 inline void
824 PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
825 {
826  mAttributeSet->reorderAttributes(replacement);
827 }
828 
829 template<typename T, Index Log2Dim>
830 inline void
831 PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
832 {
833  mAttributeSet->renameAttributes(expected, replacement);
834 }
835 
836 template<typename T, Index Log2Dim>
837 inline void
839 {
840  for (size_t i = 0; i < mAttributeSet->size(); i++) {
841  AttributeArray* array = mAttributeSet->get(i);
842  array->compact();
843  }
844 }
845 
846 template<typename T, Index Log2Dim>
847 inline void
848 PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
849 {
850  if (!attributeSet) {
851  OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
852  }
853 
854  if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
855  OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
856  }
857 
858  mAttributeSet.reset(attributeSet);
859 }
860 
861 template<typename T, Index Log2Dim>
862 inline void
863 PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
864 {
865  mAttributeSet->resetDescriptor(replacement);
866 }
867 
868 template<typename T, Index Log2Dim>
869 inline void
870 PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
871 {
872  if (offsets.size() != LeafNodeType::NUM_VALUES) {
873  OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
874  }
875 
876  for (Index index = 0; index < offsets.size(); ++index) {
877  setOffsetOnly(index, offsets[index]);
878  }
879 
880  if (updateValueMask) this->updateValueMask();
881 }
882 
883 template<typename T, Index Log2Dim>
884 inline void
886 {
887  // Ensure all of the offset values are monotonically increasing
888  for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
889  if (this->getValue(index-1) > this->getValue(index)) {
890  OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
891  }
892  }
893 
894  // Ensure all attribute arrays are of equal length
895  for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
896  if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
897  OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
898  }
899  }
900 
901  // Ensure the last voxel's offset value matches the size of each attribute array
902  if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
903  OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
904  }
905 }
906 
907 template<typename T, Index Log2Dim>
908 inline AttributeArray&
910 {
911  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
912  return *mAttributeSet->get(pos);
913 }
914 
915 template<typename T, Index Log2Dim>
916 inline const AttributeArray&
918 {
919  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
920  return *mAttributeSet->getConst(pos);
921 }
922 
923 template<typename T, Index Log2Dim>
924 inline const AttributeArray&
926 {
927  return this->attributeArray(pos);
928 }
929 
930 template<typename T, Index Log2Dim>
931 inline AttributeArray&
933 {
934  const size_t pos = mAttributeSet->find(attributeName);
935  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
936  return *mAttributeSet->get(pos);
937 }
938 
939 template<typename T, Index Log2Dim>
940 inline const AttributeArray&
942 {
943  const size_t pos = mAttributeSet->find(attributeName);
944  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
945  return *mAttributeSet->getConst(pos);
946 }
947 
948 template<typename T, Index Log2Dim>
949 inline const AttributeArray&
951 {
952  return this->attributeArray(attributeName);
953 }
954 
955 template<typename T, Index Log2Dim>
956 inline GroupHandle
957 PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
958 {
959  const AttributeArray& array = this->attributeArray(index.first);
960  assert(isGroup(array));
961 
962  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
963 
964  return GroupHandle(groupArray, index.second);
965 }
966 
967 template<typename T, Index Log2Dim>
968 inline GroupHandle
970 {
971  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
972  return this->groupHandle(index);
973 }
974 
975 template<typename T, Index Log2Dim>
976 inline GroupWriteHandle
977 PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
978 {
979  AttributeArray& array = this->attributeArray(index.first);
980  assert(isGroup(array));
981 
982  GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
983 
984  return GroupWriteHandle(groupArray, index.second);
985 }
986 
987 template<typename T, Index Log2Dim>
988 inline GroupWriteHandle
990 {
991  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
992  return this->groupWriteHandle(index);
993 }
994 
995 template<typename T, Index Log2Dim>
996 template<typename ValueIterT, typename FilterT>
999 {
1000  // generate no-op iterator if filter evaluates no indices
1001 
1002  if (filter.state() == index::NONE) {
1003  return IndexIter<ValueIterT, FilterT>(ValueIterT(), filter);
1004  }
1005 
1006  // copy filter to ensure thread-safety
1007 
1008  FilterT newFilter(filter);
1009  newFilter.reset(*this);
1010 
1011  using IterTraitsT = tree::IterTraits<LeafNodeType, ValueIterT>;
1012 
1013  // construct the value iterator and reset the filter to use this leaf
1014 
1015  ValueIterT valueIter = IterTraitsT::begin(*this);
1016 
1017  return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
1018 }
1019 
1020 template<typename T, Index Log2Dim>
1021 inline ValueVoxelCIter
1023 {
1024  const Index index = LeafNodeType::coordToOffset(ijk);
1025  assert(index < BaseLeaf::SIZE);
1026  const ValueType end = this->getValue(index);
1027  const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1028  return ValueVoxelCIter(start, end);
1029 }
1030 
1031 template<typename T, Index Log2Dim>
1034 {
1035  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1036  return IndexVoxelIter(iter, NullFilter());
1037 }
1038 
1039 template<typename T, Index Log2Dim>
1040 template<typename FilterT>
1042 PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1043 {
1044  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1045  FilterT newFilter(filter);
1046  newFilter.reset(*this);
1047  return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1048 }
1049 
1050 template<typename T, Index Log2Dim>
1051 inline Index64
1053 {
1054  return this->getLastValue();
1055 }
1056 
1057 template<typename T, Index Log2Dim>
1058 inline Index64
1060 {
1061  if (this->isEmpty()) return 0;
1062  else if (this->isDense()) return this->pointCount();
1063  return iterCount(this->beginIndexOn());
1064 }
1065 
1066 template<typename T, Index Log2Dim>
1067 inline Index64
1069 {
1070  if (this->isEmpty()) return this->pointCount();
1071  else if (this->isDense()) return 0;
1072  return iterCount(this->beginIndexOff());
1073 }
1074 
1075 template<typename T, Index Log2Dim>
1076 inline Index64
1078 {
1079  if (!this->attributeSet().descriptor().hasGroup(groupName)) {
1080  return Index64(0);
1081  }
1082  GroupFilter filter(groupName, this->attributeSet());
1083  if (filter.state() == index::ALL) {
1084  return this->pointCount();
1085  } else {
1086  return iterCount(this->beginIndexAll(filter));
1087  }
1088 }
1089 
1090 template<typename T, Index Log2Dim>
1091 inline void
1093 {
1094  ValueType start = 0, end = 0;
1095  for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1096  end = this->getValue(n);
1097  this->setValueMask(n, (end - start) > 0);
1098  start = end;
1099  }
1100 }
1101 
1102 template<typename T, Index Log2Dim>
1103 inline void
1105 {
1106  this->buffer().setValue(offset, val);
1107  this->setValueMaskOn(offset);
1108 }
1109 
1110 template<typename T, Index Log2Dim>
1111 inline void
1113 {
1114  this->buffer().setValue(offset, val);
1115 }
1116 
1117 template<typename T, Index Log2Dim>
1118 inline void
1119 PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1120 {
1121  BaseLeaf::readTopology(is, fromHalf);
1122 }
1123 
1124 template<typename T, Index Log2Dim>
1125 inline void
1126 PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1127 {
1128  BaseLeaf::writeTopology(os, toHalf);
1129 }
1130 
1131 template<typename T, Index Log2Dim>
1132 inline Index
1134 {
1135  return Index( /*voxel buffer sizes*/ 1 +
1136  /*voxel buffers*/ 1 +
1137  /*attribute metadata*/ 1 +
1138  /*attribute uniform values*/ mAttributeSet->size() +
1139  /*attribute buffers*/ mAttributeSet->size() +
1140  /*cleanup*/ 1);
1141 }
1142 
1143 template<typename T, Index Log2Dim>
1144 inline void
1145 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1146 {
1147  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1148 }
1149 
1150 template<typename T, Index Log2Dim>
1151 inline void
1152 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1153 {
1154  struct Local
1155  {
1156  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1157  {
1158  // if paged stream exists, delete it
1159  std::string key("paged:" + std::to_string(index));
1160  auto it = auxData.find(key);
1161  if (it != auxData.end()) {
1162  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1163  }
1164  }
1165 
1166  static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1167  const Index index)
1168  {
1169  std::string key("paged:" + std::to_string(index));
1170  auto it = auxData.find(key);
1171  if (it != auxData.end()) {
1172  return *(hboost::any_cast<compression::PagedInputStream::Ptr>(it->second));
1173  }
1174  else {
1175  compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1176  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1177  return *pagedStream;
1178  }
1179  }
1180 
1181  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1182  {
1183  std::string matchingKey("hasMatchingDescriptor");
1184  auto itMatching = auxData.find(matchingKey);
1185  return itMatching != auxData.end();
1186  }
1187 
1188  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1189  {
1190  std::string matchingKey("hasMatchingDescriptor");
1191  std::string descriptorKey("descriptorPtr");
1192  auto itMatching = auxData.find(matchingKey);
1193  auto itDescriptor = auxData.find(descriptorKey);
1194  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1195  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1196  }
1197 
1198  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1199  const Descriptor::Ptr descriptor)
1200  {
1201  std::string descriptorKey("descriptorPtr");
1202  std::string matchingKey("hasMatchingDescriptor");
1203  auto itMatching = auxData.find(matchingKey);
1204  if (itMatching == auxData.end()) {
1205  // if matching bool is not found, insert "true" and the descriptor
1206  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1207  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1208  }
1209  }
1210 
1211  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1212  {
1213  std::string descriptorKey("descriptorPtr");
1214  auto itDescriptor = auxData.find(descriptorKey);
1215  assert(itDescriptor != auxData.end());
1216  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1217  return descriptor;
1218  }
1219  };
1220 
1222 
1223  if (!meta) {
1224  OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1225  }
1226 
1227  const Index pass(static_cast<uint16_t>(meta->pass()));
1228  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1229 
1230  const Index attributes = (maximumPass - 4) / 2;
1231 
1232  if (pass == 0) {
1233  // pass 0 - voxel data sizes
1234  is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1235  Local::clearMatchingDescriptor(meta->auxData());
1236  }
1237  else if (pass == 1) {
1238  // pass 1 - descriptor and attribute metadata
1239  if (Local::hasMatchingDescriptor(meta->auxData())) {
1240  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1241  mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1242  }
1243  else {
1244  uint8_t header;
1245  is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1246  mAttributeSet->readDescriptor(is);
1247  if (header & uint8_t(1)) {
1248  AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1249  Local::insertDescriptor(meta->auxData(), descriptor);
1250  }
1251  // a forwards-compatibility mechanism for future use,
1252  // if a 0x2 bit is set, read and skip over a specific number of bytes
1253  if (header & uint8_t(2)) {
1254  uint64_t bytesToSkip;
1255  is.read(reinterpret_cast<char*>(&bytesToSkip), sizeof(uint64_t));
1256  if (bytesToSkip > uint64_t(0)) {
1257  auto metadata = io::getStreamMetadataPtr(is);
1258  if (metadata && metadata->seekable()) {
1259  is.seekg(bytesToSkip, std::ios_base::cur);
1260  }
1261  else {
1262  std::vector<uint8_t> tempData(bytesToSkip);
1263  is.read(reinterpret_cast<char*>(&tempData[0]), bytesToSkip);
1264  }
1265  }
1266  }
1267  // this reader is only able to read headers with 0x1 and 0x2 bits set
1268  if (header > uint8_t(3)) {
1269  OPENVDB_THROW(IoError, "Unrecognised header flags in PointDataLeafNode");
1270  }
1271  }
1272  mAttributeSet->readMetadata(is);
1273  }
1274  else if (pass < (attributes + 2)) {
1275  // pass 2...n+2 - attribute uniform values
1276  const size_t attributeIndex = pass - 2;
1277  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1278  mAttributeSet->get(attributeIndex) : nullptr;
1279  if (array) {
1280  compression::PagedInputStream& pagedStream =
1281  Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1282  pagedStream.setInputStream(is);
1283  pagedStream.setSizeOnly(true);
1284  array->readPagedBuffers(pagedStream);
1285  }
1286  }
1287  else if (pass == attributes + 2) {
1288  // pass n+2 - voxel data
1289 
1290  const Index passValue(meta->pass());
1291 
1292  // StreamMetadata pass variable used to temporarily store voxel buffer size
1293  io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1294  nonConstMeta.setPass(mVoxelBufferSize);
1295 
1296  // readBuffers() calls readCompressedValues specialization above
1297  BaseLeaf::readBuffers(is, fromHalf);
1298 
1299  // pass now reset to original value
1300  nonConstMeta.setPass(passValue);
1301  }
1302  else if (pass < (attributes*2 + 3)) {
1303  // pass n+2..2n+2 - attribute buffers
1304  const Index attributeIndex = pass - attributes - 3;
1305  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1306  mAttributeSet->get(attributeIndex) : nullptr;
1307  if (array) {
1308  compression::PagedInputStream& pagedStream =
1309  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1310  pagedStream.setInputStream(is);
1311  pagedStream.setSizeOnly(false);
1312  array->readPagedBuffers(pagedStream);
1313  }
1314  // cleanup paged stream reference in auxiliary metadata
1315  if (pass > attributes + 3) {
1316  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1317  }
1318  }
1319  else if (pass < buffers()) {
1320  // pass 2n+3 - cleanup last paged stream
1321  const Index attributeIndex = pass - attributes - 4;
1322  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1323  }
1324 }
1325 
1326 template<typename T, Index Log2Dim>
1327 inline void
1328 PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1329 {
1330  struct Local
1331  {
1332  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1333  {
1334  // if paged stream exists, flush and delete it
1335  std::string key("paged:" + std::to_string(index));
1336  auto it = auxData.find(key);
1337  if (it != auxData.end()) {
1339  stream.flush();
1340  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1341  }
1342  }
1343 
1344  static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1345  const Index index)
1346  {
1347  std::string key("paged:" + std::to_string(index));
1348  auto it = auxData.find(key);
1349  if (it != auxData.end()) {
1350  return *(hboost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1351  }
1352  else {
1353  compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1354  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1355  return *pagedStream;
1356  }
1357  }
1358 
1359  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1360  const Descriptor::Ptr descriptor)
1361  {
1362  std::string descriptorKey("descriptorPtr");
1363  std::string matchingKey("hasMatchingDescriptor");
1364  auto itMatching = auxData.find(matchingKey);
1365  auto itDescriptor = auxData.find(descriptorKey);
1366  if (itMatching == auxData.end()) {
1367  // if matching bool is not found, insert "true" and the descriptor
1368  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1369  assert(itDescriptor == auxData.end());
1370  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1371  }
1372  else {
1373  // if matching bool is found and is false, early exit (a previous descriptor did not match)
1374  bool matching = hboost::any_cast<bool>(itMatching->second);
1375  if (!matching) return;
1376  assert(itDescriptor != auxData.end());
1377  // if matching bool is true, check whether the existing descriptor matches the current one and set
1378  // matching bool to false if not
1379  const Descriptor::Ptr existingDescriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1380  if (*existingDescriptor != *descriptor) {
1381  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1382  }
1383  }
1384  }
1385 
1386  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1387  {
1388  std::string matchingKey("hasMatchingDescriptor");
1389  auto itMatching = auxData.find(matchingKey);
1390  // if matching key is not found, no matching descriptor
1391  if (itMatching == auxData.end()) return false;
1392  // if matching key is found and is false, no matching descriptor
1393  if (!hboost::any_cast<bool>(itMatching->second)) return false;
1394  return true;
1395  }
1396 
1397  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1398  {
1399  std::string descriptorKey("descriptorPtr");
1400  auto itDescriptor = auxData.find(descriptorKey);
1401  // if matching key is true, however descriptor is not found, it has already been retrieved
1402  if (itDescriptor == auxData.end()) return nullptr;
1403  // otherwise remove it and return it
1404  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1405  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1406  return descriptor;
1407  }
1408 
1409  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1410  {
1411  std::string matchingKey("hasMatchingDescriptor");
1412  std::string descriptorKey("descriptorPtr");
1413  auto itMatching = auxData.find(matchingKey);
1414  auto itDescriptor = auxData.find(descriptorKey);
1415  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1416  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1417  }
1418  };
1419 
1421 
1422  if (!meta) {
1423  OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1424  }
1425 
1426  const Index pass(static_cast<uint16_t>(meta->pass()));
1427 
1428  // leaf traversal analysis deduces the number of passes to perform for this leaf
1429  // then updates the leaf traversal value to ensure all passes will be written
1430 
1431  if (meta->countingPasses()) {
1432  const Index requiredPasses = this->buffers();
1433  if (requiredPasses > pass) {
1434  meta->setPass(requiredPasses);
1435  }
1436  return;
1437  }
1438 
1439  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1440  const Index attributes = (maximumPass - 4) / 2;
1441 
1442  if (pass == 0) {
1443  // pass 0 - voxel data sizes
1445  // track if descriptor is shared or not
1446  Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1447  }
1448  else if (pass == 1) {
1449  // pass 1 - descriptor and attribute metadata
1450  bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1451  if (matchingDescriptor) {
1452  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1453  if (descriptor) {
1454  // write a header to indicate a shared descriptor
1455  uint8_t header(1);
1456  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1457  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1458  }
1459  }
1460  else {
1461  // write a header to indicate a non-shared descriptor
1462  uint8_t header(0);
1463  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1464  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1465  }
1466  mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1467  }
1468  else if (pass < attributes + 2) {
1469  // pass 2...n+2 - attribute buffer sizes
1470  const Index attributeIndex = pass - 2;
1471  // destroy previous paged stream
1472  if (pass > 2) {
1473  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1474  }
1475  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1476  mAttributeSet->getConst(attributeIndex) : nullptr;
1477  if (array) {
1478  compression::PagedOutputStream& pagedStream =
1479  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1480  pagedStream.setOutputStream(os);
1481  pagedStream.setSizeOnly(true);
1482  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1483  }
1484  }
1485  else if (pass == attributes + 2) {
1486  const Index attributeIndex = pass - 3;
1487  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1488  // pass n+2 - voxel data
1489  BaseLeaf::writeBuffers(os, toHalf);
1490  }
1491  else if (pass < (attributes*2 + 3)) {
1492  // pass n+3...2n+3 - attribute buffers
1493  const Index attributeIndex = pass - attributes - 3;
1494  // destroy previous paged stream
1495  if (pass > attributes + 2) {
1496  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1497  }
1498  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1499  mAttributeSet->getConst(attributeIndex) : nullptr;
1500  if (array) {
1501  compression::PagedOutputStream& pagedStream =
1502  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1503  pagedStream.setOutputStream(os);
1504  pagedStream.setSizeOnly(false);
1505  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1506  }
1507  }
1508  else if (pass < buffers()) {
1509  Local::clearMatchingDescriptor(meta->auxData());
1510  // pass 2n+3 - cleanup last paged stream
1511  const Index attributeIndex = pass - attributes - 4;
1512  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1513  }
1514 }
1515 
1516 template<typename T, Index Log2Dim>
1517 inline Index64
1519 {
1520  return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1521 }
1522 
1523 template<typename T, Index Log2Dim>
1524 inline void
1525 PointDataLeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1526 {
1527  BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1528 }
1529 
1530 template<typename T, Index Log2Dim>
1531 inline CoordBBox
1533 {
1534  return BaseLeaf::getNodeBoundingBox();
1535 }
1536 
1537 template<typename T, Index Log2Dim>
1538 inline void
1539 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1540 {
1541  if (!this->allocate()) return;
1542 
1543  this->assertNonModifiableUnlessZero(value);
1544 
1545  // active state is permitted to be updated
1546 
1547  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1548  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1549  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1550  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1551  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1552  const Index offset = offsetXY + (z & (DIM-1u));
1553  this->setValueMask(offset, active);
1554  }
1555  }
1556  }
1557 }
1558 
1559 template<typename T, Index Log2Dim>
1560 inline void
1562 {
1563  this->assertNonModifiableUnlessZero(value);
1564 
1565  // active state is permitted to be updated
1566 
1567  if (active) this->setValuesOn();
1568  else this->setValuesOff();
1569 }
1570 
1571 
1572 ////////////////////////////////////////
1573 
1574 
1575 template <typename PointDataTreeT>
1576 inline AttributeSet::Descriptor::Ptr
1577 makeDescriptorUnique(PointDataTreeT& tree)
1578 {
1579  auto leafIter = tree.beginLeaf();
1580  if (!leafIter) return nullptr;
1581 
1582  const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1583  auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1584  for (; leafIter; ++leafIter) {
1585  leafIter->resetDescriptor(newDescriptor);
1586  }
1587 
1588  return newDescriptor;
1589 }
1590 
1591 
1592 template <typename PointDataTreeT>
1593 inline void
1594 setStreamingMode(PointDataTreeT& tree, bool on)
1595 {
1596  auto leafIter = tree.beginLeaf();
1597  for (; leafIter; ++leafIter) {
1598  for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1599  leafIter->attributeArray(i).setStreaming(on);
1600  }
1601  }
1602 }
1603 
1604 
1605 template <typename PointDataTreeT>
1606 inline void
1607 prefetch(PointDataTreeT& tree, bool position, bool otherAttributes)
1608 {
1609  // NOTE: the following is intentionally not multi-threaded, as the I/O
1610  // is faster if done in the order in which it is stored in the file
1611 
1612  auto leaf = tree.cbeginLeaf();
1613  if (!leaf) return;
1614 
1615  const auto& attributeSet = leaf->attributeSet();
1616 
1617  // pre-fetch leaf data
1618 
1619  for ( ; leaf; ++leaf) {
1620  leaf->buffer().data();
1621  }
1622 
1623  // pre-fetch position attribute data (position will typically have index 0)
1624 
1625  size_t positionIndex = attributeSet.find("P");
1626 
1627  if (position && positionIndex != AttributeSet::INVALID_POS) {
1628  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1629  assert(leaf->hasAttribute(positionIndex));
1630  leaf->constAttributeArray(positionIndex).loadData();
1631  }
1632  }
1633 
1634  // pre-fetch other attribute data
1635 
1636  if (otherAttributes) {
1637  const size_t attributes = attributeSet.size();
1638  for (size_t attributeIndex = 0; attributeIndex < attributes; attributeIndex++) {
1639  if (attributeIndex == positionIndex) continue;
1640  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1641  assert(leaf->hasAttribute(attributeIndex));
1642  leaf->constAttributeArray(attributeIndex).loadData();
1643  }
1644  }
1645  }
1646 }
1647 
1648 
1649 namespace internal {
1650 
1651 /// @brief Global registration of point data-related types
1652 /// @note This is called from @c openvdb::initialize, so there is
1653 /// no need to call it directly.
1654 void initialize();
1655 
1656 /// @brief Global deregistration of point data-related types
1657 /// @note This is called from @c openvdb::uninitialize, so there is
1658 /// no need to call it directly.
1659 void uninitialize();
1660 
1661 
1662 /// @brief Recursive node chain which generates a openvdb::TypeList value
1663 /// converted types of nodes to PointDataGrid nodes of the same configuration,
1664 /// rooted at RootNodeType in reverse order, from LeafNode to RootNode.
1665 /// See also TreeConverter<>.
1666 template<typename HeadT, int HeadLevel>
1668 {
1669  using SubtreeT = typename PointDataNodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1671  using Type = typename SubtreeT::template Append<RootNodeT>;
1672 };
1673 
1674 // Specialization for internal nodes which require their embedded child type to
1675 // be switched
1676 template <typename ChildT, Index Log2Dim, int HeadLevel>
1677 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, HeadLevel>
1678 {
1679  using SubtreeT = typename PointDataNodeChain<ChildT, HeadLevel-1>::Type;
1681  using Type = typename SubtreeT::template Append<InternalNodeT>;
1682 };
1683 
1684 // Specialization for the last internal node of a node chain, expected
1685 // to be templated on a leaf node
1686 template <typename ChildT, Index Log2Dim>
1687 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, /*HeadLevel=*/1>
1688 {
1692 };
1693 
1694 } // namespace internal
1695 
1696 
1697 /// @brief Similiar to ValueConverter, but allows for tree configuration conversion
1698 /// to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a
1699 /// PointDataLeafNode is not a specialization of LeafNode
1700 template <typename TreeType>
1702  using RootNodeT = typename TreeType::RootNodeType;
1705 };
1706 
1707 
1708 } // namespace points
1709 
1710 
1711 ////////////////////////////////////////
1712 
1713 
1714 namespace tree
1715 {
1716 
1717 /// Helper metafunction used to implement LeafNode::SameConfiguration
1718 /// (which, as an inner class, can't be independently specialized)
1719 template<Index Dim1, typename T2>
1720 struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1721 
1722 } // namespace tree
1723 } // namespace OPENVDB_VERSION_NAME
1724 } // namespace openvdb
1725 
1726 #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:177
Index64 onPointCount() const
Compute the total active (on) point count for the leaf.
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
AttributeSet::UniquePtr stealAttributeSet()
Steal the attribute set, a new, empty attribute set is inserted in it's place.
void setValue(const Coord &, const ValueType &)
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:249
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.
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.
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...
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
void setValueOff(const Coord &, const ValueType &)
GLuint start
Definition: glcorearb.h:474
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...
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:408
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2620
SharedPtr< StreamMetadata > Ptr
Definition: io.h:33
bool hasAttribute(const size_t pos) const
Returns true if an attribute with this index exists.
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
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.
GLuint GLuint stream
Definition: glcorearb.h:1831
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:178
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
const GLuint * buffers
Definition: glcorearb.h:660
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
GLuint const GLchar * name
Definition: glcorearb.h:785
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
void initialize()
Global registration of point data-related types.
Definition: logging.h:294
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
GLuint buffer
Definition: glcorearb.h:659
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:566
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)
GLint GLenum GLint x
Definition: glcorearb.h:408
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.
GLenum array
Definition: glew.h:9108
const char * typeNameAsString< Vec3f >()
Definition: Types.h:413
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
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
void uninitialize()
Global deregistration of point data-related types.
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:37
IndexAllIter beginIndexAll() const
Leaf index iterator.
void clearAttributes(const bool updateValueMask=true, const AttributeArray::ScopedRegistryLock *lock=nullptr)
Clear the attribute set.
GLuint GLuint end
Definition: glcorearb.h:474
bool operator==(const PointDataLeafNode &other) const
Attribute array storage for string data using Descriptor Metadata.
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
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...
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
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.
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296
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.
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:115
const AttributeArray & constAttributeArray(const size_t pos) const
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3460
GLdouble n
Definition: glcorearb.h:2007
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
GLboolean * data
Definition: glcorearb.h:130
void flush()
Manually flushes the current page to disk if non-zero.
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
GLuint GLfloat * val
Definition: glcorearb.h:1607
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
std::unique_ptr< AttributeSet > UniquePtr
Definition: AttributeSet.h:45
void fill(const CoordBBox &, const ValueType &, bool)
Library and file format version numbers.
ValueVoxelCIter beginValueVoxel(const Coord &ijk) const
Leaf value voxel iterator.
GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex &index) const
}
void setOffsetOnly(Index offset, const ValueType &val)
Typed class for storing attribute data.
Set of Attribute Arrays which tracks metadata about each array.
const void * ptr(const T *p)
Definition: format.h:3603
std::string to_string(const T &value)
Definition: format.h:3730
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Attribute Group access and filtering for iteration.
GLuint index
Definition: glcorearb.h:785
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
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_
GLboolean GLuint group
Definition: glew.h:2750
GLsizei const GLfloat * value
Definition: glcorearb.h:823
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:152
#define SIZE
Definition: simple.C:40
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:116
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
GLintptr offset
Definition: glcorearb.h:664
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:560
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:69
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 &)
GLenum GLuint coords
Definition: glew.h:7936
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:114
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
void setValueOn(const Coord &, const ValueType &)
A list of types (not necessarily unique)
Definition: TypeList.h:365
GLint y
Definition: glcorearb.h:102
Index64 pointCount() const
Compute the total point count for the leaf.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...