OpenVDB 9.0.0
PointAttribute.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, Khang Ngo
5///
6/// @file points/PointAttribute.h
7///
8/// @brief Point attribute manipulation in a VDB Point Grid.
9
10#ifndef OPENVDB_POINTS_POINT_ATTRIBUTE_HAS_BEEN_INCLUDED
11#define OPENVDB_POINTS_POINT_ATTRIBUTE_HAS_BEEN_INCLUDED
12
13#include <openvdb/openvdb.h>
14
16#include "AttributeSet.h"
17#include "AttributeGroup.h"
18#include "PointDataGrid.h"
19
20
21namespace openvdb {
23namespace OPENVDB_VERSION_NAME {
24namespace points {
25
26namespace point_attribute_internal {
27
28template <typename ValueType>
29struct Default
30{
31 static inline ValueType value() { return zeroVal<ValueType>(); }
32};
33
34} // namespace point_attribute_internal
35
36
37/// @brief Appends a new attribute to the VDB tree
38/// (this method does not require a templated AttributeType)
39///
40/// @param tree the PointDataTree to be appended to.
41/// @param name name for the new attribute.
42/// @param type the type of the attibute.
43/// @param strideOrTotalSize the stride of the attribute
44/// @param constantStride if @c false, stride is interpreted as total size of the array
45/// @param defaultValue metadata default attribute value
46/// @param hidden mark attribute as hidden
47/// @param transient mark attribute as transient
48template <typename PointDataTreeT>
49inline void appendAttribute(PointDataTreeT& tree,
50 const Name& name,
51 const NamePair& type,
52 const Index strideOrTotalSize = 1,
53 const bool constantStride = true,
54 const Metadata* defaultValue = nullptr,
55 const bool hidden = false,
56 const bool transient = false);
57
58/// @brief Appends a new attribute to the VDB tree.
59///
60/// @param tree the PointDataTree to be appended to.
61/// @param name name for the new attribute
62/// @param uniformValue the initial value of the attribute
63/// @param strideOrTotalSize the stride of the attribute
64/// @param constantStride if @c false, stride is interpreted as total size of the array
65/// @param defaultValue metadata default attribute value
66/// @param hidden mark attribute as hidden
67/// @param transient mark attribute as transient
68template <typename ValueType,
69 typename CodecType = NullCodec,
70 typename PointDataTreeT>
71inline void appendAttribute(PointDataTreeT& tree,
72 const std::string& name,
73 const ValueType& uniformValue =
75 const Index strideOrTotalSize = 1,
76 const bool constantStride = true,
77 const TypedMetadata<ValueType>* defaultValue = nullptr,
78 const bool hidden = false,
79 const bool transient = false);
80
81/// @brief Collapse the attribute into a uniform value
82///
83/// @param tree the PointDataTree in which to collapse the attribute.
84/// @param name name for the attribute.
85/// @param uniformValue value of the attribute
86template <typename ValueType, typename PointDataTreeT>
87inline void collapseAttribute( PointDataTreeT& tree,
88 const Name& name,
89 const ValueType& uniformValue =
91
92/// @brief Drops attributes from the VDB tree.
93///
94/// @param tree the PointDataTree to be dropped from.
95/// @param indices indices of the attributes to drop.
96template <typename PointDataTreeT>
97inline void dropAttributes( PointDataTreeT& tree,
98 const std::vector<size_t>& indices);
99
100/// @brief Drops attributes from the VDB tree.
101///
102/// @param tree the PointDataTree to be dropped from.
103/// @param names names of the attributes to drop.
104template <typename PointDataTreeT>
105inline void dropAttributes( PointDataTreeT& tree,
106 const std::vector<Name>& names);
107
108/// @brief Drop one attribute from the VDB tree (convenience method).
109///
110/// @param tree the PointDataTree to be dropped from.
111/// @param index index of the attribute to drop.
112template <typename PointDataTreeT>
113inline void dropAttribute( PointDataTreeT& tree,
114 const size_t& index);
115
116/// @brief Drop one attribute from the VDB tree (convenience method).
117///
118/// @param tree the PointDataTree to be dropped from.
119/// @param name name of the attribute to drop.
120template <typename PointDataTreeT>
121inline void dropAttribute( PointDataTreeT& tree,
122 const Name& name);
123
124/// @brief Rename attributes in a VDB tree.
125///
126/// @param tree the PointDataTree.
127/// @param oldNames a list of old attribute names to rename from.
128/// @param newNames a list of new attribute names to rename to.
129///
130/// @note Number of oldNames must match the number of newNames.
131///
132/// @note Duplicate names and renaming group attributes are not allowed.
133template <typename PointDataTreeT>
134inline void renameAttributes(PointDataTreeT& tree,
135 const std::vector<Name>& oldNames,
136 const std::vector<Name>& newNames);
137
138/// @brief Rename an attribute in a VDB tree.
139///
140/// @param tree the PointDataTree.
141/// @param oldName the old attribute name to rename from.
142/// @param newName the new attribute name to rename to.
143///
144/// @note newName must not already exist and must not be a group attribute.
145template <typename PointDataTreeT>
146inline void renameAttribute(PointDataTreeT& tree,
147 const Name& oldName,
148 const Name& newName);
149
150/// @brief Compact attributes in a VDB tree (if possible).
151///
152/// @param tree the PointDataTree.
153template <typename PointDataTreeT>
154inline void compactAttributes(PointDataTreeT& tree);
155
156
157////////////////////////////////////////
158
159/// @cond OPENVDB_DOCS_INTERNAL
160
161namespace point_attribute_internal {
162
163
164template <typename ValueType>
165inline void collapseAttribute(AttributeArray& array,
166 const AttributeSet::Descriptor&, const ValueType& uniformValue)
167{
168 AttributeWriteHandle<ValueType> handle(array);
169 handle.collapse(uniformValue);
170}
171
172
173inline void collapseAttribute(AttributeArray& array,
174 const AttributeSet::Descriptor& descriptor, const Name& uniformValue)
175{
176 StringAttributeWriteHandle handle(array, descriptor.getMetadata());
177 handle.collapse(uniformValue);
178}
179
180
181////////////////////////////////////////
182
183
184template <typename ValueType, typename CodecType>
185struct AttributeTypeConversion
186{
187 static const NamePair& type() {
188 return TypedAttributeArray<ValueType, CodecType>::attributeType();
189 }
190};
191
192
193template <typename CodecType>
194struct AttributeTypeConversion<Name, CodecType>
195{
196 static const NamePair& type() { return StringAttributeArray::attributeType(); }
197};
198
199
200////////////////////////////////////////
201
202
203template <typename PointDataTreeT, typename ValueType>
204struct MetadataStorage
205{
206 static void add(PointDataTreeT&, const ValueType&) {}
207
208 template<typename AttributeListType>
209 static void add(PointDataTreeT&, const AttributeListType&) {}
210};
211
212
213template <typename PointDataTreeT>
214struct MetadataStorage<PointDataTreeT, Name>
215{
216 static void add(PointDataTreeT& tree, const Name& uniformValue) {
217 MetaMap& metadata = makeDescriptorUnique(tree)->getMetadata();
218 StringMetaInserter inserter(metadata);
219 inserter.insert(uniformValue);
220 }
221
222 template<typename AttributeListType>
223 static void add(PointDataTreeT& tree, const AttributeListType& data) {
224 MetaMap& metadata = makeDescriptorUnique(tree)->getMetadata();
225 StringMetaInserter inserter(metadata);
226 Name value;
227
228 for (size_t i = 0; i < data.size(); i++) {
229 data.get(value, i);
230 inserter.insert(value);
231 }
232 }
233};
234
235
236} // namespace point_attribute_internal
237
238/// @endcond
239
240
241////////////////////////////////////////
242
243
244template <typename PointDataTreeT>
245inline void appendAttribute(PointDataTreeT& tree,
246 const Name& name,
247 const NamePair& type,
248 const Index strideOrTotalSize,
249 const bool constantStride,
250 const Metadata* defaultValue,
251 const bool hidden,
252 const bool transient)
253{
254 auto iter = tree.cbeginLeaf();
255
256 if (!iter) return;
257
258 // do not append a non-unique attribute
259
260 const auto& descriptor = iter->attributeSet().descriptor();
261 const size_t index = descriptor.find(name);
262
263 if (index != AttributeSet::INVALID_POS) {
265 "Cannot append an attribute with a non-unique name - " << name << ".");
266 }
267
268 // create a new attribute descriptor
269
270 auto newDescriptor = descriptor.duplicateAppend(name, type);
271
272 // store the attribute default value in the descriptor metadata
273
274 if (defaultValue) {
275 newDescriptor->setDefaultValue(name, *defaultValue);
276 }
277
278 // extract new pos
279
280 const size_t pos = newDescriptor->find(name);
281
282 // acquire registry lock to avoid locking when appending attributes in parallel
283
285
286 // insert attributes using the new descriptor
287
288 tree::LeafManager<PointDataTreeT> leafManager(tree);
289 leafManager.foreach(
290 [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
291 auto expected = leaf.attributeSet().descriptorPtr();
292
293 auto attribute = leaf.appendAttribute(*expected, newDescriptor,
294 pos, strideOrTotalSize, constantStride, defaultValue,
295 &lock);
296
297 if (hidden) attribute->setHidden(true);
298 if (transient) attribute->setTransient(true);
299 }, /*threaded=*/ true
300 );
301}
302
303
304////////////////////////////////////////
305
306
307template <typename ValueType, typename CodecType, typename PointDataTreeT>
308inline void appendAttribute(PointDataTreeT& tree,
309 const std::string& name,
310 const ValueType& uniformValue,
311 const Index strideOrTotalSize,
312 const bool constantStride,
313 const TypedMetadata<ValueType>* defaultValue,
314 const bool hidden,
315 const bool transient)
316{
318 "ValueType must not be derived from AttributeArray");
319
320 using point_attribute_internal::AttributeTypeConversion;
322 using point_attribute_internal::MetadataStorage;
323
324 appendAttribute(tree, name, AttributeTypeConversion<ValueType, CodecType>::type(),
325 strideOrTotalSize, constantStride, defaultValue, hidden, transient);
326
327 // if the uniform value is equal to either the default value provided
328 // through the metadata argument or the default value for this value type,
329 // it is not necessary to perform the collapse
330
331 const bool uniformIsDefault = math::isExactlyEqual(uniformValue,
332 bool(defaultValue) ? defaultValue->value() : Default<ValueType>::value());
333 if (!uniformIsDefault) {
334 MetadataStorage<PointDataTreeT, ValueType>::add(tree, uniformValue);
335 collapseAttribute<ValueType>(tree, name, uniformValue);
336 }
337}
338
339
340////////////////////////////////////////
341
342
343template <typename ValueType, typename PointDataTreeT>
344inline void collapseAttribute( PointDataTreeT& tree,
345 const Name& name,
346 const ValueType& uniformValue)
347{
349 "ValueType must not be derived from AttributeArray");
350
351 auto iter = tree.cbeginLeaf();
352
353 if (!iter) return;
354
355 const auto& descriptor = iter->attributeSet().descriptor();
356
357 // throw if attribute name does not exist
358
359 const size_t index = descriptor.find(name);
360 if (index == AttributeSet::INVALID_POS) {
361 OPENVDB_THROW(KeyError, "Cannot find attribute name in PointDataTree.");
362 }
363
364 tree::LeafManager<PointDataTreeT> leafManager(tree);
365 leafManager.foreach(
366 [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
367 assert(leaf.hasAttribute(index));
368 AttributeArray& array = leaf.attributeArray(index);
370 array, descriptor, uniformValue);
371 }, /*threaded=*/true
372 );
373}
374
375
376////////////////////////////////////////
377
378
379template <typename PointDataTreeT>
380inline void dropAttributes( PointDataTreeT& tree,
381 const std::vector<size_t>& indices)
382{
383 auto iter = tree.cbeginLeaf();
384
385 if (!iter) return;
386
387 const auto& descriptor = iter->attributeSet().descriptor();
388
389 // throw if position index present in the indices as this attribute is mandatory
390
391 const size_t positionIndex = descriptor.find("P");
392 if (positionIndex!= AttributeSet::INVALID_POS &&
393 std::find(indices.begin(), indices.end(), positionIndex) != indices.end()) {
394 OPENVDB_THROW(KeyError, "Cannot drop mandatory position attribute.");
395 }
396
397 // insert attributes using the new descriptor
398
399 auto newDescriptor = descriptor.duplicateDrop(indices);
400
401 tree::LeafManager<PointDataTreeT> leafManager(tree);
402 leafManager.foreach(
403 [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
404 auto expected = leaf.attributeSet().descriptorPtr();
405 leaf.dropAttributes(indices, *expected, newDescriptor);
406 }, /*threaded=*/true
407 );
408}
409
410
411////////////////////////////////////////
412
413
414template <typename PointDataTreeT>
415inline void dropAttributes( PointDataTreeT& tree,
416 const std::vector<Name>& names)
417{
418 auto iter = tree.cbeginLeaf();
419
420 if (!iter) return;
421
422 const AttributeSet& attributeSet = iter->attributeSet();
423 const AttributeSet::Descriptor& descriptor = attributeSet.descriptor();
424
425 std::vector<size_t> indices;
426
427 for (const Name& name : names) {
428 const size_t index = descriptor.find(name);
429
430 // do not attempt to drop an attribute that does not exist
431 if (index == AttributeSet::INVALID_POS) {
433 "Cannot drop an attribute that does not exist - " << name << ".");
434 }
435
436 indices.push_back(index);
437 }
438
439 dropAttributes(tree, indices);
440}
441
442
443////////////////////////////////////////
444
445
446template <typename PointDataTreeT>
447inline void dropAttribute( PointDataTreeT& tree,
448 const size_t& index)
449{
450 std::vector<size_t> indices{index};
451 dropAttributes(tree, indices);
452}
453
454
455template <typename PointDataTreeT>
456inline void dropAttribute( PointDataTreeT& tree,
457 const Name& name)
458{
459 std::vector<Name> names{name};
460 dropAttributes(tree, names);
461}
462
463
464////////////////////////////////////////
465
466
467template <typename PointDataTreeT>
468inline void renameAttributes( PointDataTreeT& tree,
469 const std::vector<Name>& oldNames,
470 const std::vector<Name>& newNames)
471{
472 if (oldNames.size() != newNames.size()) {
473 OPENVDB_THROW(ValueError, "Mis-matching sizes of name vectors, cannot rename attributes.");
474 }
475
476 using Descriptor = AttributeSet::Descriptor;
477
478 auto iter = tree.beginLeaf();
479
480 if (!iter) return;
481
482 const AttributeSet& attributeSet = iter->attributeSet();
483 const Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
484 auto newDescriptor = std::make_shared<Descriptor>(*descriptor);
485
486 for (size_t i = 0; i < oldNames.size(); i++) {
487 const Name& oldName = oldNames[i];
488 if (descriptor->find(oldName) == AttributeSet::INVALID_POS) {
489 OPENVDB_THROW(KeyError, "Cannot find requested attribute - " << oldName << ".");
490 }
491
492 const Name& newName = newNames[i];
493 if (descriptor->find(newName) != AttributeSet::INVALID_POS) {
495 "Cannot rename attribute as new name already exists - " << newName << ".");
496 }
497
498 const AttributeArray* array = attributeSet.getConst(oldName);
499 assert(array);
500
501 if (isGroup(*array)) {
502 OPENVDB_THROW(KeyError, "Cannot rename group attribute - " << oldName << ".");
503 }
504
505 newDescriptor->rename(oldName, newName);
506 }
507
508 for (; iter; ++iter) {
509 iter->renameAttributes(*descriptor, newDescriptor);
510 }
511}
512
513
514template <typename PointDataTreeT>
515inline void renameAttribute(PointDataTreeT& tree,
516 const Name& oldName,
517 const Name& newName)
518{
519 renameAttributes(tree, {oldName}, {newName});
520}
521
522
523////////////////////////////////////////
524
525
526template <typename PointDataTreeT>
527inline void compactAttributes(PointDataTreeT& tree)
528{
529 auto iter = tree.beginLeaf();
530 if (!iter) return;
531
532 tree::LeafManager<PointDataTreeT> leafManager(tree);
533 leafManager.foreach(
534 [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
535 leaf.compactAttributes();
536 }, /*threaded=*/ true
537 );
538}
539
540
541////////////////////////////////////////
542
543
544} // namespace points
545} // namespace OPENVDB_VERSION_NAME
546} // namespace openvdb
547
548#endif // OPENVDB_POINTS_POINT_ATTRIBUTE_HAS_BEEN_INCLUDED
Attribute array storage for string data using Descriptor Metadata.
Attribute Group access and filtering for iteration.
Set of Attribute Arrays which tracks metadata about each array.
ValueT value
Definition: GridBuilder.h:1287
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Definition: Exceptions.h:59
Base class for storing metadata information in a grid.
Definition: Metadata.h:24
Templated metadata class to hold specific types.
Definition: Metadata.h:122
T & value()
Return this metadata's value.
Definition: Metadata.h:249
Definition: Exceptions.h:65
Base class for storing attribute data.
Definition: AttributeArray.h:93
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:39
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set's descriptor, which might be shared with other sets.
Definition: AttributeSet.h:108
const AttributeArray * getConst(const std::string &name) const
Return a pointer to the attribute array whose name is name or a null pointer if no match is found.
Descriptor & descriptor()
Return a reference to this attribute set's descriptor, which might be shared with other sets.
Definition: AttributeSet.h:102
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition: LeafManager.h:483
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:444
void appendAttribute(PointDataTreeT &tree, const std::string &name, const ValueType &uniformValue=point_attribute_internal::Default< ValueType >::value(), const Index strideOrTotalSize=1, const bool constantStride=true, const TypedMetadata< ValueType > *defaultValue=nullptr, const bool hidden=false, const bool transient=false)
Appends a new attribute to the VDB tree.
Definition: PointAttribute.h:308
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttribute.h:527
void collapseAttribute(PointDataTreeT &tree, const Name &name, const ValueType &uniformValue=point_attribute_internal::Default< ValueType >::value())
Collapse the attribute into a uniform value.
Definition: PointAttribute.h:344
void dropAttributes(PointDataTreeT &tree, const std::vector< Name > &names)
Drops attributes from the VDB tree.
Definition: PointAttribute.h:415
void dropAttribute(PointDataTreeT &tree, const Name &name)
Drop one attribute from the VDB tree (convenience method).
Definition: PointAttribute.h:456
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
void renameAttribute(PointDataTreeT &tree, const Name &oldName, const Name &newName)
Rename an attribute in a VDB tree.
Definition: PointAttribute.h:515
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1577
std::string Name
Definition: Name.h:17
Index32 Index
Definition: Types.h:54
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:39
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
static ValueType value()
Definition: PointAttribute.h:31
#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