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