OpenVDB 9.0.0
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{
50
51 const bool seek = destBuf == nullptr;
52
53 const size_t destBytes = destCount*sizeof(PointDataIndex32);
54 const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
55 if (destBytes >= maximumBytes) {
56 OPENVDB_THROW(openvdb::IoError, "Cannot read more than " <<
57 maximumBytes << " bytes in voxel values.")
58 }
59
60 uint16_t bytes16;
61
63
64 if (seek && meta) {
65 // buffer size temporarily stored in the StreamMetadata pass
66 // to avoid having to perform an expensive disk read for 2-bytes
67 bytes16 = static_cast<uint16_t>(meta->pass());
68 // seek over size of the compressed buffer
69 is.seekg(sizeof(uint16_t), std::ios_base::cur);
70 }
71 else {
72 // otherwise read from disk
73 is.read(reinterpret_cast<char*>(&bytes16), sizeof(uint16_t));
74 }
75
76 if (bytes16 == std::numeric_limits<uint16_t>::max()) {
77 // read or seek uncompressed data
78 if (seek) {
79 is.seekg(destBytes, std::ios_base::cur);
80 }
81 else {
82 is.read(reinterpret_cast<char*>(destBuf), destBytes);
83 }
84 }
85 else {
86 // read or seek uncompressed data
87 if (seek) {
88 is.seekg(int(bytes16), std::ios_base::cur);
89 }
90 else {
91 // decompress into the destination buffer
92 std::unique_ptr<char[]> bloscBuffer(new char[int(bytes16)]);
93 is.read(bloscBuffer.get(), bytes16);
94 std::unique_ptr<char[]> buffer = bloscDecompress( bloscBuffer.get(),
95 destBytes,
96 /*resize=*/false);
97 std::memcpy(destBuf, buffer.get(), destBytes);
98 }
99 }
100}
101
102/// @brief openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to
103/// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
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{
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{
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 {
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 {
488 return reinterpret_cast<const NodeT*>(this);
490 }
491 //@}
492
493 // I/O methods
494
495 void readTopology(std::istream& is, bool fromHalf = false);
496 void writeTopology(std::ostream& os, bool toHalf = false) const;
497
498 Index buffers() const;
499
500 void readBuffers(std::istream& is, bool fromHalf = false);
501 void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
502 void writeBuffers(std::ostream& os, bool toHalf = false) const;
503
504
505 Index64 memUsage() const;
506
507 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
508
509 /// @brief Return the bounding box of this node, i.e., the full index space
510 /// spanned by this leaf node.
511 CoordBBox getNodeBoundingBox() const;
512
513 ////////////////////////////////////////
514
515 // Disable all write methods to avoid unintentional changes
516 // to the point-array offsets.
517
519 assert(false && "Cannot modify voxel values in a PointDataTree.");
520 }
521
522 // some methods silently ignore attempts to modify the
523 // point-array offsets if a zero value is used
524
526 if (value != zeroVal<T>()) this->assertNonmodifiable();
527 }
528
529 void setActiveState(const Coord& xyz, bool on) { BaseLeaf::setActiveState(xyz, on); }
530 void setActiveState(Index offset, bool on) { BaseLeaf::setActiveState(offset, on); }
531
532 void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
533 void setValueOnly(Index, const ValueType&) { assertNonmodifiable(); }
534
535 void setValueOff(const Coord& xyz) { BaseLeaf::setValueOff(xyz); }
536 void setValueOff(Index offset) { BaseLeaf::setValueOff(offset); }
537
538 void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
539 void setValueOff(Index, const ValueType&) { assertNonmodifiable(); }
540
541 void setValueOn(const Coord& xyz) { BaseLeaf::setValueOn(xyz); }
542 void setValueOn(Index offset) { BaseLeaf::setValueOn(offset); }
543
544 void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
545 void setValueOn(Index, const ValueType&) { assertNonmodifiable(); }
546
547 void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
548
549 void setValuesOn() { BaseLeaf::setValuesOn(); }
550 void setValuesOff() { BaseLeaf::setValuesOff(); }
551
552 template<typename ModifyOp>
553 void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
554
555 template<typename ModifyOp>
556 void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
557
558 template<typename ModifyOp>
559 void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
560
561 // clipping is not yet supported
562 void clip(const CoordBBox&, const ValueType& value) { assertNonModifiableUnlessZero(value); }
563
564 void fill(const CoordBBox&, const ValueType&, bool);
565 void fill(const ValueType& value) { assertNonModifiableUnlessZero(value); }
566 void fill(const ValueType&, bool);
567
568 template<typename AccessorT>
569 void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
570
571 template<typename ModifyOp, typename AccessorT>
572 void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
573 assertNonmodifiable();
574 }
575
576 template<typename AccessorT>
577 void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
578
579 template<typename AccessorT>
580 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& parent) {
581 BaseLeaf::setActiveStateAndCache(xyz, on, parent);
582 }
583
584 void resetBackground(const ValueType&, const ValueType& newBackground) {
585 assertNonModifiableUnlessZero(newBackground);
586 }
587
588 void signedFloodFill(const ValueType&) { assertNonmodifiable(); }
589 void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); }
590
591 void negate() { assertNonmodifiable(); }
592
593 friend class ::TestPointDataLeaf;
594
595 using ValueOn = typename BaseLeaf::ValueOn;
596 using ValueOff = typename BaseLeaf::ValueOff;
597 using ValueAll = typename BaseLeaf::ValueAll;
598
599private:
600 AttributeSet::UniquePtr mAttributeSet;
601 uint16_t mVoxelBufferSize = 0;
602
603protected:
604 using ChildOn = typename BaseLeaf::ChildOn;
605 using ChildOff = typename BaseLeaf::ChildOff;
606 using ChildAll = typename BaseLeaf::ChildAll;
607
611
612 // During topology-only construction, access is needed
613 // to protected/private members of other template instances.
614 template<typename, Index> friend class PointDataLeafNode;
615
619
620public:
621 /// @brief Leaf value voxel iterator
622 ValueVoxelCIter beginValueVoxel(const Coord& ijk) const;
623
624public:
625
626 using ValueOnIter = typename BaseLeaf::template ValueIter<
628 using ValueOnCIter = typename BaseLeaf::template ValueIter<
630 using ValueOffIter = typename BaseLeaf::template ValueIter<
632 using ValueOffCIter = typename BaseLeaf::template ValueIter<
634 using ValueAllIter = typename BaseLeaf::template ValueIter<
636 using ValueAllCIter = typename BaseLeaf::template ValueIter<
638 using ChildOnIter = typename BaseLeaf::template ChildIter<
640 using ChildOnCIter = typename BaseLeaf::template ChildIter<
642 using ChildOffIter = typename BaseLeaf::template ChildIter<
644 using ChildOffCIter = typename BaseLeaf::template ChildIter<
646 using ChildAllIter = typename BaseLeaf::template DenseIter<
648 using ChildAllCIter = typename BaseLeaf::template DenseIter<
649 const PointDataLeafNode, const ValueType, ChildAll>;
650
655
656 /// @brief Leaf index iterator
658 {
659 NullFilter filter;
660 return this->beginIndex<ValueAllCIter, NullFilter>(filter);
661 }
663 {
664 NullFilter filter;
665 return this->beginIndex<ValueOnCIter, NullFilter>(filter);
666 }
668 {
669 NullFilter filter;
670 return this->beginIndex<ValueOffCIter, NullFilter>(filter);
671 }
672
673 template<typename IterT, typename FilterT>
674 IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
675
676 /// @brief Filtered leaf index iterator
677 template<typename FilterT>
679 {
680 return this->beginIndex<ValueAllCIter, FilterT>(filter);
681 }
682 template<typename FilterT>
684 {
685 return this->beginIndex<ValueOnCIter, FilterT>(filter);
686 }
687 template<typename FilterT>
689 {
690 return this->beginIndex<ValueOffCIter, FilterT>(filter);
691 }
692
693 /// @brief Leaf index iterator from voxel
694 IndexVoxelIter beginIndexVoxel(const Coord& ijk) const;
695
696 /// @brief Filtered leaf index iterator from voxel
697 template<typename FilterT>
698 IndexIter<ValueVoxelCIter, FilterT> beginIndexVoxel(const Coord& ijk, const FilterT& filter) const;
699
700#define VMASK_ this->getValueMask()
701 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
702 ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
703 ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
704 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
705 ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
706 ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
707 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
708 ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
709 ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
710
711 ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
712 ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
713 ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
714 ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
715 ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
716 ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
717 ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
718 ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
719 ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
720
721 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
722 ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
723 ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
724 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
725 ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
726 ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
727 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
728 ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
729 ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
730
731 ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
732 ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
733 ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
734 ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
735 ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
736 ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
737 ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
738 ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
739 ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
740#undef VMASK_
741}; // struct PointDataLeafNode
742
743////////////////////////////////////////
744
745// PointDataLeafNode implementation
746
747template<typename T, Index Log2Dim>
748inline AttributeSet::UniquePtr
750{
751 AttributeSet::UniquePtr ptr = std::make_unique<AttributeSet>();
752 std::swap(ptr, mAttributeSet);
753 return ptr;
754}
755
756template<typename T, Index Log2Dim>
757inline void
758PointDataLeafNode<T, Log2Dim>::initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength,
760{
761 if (descriptor->size() != 1 ||
762 descriptor->find("P") == AttributeSet::INVALID_POS ||
763 descriptor->valueType(0) != typeNameAsString<Vec3f>())
764 {
765 OPENVDB_THROW(IndexError, "Initializing attributes only allowed with one Vec3f position attribute.");
766 }
767
768 mAttributeSet.reset(new AttributeSet(descriptor, arrayLength, lock));
769}
770
771template<typename T, Index Log2Dim>
772inline void
775{
776 mAttributeSet.reset(new AttributeSet(*mAttributeSet, 0, lock));
777
778 // zero voxel values
779
780 this->buffer().fill(ValueType(0));
781
782 // if updateValueMask, also de-activate all voxels
783
784 if (updateValueMask) this->setValuesOff();
785}
786
787template<typename T, Index Log2Dim>
788inline bool
790{
791 return pos < mAttributeSet->size();
792}
793
794template<typename T, Index Log2Dim>
795inline bool
797{
798 const size_t pos = mAttributeSet->find(attributeName);
799 return pos != AttributeSet::INVALID_POS;
800}
801
802template<typename T, Index Log2Dim>
804PointDataLeafNode<T, Log2Dim>::appendAttribute( const Descriptor& expected, Descriptor::Ptr& replacement,
805 const size_t pos, const Index strideOrTotalSize,
806 const bool constantStride,
807 const Metadata* metadata,
809{
810 return mAttributeSet->appendAttribute(
811 expected, replacement, pos, strideOrTotalSize, constantStride, metadata, lock);
812}
813
814template<typename T, Index Log2Dim>
815inline void
817 const Descriptor& expected, Descriptor::Ptr& replacement)
818{
819 mAttributeSet->dropAttributes(pos, expected, replacement);
820}
821
822template<typename T, Index Log2Dim>
823inline void
824PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
825{
826 mAttributeSet->reorderAttributes(replacement);
827}
828
829template<typename T, Index Log2Dim>
830inline void
831PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
832{
833 mAttributeSet->renameAttributes(expected, replacement);
834}
835
836template<typename T, Index Log2Dim>
837inline void
839{
840 for (size_t i = 0; i < mAttributeSet->size(); i++) {
841 AttributeArray* array = mAttributeSet->get(i);
842 array->compact();
843 }
844}
845
846template<typename T, Index Log2Dim>
847inline void
848PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
849{
850 if (!attributeSet) {
851 OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
852 }
853
854 if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
855 OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
856 }
857
858 mAttributeSet.reset(attributeSet);
859}
860
861template<typename T, Index Log2Dim>
862inline void
863PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
864{
865 mAttributeSet->resetDescriptor(replacement);
866}
867
868template<typename T, Index Log2Dim>
869inline void
870PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
871{
872 if (offsets.size() != LeafNodeType::NUM_VALUES) {
873 OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
874 }
875
876 for (Index index = 0; index < offsets.size(); ++index) {
877 setOffsetOnly(index, offsets[index]);
878 }
879
880 if (updateValueMask) this->updateValueMask();
881}
882
883template<typename T, Index Log2Dim>
884inline void
886{
887 // Ensure all of the offset values are monotonically increasing
888 for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
889 if (this->getValue(index-1) > this->getValue(index)) {
890 OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
891 }
892 }
893
894 // Ensure all attribute arrays are of equal length
895 for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
896 if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
897 OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
898 }
899 }
900
901 // Ensure the last voxel's offset value matches the size of each attribute array
902 if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
903 OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
904 }
905}
906
907template<typename T, Index Log2Dim>
908inline AttributeArray&
910{
911 if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
912 return *mAttributeSet->get(pos);
913}
914
915template<typename T, Index Log2Dim>
916inline const AttributeArray&
918{
919 if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
920 return *mAttributeSet->getConst(pos);
921}
922
923template<typename T, Index Log2Dim>
924inline const AttributeArray&
926{
927 return this->attributeArray(pos);
928}
929
930template<typename T, Index Log2Dim>
931inline AttributeArray&
933{
934 const size_t pos = mAttributeSet->find(attributeName);
935 if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
936 return *mAttributeSet->get(pos);
937}
938
939template<typename T, Index Log2Dim>
940inline const AttributeArray&
942{
943 const size_t pos = mAttributeSet->find(attributeName);
944 if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
945 return *mAttributeSet->getConst(pos);
946}
947
948template<typename T, Index Log2Dim>
949inline const AttributeArray&
951{
952 return this->attributeArray(attributeName);
953}
954
955template<typename T, Index Log2Dim>
956inline GroupHandle
957PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
958{
959 const AttributeArray& array = this->attributeArray(index.first);
960 assert(isGroup(array));
961
962 const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
963
964 return GroupHandle(groupArray, index.second);
965}
966
967template<typename T, Index Log2Dim>
968inline GroupHandle
970{
971 const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
972 return this->groupHandle(index);
973}
974
975template<typename T, Index Log2Dim>
976inline GroupWriteHandle
977PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
978{
979 AttributeArray& array = this->attributeArray(index.first);
980 assert(isGroup(array));
981
982 GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
983
984 return GroupWriteHandle(groupArray, index.second);
985}
986
987template<typename T, Index Log2Dim>
988inline GroupWriteHandle
990{
991 const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
992 return this->groupWriteHandle(index);
993}
994
995template<typename T, Index Log2Dim>
996template<typename ValueIterT, typename FilterT>
999{
1000 // generate no-op iterator if filter evaluates no indices
1001
1002 if (filter.state() == index::NONE) {
1003 return IndexIter<ValueIterT, FilterT>(ValueIterT(), filter);
1004 }
1005
1006 // copy filter to ensure thread-safety
1007
1008 FilterT newFilter(filter);
1009 newFilter.reset(*this);
1010
1012
1013 // construct the value iterator and reset the filter to use this leaf
1014
1015 ValueIterT valueIter = IterTraitsT::begin(*this);
1016
1017 return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
1018}
1019
1020template<typename T, Index Log2Dim>
1021inline ValueVoxelCIter
1023{
1024 const Index index = LeafNodeType::coordToOffset(ijk);
1025 assert(index < BaseLeaf::SIZE);
1026 const ValueType end = this->getValue(index);
1027 const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1028 return ValueVoxelCIter(start, end);
1029}
1030
1031template<typename T, Index Log2Dim>
1034{
1035 ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1036 return IndexVoxelIter(iter, NullFilter());
1037}
1038
1039template<typename T, Index Log2Dim>
1040template<typename FilterT>
1042PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1043{
1044 ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1045 FilterT newFilter(filter);
1046 newFilter.reset(*this);
1047 return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1048}
1049
1050template<typename T, Index Log2Dim>
1051inline Index64
1053{
1054 return this->getLastValue();
1055}
1056
1057template<typename T, Index Log2Dim>
1058inline Index64
1060{
1061 if (this->isEmpty()) return 0;
1062 else if (this->isDense()) return this->pointCount();
1063 return iterCount(this->beginIndexOn());
1064}
1065
1066template<typename T, Index Log2Dim>
1067inline Index64
1069{
1070 if (this->isEmpty()) return this->pointCount();
1071 else if (this->isDense()) return 0;
1072 return iterCount(this->beginIndexOff());
1073}
1074
1075template<typename T, Index Log2Dim>
1076inline Index64
1078{
1079 if (!this->attributeSet().descriptor().hasGroup(groupName)) {
1080 return Index64(0);
1081 }
1082 GroupFilter filter(groupName, this->attributeSet());
1083 if (filter.state() == index::ALL) {
1084 return this->pointCount();
1085 } else {
1086 return iterCount(this->beginIndexAll(filter));
1087 }
1088}
1089
1090template<typename T, Index Log2Dim>
1091inline void
1093{
1094 ValueType start = 0, end = 0;
1095 for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1096 end = this->getValue(n);
1097 this->setValueMask(n, (end - start) > 0);
1098 start = end;
1099 }
1100}
1101
1102template<typename T, Index Log2Dim>
1103inline void
1105{
1106 this->buffer().setValue(offset, val);
1107 this->setValueMaskOn(offset);
1108}
1109
1110template<typename T, Index Log2Dim>
1111inline void
1113{
1114 this->buffer().setValue(offset, val);
1115}
1116
1117template<typename T, Index Log2Dim>
1118inline void
1119PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1120{
1121 BaseLeaf::readTopology(is, fromHalf);
1122}
1123
1124template<typename T, Index Log2Dim>
1125inline void
1126PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1127{
1128 BaseLeaf::writeTopology(os, toHalf);
1129}
1130
1131template<typename T, Index Log2Dim>
1132inline Index
1134{
1135 return Index( /*voxel buffer sizes*/ 1 +
1136 /*voxel buffers*/ 1 +
1137 /*attribute metadata*/ 1 +
1138 /*attribute uniform values*/ mAttributeSet->size() +
1139 /*attribute buffers*/ mAttributeSet->size() +
1140 /*cleanup*/ 1);
1141}
1142
1143template<typename T, Index Log2Dim>
1144inline void
1145PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1146{
1147 this->readBuffers(is, CoordBBox::inf(), fromHalf);
1148}
1149
1150template<typename T, Index Log2Dim>
1151inline void
1152PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1153{
1154 struct Local
1155 {
1156 static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1157 {
1158 // if paged stream exists, delete it
1159 std::string key("paged:" + std::to_string(index));
1160 auto it = auxData.find(key);
1161 if (it != auxData.end()) {
1162 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1163 }
1164 }
1165
1166 static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1167 const Index index)
1168 {
1169 std::string key("paged:" + std::to_string(index));
1170 auto it = auxData.find(key);
1171 if (it != auxData.end()) {
1172 return *(boost::any_cast<compression::PagedInputStream::Ptr>(it->second));
1173 }
1174 else {
1175 compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1176 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1177 return *pagedStream;
1178 }
1179 }
1180
1181 static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1182 {
1183 std::string matchingKey("hasMatchingDescriptor");
1184 auto itMatching = auxData.find(matchingKey);
1185 return itMatching != auxData.end();
1186 }
1187
1188 static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1189 {
1190 std::string matchingKey("hasMatchingDescriptor");
1191 std::string descriptorKey("descriptorPtr");
1192 auto itMatching = auxData.find(matchingKey);
1193 auto itDescriptor = auxData.find(descriptorKey);
1194 if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1195 if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1196 }
1197
1198 static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1199 const Descriptor::Ptr descriptor)
1200 {
1201 std::string descriptorKey("descriptorPtr");
1202 std::string matchingKey("hasMatchingDescriptor");
1203 auto itMatching = auxData.find(matchingKey);
1204 if (itMatching == auxData.end()) {
1205 // if matching bool is not found, insert "true" and the descriptor
1206 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1207 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1208 }
1209 }
1210
1211 static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1212 {
1213 std::string descriptorKey("descriptorPtr");
1214 auto itDescriptor = auxData.find(descriptorKey);
1215 assert(itDescriptor != auxData.end());
1216 const Descriptor::Ptr descriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1217 return descriptor;
1218 }
1219 };
1220
1222
1223 if (!meta) {
1224 OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1225 }
1226
1227 const Index pass(static_cast<uint16_t>(meta->pass()));
1228 const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1229
1230 const Index attributes = (maximumPass - 4) / 2;
1231
1232 if (pass == 0) {
1233 // pass 0 - voxel data sizes
1234 is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1235 Local::clearMatchingDescriptor(meta->auxData());
1236 }
1237 else if (pass == 1) {
1238 // pass 1 - descriptor and attribute metadata
1239 if (Local::hasMatchingDescriptor(meta->auxData())) {
1240 AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1241 mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1242 }
1243 else {
1244 uint8_t header;
1245 is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1246 mAttributeSet->readDescriptor(is);
1247 if (header & uint8_t(1)) {
1248 AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1249 Local::insertDescriptor(meta->auxData(), descriptor);
1250 }
1251 // a forwards-compatibility mechanism for future use,
1252 // if a 0x2 bit is set, read and skip over a specific number of bytes
1253 if (header & uint8_t(2)) {
1254 uint64_t bytesToSkip;
1255 is.read(reinterpret_cast<char*>(&bytesToSkip), sizeof(uint64_t));
1256 if (bytesToSkip > uint64_t(0)) {
1257 auto metadata = io::getStreamMetadataPtr(is);
1258 if (metadata && metadata->seekable()) {
1259 is.seekg(bytesToSkip, std::ios_base::cur);
1260 }
1261 else {
1262 std::vector<uint8_t> tempData(bytesToSkip);
1263 is.read(reinterpret_cast<char*>(&tempData[0]), bytesToSkip);
1264 }
1265 }
1266 }
1267 // this reader is only able to read headers with 0x1 and 0x2 bits set
1268 if (header > uint8_t(3)) {
1269 OPENVDB_THROW(IoError, "Unrecognised header flags in PointDataLeafNode");
1270 }
1271 }
1272 mAttributeSet->readMetadata(is);
1273 }
1274 else if (pass < (attributes + 2)) {
1275 // pass 2...n+2 - attribute uniform values
1276 const size_t attributeIndex = pass - 2;
1277 AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1278 mAttributeSet->get(attributeIndex) : nullptr;
1279 if (array) {
1280 compression::PagedInputStream& pagedStream =
1281 Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1282 pagedStream.setInputStream(is);
1283 pagedStream.setSizeOnly(true);
1284 array->readPagedBuffers(pagedStream);
1285 }
1286 }
1287 else if (pass == attributes + 2) {
1288 // pass n+2 - voxel data
1289
1290 const Index passValue(meta->pass());
1291
1292 // StreamMetadata pass variable used to temporarily store voxel buffer size
1293 io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1294 nonConstMeta.setPass(mVoxelBufferSize);
1295
1296 // readBuffers() calls readCompressedValues specialization above
1297 BaseLeaf::readBuffers(is, fromHalf);
1298
1299 // pass now reset to original value
1300 nonConstMeta.setPass(passValue);
1301 }
1302 else if (pass < (attributes*2 + 3)) {
1303 // pass n+2..2n+2 - attribute buffers
1304 const Index attributeIndex = pass - attributes - 3;
1305 AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1306 mAttributeSet->get(attributeIndex) : nullptr;
1307 if (array) {
1308 compression::PagedInputStream& pagedStream =
1309 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1310 pagedStream.setInputStream(is);
1311 pagedStream.setSizeOnly(false);
1312 array->readPagedBuffers(pagedStream);
1313 }
1314 // cleanup paged stream reference in auxiliary metadata
1315 if (pass > attributes + 3) {
1316 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1317 }
1318 }
1319 else if (pass < buffers()) {
1320 // pass 2n+3 - cleanup last paged stream
1321 const Index attributeIndex = pass - attributes - 4;
1322 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1323 }
1324}
1325
1326template<typename T, Index Log2Dim>
1327inline void
1328PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1329{
1330 struct Local
1331 {
1332 static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1333 {
1334 // if paged stream exists, flush and delete it
1335 std::string key("paged:" + std::to_string(index));
1336 auto it = auxData.find(key);
1337 if (it != auxData.end()) {
1338 compression::PagedOutputStream& stream = *(boost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1339 stream.flush();
1340 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1341 }
1342 }
1343
1344 static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1345 const Index index)
1346 {
1347 std::string key("paged:" + std::to_string(index));
1348 auto it = auxData.find(key);
1349 if (it != auxData.end()) {
1350 return *(boost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1351 }
1352 else {
1353 compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1354 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1355 return *pagedStream;
1356 }
1357 }
1358
1359 static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1360 const Descriptor::Ptr descriptor)
1361 {
1362 std::string descriptorKey("descriptorPtr");
1363 std::string matchingKey("hasMatchingDescriptor");
1364 auto itMatching = auxData.find(matchingKey);
1365 auto itDescriptor = auxData.find(descriptorKey);
1366 if (itMatching == auxData.end()) {
1367 // if matching bool is not found, insert "true" and the descriptor
1368 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1369 assert(itDescriptor == auxData.end());
1370 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1371 }
1372 else {
1373 // if matching bool is found and is false, early exit (a previous descriptor did not match)
1374 bool matching = boost::any_cast<bool>(itMatching->second);
1375 if (!matching) return;
1376 assert(itDescriptor != auxData.end());
1377 // if matching bool is true, check whether the existing descriptor matches the current one and set
1378 // matching bool to false if not
1379 const Descriptor::Ptr existingDescriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1380 if (*existingDescriptor != *descriptor) {
1381 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1382 }
1383 }
1384 }
1385
1386 static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1387 {
1388 std::string matchingKey("hasMatchingDescriptor");
1389 auto itMatching = auxData.find(matchingKey);
1390 // if matching key is not found, no matching descriptor
1391 if (itMatching == auxData.end()) return false;
1392 // if matching key is found and is false, no matching descriptor
1393 if (!boost::any_cast<bool>(itMatching->second)) return false;
1394 return true;
1395 }
1396
1397 static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1398 {
1399 std::string descriptorKey("descriptorPtr");
1400 auto itDescriptor = auxData.find(descriptorKey);
1401 // if matching key is true, however descriptor is not found, it has already been retrieved
1402 if (itDescriptor == auxData.end()) return nullptr;
1403 // otherwise remove it and return it
1404 const Descriptor::Ptr descriptor = boost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1405 (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1406 return descriptor;
1407 }
1408
1409 static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1410 {
1411 std::string matchingKey("hasMatchingDescriptor");
1412 std::string descriptorKey("descriptorPtr");
1413 auto itMatching = auxData.find(matchingKey);
1414 auto itDescriptor = auxData.find(descriptorKey);
1415 if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1416 if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1417 }
1418 };
1419
1421
1422 if (!meta) {
1423 OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1424 }
1425
1426 const Index pass(static_cast<uint16_t>(meta->pass()));
1427
1428 // leaf traversal analysis deduces the number of passes to perform for this leaf
1429 // then updates the leaf traversal value to ensure all passes will be written
1430
1431 if (meta->countingPasses()) {
1432 const Index requiredPasses = this->buffers();
1433 if (requiredPasses > pass) {
1434 meta->setPass(requiredPasses);
1435 }
1436 return;
1437 }
1438
1439 const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1440 const Index attributes = (maximumPass - 4) / 2;
1441
1442 if (pass == 0) {
1443 // pass 0 - voxel data sizes
1444 io::writeCompressedValuesSize(os, this->buffer().data(), SIZE);
1445 // track if descriptor is shared or not
1446 Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1447 }
1448 else if (pass == 1) {
1449 // pass 1 - descriptor and attribute metadata
1450 bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1451 if (matchingDescriptor) {
1452 AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1453 if (descriptor) {
1454 // write a header to indicate a shared descriptor
1455 uint8_t header(1);
1456 os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1457 mAttributeSet->writeDescriptor(os, /*transient=*/false);
1458 }
1459 }
1460 else {
1461 // write a header to indicate a non-shared descriptor
1462 uint8_t header(0);
1463 os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1464 mAttributeSet->writeDescriptor(os, /*transient=*/false);
1465 }
1466 mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1467 }
1468 else if (pass < attributes + 2) {
1469 // pass 2...n+2 - attribute buffer sizes
1470 const Index attributeIndex = pass - 2;
1471 // destroy previous paged stream
1472 if (pass > 2) {
1473 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1474 }
1475 const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1476 mAttributeSet->getConst(attributeIndex) : nullptr;
1477 if (array) {
1478 compression::PagedOutputStream& pagedStream =
1479 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1480 pagedStream.setOutputStream(os);
1481 pagedStream.setSizeOnly(true);
1482 array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1483 }
1484 }
1485 else if (pass == attributes + 2) {
1486 const Index attributeIndex = pass - 3;
1487 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1488 // pass n+2 - voxel data
1489 BaseLeaf::writeBuffers(os, toHalf);
1490 }
1491 else if (pass < (attributes*2 + 3)) {
1492 // pass n+3...2n+3 - attribute buffers
1493 const Index attributeIndex = pass - attributes - 3;
1494 // destroy previous paged stream
1495 if (pass > attributes + 2) {
1496 Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1497 }
1498 const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1499 mAttributeSet->getConst(attributeIndex) : nullptr;
1500 if (array) {
1501 compression::PagedOutputStream& pagedStream =
1502 Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1503 pagedStream.setOutputStream(os);
1504 pagedStream.setSizeOnly(false);
1505 array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1506 }
1507 }
1508 else if (pass < buffers()) {
1509 Local::clearMatchingDescriptor(meta->auxData());
1510 // pass 2n+3 - cleanup last paged stream
1511 const Index attributeIndex = pass - attributes - 4;
1512 Local::destroyPagedStream(meta->auxData(), attributeIndex);
1513 }
1514}
1515
1516template<typename T, Index Log2Dim>
1517inline Index64
1519{
1520 return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1521}
1522
1523template<typename T, Index Log2Dim>
1524inline void
1526{
1527 BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1528}
1529
1530template<typename T, Index Log2Dim>
1531inline CoordBBox
1533{
1534 return BaseLeaf::getNodeBoundingBox();
1535}
1536
1537template<typename T, Index Log2Dim>
1538inline void
1540{
1541 if (!this->allocate()) return;
1542
1543 this->assertNonModifiableUnlessZero(value);
1544
1545 // active state is permitted to be updated
1546
1547 for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1548 const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1549 for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1550 const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1551 for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1552 const Index offset = offsetXY + (z & (DIM-1u));
1553 this->setValueMask(offset, active);
1554 }
1555 }
1556 }
1557}
1558
1559template<typename T, Index Log2Dim>
1560inline void
1562{
1563 this->assertNonModifiableUnlessZero(value);
1564
1565 // active state is permitted to be updated
1566
1567 if (active) this->setValuesOn();
1568 else this->setValuesOff();
1569}
1570
1571
1572////////////////////////////////////////
1573
1574
1575template <typename PointDataTreeT>
1576inline AttributeSet::Descriptor::Ptr
1577makeDescriptorUnique(PointDataTreeT& tree)
1578{
1579 auto leafIter = tree.beginLeaf();
1580 if (!leafIter) return nullptr;
1581
1582 const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1583 auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1584 for (; leafIter; ++leafIter) {
1585 leafIter->resetDescriptor(newDescriptor);
1586 }
1587
1588 return newDescriptor;
1589}
1590
1591
1592template <typename PointDataTreeT>
1593inline void
1594setStreamingMode(PointDataTreeT& tree, bool on)
1595{
1596 auto leafIter = tree.beginLeaf();
1597 for (; leafIter; ++leafIter) {
1598 for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1599 leafIter->attributeArray(i).setStreaming(on);
1600 }
1601 }
1602}
1603
1604
1605template <typename PointDataTreeT>
1606inline void
1607prefetch(PointDataTreeT& tree, bool position, bool otherAttributes)
1608{
1609 // NOTE: the following is intentionally not multi-threaded, as the I/O
1610 // is faster if done in the order in which it is stored in the file
1611
1612 auto leaf = tree.cbeginLeaf();
1613 if (!leaf) return;
1614
1615 const auto& attributeSet = leaf->attributeSet();
1616
1617 // pre-fetch leaf data
1618
1619 for ( ; leaf; ++leaf) {
1620 leaf->buffer().data();
1621 }
1622
1623 // pre-fetch position attribute data (position will typically have index 0)
1624
1625 size_t positionIndex = attributeSet.find("P");
1626
1627 if (position && positionIndex != AttributeSet::INVALID_POS) {
1628 for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1629 assert(leaf->hasAttribute(positionIndex));
1630 leaf->constAttributeArray(positionIndex).loadData();
1631 }
1632 }
1633
1634 // pre-fetch other attribute data
1635
1636 if (otherAttributes) {
1637 const size_t attributes = attributeSet.size();
1638 for (size_t attributeIndex = 0; attributeIndex < attributes; attributeIndex++) {
1639 if (attributeIndex == positionIndex) continue;
1640 for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1641 assert(leaf->hasAttribute(attributeIndex));
1642 leaf->constAttributeArray(attributeIndex).loadData();
1643 }
1644 }
1645 }
1646}
1647
1648
1649namespace internal {
1650
1651/// @brief Global registration of point data-related types
1652/// @note This is called from @c openvdb::initialize, so there is
1653/// no need to call it directly.
1655
1656/// @brief Global deregistration of point data-related types
1657/// @note This is called from @c openvdb::uninitialize, so there is
1658/// no need to call it directly.
1660
1661
1662/// @brief Recursive node chain which generates a openvdb::TypeList value
1663/// converted types of nodes to PointDataGrid nodes of the same configuration,
1664/// rooted at RootNodeType in reverse order, from LeafNode to RootNode.
1665/// See also TreeConverter<>.
1666template<typename HeadT, int HeadLevel>
1668{
1669 using SubtreeT = typename PointDataNodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1671 using Type = typename SubtreeT::template Append<RootNodeT>;
1672};
1673
1674// Specialization for internal nodes which require their embedded child type to
1675// be switched
1676template <typename ChildT, Index Log2Dim, int HeadLevel>
1677struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, HeadLevel>
1678{
1679 using SubtreeT = typename PointDataNodeChain<ChildT, HeadLevel-1>::Type;
1681 using Type = typename SubtreeT::template Append<InternalNodeT>;
1682};
1683
1684// Specialization for the last internal node of a node chain, expected
1685// to be templated on a leaf node
1686template <typename ChildT, Index Log2Dim>
1687struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, /*HeadLevel=*/1>
1688{
1692};
1693
1694} // namespace internal
1695
1696
1697/// @brief Similiar to ValueConverter, but allows for tree configuration conversion
1698/// to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a
1699/// PointDataLeafNode is not a specialization of LeafNode
1700template <typename TreeType>
1702 using RootNodeT = typename TreeType::RootNodeType;
1705};
1706
1707
1708} // namespace points
1709
1710
1711////////////////////////////////////////
1712
1713
1714namespace tree
1715{
1716
1717/// Helper metafunction used to implement LeafNode::SameConfiguration
1718/// (which, as an inner class, can't be independently specialized)
1719template<Index Dim1, typename T2>
1720struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1721
1722} // namespace tree
1723} // namespace OPENVDB_VERSION_NAME
1724} // namespace openvdb
1725
1726#endif // OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
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:1287
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:116
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
SIMD Intrinsic Headers.
Definition: Platform.h:115
#define VMASK_
Definition: PointDataGrid.h:700
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:577
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:570
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:564
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:205
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
Definition: StreamCompression.h:214
void setInputStream(std::istream &is)
Definition: StreamCompression.h:219
std::shared_ptr< PagedInputStream > Ptr
Definition: StreamCompression.h:207
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:242
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
Definition: StreamCompression.h:251
void setOutputStream(std::ostream &os)
Definition: StreamCompression.h:256
std::shared_ptr< PagedOutputStream > Ptr
Definition: StreamCompression.h:244
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:248
const Coord & min() const
Definition: Coord.h:320
const Coord & max() const
Definition: Coord.h:321
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition: Coord.h:318
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 Index size() const =0
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:721
void setValueOn(Index offset)
Definition: PointDataGrid.h:542
void setValueOff(const Coord &, const ValueType &)
Definition: PointDataGrid.h:538
ChildOnCIter beginChildOn() const
Definition: PointDataGrid.h:722
ChildOnIter beginChildOn()
Definition: PointDataGrid.h:723
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
Definition: PointDataGrid.h:580
ValueOnIter endValueOn()
Definition: PointDataGrid.h:713
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:704
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
Definition: PointDataGrid.h:639
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:733
ValueAllIter endValueAll()
Definition: PointDataGrid.h:719
void modifyValue(Index, const ModifyOp &)
Definition: PointDataGrid.h:553
void setValueOn(Index, const ValueType &)
Definition: PointDataGrid.h:545
void setValuesOff()
Definition: PointDataGrid.h:550
ValueAllCIter endValueAll() const
Definition: PointDataGrid.h:718
const PointDataLeafNode * probeLeaf(const Coord &) const
Definition: PointDataGrid.h:482
ChildOffCIter endChildOff() const
Definition: PointDataGrid.h:735
void setValueOff(Index, const ValueType &)
Definition: PointDataGrid.h:539
PointDataLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointDataGrid.h:314
ValueAllCIter cbeginValueAll() const
Definition: PointDataGrid.h:707
typename BaseLeaf::ChildOff ChildOff
Definition: PointDataGrid.h:605
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:533
std::shared_ptr< PointDataLeafNode > Ptr
Definition: PointDataGrid.h:243
IndexAllIter beginIndexAll() const
Leaf index iterator.
Definition: PointDataGrid.h:657
ValueOnCIter beginValueOn() const
Definition: PointDataGrid.h:702
typename BaseLeaf::ChildOn ChildOn
Definition: PointDataGrid.h:604
void signedFloodFill(const ValueType &, const ValueType &)
Definition: PointDataGrid.h:589
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
Definition: PointDataGrid.h:274
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:559
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
Definition: PointDataGrid.h:635
typename BaseLeaf::ChildAll ChildAll
Definition: PointDataGrid.h:606
IndexIter< IterT, FilterT > beginIndex(const FilterT &filter) const
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
Definition: PointDataGrid.h:631
ValueOnCIter cendValueOn() const
Definition: PointDataGrid.h:711
ValueOffCIter beginValueOff() const
Definition: PointDataGrid.h:705
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:863
IndexOffIter beginIndexOff() const
Definition: PointDataGrid.h:667
ChildAllCIter cbeginChildAll() const
Definition: PointDataGrid.h:727
ChildOffIter endChildOff()
Definition: PointDataGrid.h:736
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition: PointDataGrid.h:572
void setValueOnly(const Coord &, const ValueType &)
Definition: PointDataGrid.h:532
ChildAllIter beginChildAll()
Definition: PointDataGrid.h:729
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Definition: PointDataGrid.h:479
void setActiveState(const Coord &xyz, bool on)
Definition: PointDataGrid.h:529
ValueOnIter beginValueOn()
Definition: PointDataGrid.h:703
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
Definition: PointDataGrid.h:645
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Definition: PointDataGrid.h:463
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
Definition: PointDataGrid.h:678
void assertNonModifiableUnlessZero(const ValueType &value)
Definition: PointDataGrid.h:525
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Definition: PointDataGrid.h:481
ChildOffCIter cbeginChildOff() const
Definition: PointDataGrid.h:724
ChildOffIter beginChildOff()
Definition: PointDataGrid.h:726
ChildOffCIter beginChildOff() const
Definition: PointDataGrid.h:725
void setValueOff(const Coord &xyz)
Definition: PointDataGrid.h:535
bool operator!=(const PointDataLeafNode &other) const
Definition: PointDataGrid.h:450
ValueOffIter endValueOff()
Definition: PointDataGrid.h:716
void setValueOff(Index offset)
Definition: PointDataGrid.h:536
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
Definition: PointDataGrid.h:683
ChildAllCIter endChildAll() const
Definition: PointDataGrid.h:738
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Definition: PointDataGrid.h:484
ValueOnCIter cbeginValueOn() const
Definition: PointDataGrid.h:701
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: PointDataGrid.h:649
void clip(const CoordBBox &, const ValueType &value)
Definition: PointDataGrid.h:562
ChildOnCIter endChildOn() const
Definition: PointDataGrid.h:732
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
Definition: PointDataGrid.h:824
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointDataGrid.h:629
ChildOnCIter cendChildOn() const
Definition: PointDataGrid.h:731
ChildAllCIter cendChildAll() const
Definition: PointDataGrid.h:737
PointDataLeafNode()
Default constructor.
Definition: PointDataGrid.h:268
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Definition: PointDataGrid.h:322
void assertNonmodifiable()
Definition: PointDataGrid.h:518
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:577
ChildAllIter endChildAll()
Definition: PointDataGrid.h:739
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
Definition: PointDataGrid.h:688
void resetBackground(const ValueType &, const ValueType &newBackground)
Definition: PointDataGrid.h:584
typename NodeMaskType::OffIterator MaskOffIterator
Definition: PointDataGrid.h:609
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
Definition: PointDataGrid.h:303
void setValue(const Coord &, const ValueType &)
Definition: PointDataGrid.h:547
ValueAllCIter cendValueAll() const
Definition: PointDataGrid.h:717
void negate()
Definition: PointDataGrid.h:591
ChildAllCIter beginChildAll() const
Definition: PointDataGrid.h:728
typename BaseLeaf::ValueAll ValueAll
Definition: PointDataGrid.h:597
std::pair< ValueType, ValueType > ValueTypePair
Definition: PointDataGrid.h:246
void setValuesOn()
Definition: PointDataGrid.h:549
AttributeSet::Descriptor Descriptor
Definition: PointDataGrid.h:249
typename BaseLeaf::ValueOn ValueOn
Definition: PointDataGrid.h:595
ChildOffCIter cendChildOff() const
Definition: PointDataGrid.h:734
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Definition: PointDataGrid.h:454
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointDataGrid.h:569
void fill(const ValueType &value)
Definition: PointDataGrid.h:565
typename NodeMaskType::OnIterator MaskOnIterator
Definition: PointDataGrid.h:608
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
Definition: PointDataGrid.h:643
void addLeaf(PointDataLeafNode *)
Definition: PointDataGrid.h:452
void signedFloodFill(const ValueType &)
Definition: PointDataGrid.h:588
ValueOffIter beginValueOff()
Definition: PointDataGrid.h:706
void setValueOn(const Coord &xyz)
Definition: PointDataGrid.h:541
void setActiveState(Index offset, bool on)
Definition: PointDataGrid.h:530
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: PointDataGrid.h:633
IndexOnIter beginIndexOn() const
Definition: PointDataGrid.h:662
typename BaseLeaf::ValueOff ValueOff
Definition: PointDataGrid.h:596
void modifyValue(const Coord &, const ModifyOp &)
Definition: PointDataGrid.h:556
ValueOffCIter cendValueOff() const
Definition: PointDataGrid.h:714
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
Definition: PointDataGrid.h:641
void fill(const CoordBBox &, const ValueType &, bool)
Definition: PointDataGrid.h:1539
ValueOffCIter endValueOff() const
Definition: PointDataGrid.h:715
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
Definition: PointDataGrid.h:627
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:712
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: PointDataGrid.h:610
ValueAllCIter beginValueAll() const
Definition: PointDataGrid.h:708
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
Definition: PointDataGrid.h:647
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:637
void setValueOn(const Coord &, const ValueType &)
Definition: PointDataGrid.h:544
ValueAllIter beginValueAll()
Definition: PointDataGrid.h:709
std::vector< ValueType > IndexArray
Definition: PointDataGrid.h:247
Typed class for storing attribute data.
Definition: AttributeArray.h:533
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:176
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
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
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...
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
Definition: PointDataGrid.h:139
void writeCompressedValues(std::ostream &os, PointDataIndex32 *srcBuf, Index srcCount, const util::NodeMask< 3 > &, const util::NodeMask< 3 > &, bool)
openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask,...
Definition: PointDataGrid.h:106
void readCompressedValues(std::istream &is, PointDataIndex32 *destBuf, Index destCount, const util::NodeMask< 3 > &, bool)
openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to ignore the value mask,...
Definition: PointDataGrid.h:46
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme,...
@ ALL
Definition: IndexIterator.h:43
@ NONE
Definition: IndexIterator.h:42
void uninitialize()
Global deregistration of point data-related types.
void initialize()
Global registration of point data-related types.
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:1594
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:1607
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
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
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:63
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:1577
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:408
std::string Name
Definition: Name.h:17
const char * typeNameAsString< Vec3f >()
Definition: Types.h:417
Index32 Index
Definition: Types.h:54
int32_t Int32
Definition: Types.h:56
uint64_t Index64
Definition: Types.h:53
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:69
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
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:366
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:1701
typename TreeType::RootNodeType RootNodeT
Definition: PointDataGrid.h:1702
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
Definition: PointDataGrid.h:1703
typename PointDataNodeChain< ChildT, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1679
typename SubtreeT::template Append< InternalNodeT > Type
Definition: PointDataGrid.h:1681
Recursive node chain which generates a openvdb::TypeList value converted types of nodes to PointDataG...
Definition: PointDataGrid.h:1668
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition: PointDataGrid.h:1669
typename SubtreeT::template Append< RootNodeT > Type
Definition: PointDataGrid.h:1671
Definition: PointIndexGrid.h:1358
Definition: TreeIterator.h:60
Definition: LeafNode.h:211
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:251
Definition: LeafNode.h:211
Definition: LeafNode.h:211
Definition: LeafNode.h:210
Definition: LeafNode.h:210
Definition: LeafNode.h:210
Definition: LeafNode.h:923
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202