OpenVDB  8.0.1
PointDataGrid.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
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 
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 
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 
175 
176 
177 namespace points {
178 
179 
180 // forward declaration
181 template<typename T, Index Log2Dim> class PointDataLeafNode;
182 
186 
187 
190 
191 
199 template <typename PointDataTreeT>
200 inline AttributeSet::Descriptor::Ptr
201 makeDescriptorUnique(PointDataTreeT& tree);
202 
203 
213 template <typename PointDataTreeT>
214 inline void
215 setStreamingMode(PointDataTreeT& tree, bool on = true);
216 
217 
224 template <typename PointDataTreeT>
225 inline void
226 prefetch(PointDataTreeT& tree, bool position = true, bool otherAttributes = true);
227 
228 
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 
243  using Descriptor = AttributeSet::Descriptor;
244 
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 
263  : mAttributeSet(new AttributeSet) { }
264 
265  ~PointDataLeafNode() = default;
266 
268  explicit PointDataLeafNode(const PointDataLeafNode& other)
269  : BaseLeaf(other)
270  , mAttributeSet(new AttributeSet(*other.mAttributeSet)) { }
271 
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 
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  {
285  assertNonModifiableUnlessZero(value);
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 
316  const AttributeSet& attributeSet() const { return *mAttributeSet; }
317 
319  AttributeSet::UniquePtr stealAttributeSet();
320 
322  void initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
323  const AttributeArray::ScopedRegistryLock* lock = nullptr);
325  void clearAttributes(const bool updateValueMask = true,
326  const AttributeArray::ScopedRegistryLock* lock = nullptr);
327 
330  bool hasAttribute(const size_t pos) const;
333  bool hasAttribute(const Name& attributeName) const;
334 
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 
353  void dropAttributes(const std::vector<size_t>& pos,
354  const Descriptor& expected, Descriptor::Ptr& replacement);
357  void reorderAttributes(const Descriptor::Ptr& replacement);
361  void renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement);
363  void compactAttributes();
364 
370  void replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors = false);
371 
374  void resetDescriptor(const Descriptor::Ptr& replacement);
375 
379  void setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask = true);
380 
383  void validateOffsets() const;
384 
390  AttributeArray& attributeArray(const size_t pos);
391  const AttributeArray& attributeArray(const size_t pos) const;
392  const AttributeArray& constAttributeArray(const size_t pos) const;
399  AttributeArray& attributeArray(const Name& attributeName);
400  const AttributeArray& attributeArray(const Name& attributeName) const;
401  const AttributeArray& constAttributeArray(const Name& attributeName) const;
403 
405  GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const;
407  GroupHandle groupHandle(const Name& group) const;
409  GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index);
411  GroupWriteHandle groupWriteHandle(const Name& name);
412 
414  Index64 pointCount() const;
416  Index64 onPointCount() const;
418  Index64 offPointCount() const;
420  Index64 groupPointCount(const Name& groupName) const;
421 
423  void updateValueMask();
424 
426 
427  void setOffsetOn(Index offset, const ValueType& val);
428  void setOffsetOnly(Index offset, const ValueType& val);
429 
432  template<typename OtherType, Index OtherLog2Dim>
434  return BaseLeaf::hasSameTopology(other);
435  }
436 
439  bool operator==(const PointDataLeafNode& other) const {
440  if(BaseLeaf::operator==(other) != true) return false;
441  return (*this->mAttributeSet == *other.mAttributeSet);
442  }
443 
444  bool operator!=(const PointDataLeafNode& other) const { return !(other == *this); }
445 
447  template<typename AccessorT>
448  void addLeafAndCache(PointDataLeafNode*, AccessorT&) {}
449 
451  PointDataLeafNode* touchLeaf(const Coord&) { return this; }
453  template<typename AccessorT>
454  PointDataLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
455 
456  template<typename NodeT, typename AccessorT>
457  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
458  {
460  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
461  return reinterpret_cast<NodeT*>(this);
463  }
464  PointDataLeafNode* probeLeaf(const Coord&) { return this; }
465  template<typename AccessorT>
466  PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
468 
470  const PointDataLeafNode* probeConstLeaf(const Coord&) const { return this; }
472  template<typename AccessorT>
473  const PointDataLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
474  template<typename AccessorT>
475  const PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
476  const PointDataLeafNode* probeLeaf(const Coord&) const { return this; }
477  template<typename NodeT, typename AccessorT>
478  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
479  {
481  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
482  return reinterpret_cast<const NodeT*>(this);
484  }
486 
487  // I/O methods
488 
489  void readTopology(std::istream& is, bool fromHalf = false);
490  void writeTopology(std::ostream& os, bool toHalf = false) const;
491 
492  Index buffers() const;
493 
494  void readBuffers(std::istream& is, bool fromHalf = false);
495  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
496  void writeBuffers(std::ostream& os, bool toHalf = false) const;
497 
498 
499  Index64 memUsage() const;
500 
501  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
502 
505  CoordBBox getNodeBoundingBox() const;
506 
508 
509  // Disable all write methods to avoid unintentional changes
510  // to the point-array offsets.
511 
513  assert(false && "Cannot modify voxel values in a PointDataTree.");
514  }
515 
516  // some methods silently ignore attempts to modify the
517  // point-array offsets if a zero value is used
518 
520  if (value != zeroVal<T>()) this->assertNonmodifiable();
521  }
522 
523  void setActiveState(const Coord& xyz, bool on) { BaseLeaf::setActiveState(xyz, on); }
524  void setActiveState(Index offset, bool on) { BaseLeaf::setActiveState(offset, on); }
525 
526  void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
527  void setValueOnly(Index, const ValueType&) { assertNonmodifiable(); }
528 
529  void setValueOff(const Coord& xyz) { BaseLeaf::setValueOff(xyz); }
530  void setValueOff(Index offset) { BaseLeaf::setValueOff(offset); }
531 
532  void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
533  void setValueOff(Index, const ValueType&) { assertNonmodifiable(); }
534 
535  void setValueOn(const Coord& xyz) { BaseLeaf::setValueOn(xyz); }
536  void setValueOn(Index offset) { BaseLeaf::setValueOn(offset); }
537 
538  void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
539  void setValueOn(Index, const ValueType&) { assertNonmodifiable(); }
540 
541  void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
542 
543  void setValuesOn() { BaseLeaf::setValuesOn(); }
544  void setValuesOff() { BaseLeaf::setValuesOff(); }
545 
546  template<typename ModifyOp>
547  void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
548 
549  template<typename ModifyOp>
550  void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
551 
552  template<typename ModifyOp>
553  void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
554 
555  // clipping is not yet supported
556  void clip(const CoordBBox&, const ValueType& value) { assertNonModifiableUnlessZero(value); }
557 
558  void fill(const CoordBBox&, const ValueType&, bool);
559  void fill(const ValueType& value) { assertNonModifiableUnlessZero(value); }
560  void fill(const ValueType&, bool);
561 
562  template<typename AccessorT>
563  void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
564 
565  template<typename ModifyOp, typename AccessorT>
566  void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
567  assertNonmodifiable();
568  }
569 
570  template<typename AccessorT>
571  void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
572 
573  template<typename AccessorT>
574  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& parent) {
575  BaseLeaf::setActiveStateAndCache(xyz, on, parent);
576  }
577 
578  void resetBackground(const ValueType&, const ValueType& newBackground) {
579  assertNonModifiableUnlessZero(newBackground);
580  }
581 
582  void signedFloodFill(const ValueType&) { assertNonmodifiable(); }
583  void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); }
584 
585  void negate() { assertNonmodifiable(); }
586 
587  friend class ::TestPointDataLeaf;
588 
589  using ValueOn = typename BaseLeaf::ValueOn;
590  using ValueOff = typename BaseLeaf::ValueOff;
591  using ValueAll = typename BaseLeaf::ValueAll;
592 
593 private:
594  AttributeSet::UniquePtr mAttributeSet;
595  uint16_t mVoxelBufferSize = 0;
596 
597 protected:
598  using ChildOn = typename BaseLeaf::ChildOn;
599  using ChildOff = typename BaseLeaf::ChildOff;
600  using ChildAll = typename BaseLeaf::ChildAll;
601 
605 
606  // During topology-only construction, access is needed
607  // to protected/private members of other template instances.
608  template<typename, Index> friend class PointDataLeafNode;
609 
613 
614 public:
616  ValueVoxelCIter beginValueVoxel(const Coord& ijk) const;
617 
618 public:
619 
620  using ValueOnIter = typename BaseLeaf::template ValueIter<
622  using ValueOnCIter = typename BaseLeaf::template ValueIter<
623  MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn>;
624  using ValueOffIter = typename BaseLeaf::template ValueIter<
625  MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff>;
626  using ValueOffCIter = typename BaseLeaf::template ValueIter<
627  MaskOffIterator,const PointDataLeafNode,const ValueType,ValueOff>;
628  using ValueAllIter = typename BaseLeaf::template ValueIter<
629  MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll>;
630  using ValueAllCIter = typename BaseLeaf::template ValueIter<
631  MaskDenseIterator,const PointDataLeafNode,const ValueType,ValueAll>;
632  using ChildOnIter = typename BaseLeaf::template ChildIter<
633  MaskOnIterator, PointDataLeafNode, ChildOn>;
634  using ChildOnCIter = typename BaseLeaf::template ChildIter<
635  MaskOnIterator, const PointDataLeafNode, ChildOn>;
636  using ChildOffIter = typename BaseLeaf::template ChildIter<
637  MaskOffIterator, PointDataLeafNode, ChildOff>;
638  using ChildOffCIter = typename BaseLeaf::template ChildIter<
639  MaskOffIterator, const PointDataLeafNode, ChildOff>;
640  using ChildAllIter = typename BaseLeaf::template DenseIter<
641  PointDataLeafNode, ValueType, ChildAll>;
642  using ChildAllCIter = typename BaseLeaf::template DenseIter<
643  const PointDataLeafNode, const ValueType, ChildAll>;
644 
649 
652  {
653  NullFilter filter;
654  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
655  }
657  {
658  NullFilter filter;
659  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
660  }
662  {
663  NullFilter filter;
664  return this->beginIndex<ValueOffCIter, NullFilter>(filter);
665  }
666 
667  template<typename IterT, typename FilterT>
668  IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
669 
671  template<typename FilterT>
673  {
674  return this->beginIndex<ValueAllCIter, FilterT>(filter);
675  }
676  template<typename FilterT>
677  IndexIter<ValueOnCIter, FilterT> beginIndexOn(const FilterT& filter) const
678  {
679  return this->beginIndex<ValueOnCIter, FilterT>(filter);
680  }
681  template<typename FilterT>
683  {
684  return this->beginIndex<ValueOffCIter, FilterT>(filter);
685  }
686 
688  IndexVoxelIter beginIndexVoxel(const Coord& ijk) const;
689 
691  template<typename FilterT>
692  IndexIter<ValueVoxelCIter, FilterT> beginIndexVoxel(const Coord& ijk, const FilterT& filter) const;
693 
694 #define VMASK_ this->getValueMask()
695  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
696  ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
697  ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
698  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
699  ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
700  ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
701  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
702  ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
703  ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
704 
705  ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
706  ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
707  ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
708  ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
709  ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
710  ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
711  ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
712  ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
713  ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
714 
715  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
716  ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
717  ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
718  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
719  ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
720  ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
721  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
722  ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
723  ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
724 
725  ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
726  ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
727  ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
728  ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
729  ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
730  ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
731  ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
732  ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
733  ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
734 #undef VMASK_
735 }; // struct PointDataLeafNode
736 
738 
739 // PointDataLeafNode implementation
740 
741 template<typename T, Index Log2Dim>
744 {
745  AttributeSet::UniquePtr ptr = std::make_unique<AttributeSet>();
746  std::swap(ptr, mAttributeSet);
747  return ptr;
748 }
749 
750 template<typename T, Index Log2Dim>
751 inline void
752 PointDataLeafNode<T, Log2Dim>::initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
754 {
755  if (descriptor->size() != 1 ||
756  descriptor->find("P") == AttributeSet::INVALID_POS ||
757  descriptor->valueType(0) != typeNameAsString<Vec3f>())
758  {
759  OPENVDB_THROW(IndexError, "Initializing attributes only allowed with one Vec3f position attribute.");
760  }
761 
762  mAttributeSet.reset(new AttributeSet(descriptor, arrayLength, lock));
763 }
764 
765 template<typename T, Index Log2Dim>
766 inline void
769 {
770  mAttributeSet.reset(new AttributeSet(*mAttributeSet, 0, lock));
771 
772  // zero voxel values
773 
774  this->buffer().fill(ValueType(0));
775 
776  // if updateValueMask, also de-activate all voxels
777 
778  if (updateValueMask) this->setValuesOff();
779 }
780 
781 template<typename T, Index Log2Dim>
782 inline bool
784 {
785  return pos < mAttributeSet->size();
786 }
787 
788 template<typename T, Index Log2Dim>
789 inline bool
791 {
792  const size_t pos = mAttributeSet->find(attributeName);
793  return pos != AttributeSet::INVALID_POS;
794 }
795 
796 template<typename T, Index Log2Dim>
797 inline AttributeArray::Ptr
798 PointDataLeafNode<T, Log2Dim>::appendAttribute( const Descriptor& expected, Descriptor::Ptr& replacement,
799  const size_t pos, const Index strideOrTotalSize,
800  const bool constantStride,
801  const Metadata* metadata,
803 {
804  return mAttributeSet->appendAttribute(
805  expected, replacement, pos, strideOrTotalSize, constantStride, metadata, lock);
806 }
807 
808 template<typename T, Index Log2Dim>
809 inline void
810 PointDataLeafNode<T, Log2Dim>::dropAttributes(const std::vector<size_t>& pos,
811  const Descriptor& expected, Descriptor::Ptr& replacement)
812 {
813  mAttributeSet->dropAttributes(pos, expected, replacement);
814 }
815 
816 template<typename T, Index Log2Dim>
817 inline void
818 PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
819 {
820  mAttributeSet->reorderAttributes(replacement);
821 }
822 
823 template<typename T, Index Log2Dim>
824 inline void
825 PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
826 {
827  mAttributeSet->renameAttributes(expected, replacement);
828 }
829 
830 template<typename T, Index Log2Dim>
831 inline void
833 {
834  for (size_t i = 0; i < mAttributeSet->size(); i++) {
835  AttributeArray* array = mAttributeSet->get(i);
836  array->compact();
837  }
838 }
839 
840 template<typename T, Index Log2Dim>
841 inline void
842 PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
843 {
844  if (!attributeSet) {
845  OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
846  }
847 
848  if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
849  OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
850  }
851 
852  mAttributeSet.reset(attributeSet);
853 }
854 
855 template<typename T, Index Log2Dim>
856 inline void
857 PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
858 {
859  mAttributeSet->resetDescriptor(replacement);
860 }
861 
862 template<typename T, Index Log2Dim>
863 inline void
864 PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
865 {
866  if (offsets.size() != LeafNodeType::NUM_VALUES) {
867  OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
868  }
869 
870  for (Index index = 0; index < offsets.size(); ++index) {
871  setOffsetOnly(index, offsets[index]);
872  }
873 
874  if (updateValueMask) this->updateValueMask();
875 }
876 
877 template<typename T, Index Log2Dim>
878 inline void
880 {
881  // Ensure all of the offset values are monotonically increasing
882  for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
883  if (this->getValue(index-1) > this->getValue(index)) {
884  OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
885  }
886  }
887 
888  // Ensure all attribute arrays are of equal length
889  for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
890  if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
891  OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
892  }
893  }
894 
895  // Ensure the last voxel's offset value matches the size of each attribute array
896  if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
897  OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
898  }
899 }
900 
901 template<typename T, Index Log2Dim>
902 inline AttributeArray&
904 {
905  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
906  return *mAttributeSet->get(pos);
907 }
908 
909 template<typename T, Index Log2Dim>
910 inline const AttributeArray&
912 {
913  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
914  return *mAttributeSet->getConst(pos);
915 }
916 
917 template<typename T, Index Log2Dim>
918 inline const AttributeArray&
920 {
921  return this->attributeArray(pos);
922 }
923 
924 template<typename T, Index Log2Dim>
925 inline AttributeArray&
927 {
928  const size_t pos = mAttributeSet->find(attributeName);
929  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
930  return *mAttributeSet->get(pos);
931 }
932 
933 template<typename T, Index Log2Dim>
934 inline const AttributeArray&
936 {
937  const size_t pos = mAttributeSet->find(attributeName);
938  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
939  return *mAttributeSet->getConst(pos);
940 }
941 
942 template<typename T, Index Log2Dim>
943 inline const AttributeArray&
945 {
946  return this->attributeArray(attributeName);
947 }
948 
949 template<typename T, Index Log2Dim>
950 inline GroupHandle
951 PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
952 {
953  const AttributeArray& array = this->attributeArray(index.first);
954  assert(isGroup(array));
955 
956  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
957 
958  return GroupHandle(groupArray, index.second);
959 }
960 
961 template<typename T, Index Log2Dim>
962 inline GroupHandle
964 {
965  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
966  return this->groupHandle(index);
967 }
968 
969 template<typename T, Index Log2Dim>
970 inline GroupWriteHandle
971 PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
972 {
973  AttributeArray& array = this->attributeArray(index.first);
974  assert(isGroup(array));
975 
976  GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
977 
978  return GroupWriteHandle(groupArray, index.second);
979 }
980 
981 template<typename T, Index Log2Dim>
982 inline GroupWriteHandle
984 {
985  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
986  return this->groupWriteHandle(index);
987 }
988 
989 template<typename T, Index Log2Dim>
990 template<typename ValueIterT, typename FilterT>
992 PointDataLeafNode<T, Log2Dim>::beginIndex(const FilterT& filter) const
993 {
994  // generate no-op iterator if filter evaluates no indices
995 
996  if (filter.state() == index::NONE) {
997  return IndexIter<ValueIterT, FilterT>(ValueIterT(), filter);
998  }
999 
1000  // copy filter to ensure thread-safety
1001 
1002  FilterT newFilter(filter);
1003  newFilter.reset(*this);
1004 
1005  using IterTraitsT = tree::IterTraits<LeafNodeType, ValueIterT>;
1006 
1007  // construct the value iterator and reset the filter to use this leaf
1008 
1009  ValueIterT valueIter = IterTraitsT::begin(*this);
1010 
1011  return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
1012 }
1013 
1014 template<typename T, Index Log2Dim>
1015 inline ValueVoxelCIter
1017 {
1018  const Index index = LeafNodeType::coordToOffset(ijk);
1019  assert(index < BaseLeaf::SIZE);
1020  const ValueType end = this->getValue(index);
1021  const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1022  return ValueVoxelCIter(start, end);
1023 }
1024 
1025 template<typename T, Index Log2Dim>
1028 {
1029  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1030  return IndexVoxelIter(iter, NullFilter());
1031 }
1032 
1033 template<typename T, Index Log2Dim>
1034 template<typename FilterT>
1036 PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1037 {
1038  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1039  FilterT newFilter(filter);
1040  newFilter.reset(*this);
1041  return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1042 }
1043 
1044 template<typename T, Index Log2Dim>
1045 inline Index64
1047 {
1048  return this->getLastValue();
1049 }
1050 
1051 template<typename T, Index Log2Dim>
1052 inline Index64
1054 {
1055  if (this->isEmpty()) return 0;
1056  else if (this->isDense()) return this->pointCount();
1057  return iterCount(this->beginIndexOn());
1058 }
1059 
1060 template<typename T, Index Log2Dim>
1061 inline Index64
1063 {
1064  if (this->isEmpty()) return this->pointCount();
1065  else if (this->isDense()) return 0;
1066  return iterCount(this->beginIndexOff());
1067 }
1068 
1069 template<typename T, Index Log2Dim>
1070 inline Index64
1072 {
1073  if (!this->attributeSet().descriptor().hasGroup(groupName)) {
1074  return Index64(0);
1075  }
1076  GroupFilter filter(groupName, this->attributeSet());
1077  if (filter.state() == index::ALL) {
1078  return this->pointCount();
1079  } else {
1080  return iterCount(this->beginIndexAll(filter));
1081  }
1082 }
1083 
1084 template<typename T, Index Log2Dim>
1085 inline void
1087 {
1088  ValueType start = 0, end = 0;
1089  for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1090  end = this->getValue(n);
1091  this->setValueMask(n, (end - start) > 0);
1092  start = end;
1093  }
1094 }
1095 
1096 template<typename T, Index Log2Dim>
1097 inline void
1099 {
1100  this->buffer().setValue(offset, val);
1101  this->setValueMaskOn(offset);
1102 }
1103 
1104 template<typename T, Index Log2Dim>
1105 inline void
1107 {
1108  this->buffer().setValue(offset, val);
1109 }
1110 
1111 template<typename T, Index Log2Dim>
1112 inline void
1113 PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1114 {
1115  BaseLeaf::readTopology(is, fromHalf);
1116 }
1117 
1118 template<typename T, Index Log2Dim>
1119 inline void
1120 PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1121 {
1122  BaseLeaf::writeTopology(os, toHalf);
1123 }
1124 
1125 template<typename T, Index Log2Dim>
1126 inline Index
1128 {
1129  return Index( /*voxel buffer sizes*/ 1 +
1130  /*voxel buffers*/ 1 +
1131  /*attribute metadata*/ 1 +
1132  /*attribute uniform values*/ mAttributeSet->size() +
1133  /*attribute buffers*/ mAttributeSet->size() +
1134  /*cleanup*/ 1);
1135 }
1136 
1137 template<typename T, Index Log2Dim>
1138 inline void
1139 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1140 {
1141  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1142 }
1143 
1144 template<typename T, Index Log2Dim>
1145 inline void
1146 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1147 {
1148  struct Local
1149  {
1150  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1151  {
1152  // if paged stream exists, delete it
1153  std::string key("paged:" + std::to_string(index));
1154  auto it = auxData.find(key);
1155  if (it != auxData.end()) {
1156  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1157  }
1158  }
1159 
1160  static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1161  const Index index)
1162  {
1163  std::string key("paged:" + std::to_string(index));
1164  auto it = auxData.find(key);
1165  if (it != auxData.end()) {
1166  return *(boost::any_cast<compression::PagedInputStream::Ptr>(it->second));
1167  }
1168  else {
1169  compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1170  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1171  return *pagedStream;
1172  }
1173  }
1174 
1175  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1176  {
1177  std::string matchingKey("hasMatchingDescriptor");
1178  auto itMatching = auxData.find(matchingKey);
1179  return itMatching != auxData.end();
1180  }
1181 
1182  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1183  {
1184  std::string matchingKey("hasMatchingDescriptor");
1185  std::string descriptorKey("descriptorPtr");
1186  auto itMatching = auxData.find(matchingKey);
1187  auto itDescriptor = auxData.find(descriptorKey);
1188  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1189  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1190  }
1191 
1192  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1193  const Descriptor::Ptr descriptor)
1194  {
1195  std::string descriptorKey("descriptorPtr");
1196  std::string matchingKey("hasMatchingDescriptor");
1197  auto itMatching = auxData.find(matchingKey);
1198  if (itMatching == auxData.end()) {
1199  // if matching bool is not found, insert "true" and the descriptor
1200  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1201  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1202  }
1203  }
1204 
1205  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1206  {
1207  std::string descriptorKey("descriptorPtr");
1208  auto itDescriptor = auxData.find(descriptorKey);
1209  assert(itDescriptor != auxData.end());
1210  const Descriptor::Ptr descriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1211  return descriptor;
1212  }
1213  };
1214 
1216 
1217  if (!meta) {
1218  OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1219  }
1220 
1221  const Index pass(static_cast<uint16_t>(meta->pass()));
1222  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1223 
1224  const Index attributes = (maximumPass - 4) / 2;
1225 
1226  if (pass == 0) {
1227  // pass 0 - voxel data sizes
1228  is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1229  Local::clearMatchingDescriptor(meta->auxData());
1230  }
1231  else if (pass == 1) {
1232  // pass 1 - descriptor and attribute metadata
1233  if (Local::hasMatchingDescriptor(meta->auxData())) {
1234  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1235  mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1236  }
1237  else {
1238  uint8_t header;
1239  is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1240  mAttributeSet->readDescriptor(is);
1241  if (header & uint8_t(1)) {
1242  AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1243  Local::insertDescriptor(meta->auxData(), descriptor);
1244  }
1245  // a forwards-compatibility mechanism for future use,
1246  // if a 0x2 bit is set, read and skip over a specific number of bytes
1247  if (header & uint8_t(2)) {
1248  uint64_t bytesToSkip;
1249  is.read(reinterpret_cast<char*>(&bytesToSkip), sizeof(uint64_t));
1250  if (bytesToSkip > uint64_t(0)) {
1251  auto metadata = io::getStreamMetadataPtr(is);
1252  if (metadata && metadata->seekable()) {
1253  is.seekg(bytesToSkip, std::ios_base::cur);
1254  }
1255  else {
1256  std::vector<uint8_t> tempData(bytesToSkip);
1257  is.read(reinterpret_cast<char*>(&tempData[0]), bytesToSkip);
1258  }
1259  }
1260  }
1261  // this reader is only able to read headers with 0x1 and 0x2 bits set
1262  if (header > uint8_t(3)) {
1263  OPENVDB_THROW(IoError, "Unrecognised header flags in PointDataLeafNode");
1264  }
1265  }
1266  mAttributeSet->readMetadata(is);
1267  }
1268  else if (pass < (attributes + 2)) {
1269  // pass 2...n+2 - attribute uniform values
1270  const size_t attributeIndex = pass - 2;
1271  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1272  mAttributeSet->get(attributeIndex) : nullptr;
1273  if (array) {
1274  compression::PagedInputStream& pagedStream =
1275  Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1276  pagedStream.setInputStream(is);
1277  pagedStream.setSizeOnly(true);
1278  array->readPagedBuffers(pagedStream);
1279  }
1280  }
1281  else if (pass == attributes + 2) {
1282  // pass n+2 - voxel data
1283 
1284  const Index passValue(meta->pass());
1285 
1286  // StreamMetadata pass variable used to temporarily store voxel buffer size
1287  io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1288  nonConstMeta.setPass(mVoxelBufferSize);
1289 
1290  // readBuffers() calls readCompressedValues specialization above
1291  BaseLeaf::readBuffers(is, fromHalf);
1292 
1293  // pass now reset to original value
1294  nonConstMeta.setPass(passValue);
1295  }
1296  else if (pass < (attributes*2 + 3)) {
1297  // pass n+2..2n+2 - attribute buffers
1298  const Index attributeIndex = pass - attributes - 3;
1299  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1300  mAttributeSet->get(attributeIndex) : nullptr;
1301  if (array) {
1302  compression::PagedInputStream& pagedStream =
1303  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1304  pagedStream.setInputStream(is);
1305  pagedStream.setSizeOnly(false);
1306  array->readPagedBuffers(pagedStream);
1307  }
1308  // cleanup paged stream reference in auxiliary metadata
1309  if (pass > attributes + 3) {
1310  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1311  }
1312  }
1313  else if (pass < buffers()) {
1314  // pass 2n+3 - cleanup last paged stream
1315  const Index attributeIndex = pass - attributes - 4;
1316  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1317  }
1318 }
1319 
1320 template<typename T, Index Log2Dim>
1321 inline void
1322 PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1323 {
1324  struct Local
1325  {
1326  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1327  {
1328  // if paged stream exists, flush and delete it
1329  std::string key("paged:" + std::to_string(index));
1330  auto it = auxData.find(key);
1331  if (it != auxData.end()) {
1332  compression::PagedOutputStream& stream = *(boost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1333  stream.flush();
1334  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1335  }
1336  }
1337 
1338  static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1339  const Index index)
1340  {
1341  std::string key("paged:" + std::to_string(index));
1342  auto it = auxData.find(key);
1343  if (it != auxData.end()) {
1344  return *(boost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1345  }
1346  else {
1347  compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1348  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1349  return *pagedStream;
1350  }
1351  }
1352 
1353  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1354  const Descriptor::Ptr descriptor)
1355  {
1356  std::string descriptorKey("descriptorPtr");
1357  std::string matchingKey("hasMatchingDescriptor");
1358  auto itMatching = auxData.find(matchingKey);
1359  auto itDescriptor = auxData.find(descriptorKey);
1360  if (itMatching == auxData.end()) {
1361  // if matching bool is not found, insert "true" and the descriptor
1362  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1363  assert(itDescriptor == auxData.end());
1364  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1365  }
1366  else {
1367  // if matching bool is found and is false, early exit (a previous descriptor did not match)
1368  bool matching = boost::any_cast<bool>(itMatching->second);
1369  if (!matching) return;
1370  assert(itDescriptor != auxData.end());
1371  // if matching bool is true, check whether the existing descriptor matches the current one and set
1372  // matching bool to false if not
1373  const Descriptor::Ptr existingDescriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1374  if (*existingDescriptor != *descriptor) {
1375  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1376  }
1377  }
1378  }
1379 
1380  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1381  {
1382  std::string matchingKey("hasMatchingDescriptor");
1383  auto itMatching = auxData.find(matchingKey);
1384  // if matching key is not found, no matching descriptor
1385  if (itMatching == auxData.end()) return false;
1386  // if matching key is found and is false, no matching descriptor
1387  if (!boost::any_cast<bool>(itMatching->second)) return false;
1388  return true;
1389  }
1390 
1391  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1392  {
1393  std::string descriptorKey("descriptorPtr");
1394  auto itDescriptor = auxData.find(descriptorKey);
1395  // if matching key is true, however descriptor is not found, it has already been retrieved
1396  if (itDescriptor == auxData.end()) return nullptr;
1397  // otherwise remove it and return it
1398  const Descriptor::Ptr descriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1399  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1400  return descriptor;
1401  }
1402 
1403  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1404  {
1405  std::string matchingKey("hasMatchingDescriptor");
1406  std::string descriptorKey("descriptorPtr");
1407  auto itMatching = auxData.find(matchingKey);
1408  auto itDescriptor = auxData.find(descriptorKey);
1409  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1410  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1411  }
1412  };
1413 
1415 
1416  if (!meta) {
1417  OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1418  }
1419 
1420  const Index pass(static_cast<uint16_t>(meta->pass()));
1421 
1422  // leaf traversal analysis deduces the number of passes to perform for this leaf
1423  // then updates the leaf traversal value to ensure all passes will be written
1424 
1425  if (meta->countingPasses()) {
1426  const Index requiredPasses = this->buffers();
1427  if (requiredPasses > pass) {
1428  meta->setPass(requiredPasses);
1429  }
1430  return;
1431  }
1432 
1433  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1434  const Index attributes = (maximumPass - 4) / 2;
1435 
1436  if (pass == 0) {
1437  // pass 0 - voxel data sizes
1438  io::writeCompressedValuesSize(os, this->buffer().data(), SIZE);
1439  // track if descriptor is shared or not
1440  Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1441  }
1442  else if (pass == 1) {
1443  // pass 1 - descriptor and attribute metadata
1444  bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1445  if (matchingDescriptor) {
1446  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1447  if (descriptor) {
1448  // write a header to indicate a shared descriptor
1449  uint8_t header(1);
1450  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1451  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1452  }
1453  }
1454  else {
1455  // write a header to indicate a non-shared descriptor
1456  uint8_t header(0);
1457  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1458  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1459  }
1460  mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1461  }
1462  else if (pass < attributes + 2) {
1463  // pass 2...n+2 - attribute buffer sizes
1464  const Index attributeIndex = pass - 2;
1465  // destroy previous paged stream
1466  if (pass > 2) {
1467  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1468  }
1469  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1470  mAttributeSet->getConst(attributeIndex) : nullptr;
1471  if (array) {
1472  compression::PagedOutputStream& pagedStream =
1473  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1474  pagedStream.setOutputStream(os);
1475  pagedStream.setSizeOnly(true);
1476  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1477  }
1478  }
1479  else if (pass == attributes + 2) {
1480  const Index attributeIndex = pass - 3;
1481  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1482  // pass n+2 - voxel data
1483  BaseLeaf::writeBuffers(os, toHalf);
1484  }
1485  else if (pass < (attributes*2 + 3)) {
1486  // pass n+3...2n+3 - attribute buffers
1487  const Index attributeIndex = pass - attributes - 3;
1488  // destroy previous paged stream
1489  if (pass > attributes + 2) {
1490  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1491  }
1492  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1493  mAttributeSet->getConst(attributeIndex) : nullptr;
1494  if (array) {
1495  compression::PagedOutputStream& pagedStream =
1496  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1497  pagedStream.setOutputStream(os);
1498  pagedStream.setSizeOnly(false);
1499  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1500  }
1501  }
1502  else if (pass < buffers()) {
1503  Local::clearMatchingDescriptor(meta->auxData());
1504  // pass 2n+3 - cleanup last paged stream
1505  const Index attributeIndex = pass - attributes - 4;
1506  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1507  }
1508 }
1509 
1510 template<typename T, Index Log2Dim>
1511 inline Index64
1513 {
1514  return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1515 }
1516 
1517 template<typename T, Index Log2Dim>
1518 inline void
1519 PointDataLeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1520 {
1521  BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1522 }
1523 
1524 template<typename T, Index Log2Dim>
1525 inline CoordBBox
1527 {
1528  return BaseLeaf::getNodeBoundingBox();
1529 }
1530 
1531 template<typename T, Index Log2Dim>
1532 inline void
1533 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1534 {
1535  if (!this->allocate()) return;
1536 
1537  this->assertNonModifiableUnlessZero(value);
1538 
1539  // active state is permitted to be updated
1540 
1541  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1542  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1543  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1544  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1545  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1546  const Index offset = offsetXY + (z & (DIM-1u));
1547  this->setValueMask(offset, active);
1548  }
1549  }
1550  }
1551 }
1552 
1553 template<typename T, Index Log2Dim>
1554 inline void
1556 {
1557  this->assertNonModifiableUnlessZero(value);
1558 
1559  // active state is permitted to be updated
1560 
1561  if (active) this->setValuesOn();
1562  else this->setValuesOff();
1563 }
1564 
1565 
1567 
1568 
1569 template <typename PointDataTreeT>
1570 inline AttributeSet::Descriptor::Ptr
1571 makeDescriptorUnique(PointDataTreeT& tree)
1572 {
1573  auto leafIter = tree.beginLeaf();
1574  if (!leafIter) return nullptr;
1575 
1576  const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1577  auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1578  for (; leafIter; ++leafIter) {
1579  leafIter->resetDescriptor(newDescriptor);
1580  }
1581 
1582  return newDescriptor;
1583 }
1584 
1585 
1586 template <typename PointDataTreeT>
1587 inline void
1588 setStreamingMode(PointDataTreeT& tree, bool on)
1589 {
1590  auto leafIter = tree.beginLeaf();
1591  for (; leafIter; ++leafIter) {
1592  for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1593  leafIter->attributeArray(i).setStreaming(on);
1594  }
1595  }
1596 }
1597 
1598 
1599 template <typename PointDataTreeT>
1600 inline void
1601 prefetch(PointDataTreeT& tree, bool position, bool otherAttributes)
1602 {
1603  // NOTE: the following is intentionally not multi-threaded, as the I/O
1604  // is faster if done in the order in which it is stored in the file
1605 
1606  auto leaf = tree.cbeginLeaf();
1607  if (!leaf) return;
1608 
1609  const auto& attributeSet = leaf->attributeSet();
1610 
1611  // pre-fetch leaf data
1612 
1613  for ( ; leaf; ++leaf) {
1614  leaf->buffer().data();
1615  }
1616 
1617  // pre-fetch position attribute data (position will typically have index 0)
1618 
1619  size_t positionIndex = attributeSet.find("P");
1620 
1621  if (position && positionIndex != AttributeSet::INVALID_POS) {
1622  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1623  assert(leaf->hasAttribute(positionIndex));
1624  leaf->constAttributeArray(positionIndex).loadData();
1625  }
1626  }
1627 
1628  // pre-fetch other attribute data
1629 
1630  if (otherAttributes) {
1631  const size_t attributes = attributeSet.size();
1632  for (size_t attributeIndex = 0; attributeIndex < attributes; attributeIndex++) {
1633  if (attributeIndex == positionIndex) continue;
1634  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1635  assert(leaf->hasAttribute(attributeIndex));
1636  leaf->constAttributeArray(attributeIndex).loadData();
1637  }
1638  }
1639  }
1640 }
1641 
1642 
1643 namespace internal {
1644 
1648 void initialize();
1649 
1653 void uninitialize();
1654 
1655 
1660 template<typename HeadT, int HeadLevel>
1662 {
1663  using SubtreeT = typename PointDataNodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1665  using Type = typename SubtreeT::template Append<RootNodeT>;
1666 };
1667 
1668 // Specialization for internal nodes which require their embedded child type to
1669 // be switched
1670 template <typename ChildT, Index Log2Dim, int HeadLevel>
1671 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, HeadLevel>
1672 {
1673  using SubtreeT = typename PointDataNodeChain<ChildT, HeadLevel-1>::Type;
1675  using Type = typename SubtreeT::template Append<InternalNodeT>;
1676 };
1677 
1678 // Specialization for the last internal node of a node chain, expected
1679 // to be templated on a leaf node
1680 template <typename ChildT, Index Log2Dim>
1681 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, /*HeadLevel=*/1>
1682 {
1686 };
1687 
1688 } // namespace internal
1689 
1690 
1694 template <typename TreeType>
1696  using RootNodeT = typename TreeType::RootNodeType;
1699 };
1700 
1701 
1702 } // namespace points
1703 
1704 
1706 
1707 
1708 namespace tree
1709 {
1710 
1713 template<Index Dim1, typename T2>
1714 struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1715 
1716 } // namespace tree
1717 } // namespace OPENVDB_VERSION_NAME
1718 } // namespace openvdb
1719 
1720 #endif // OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
Definition: AttributeGroup.h:72
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
void setValueOnly(const Coord &, const ValueType &)
Definition: PointDataGrid.h:526
void fill(const ValueType &value)
Definition: PointDataGrid.h:559
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:121
Index64 memUsage() const
Definition: PointDataGrid.h:1512
void setValueOff(Index offset)
Definition: PointDataGrid.h:530
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:466
PointIndex< Index32, 1 > PointDataIndex32
Definition: openvdb/Types.h:159
void assertNonModifiableUnlessZero(const ValueType &value)
Definition: PointDataGrid.h:519
Definition: LeafNode.h:203
typename BaseLeaf::ChildOn ChildOn
Definition: PointDataGrid.h:598
ValueOnCIter endValueOn() const
Definition: PointDataGrid.h:706
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
Definition: TreeIterator.h:59
Attribute Group access and filtering for iteration.
Definition: NodeMasks.h:270
ChildAllCIter cendChildAll() const
Definition: PointDataGrid.h:731
void setValueOn(Index offset)
Definition: PointDataGrid.h:536
Definition: openvdb/Exceptions.h:60
void setValueOff(const Coord &xyz)
Definition: PointDataGrid.h:529
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Definition: PointDataGrid.h:1661
AttributeSet::Descriptor Descriptor
Definition: PointDataGrid.h:243
void setValueOn(const Coord &, const ValueType &)
Definition: PointDataGrid.h:538
ValueOffCIter cbeginValueOff() const
Definition: PointDataGrid.h:698
#define OPENVDB_THROW(exception, message)
Definition: openvdb/Exceptions.h:74
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
Definition: IndexIterator.h:314
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:454
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: openvdb/Types.h:542
void setValueOn(const Coord &xyz)
Definition: PointDataGrid.h:535
IndexAllIter beginIndexAll() const
Leaf index iterator.
Definition: PointDataGrid.h:651
void initialize()
Global registration of point data-related types.
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:280
static index::State state()
Definition: AttributeGroup.h:145
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
Definition: PointDataGrid.h:682
void setValueOnly(Index, const ValueType &)
Definition: PointDataGrid.h:527
std::shared_ptr< PointDataLeafNode > Ptr
Definition: PointDataGrid.h:237
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: PointDataGrid.h:627
typename NodeMaskType::OnIterator MaskOnIterator
Definition: PointDataGrid.h:602
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
typename TreeType::RootNodeType RootNodeT
Definition: PointDataGrid.h:1696
#define VMASK_
Definition: PointDataGrid.h:694
ChildOffCIter cbeginChildOff() const
Definition: PointDataGrid.h:718
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Definition: PointDataGrid.h:316
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition: PointDataGrid.h:566
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:308
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
Definition: PointDataGrid.h:274
ValueOnCIter cendValueOn() const
Definition: PointDataGrid.h:705
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:102
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.
Attribute Array storage templated on type and compression codec.
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: PointDataGrid.h:604
void writeCompressedValues(std::ostream &os, PointDataIndex32 *srcBuf, Index srcCount, const util::NodeMask< 3 > &, const util::NodeMask< 3 > &, bool)
openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask...
Definition: PointDataGrid.h:106
uint64_t Index64
Definition: openvdb/Types.h:31
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
Definition: StreamCompression.h:218
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttribute.h:524
std::pair< ValueType, ValueType > ValueTypePair
Definition: PointDataGrid.h:240
Definition: PointDataGrid.h:170
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:473
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: PointDataGrid.h:464
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
Definition: PointDataGrid.h:304
int32_t Int32
Definition: openvdb/Types.h:34
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
Definition: PointDataGrid.h:635
ChildOffCIter beginChildOff() const
Definition: PointDataGrid.h:719
void negate()
Definition: PointDataGrid.h:585
Definition: AttributeGroup.h:101
ValueOnIter beginValueOn()
Definition: PointDataGrid.h:697
typename BaseLeaf::ValueOff ValueOff
Definition: PointDataGrid.h:590
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:30
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
Definition: PointDataGrid.h:290
ValueOffCIter cendValueOff() const
Definition: PointDataGrid.h:708
typename SubtreeT::template Append< InternalNodeT > Type
Definition: PointDataGrid.h:1675
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:208
Definition: Tree.h:174
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1571
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
Definition: PointDataGrid.h:574
typename NodeMaskType::OffIterator MaskOffIterator
Definition: PointDataGrid.h:603
Definition: NodeMasks.h:208
ValueAllIter endValueAll()
Definition: PointDataGrid.h:713
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
Definition: PointDataGrid.h:629
typename BaseLeaf::ValueAll ValueAll
Definition: PointDataGrid.h:591
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Definition: PointDataGrid.h:448
ChildAllIter beginChildAll()
Definition: PointDataGrid.h:723
Definition: LeafNode.h:203
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
Definition: PointDataGrid.h:818
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointDataGrid.h:623
Base class for storing metadata information in a grid.
Definition: Metadata.h:23
ValueOffIter endValueOff()
Definition: PointDataGrid.h:710
ChildOnCIter cendChildOn() const
Definition: PointDataGrid.h:725
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:553
void setValue(const Coord &, const ValueType &)
Definition: PointDataGrid.h:541
ValueAllCIter cbeginValueAll() const
Definition: PointDataGrid.h:701
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:475
Convenience wrappers to using Blosc and reading and writing of Paged data.
void setActiveState(const Coord &xyz, bool on)
Definition: PointDataGrid.h:523
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:476
std::shared_ptr< PagedInputStream > Ptr
Definition: StreamCompression.h:211
Definition: LeafNode.h:203
std::shared_ptr< PagedOutputStream > Ptr
Definition: StreamCompression.h:248
ChildOnCIter beginChildOn() const
Definition: PointDataGrid.h:716
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:101
Definition: RootNode.h:38
Definition: PointIndexGrid.h:52
ValueOnIter endValueOn()
Definition: PointDataGrid.h:707
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition: io.h:124
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
Definition: PointDataGrid.h:139
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
Definition: PointDataGrid.h:639
void setValuesOff()
Definition: PointDataGrid.h:544
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:245
PointDataLeafNode()
Default constructor.
Definition: PointDataGrid.h:262
void uninitialize()
Global deregistration of point data-related types.
std::map< std::string, boost::any > AuxDataMap
Definition: io.h:92
Integer wrapper, required to distinguish PointIndexGrid and PointDataGrid from Int32Grid and Int64Gri...
Definition: openvdb/Types.h:134
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointDataGrid.h:457
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
Definition: PointDataGrid.h:1588
typename BaseLeaf::ChildAll ChildAll
Definition: PointDataGrid.h:600
bool operator==(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:439
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:571
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:38
void modifyValue(Index, const ModifyOp &)
Definition: PointDataGrid.h:547
Definition: openvdb/Exceptions.h:57
ChildAllCIter beginChildAll() const
Definition: PointDataGrid.h:722
ValueOnCIter cbeginValueOn() const
Definition: PointDataGrid.h:695
void resetBackground(const ValueType &, const ValueType &newBackground)
Definition: PointDataGrid.h:578
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:64
T ValueType
Definition: PointDataGrid.h:239
std::vector< ValueType > IndexArray
Definition: PointDataGrid.h:241
void setInputStream(std::istream &is)
Definition: StreamCompression.h:223
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
Definition: PointAttribute.h:377
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
Definition: StreamCompression.h:255
Definition: openvdb/Exceptions.h:13
Index filtering on group membership.
Definition: AttributeGroup.h:134
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
SIMD Intrinsic Headers.
Definition: Platform.h:92
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:37
Definition: LeafNode.h:204
ValueOffCIter beginValueOff() const
Definition: PointDataGrid.h:699
ChildAllCIter cbeginChildAll() const
Definition: PointDataGrid.h:721
void flush()
Manually flushes the current page to disk if non-zero.
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...
Definition: IndexIterator.h:139
void setValueOff(const Coord &, const ValueType &)
Definition: PointDataGrid.h:532
const char * typeNameAsString< Vec3f >()
Definition: openvdb/Types.h:395
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
ValueOffCIter endValueOff() const
Definition: PointDataGrid.h:709
void fill(const CoordBBox &, const ValueType &, bool)
Definition: PointDataGrid.h:1533
void modifyValue(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:550
ChildOffIter endChildOff()
Definition: PointDataGrid.h:730
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...
virtual Index size() const =0
typename BaseLeaf::ChildOff ChildOff
Definition: PointDataGrid.h:599
ValueOnCIter beginValueOn() const
Definition: PointDataGrid.h:696
void setValueOn(Index, const ValueType &)
Definition: PointDataGrid.h:539
IndexOnIter beginIndexOn() const
Definition: PointDataGrid.h:656
void clip(const CoordBBox &, const ValueType &value)
Definition: PointDataGrid.h:556
std::shared_ptr< Descriptor > DescriptorPtr
Definition: AttributeSet.h:49
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:563
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
Definition: PointDataGrid.h:641
ChildOffIter beginChildOff()
Definition: PointDataGrid.h:720
Library and file format version numbers.
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition: PointAttribute.h:465
void setValuesOn()
Definition: PointDataGrid.h:543
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
Definition: PointDataGrid.h:297
Definition: IndexIterator.h:43
std::unique_ptr< AttributeSet > UniquePtr
Definition: AttributeSet.h:45
ValueOffIter beginValueOff()
Definition: PointDataGrid.h:700
Similiar to ValueConverter, but allows for tree configuration conversion to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a PointDataLeafNode is not a specialization of LeafNode.
Definition: PointDataGrid.h:1695
ChildOnCIter endChildOn() const
Definition: PointDataGrid.h:726
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
Definition: PointDataGrid.h:1697
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
Definition: PointDataGrid.h:633
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:125
Typed class for storing attribute data.
Definition: AttributeArray.h:555
Definition: LeafNode.h:204
ChildAllIter endChildAll()
Definition: PointDataGrid.h:733
void reset(Index32 begin, Index32 end)
Reset the begining and end of the iterator.
Definition: IndexIterator.h:252
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:93
typename PointDataNodeChain< ChildT, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1673
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
Definition: PointDataGrid.h:625
void signedFloodFill(const ValueType &, const ValueType &)
Definition: PointDataGrid.h:583
Definition: openvdb/Exceptions.h:65
ChildOnIter beginChildOn()
Definition: PointDataGrid.h:717
ChildOffCIter endChildOff() const
Definition: PointDataGrid.h:729
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
Definition: PointDataGrid.h:672
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:69
Definition: LeafNode.h:204
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
IndexOffIter beginIndexOff() const
Definition: PointDataGrid.h:661
ChildAllCIter endChildAll() const
Definition: PointDataGrid.h:732
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointDataGrid.h:478
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:63
A list of types (not necessarily unique)
Definition: TypeList.h:365
Tag dispatch class that distinguishes constructors during file input.
Definition: openvdb/Types.h:548
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1663
ChildOnCIter cbeginChildOn() const
Definition: PointDataGrid.h:715
void setActiveState(Index offset, bool on)
Definition: PointDataGrid.h:524
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
Definition: PointDataGrid.h:621
SharedPtr< StreamMetadata > Ptr
Definition: io.h:33
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:242
std::string Name
Definition: Name.h:17
Attribute array storage for string data using Descriptor Metadata.
Base class for storing attribute data.
Definition: AttributeArray.h:92
Definition: PointDataGrid.h:181
typename BaseLeaf::ValueOn ValueOn
Definition: PointDataGrid.h:589
void appendAttribute(PointDataTreeT &tree, const Name &name, const NamePair &type, const Index strideOrTotalSize=1, const bool constantStride=true, const Metadata *defaultValue=nullptr, const bool hidden=false, const bool transient=false)
Appends a new attribute to the VDB tree (this method does not require a templated AttributeType) ...
Definition: PointAttribute.h:242
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: PointDataGrid.h:643
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...
Definition: PointDataGrid.h:857
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
Definition: PointDataGrid.h:268
typename SubtreeT::template Append< RootNodeT > Type
Definition: PointDataGrid.h:1665
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:153
void readCompressedValues(std::istream &is, PointDataIndex32 *destBuf, Index destCount, const util::NodeMask< 3 > &, bool)
openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask...
Definition: PointDataGrid.h:46
Definition: openvdb/Exceptions.h:58
ValueAllCIter endValueAll() const
Definition: PointDataGrid.h:712
ValueAllCIter beginValueAll() const
Definition: PointDataGrid.h:702
Definition: NodeMasks.h:239
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
Definition: PointDataGrid.h:637
void signedFloodFill(const ValueType &)
Definition: PointDataGrid.h:582
void setValueOff(Index, const ValueType &)
Definition: PointDataGrid.h:533
void assertNonmodifiable()
Definition: PointDataGrid.h:512
ValueAllCIter cendValueAll() const
Definition: PointDataGrid.h:711
Set of Attribute Arrays which tracks metadata about each array.
void prefetch(PointDataTreeT &tree, bool position=true, bool otherAttributes=true)
Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order to accelerate sub...
Definition: PointDataGrid.h:1601
Definition: IndexIterator.h:42
ChildOffCIter cendChildOff() const
Definition: PointDataGrid.h:728
bool hasSameTopology(const PointDataLeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition: PointDataGrid.h:433
ValueAllIter beginValueAll()
Definition: PointDataGrid.h:703
Definition: InternalNode.h:33
ChildOnIter endChildOn()
Definition: PointDataGrid.h:727
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
Definition: PointDataGrid.h:677
bool operator!=(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:444
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: PointDataGrid.h:631
void addLeaf(PointDataLeafNode *)
Definition: PointDataGrid.h:446
void setOutputStream(std::ostream &os)
Definition: StreamCompression.h:260
Index32 Index
Definition: openvdb/Types.h:32