OpenVDB 10.0.1
Loading...
Searching...
No Matches
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 =
74 point_attribute_internal::Default<ValueType>::value(),
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 =
90 point_attribute_internal::Default<ValueType>::value());
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{
317 static_assert(!std::is_base_of<AttributeArray, ValueType>::value,
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{
348 static_assert(!std::is_base_of<AttributeArray, ValueType>::value,
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);
369 point_attribute_internal::collapseAttribute(
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:1290
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
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition PointAttribute.h:527
void dropAttribute(PointDataTreeT &tree, const size_t &index)
Drop one attribute from the VDB tree (convenience method).
Definition PointAttribute.h:447
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
bool isGroup(const AttributeArray &array)
Definition AttributeGroup.h:63
void appendAttribute(PointDataTreeT &tree, const Name &name, const NamePair &type, const Index strideOrTotalSize=1, const bool constantStride=true, const Metadata *defaultValue=nullptr, const bool hidden=false, const bool transient=false)
Appends a new attribute to the VDB tree (this method does not require a templated AttributeType)
Definition PointAttribute.h:245
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
Definition PointAttribute.h:380
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition PointAttribute.h:468
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:1589
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:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212