HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PointDataGrid.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2017 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
29 ///////////////////////////////////////////////////////////////////////////
30 
31 /// @author Dan Bailey
32 ///
33 /// @file points/PointDataGrid.h
34 ///
35 /// @brief Attribute-owned data structure for points. Point attributes are
36 /// stored in leaf nodes and ordered by voxel for fast random and
37 /// sequential access.
38 
39 #ifndef OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
40 #define OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
41 
42 #include <openvdb/Grid.h>
43 #include <openvdb/tree/Tree.h>
44 #include <openvdb/tree/LeafNode.h>
46 #include "AttributeArray.h"
47 #include "AttributeArrayString.h"
48 #include "AttributeGroup.h"
49 #include "AttributeSet.h"
50 #include "StreamCompression.h"
51 #include <type_traits> // std::is_same
52 #include <utility> // std::pair, std::make_pair
53 
54 
55 class TestPointDataLeaf;
56 
57 namespace openvdb {
59 namespace OPENVDB_VERSION_NAME {
60 
61 namespace io
62 {
63 
64 /// @brief openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to
65 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
66 template<>
67 inline void
68 readCompressedValues( std::istream& is, PointDataIndex32* destBuf, Index destCount,
69  const util::NodeMask<3>& /*valueMask*/, bool /*fromHalf*/)
70 {
72 
73  const bool seek = destBuf == nullptr;
74 
75  const size_t destBytes = destCount*sizeof(PointDataIndex32);
76  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
77  if (destBytes >= maximumBytes) {
78  OPENVDB_THROW(openvdb::IoError, "Cannot read more than " <<
79  maximumBytes << " bytes in voxel values.")
80  }
81 
82  uint16_t bytes16;
83 
85 
86  if (seek && meta) {
87  // buffer size temporarily stored in the StreamMetadata pass
88  // to avoid having to perform an expensive disk read for 2-bytes
89  bytes16 = static_cast<uint16_t>(meta->pass());
90  // seek over size of the compressed buffer
91  is.seekg(sizeof(uint16_t), std::ios_base::cur);
92  }
93  else {
94  // otherwise read from disk
95  is.read(reinterpret_cast<char*>(&bytes16), sizeof(uint16_t));
96  }
97 
98  if (bytes16 == std::numeric_limits<uint16_t>::max()) {
99  // read or seek uncompressed data
100  if (seek) {
101  is.seekg(destBytes, std::ios_base::cur);
102  }
103  else {
104  is.read(reinterpret_cast<char*>(destBuf), destBytes);
105  }
106  }
107  else {
108  // read or seek uncompressed data
109  if (seek) {
110  is.seekg(int(bytes16), std::ios_base::cur);
111  }
112  else {
113  // decompress into the destination buffer
114  std::unique_ptr<char[]> bloscBuffer(new char[int(bytes16)]);
115  is.read(bloscBuffer.get(), bytes16);
116  std::unique_ptr<char[]> buffer = bloscDecompress( bloscBuffer.get(),
117  destBytes,
118  /*resize=*/false);
119  std::memcpy(destBuf, buffer.get(), destBytes);
120  }
121  }
122 }
123 
124 /// @brief openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to
125 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
126 template<>
127 inline void
128 writeCompressedValues( std::ostream& os, PointDataIndex32* srcBuf, Index srcCount,
129  const util::NodeMask<3>& /*valueMask*/,
130  const util::NodeMask<3>& /*childMask*/, bool /*toHalf*/)
131 {
133 
134  const size_t srcBytes = srcCount*sizeof(PointDataIndex32);
135  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
136  if (srcBytes >= maximumBytes) {
137  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
138  maximumBytes << " bytes in voxel values.")
139  }
140 
141  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
142 
143  size_t compressedBytes;
144  std::unique_ptr<char[]> buffer = bloscCompress( charBuffer, srcBytes,
145  compressedBytes, /*resize=*/false);
146 
147  if (compressedBytes > 0) {
148  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
149  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
150  os.write(reinterpret_cast<const char*>(buffer.get()), compressedBytes);
151  }
152  else {
153  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
154  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
155  os.write(reinterpret_cast<const char*>(srcBuf), srcBytes);
156  }
157 }
158 
159 template <typename T>
160 inline void
161 writeCompressedValuesSize(std::ostream& os, const T* srcBuf, Index srcCount)
162 {
164 
165  const size_t srcBytes = srcCount*sizeof(T);
166  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
167  if (srcBytes >= maximumBytes) {
168  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
169  maximumBytes << " bytes in voxel values.")
170  }
171 
172  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
173 
174  // calculate voxel buffer size after compression
175  size_t compressedBytes = bloscCompressedSize(charBuffer, srcBytes);
176 
177  if (compressedBytes > 0) {
178  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
179  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
180  }
181  else {
182  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
183  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
184  }
185 }
186 
187 } // namespace io
188 
189 
190 // forward declaration
191 namespace tree {
192  template<Index, typename> struct SameLeafConfig;
193 }
194 
195 
196 ////////////////////////////////////////
197 
198 
199 namespace points {
200 
201 
202 // forward declaration
203 template<typename T, Index Log2Dim> class PointDataLeafNode;
204 
205 /// @brief Point index tree configured to match the default VDB configurations.
208 
209 
210 /// @brief Point data grid.
212 
213 
214 /// @brief Deep copy the descriptor across all leaf nodes.
215 ///
216 /// @param tree the PointDataTree.
217 ///
218 /// @return the new descriptor.
219 ///
220 /// @note This method will fail if the Descriptors in the tree are not all identical.
221 template <typename PointDataTreeT>
222 inline AttributeSet::Descriptor::Ptr
223 makeDescriptorUnique(PointDataTreeT& tree);
224 
225 
226 /// @brief Toggle the streaming mode on all attributes in the tree to collapse the attributes
227 /// after deconstructing a bound AttributeHandle to each array. This results in better
228 /// memory efficiency when the data is streamed into another data structure
229 /// (typically for rendering).
230 ///
231 /// @param tree the PointDataTree.
232 /// @param on @c true to enable streaming
233 ///
234 /// @note Multiple threads cannot safely access the same AttributeArray when using streaming.
235 template <typename PointDataTreeT>
236 inline void
237 setStreamingMode(PointDataTreeT& tree, bool on = true);
238 
239 
240 ////////////////////////////////////////
241 
242 
243 template <typename T, Index Log2Dim>
244 class PointDataLeafNode : public tree::LeafNode<T, Log2Dim>, io::MultiPass {
245 
246 public:
248  using Ptr = std::shared_ptr<PointDataLeafNode>;
249 
250  using ValueType = T;
251  using ValueTypePair = std::pair<ValueType, ValueType>;
252  using IndexArray = std::vector<ValueType>;
253 
255 
256  ////////////////////////////////////////
257 
258  // The following methods had to be copied from the LeafNode class
259  // to make the derived PointDataLeafNode class compatible with the tree structure.
260 
263 
264  using BaseLeaf::LOG2DIM;
265  using BaseLeaf::TOTAL;
266  using BaseLeaf::DIM;
267  using BaseLeaf::NUM_VALUES;
268  using BaseLeaf::NUM_VOXELS;
269  using BaseLeaf::SIZE;
270  using BaseLeaf::LEVEL;
271 
272  /// Default constructor
274  : mAttributeSet(new AttributeSet) { }
275 
276  ~PointDataLeafNode() = default;
277 
278  /// Construct using deep copy of other PointDataLeafNode
279  explicit PointDataLeafNode(const PointDataLeafNode& other)
280  : BaseLeaf(other)
281  , mAttributeSet(new AttributeSet(*other.mAttributeSet)) { }
282 
283  /// Construct using supplied origin, value and active status
284  explicit
285  PointDataLeafNode(const Coord& coords, const T& value = zeroVal<T>(), bool active = false)
286  : BaseLeaf(coords, zeroVal<T>(), active)
287  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
288 
289  /// Construct using supplied origin, value and active status
290  /// use attribute map from another PointDataLeafNode
291  PointDataLeafNode(const PointDataLeafNode& other, const Coord& coords,
292  const T& value = zeroVal<T>(), bool active = false)
293  : BaseLeaf(coords, zeroVal<T>(), active)
294  , mAttributeSet(new AttributeSet(*other.mAttributeSet))
295  {
297  }
298 
299  // Copy-construct from a PointIndexLeafNode with the same configuration but a different ValueType.
300  template<typename OtherValueType>
302  : BaseLeaf(other)
303  , mAttributeSet(new AttributeSet) { }
304 
305  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
306  // Used for topology copies - explicitly sets the value (background) to zeroVal
307  template <typename ValueType>
309  : BaseLeaf(other, zeroVal<T>(), TopologyCopy())
310  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
311 
312  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
313  // Used for topology copies - explicitly sets the on and off value (background) to zeroVal
314  template <typename ValueType>
315  PointDataLeafNode(const tree::LeafNode<ValueType, Log2Dim>& other, const T& /*offValue*/, const T& /*onValue*/, TopologyCopy)
316  : BaseLeaf(other, zeroVal<T>(), zeroVal<T>(), TopologyCopy())
317  , mAttributeSet(new AttributeSet) { }
318 
319 #ifndef OPENVDB_2_ABI_COMPATIBLE
320  PointDataLeafNode(PartialCreate, const Coord& coords,
321  const T& value = zeroVal<T>(), bool active = false)
322  : BaseLeaf(PartialCreate(), coords, value, active)
323  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
324 #endif
325 
326 public:
327 
328  /// Retrieve the attribute set.
329  const AttributeSet& attributeSet() const { return *mAttributeSet; }
330 
331  /// @brief Create a new attribute set. Existing attributes will be removed.
332  void initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength);
333  /// @brief Clear the attribute set.
334  void clearAttributes(const bool updateValueMask = true);
335 
336  /// @brief Returns @c true if an attribute with this index exists.
337  /// @param pos Index of the attribute
338  bool hasAttribute(const size_t pos) const;
339  /// @brief Returns @c true if an attribute with this name exists.
340  /// @param attributeName Name of the attribute
341  bool hasAttribute(const Name& attributeName) const;
342 
343  /// @brief Append an attribute to the leaf.
344  /// @param expected Existing descriptor is expected to match this parameter.
345  /// @param replacement New descriptor to replace the existing one.
346  /// @param pos Index of the new attribute in the descriptor replacement.
347  /// @param strideOrTotalSize Stride of the attribute array (if constantStride), total size otherwise
348  /// @param constantStride if @c false, stride is interpreted as total size of the array
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 
353  /// @brief Drop list of attributes.
354  /// @param pos vector of attribute indices to drop
355  /// @param expected Existing descriptor is expected to match this parameter.
356  /// @param replacement New descriptor to replace the existing one.
357  void dropAttributes(const std::vector<size_t>& pos,
358  const Descriptor& expected, Descriptor::Ptr& replacement);
359  /// @brief Reorder attribute set.
360  /// @param replacement New descriptor to replace the existing one.
361  void reorderAttributes(const Descriptor::Ptr& replacement);
362  /// @brief Rename attributes in attribute set (order must remain the same).
363  /// @param expected Existing descriptor is expected to match this parameter.
364  /// @param replacement New descriptor to replace the existing one.
365  void renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement);
366  /// @brief Compact all attributes in attribute set.
367  void compactAttributes();
368 
369  /// @brief Replace the underlying attribute set with the given @a attributeSet.
370  /// @details This leaf will assume ownership of the given attribute set. The descriptors must
371  /// match and the voxel offsets values will need updating if the point order is different.
372  /// @throws ValueError if @a allowMismatchingDescriptors is @c false and the descriptors
373  /// do not match
374  void replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors = false);
375 
376  /// @brief Replace the descriptor with a new one
377  /// The new Descriptor must exactly match the old one
378  void resetDescriptor(const Descriptor::Ptr& replacement);
379 
380  /// @brief Sets all of the voxel offset values on this leaf, from the given vector
381  /// of @a offsets. If @a updateValueMask is true, then the active value mask will
382  /// be updated so voxels with points are active and empty voxels are inactive.
383  void setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask = true);
384 
385  /// @brief Throws an error if the voxel values on this leaf are not monotonically
386  /// increasing or within the bounds of the attribute arrays
387  void validateOffsets() const;
388 
389  /// @brief Read-write attribute array reference from index
390  /// {
391  AttributeArray& attributeArray(const size_t pos);
392  const AttributeArray& attributeArray(const size_t pos) const;
393  const AttributeArray& constAttributeArray(const size_t pos) const;
394  /// }
395  /// @brief Read-write attribute array reference from name
396  /// {
397  AttributeArray& attributeArray(const Name& attributeName);
398  const AttributeArray& attributeArray(const Name& attributeName) const;
399  const AttributeArray& constAttributeArray(const Name& attributeName) const;
400  /// }
401 
402  /// @brief Read-only group handle from group index
403  GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const;
404  /// @brief Read-only group handle from group name
405  GroupHandle groupHandle(const Name& group) const;
406  /// @brief Read-write group handle from group index
407  GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index);
408  /// @brief Read-write group handle from group name
410 
411  /// @brief Compute the total point count for the leaf
412  Index64 pointCount() const;
413  /// @brief Compute the total active (on) point count for the leaf
414  Index64 onPointCount() const;
415  /// @brief Compute the total inactive (off) point count for the leaf
416  Index64 offPointCount() const;
417  /// @brief Compute the point count in a specific group for the leaf
418  Index64 groupPointCount(const Name& groupName) const;
419 
420  /// @brief Activate voxels with non-zero points, deactivate voxels with zero points.
421  void updateValueMask();
422 
423  ////////////////////////////////////////
424 
425  void setOffsetOn(Index offset, const ValueType& val);
426  void setOffsetOnly(Index offset, const ValueType& val);
427 
428  /// @brief Return @c true if the given node (which may have a different @c ValueType
429  /// than this node) has the same active value topology as this node.
430  template<typename OtherType, Index OtherLog2Dim>
432  return BaseLeaf::hasSameTopology(other);
433  }
434 
435  /// Check for buffer, state and origin equivalence first.
436  /// If this returns true, do a deeper comparison on the attribute set to check
437  bool operator==(const PointDataLeafNode& other) const {
438  if(BaseLeaf::operator==(other) != true) return false;
439  return (*this->mAttributeSet == *other.mAttributeSet);
440  }
441 
442  bool operator!=(const PointDataLeafNode& other) const { return !(other == *this); }
443 
445  template<typename AccessorT>
446  void addLeafAndCache(PointDataLeafNode*, AccessorT&) {}
447 
448  //@{
449  /// @brief Return a pointer to this node.
450  PointDataLeafNode* touchLeaf(const Coord&) { return this; }
451  template<typename AccessorT>
452  PointDataLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
453 
454  template<typename NodeT, typename AccessorT>
455  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
456  {
458  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
459  return reinterpret_cast<NodeT*>(this);
461  }
462  PointDataLeafNode* probeLeaf(const Coord&) { return this; }
463  template<typename AccessorT>
464  PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
465  //@}
466 
467  //@{
468  /// @brief Return a @const pointer to this node.
469  const PointDataLeafNode* probeConstLeaf(const Coord&) const { return this; }
470  template<typename AccessorT>
471  const PointDataLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
472  template<typename AccessorT>
473  const PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
474  const PointDataLeafNode* probeLeaf(const Coord&) const { return this; }
475  template<typename NodeT, typename AccessorT>
476  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
477  {
479  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
480  return reinterpret_cast<const NodeT*>(this);
482  }
483  //@}
484 
485  // I/O methods
486 
487  void readTopology(std::istream& is, bool fromHalf = false);
488  void writeTopology(std::ostream& os, bool toHalf = false) const;
489 
490  Index buffers() const;
491 
492  void readBuffers(std::istream& is, bool fromHalf = false);
493  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
494  void writeBuffers(std::ostream& os, bool toHalf = false) const;
495 
496 
497  Index64 memUsage() const;
498 
499  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
500 
501  /// @brief Return the bounding box of this node, i.e., the full index space
502  /// spanned by this leaf node.
503  CoordBBox getNodeBoundingBox() const;
504 
505  ////////////////////////////////////////
506 
507  // Disable all write methods to avoid unintentional changes
508  // to the point-array offsets.
509 
511  assert(false && "Cannot modify voxel values in a PointDataTree.");
512  }
513 
514  // some methods silently ignore attempts to modify the
515  // point-array offsets if a zero value is used
516 
518  if (value != zeroVal<T>()) this->assertNonmodifiable();
519  }
520 
521  void setActiveState(const Coord& xyz, bool on) { BaseLeaf::setActiveState(xyz, on); }
522  void setActiveState(Index offset, bool on) { BaseLeaf::setActiveState(offset, on); }
523 
524  void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
526 
527  void setValueOff(const Coord& xyz) { BaseLeaf::setValueOff(xyz); }
529 
530  void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
532 
533  void setValueOn(const Coord& xyz) { BaseLeaf::setValueOn(xyz); }
535 
536  void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
538 
539  void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
540 
543 
544  template<typename ModifyOp>
545  void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
546 
547  template<typename ModifyOp>
548  void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
549 
550  template<typename ModifyOp>
551  void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
552 
553  // clipping is not yet supported
554  void clip(const CoordBBox&, const ValueType& value) { assertNonModifiableUnlessZero(value); }
555 
556  void fill(const CoordBBox&, const ValueType&, bool);
558  void fill(const ValueType&, bool);
559 
560  template<typename AccessorT>
561  void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
562 
563  template<typename ModifyOp, typename AccessorT>
564  void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
566  }
567 
568  template<typename AccessorT>
569  void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
570 
571  template<typename AccessorT>
572  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& parent) {
573  BaseLeaf::setActiveStateAndCache(xyz, on, parent);
574  }
575 
576  void resetBackground(const ValueType&, const ValueType& newBackground) {
577  assertNonModifiableUnlessZero(newBackground);
578  }
579 
582 
584 
585  friend class ::TestPointDataLeaf;
586 
587  using ValueOn = typename BaseLeaf::ValueOn;
588  using ValueOff = typename BaseLeaf::ValueOff;
589  using ValueAll = typename BaseLeaf::ValueAll;
590 
591 private:
592  std::unique_ptr<AttributeSet> mAttributeSet;
593  uint16_t mVoxelBufferSize = 0;
594 
595 protected:
596  using ChildOn = typename BaseLeaf::ChildOn;
597  using ChildOff = typename BaseLeaf::ChildOff;
598  using ChildAll = typename BaseLeaf::ChildAll;
599 
603 
604  // During topology-only construction, access is needed
605  // to protected/private members of other template instances.
606  template<typename, Index> friend class PointDataLeafNode;
607 
611 
612 public:
613  /// @brief Leaf value voxel iterator
614  ValueVoxelCIter beginValueVoxel(const Coord& ijk) const;
615 
616 public:
617 
618 #ifdef _MSC_VER
619  using ValueOnIter = typename BaseLeaf::ValueIter<
621  using ValueOnCIter = typename BaseLeaf::ValueIter<
623  using ValueOffIter = typename BaseLeaf::ValueIter<
625  using ValueOffCIter = typename BaseLeaf::ValueIter<
627  using ValueAllIter = typename BaseLeaf::ValueIter<
629  using ValueAllCIter = typename BaseLeaf::ValueIter<
631  using ChildOnIter = typename BaseLeaf::ChildIter<
633  using ChildOnCIter = typename BaseLeaf::ChildIter<
635  using ChildOffIter = typename BaseLeaf::ChildIter<
637  using ChildOffCIter = typename BaseLeaf::ChildIter<
639  using ChildAllIter = typename BaseLeaf::DenseIter<
641  using ChildAllCIter = typename BaseLeaf::DenseIter<
642  const PointDataLeafNode, const ValueType, ChildAll>;
643 #else
644  using ValueOnIter = typename BaseLeaf::template ValueIter<
646  using ValueOnCIter = typename BaseLeaf::template ValueIter<
648  using ValueOffIter = typename BaseLeaf::template ValueIter<
650  using ValueOffCIter = typename BaseLeaf::template ValueIter<
652  using ValueAllIter = typename BaseLeaf::template ValueIter<
654  using ValueAllCIter = typename BaseLeaf::template ValueIter<
656  using ChildOnIter = typename BaseLeaf::template ChildIter<
658  using ChildOnCIter = typename BaseLeaf::template ChildIter<
660  using ChildOffIter = typename BaseLeaf::template ChildIter<
662  using ChildOffCIter = typename BaseLeaf::template ChildIter<
664  using ChildAllIter = typename BaseLeaf::template DenseIter<
666  using ChildAllCIter = typename BaseLeaf::template DenseIter<
668 #endif
669 
674 
675  /// @brief Leaf index iterator
676  IndexAllIter beginIndexAll() const;
677  IndexOnIter beginIndexOn() const;
678  IndexOffIter beginIndexOff() const;
679 
680  template<typename IterT, typename FilterT>
681  IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
682 
683  /// @brief Filtered leaf index iterator
684  template<typename FilterT>
686  template<typename FilterT>
688  template<typename FilterT>
690 
691  /// @brief Leaf index iterator from voxel
692  IndexVoxelIter beginIndexVoxel(const Coord& ijk) const;
693 
694  /// @brief Filtered leaf index iterator from voxel
695  template<typename FilterT>
696  IndexIter<ValueVoxelCIter, FilterT> beginIndexVoxel(const Coord& ijk, const FilterT& filter) const;
697 
698 #define VMASK_ this->getValueMask()
699  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
700  ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
701  ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
702  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
703  ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
704  ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
705  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
706  ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
707  ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
708 
709  ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
710  ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
711  ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
712  ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
713  ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
714  ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
715  ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
716  ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
717  ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
718 
719  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
720  ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
721  ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
722  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
723  ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
724  ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
725  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
726  ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
727  ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
728 
729  ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
730  ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
731  ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
732  ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
733  ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
734  ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
735  ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
736  ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
737  ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
738 #undef VMASK_
739 }; // struct PointDataLeafNode
740 
741 ////////////////////////////////////////
742 
743 // PointDataLeafNode implementation
744 
745 template<typename T, Index Log2Dim>
746 inline void
747 PointDataLeafNode<T, Log2Dim>::initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength)
748 {
749  if (descriptor->size() != 1 ||
750  descriptor->find("P") == AttributeSet::INVALID_POS ||
751  descriptor->valueType(0) != typeNameAsString<Vec3f>())
752  {
753  OPENVDB_THROW(IndexError, "Initializing attributes only allowed with one Vec3f position attribute.");
754  }
755 
756  mAttributeSet.reset(new AttributeSet(descriptor, arrayLength));
757 }
758 
759 template<typename T, Index Log2Dim>
760 inline void
762 {
763  mAttributeSet.reset(new AttributeSet(*mAttributeSet, 0));
764 
765  // zero voxel values
766 
767  for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
768  this->setOffsetOnly(n, 0);
769  }
770 
771  // if updateValueMask, also de-activate all voxels
772 
773  if (updateValueMask) this->setValuesOff();
774 }
775 
776 template<typename T, Index Log2Dim>
777 inline bool
779 {
780  return pos < mAttributeSet->size();
781 }
782 
783 template<typename T, Index Log2Dim>
784 inline bool
786 {
787  const size_t pos = mAttributeSet->find(attributeName);
788  return pos != AttributeSet::INVALID_POS;
789 }
790 
791 template<typename T, Index Log2Dim>
792 inline AttributeArray::Ptr
793 PointDataLeafNode<T, Log2Dim>::appendAttribute( const Descriptor& expected, Descriptor::Ptr& replacement,
794  const size_t pos, const Index strideOrTotalSize,
795  const bool constantStride)
796 {
797  return mAttributeSet->appendAttribute(expected, replacement, pos, strideOrTotalSize, constantStride);
798 }
799 
800 template<typename T, Index Log2Dim>
801 inline void
802 PointDataLeafNode<T, Log2Dim>::dropAttributes(const std::vector<size_t>& pos,
803  const Descriptor& expected, Descriptor::Ptr& replacement)
804 {
805  mAttributeSet->dropAttributes(pos, expected, replacement);
806 }
807 
808 template<typename T, Index Log2Dim>
809 inline void
810 PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
811 {
812  mAttributeSet->reorderAttributes(replacement);
813 }
814 
815 template<typename T, Index Log2Dim>
816 inline void
817 PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
818 {
819  mAttributeSet->renameAttributes(expected, replacement);
820 }
821 
822 template<typename T, Index Log2Dim>
823 inline void
825 {
826  for (size_t i = 0; i < mAttributeSet->size(); i++) {
827  AttributeArray* array = mAttributeSet->get(i);
828  array->compact();
829  }
830 }
831 
832 template<typename T, Index Log2Dim>
833 inline void
834 PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
835 {
836  if (!attributeSet) {
837  OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
838  }
839 
840  if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
841  OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
842  }
843 
844  mAttributeSet.reset(attributeSet);
845 }
846 
847 template<typename T, Index Log2Dim>
848 inline void
849 PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
850 {
851  mAttributeSet->resetDescriptor(replacement);
852 }
853 
854 template<typename T, Index Log2Dim>
855 inline void
856 PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
857 {
858  if (offsets.size() != LeafNodeType::NUM_VALUES) {
859  OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
860  }
861 
862  for (Index index = 0; index < offsets.size(); ++index) {
863  setOffsetOnly(index, offsets[index]);
864  }
865 
866  if (updateValueMask) this->updateValueMask();
867 }
868 
869 template<typename T, Index Log2Dim>
870 inline void
872 {
873  // Ensure all of the offset values are monotonically increasing
874  for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
875  if (this->getValue(index-1) > this->getValue(index)) {
876  OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
877  }
878  }
879 
880  // Ensure all attribute arrays are of equal length
881  for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
882  if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
883  OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
884  }
885  }
886 
887  // Ensure the last voxel's offset value matches the size of each attribute array
888  if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
889  OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
890  }
891 }
892 
893 template<typename T, Index Log2Dim>
894 inline AttributeArray&
896 {
897  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
898  return *mAttributeSet->get(pos);
899 }
900 
901 template<typename T, Index Log2Dim>
902 inline const AttributeArray&
904 {
905  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
906  return *mAttributeSet->getConst(pos);
907 }
908 
909 template<typename T, Index Log2Dim>
910 inline const AttributeArray&
912 {
913  return this->attributeArray(pos);
914 }
915 
916 template<typename T, Index Log2Dim>
917 inline AttributeArray&
919 {
920  const size_t pos = mAttributeSet->find(attributeName);
921  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
922  return *mAttributeSet->get(pos);
923 }
924 
925 template<typename T, Index Log2Dim>
926 inline const AttributeArray&
928 {
929  const size_t pos = mAttributeSet->find(attributeName);
930  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
931  return *mAttributeSet->getConst(pos);
932 }
933 
934 template<typename T, Index Log2Dim>
935 inline const AttributeArray&
937 {
938  return this->attributeArray(attributeName);
939 }
940 
941 template<typename T, Index Log2Dim>
942 inline GroupHandle
943 PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
944 {
945  const AttributeArray& array = this->attributeArray(index.first);
946  assert(isGroup(array));
947 
948  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
949 
950  return GroupHandle(groupArray, index.second);
951 }
952 
953 template<typename T, Index Log2Dim>
954 inline GroupHandle
956 {
957  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
958  return this->groupHandle(index);
959 }
960 
961 template<typename T, Index Log2Dim>
962 inline GroupWriteHandle
963 PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
964 {
965  AttributeArray& array = this->attributeArray(index.first);
966  assert(isGroup(array));
967 
968  GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
969 
970  return GroupWriteHandle(groupArray, index.second);
971 }
972 
973 template<typename T, Index Log2Dim>
974 inline GroupWriteHandle
976 {
977  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
978  return this->groupWriteHandle(index);
979 }
980 
981 template<typename T, Index Log2Dim>
982 template<typename ValueIterT, typename FilterT>
985 {
986  using IterTraitsT = tree::IterTraits<LeafNodeType, ValueIterT>;
987 
988  // construct the value iterator and reset the filter to use this leaf
989 
990  ValueIterT valueIter = IterTraitsT::begin(*this);
991  FilterT newFilter(filter);
992  newFilter.reset(*this);
993 
994  return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
995 }
996 
997 template<typename T, Index Log2Dim>
998 template<typename FilterT>
1001 {
1002  return this->beginIndex<ValueAllCIter, FilterT>(filter);
1003 }
1004 
1005 template<typename T, Index Log2Dim>
1006 template<typename FilterT>
1009 {
1010  return this->beginIndex<ValueOnCIter, FilterT>(filter);
1011 }
1012 
1013 template<typename T, Index Log2Dim>
1014 template<typename FilterT>
1017 {
1018  return this->beginIndex<ValueOffCIter, FilterT>(filter);
1019 }
1020 
1021 template<typename T, Index Log2Dim>
1024 {
1026  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
1027 }
1028 
1029 template<typename T, Index Log2Dim>
1032 {
1034  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
1035 }
1036 
1037 template<typename T, Index Log2Dim>
1040 {
1042  return this->beginIndex<ValueOffCIter, NullFilter>(filter);
1043 }
1044 
1045 template<typename T, Index Log2Dim>
1046 inline ValueVoxelCIter
1048 {
1049  const Index index = LeafNodeType::coordToOffset(ijk);
1050  assert(index < BaseLeaf::SIZE);
1051  const ValueType end = this->getValue(index);
1052  const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1053  return ValueVoxelCIter(start, end);
1054 }
1055 
1056 template<typename T, Index Log2Dim>
1059 {
1060  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1061  return IndexVoxelIter(iter, NullFilter());
1062 }
1063 
1064 template<typename T, Index Log2Dim>
1065 template<typename FilterT>
1067 PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1068 {
1069  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1070  FilterT newFilter(filter);
1071  newFilter.reset(*this);
1072  return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1073 }
1074 
1075 template<typename T, Index Log2Dim>
1076 inline Index64
1078 {
1079  return iterCount(this->beginIndexAll());
1080 }
1081 
1082 template<typename T, Index Log2Dim>
1083 inline Index64
1085 {
1086  if (this->isEmpty()) return 0;
1087  else if (this->isDense()) return this->pointCount();
1088  return iterCount(this->beginIndexOn());
1089 }
1090 
1091 template<typename T, Index Log2Dim>
1092 inline Index64
1094 {
1095  if (this->isEmpty()) return this->pointCount();
1096  else if (this->isDense()) return 0;
1097  return iterCount(this->beginIndexOff());
1098 }
1099 
1100 template<typename T, Index Log2Dim>
1101 inline Index64
1103 {
1104  GroupFilter filter(groupName);
1105  return iterCount(this->beginIndexAll(filter));
1106 }
1107 
1108 template<typename T, Index Log2Dim>
1109 inline void
1111 {
1112  ValueType start = 0, end = 0;
1113  for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1114  end = this->getValue(n);
1115  this->setValueMask(n, (end - start) > 0);
1116  start = end;
1117  }
1118 }
1119 
1120 template<typename T, Index Log2Dim>
1121 inline void
1123 {
1124  this->buffer().setValue(offset, val);
1125  this->setValueMaskOn(offset);
1126 }
1127 
1128 template<typename T, Index Log2Dim>
1129 inline void
1131 {
1132  this->buffer().setValue(offset, val);
1133 }
1134 
1135 template<typename T, Index Log2Dim>
1136 inline void
1137 PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1138 {
1139  BaseLeaf::readTopology(is, fromHalf);
1140 }
1141 
1142 template<typename T, Index Log2Dim>
1143 inline void
1144 PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1145 {
1146  BaseLeaf::writeTopology(os, toHalf);
1147 }
1148 
1149 template<typename T, Index Log2Dim>
1150 inline Index
1152 {
1153  return Index( /*voxel buffer sizes*/ 1 +
1154  /*voxel buffers*/ 1 +
1155  /*attribute metadata*/ 1 +
1156  /*attribute uniform values*/ mAttributeSet->size() +
1157  /*attribute buffers*/ mAttributeSet->size() +
1158  /*cleanup*/ 1);
1159 }
1160 
1161 template<typename T, Index Log2Dim>
1162 inline void
1163 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1164 {
1165  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1166 }
1167 
1168 template<typename T, Index Log2Dim>
1169 inline void
1170 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1171 {
1172  struct Local
1173  {
1174  static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1175  const Index index)
1176  {
1177  std::string key("paged:" + std::to_string(index));
1178  auto it = auxData.find(key);
1179  if (it != auxData.end()) {
1180  return *(hboost::any_cast<compression::PagedInputStream::Ptr>(it->second));
1181  }
1182  else {
1183  compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1184  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1185  return *pagedStream;
1186  }
1187  }
1188 
1189  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1190  {
1191  std::string matchingKey("hasMatchingDescriptor");
1192  auto itMatching = auxData.find(matchingKey);
1193  return itMatching != auxData.end();
1194  }
1195 
1196  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1197  {
1198  std::string matchingKey("hasMatchingDescriptor");
1199  std::string descriptorKey("descriptorPtr");
1200  auto itMatching = auxData.find(matchingKey);
1201  auto itDescriptor = auxData.find(descriptorKey);
1202  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1203  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1204  }
1205 
1206  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1207  const Descriptor::Ptr descriptor)
1208  {
1209  std::string descriptorKey("descriptorPtr");
1210  std::string matchingKey("hasMatchingDescriptor");
1211  auto itMatching = auxData.find(matchingKey);
1212  if (itMatching == auxData.end()) {
1213  // if matching bool is not found, insert "true" and the descriptor
1214  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1215  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1216  }
1217  }
1218 
1219  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1220  {
1221  std::string descriptorKey("descriptorPtr");
1222  auto itDescriptor = auxData.find(descriptorKey);
1223  assert(itDescriptor != auxData.end());
1224  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1225  return descriptor;
1226  }
1227  };
1228 
1230 
1231  if (!meta) {
1232  OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1233  }
1234 
1235  const Index pass = meta->pass();
1236 
1237  const Index attributes = (this->buffers() - 4) / 2;
1238 
1239  if (pass == 0) {
1240  // pass 0 - voxel data sizes
1241  is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1242  Local::clearMatchingDescriptor(meta->auxData());
1243  }
1244  else if (pass == 1) {
1245  // pass 1 - descriptor and attribute metadata
1246  if (Local::hasMatchingDescriptor(meta->auxData())) {
1247  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1248  mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1249  }
1250  else {
1251  uint8_t header;
1252  is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1253  mAttributeSet->readDescriptor(is);
1254  if (header == uint8_t(1)) {
1255  AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1256  Local::insertDescriptor(meta->auxData(), descriptor);
1257  }
1258  }
1259  mAttributeSet->readMetadata(is);
1260  }
1261  else if (pass < (attributes + 2)) {
1262  // pass 2...n+2 - attribute uniform values
1263  const size_t attributeIndex = pass - 2;
1264  AttributeArray* array = mAttributeSet->get(attributeIndex);
1265  if (array) {
1266  compression::PagedInputStream& pagedStream =
1267  Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1268  pagedStream.setInputStream(is);
1269  pagedStream.setSizeOnly(true);
1270  array->readPagedBuffers(pagedStream);
1271  }
1272  }
1273  else if (pass == attributes + 2) {
1274  // pass n+2 - voxel data
1275 
1276  // StreamMetadata pass variable used to temporarily store voxel buffer size
1277  io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1278  nonConstMeta.setPass(mVoxelBufferSize);
1279 
1280  // readBuffers() calls readCompressedValues specialization above
1281  BaseLeaf::readBuffers(is, fromHalf);
1282 
1283  // pass now reset to original value
1284  nonConstMeta.setPass(pass);
1285  }
1286  else if (pass < (attributes*2 + 3)) {
1287  // pass n+2..2n+2 - attribute buffers
1288  const Index attributeIndex = pass - attributes - 3;
1289  AttributeArray* array = mAttributeSet->get(attributeIndex);
1290  if (array) {
1291  compression::PagedInputStream& pagedStream =
1292  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1293  pagedStream.setInputStream(is);
1294  pagedStream.setSizeOnly(false);
1295  array->readPagedBuffers(pagedStream);
1296  }
1297  }
1298 }
1299 
1300 template<typename T, Index Log2Dim>
1301 inline void
1302 PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1303 {
1304  struct Local
1305  {
1306  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1307  {
1308  // if paged stream exists, flush and delete it
1309  std::string key("paged:" + std::to_string(index));
1310  auto it = auxData.find(key);
1311  if (it != auxData.end()) {
1313  stream.flush();
1314  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1315  }
1316  }
1317 
1318  static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1319  const Index index)
1320  {
1321  std::string key("paged:" + std::to_string(index));
1322  auto it = auxData.find(key);
1323  if (it != auxData.end()) {
1324  return *(hboost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1325  }
1326  else {
1327  compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1328  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1329  return *pagedStream;
1330  }
1331  }
1332 
1333  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1334  const Descriptor::Ptr descriptor)
1335  {
1336  std::string descriptorKey("descriptorPtr");
1337  std::string matchingKey("hasMatchingDescriptor");
1338  auto itMatching = auxData.find(matchingKey);
1339  auto itDescriptor = auxData.find(descriptorKey);
1340  if (itMatching == auxData.end()) {
1341  // if matching bool is not found, insert "true" and the descriptor
1342  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1343  assert(itDescriptor == auxData.end());
1344  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1345  }
1346  else {
1347  // if matching bool is found and is false, early exit (a previous descriptor did not match)
1348  bool matching = hboost::any_cast<bool>(itMatching->second);
1349  if (!matching) return;
1350  assert(itDescriptor != auxData.end());
1351  // if matching bool is true, check whether the existing descriptor matches the current one and set
1352  // matching bool to false if not
1353  const Descriptor::Ptr existingDescriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1354  if (*existingDescriptor != *descriptor) {
1355  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1356  }
1357  }
1358  }
1359 
1360  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1361  {
1362  std::string matchingKey("hasMatchingDescriptor");
1363  auto itMatching = auxData.find(matchingKey);
1364  // if matching key is not found, no matching descriptor
1365  if (itMatching == auxData.end()) return false;
1366  // if matching key is found and is false, no matching descriptor
1367  if (!hboost::any_cast<bool>(itMatching->second)) return false;
1368  return true;
1369  }
1370 
1371  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1372  {
1373  std::string descriptorKey("descriptorPtr");
1374  auto itDescriptor = auxData.find(descriptorKey);
1375  // if matching key is true, however descriptor is not found, it has already been retrieved
1376  if (itDescriptor == auxData.end()) return nullptr;
1377  // otherwise remove it and return it
1378  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1379  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1380  return descriptor;
1381  }
1382 
1383  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1384  {
1385  std::string matchingKey("hasMatchingDescriptor");
1386  std::string descriptorKey("descriptorPtr");
1387  auto itMatching = auxData.find(matchingKey);
1388  auto itDescriptor = auxData.find(descriptorKey);
1389  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1390  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1391  }
1392  };
1393 
1395 
1396  if (!meta) {
1397  OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1398  }
1399 
1400  const Index pass = meta->pass();
1401 
1402  // leaf traversal analysis deduces the number of passes to perform for this leaf
1403  // then updates the leaf traversal value to ensure all passes will be written
1404 
1405  if (meta->countingPasses()) {
1406  const Index requiredPasses = this->buffers();
1407  if (requiredPasses > pass) {
1408  meta->setPass(requiredPasses);
1409  }
1410  return;
1411  }
1412 
1413  const Index attributes = (this->buffers() - 4) / 2;
1414 
1415  if (pass == 0) {
1416  // pass 0 - voxel data sizes
1418  // track if descriptor is shared or not
1419  Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1420  }
1421  else if (pass == 1) {
1422  // pass 1 - descriptor and attribute metadata
1423  bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1424  if (matchingDescriptor) {
1425  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1426  if (descriptor) {
1427  // write a header to indicate a shared descriptor
1428  uint8_t header(1);
1429  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1430  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1431  }
1432  }
1433  else {
1434  // write a header to indicate a non-shared descriptor
1435  uint8_t header(0);
1436  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1437  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1438  }
1439  mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1440  }
1441  else if (pass < attributes + 2) {
1442  // pass 2...n+2 - attribute buffer sizes
1443  const Index attributeIndex = pass - 2;
1444  // destroy previous paged stream
1445  if (pass > 2) {
1446  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1447  }
1448  const AttributeArray* array = mAttributeSet->getConst(attributeIndex);
1449  if (array) {
1450  compression::PagedOutputStream& pagedStream =
1451  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1452  pagedStream.setOutputStream(os);
1453  pagedStream.setSizeOnly(true);
1454  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1455  }
1456  }
1457  else if (pass == attributes + 2) {
1458  const Index attributeIndex = pass - 3;
1459  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1460  // pass n+2 - voxel data
1461  BaseLeaf::writeBuffers(os, toHalf);
1462  }
1463  else if (pass < (attributes*2 + 3)) {
1464  // pass n+3...2n+3 - attribute buffers
1465  const Index attributeIndex = pass - attributes - 3;
1466  // destroy previous paged stream
1467  if (pass > attributes + 2) {
1468  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1469  }
1470  const AttributeArray* array = mAttributeSet->getConst(attributeIndex);
1471  if (array) {
1472  compression::PagedOutputStream& pagedStream =
1473  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1474  pagedStream.setOutputStream(os);
1475  pagedStream.setSizeOnly(false);
1476  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1477  }
1478  }
1479  else if (pass < buffers()) {
1480  Local::clearMatchingDescriptor(meta->auxData());
1481  // pass 2n+3 - cleanup last paged stream
1482  const Index attributeIndex = pass - attributes - 4;
1483  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1484  }
1485 }
1486 
1487 template<typename T, Index Log2Dim>
1488 inline Index64
1490 {
1491  return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1492 }
1493 
1494 template<typename T, Index Log2Dim>
1495 inline void
1496 PointDataLeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1497 {
1498  BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1499 }
1500 
1501 template<typename T, Index Log2Dim>
1502 inline CoordBBox
1504 {
1505  return BaseLeaf::getNodeBoundingBox();
1506 }
1507 
1508 template<typename T, Index Log2Dim>
1509 inline void
1510 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1511 {
1512 #ifndef OPENVDB_2_ABI_COMPATIBLE
1513  if (!this->allocate()) return;
1514 #endif
1515 
1516  this->assertNonModifiableUnlessZero(value);
1517 
1518  // active state is permitted to be updated
1519 
1520  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1521  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1522  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1523  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1524  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1525  const Index offset = offsetXY + (z & (DIM-1u));
1526  this->setValueMask(offset, active);
1527  }
1528  }
1529  }
1530 }
1531 
1532 template<typename T, Index Log2Dim>
1533 inline void
1535 {
1536  this->assertNonModifiableUnlessZero(value);
1537 
1538  // active state is permitted to be updated
1539 
1540  if (active) this->setValuesOn();
1541  else this->setValuesOff();
1542 }
1543 
1544 
1545 ////////////////////////////////////////
1546 
1547 
1548 template <typename PointDataTreeT>
1549 inline AttributeSet::Descriptor::Ptr
1550 makeDescriptorUnique(PointDataTreeT& tree)
1551 {
1552  auto leafIter = tree.beginLeaf();
1553  if (!leafIter) return nullptr;
1554 
1555  const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1556  auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1557  for (; leafIter; ++leafIter) {
1558  leafIter->resetDescriptor(newDescriptor);
1559  }
1560 
1561  return newDescriptor;
1562 }
1563 
1564 
1565 template <typename PointDataTreeT>
1566 inline void
1567 setStreamingMode(PointDataTreeT& tree, bool on)
1568 {
1569  auto leafIter = tree.beginLeaf();
1570  for (; leafIter; ++leafIter) {
1571  for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1572  leafIter->attributeArray(i).setStreaming(on);
1573  }
1574  }
1575 }
1576 
1577 
1578 /// @brief Global registration of point data-related types
1579 void initialize();
1580 
1581 /// @brief Global deregistration of point data-related types
1582 void uninitialize();
1583 
1584 } // namespace points
1585 
1586 
1587 ////////////////////////////////////////
1588 
1589 
1590 namespace tree
1591 {
1592 
1593 /// Helper metafunction used to implement LeafNode::SameConfiguration
1594 /// (which, as an inner class, can't be independently specialized)
1595 template<Index Dim1, typename T2>
1596 struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1597 
1598 } // namespace tree
1599 } // namespace OPENVDB_VERSION_NAME
1600 } // namespace openvdb
1601 
1602 #endif // OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
1603 
1604 // Copyright (c) 2012-2017 DreamWorks Animation LLC
1605 // All rights reserved. This software is distributed under the
1606 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
GLuint GLuint stream
Definition: glcorearb.h:1831
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:195
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.
void setValue(const Coord &, const ValueType &)
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:267
Definition: ImfName.h:53
Descriptor & descriptor()
Return a reference to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:121
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 setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNode.h:436
void setValueOff(const Coord &, const ValueType &)
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
GLuint start
Definition: glcorearb.h:474
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:462
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.
SharedPtr< StreamMetadata > Ptr
Definition: io.h:59
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.
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
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:140
void updateValueMask()
Activate voxels with non-zero points, deactivate voxels with zero points.
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
IndexIter< IterT, FilterT > beginIndex(const FilterT &filter) const
AttributeArray::Ptr appendAttribute(const Descriptor &expected, Descriptor::Ptr &replacement, const size_t pos, const Index strideOrTotalSize=1, const bool constantStride=true)
Append an attribute to the leaf.
void readBuffers(std::istream &is, bool fromHalf=false)
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:58
void initializeAttributes(const Descriptor::Ptr &descriptor, const Index arrayLength)
Create a new attribute set. Existing attributes will be removed.
GLint y
Definition: glcorearb.h:102
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a pointer to this node.
void signedFloodFill(const ValueType &, const ValueType &)
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
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:62
OffMaskIterator< NodeMask > OffIterator
Definition: NodeMasks.h:344
GLuint buffer
Definition: glcorearb.h:659
png_uint_32 i
Definition: png.h:2877
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:505
virtual void writePagedBuffers(compression::PagedOutputStream &, bool outputTransient) const =0
Index64 pointCount(const PointDataTreeT &tree, const bool inCoreOnly=false)
Total points in the PointDataTree.
Definition: PointCount.h:198
void readTopology(std::istream &is, bool fromHalf=false)
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don't change its value.
Definition: LeafNode.h:1079
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
void setValuesOn()
Mark all voxels as active but don't change their values.
Definition: LeafNode.h:482
bool isGroup(const AttributeArray &array)
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2620
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:132
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
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.
const char * typeNameAsString< Vec3f >()
Definition: Types.h:343
GLdouble n
Definition: glcorearb.h:2007
Base class for storing attribute data.
typename NodeMaskType::OffIterator MaskOffIterator
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:72
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: LeafNode.h:598
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:302
#define OPENVDB_VERSION_NAME
Definition: version.h:43
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.
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:60
GLuint GLuint end
Definition: glcorearb.h:474
bool operator==(const PointDataLeafNode &other) const
Attribute array storage for string data using Descriptor Metadata.
GLintptr offset
Definition: glcorearb.h:664
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
void clip(const CoordBBox &, const ValueType &value)
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
void setValueOnly(const Coord &, const ValueType &)
void initialize()
Global registration of point data-related types.
Definition: logging.h:316
void setOffsetOn(Index offset, const ValueType &val)
Convenience wrappers to using Blosc and reading and writing of Paged data.
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition: LeafNode.h:426
GLboolean * data
Definition: glcorearb.h:130
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
GLuint const GLchar * name
Definition: glcorearb.h:785
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:54
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:129
const AttributeArray & constAttributeArray(const size_t pos) const
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
const GLuint * buffers
Definition: glcorearb.h:660
void flush()
Manually flushes the current page to disk if non-zero.
GLsizei const GLfloat * value
Definition: glcorearb.h:823
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.
void fill(const CoordBBox &, const ValueType &, bool)
ValueVoxelCIter beginValueVoxel(const Coord &ijk) const
Leaf value voxel iterator.
OnMaskIterator< NodeMask > OnIterator
Definition: NodeMasks.h:343
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.
void uninitialize()
Global deregistration of point data-related types.
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)
GLint GLenum GLint x
Definition: glcorearb.h:408
GLuint GLfloat * val
Definition: glcorearb.h:1607
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
#define VMASK_
std::map< std::string, hboost::any > AuxDataMap
Definition: io.h:113
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
IndexAllIter beginIndexAll() const
Leaf index iterator.
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:173
#define SIZE
Definition: simple.C:40
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:130
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
void writeBuffers(std::ostream &os, bool toHalf=false) const
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:503
void setValuesOff()
Mark all voxels as inactive but don't change their values.
Definition: LeafNode.h:484
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:56
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
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
void clearAttributes(const bool updateValueMask=true)
Clear the attribute set.
bool hasSameTopology(const LeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition: LeafNode.h:1440
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:94
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.
typename NodeMaskType::DenseIterator MaskDenseIterator
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
DenseMaskIterator< NodeMask > DenseIterator
Definition: NodeMasks.h:345
AttributeArray & attributeArray(const size_t pos)
Read-write attribute array reference from index {.
void setValueOn(const Coord &, const ValueType &)
Index64 pointCount() const
Compute the total point count for the leaf.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296