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