OpenVDB  9.1.1
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 
15 #include "AttributeArrayString.h"
16 #include "AttributeSet.h"
17 #include "AttributeGroup.h"
18 #include "PointDataGrid.h"
19 
20 
21 namespace openvdb {
23 namespace OPENVDB_VERSION_NAME {
24 namespace points {
25 
26 namespace point_attribute_internal {
27 
28 template <typename ValueType>
29 struct 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
48 template <typename PointDataTreeT>
49 inline 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
68 template <typename ValueType,
69  typename CodecType = NullCodec,
70  typename PointDataTreeT>
71 inline 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
86 template <typename ValueType, typename PointDataTreeT>
87 inline 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.
96 template <typename PointDataTreeT>
97 inline 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.
104 template <typename PointDataTreeT>
105 inline 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.
112 template <typename PointDataTreeT>
113 inline 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.
120 template <typename PointDataTreeT>
121 inline 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.
133 template <typename PointDataTreeT>
134 inline 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.
145 template <typename PointDataTreeT>
146 inline 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.
153 template <typename PointDataTreeT>
154 inline void compactAttributes(PointDataTreeT& tree);
155 
156 
157 ////////////////////////////////////////
158 
159 /// @cond OPENVDB_DOCS_INTERNAL
160 
161 namespace point_attribute_internal {
162 
163 
164 template <typename ValueType>
165 inline void collapseAttribute(AttributeArray& array,
166  const AttributeSet::Descriptor&, const ValueType& uniformValue)
167 {
168  AttributeWriteHandle<ValueType> handle(array);
169  handle.collapse(uniformValue);
170 }
171 
172 
173 inline 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 
184 template <typename ValueType, typename CodecType>
185 struct AttributeTypeConversion
186 {
187  static const NamePair& type() {
189  }
190 };
191 
192 
193 template <typename CodecType>
194 struct AttributeTypeConversion<Name, CodecType>
195 {
196  static const NamePair& type() { return StringAttributeArray::attributeType(); }
197 };
198 
199 
200 ////////////////////////////////////////
201 
202 
203 template <typename PointDataTreeT, typename ValueType>
204 struct MetadataStorage
205 {
206  static void add(PointDataTreeT&, const ValueType&) {}
207 
208  template<typename AttributeListType>
209  static void add(PointDataTreeT&, const AttributeListType&) {}
210 };
211 
212 
213 template <typename PointDataTreeT>
214 struct 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 
244 template <typename PointDataTreeT>
245 inline 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 
307 template <typename ValueType, typename CodecType, typename PointDataTreeT>
308 inline 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 
343 template <typename ValueType, typename PointDataTreeT>
344 inline 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 
379 template <typename PointDataTreeT>
380 inline 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 
414 template <typename PointDataTreeT>
415 inline 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 
446 template <typename PointDataTreeT>
447 inline void dropAttribute( PointDataTreeT& tree,
448  const size_t& index)
449 {
450  std::vector<size_t> indices{index};
451  dropAttributes(tree, indices);
452 }
453 
454 
455 template <typename PointDataTreeT>
456 inline 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 
467 template <typename PointDataTreeT>
468 inline 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 
514 template <typename PointDataTreeT>
515 inline void renameAttribute(PointDataTreeT& tree,
516  const Name& oldName,
517  const Name& newName)
518 {
519  renameAttributes(tree, {oldName}, {newName});
520 }
521 
522 
523 ////////////////////////////////////////
524 
525 
526 template <typename PointDataTreeT>
527 inline 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
Templated metadata class to hold specific types.
Definition: Metadata.h:121
Index32 Index
Definition: Types.h:54
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:38
Attribute Group access and filtering for iteration.
void dropAttribute(PointDataTreeT &tree, const Name &name)
Drop one attribute from the VDB tree (convenience method).
Definition: PointAttribute.h:456
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
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
Definition: Exceptions.h:59
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:39
static ValueType value()
Definition: PointAttribute.h:31
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:108
Definition: AttributeArray.h:463
Definition: Exceptions.h:65
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...
T & value()
Return this metadata&#39;s value.
Definition: Metadata.h:249
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
Write-able version of AttributeHandle.
Definition: AttributeArray.h:888
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:63
Definition: Exceptions.h:13
ValueT value
Definition: GridBuilder.h:1287
void renameAttribute(PointDataTreeT &tree, const Name &oldName, const Name &newName)
Rename an attribute in a VDB tree.
Definition: PointAttribute.h:515
Base class for storing metadata information in a grid.
Definition: Metadata.h:23
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1589
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttribute.h:527
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:443
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition: PointAttribute.h:468
Attribute array storage for string data using Descriptor Metadata.
Definition: AttributeArrayString.h:186
Class to help with insertion of keyed string values into metadata.
Definition: AttributeArrayString.h:88
Index insert(const Name &name, Index hint=Index(0))
Insert the string into the metadata using the hint if non-zero.
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:102
Base class for storing attribute data.
Definition: AttributeArray.h:92
std::string Name
Definition: Name.h:17
Typed class for storing attribute data.
Definition: AttributeArray.h:538
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
void collapse()
Set membership for the whole array and attempt to collapse.
Set of Attribute Arrays which tracks metadata about each array.
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:19
void dropAttributes(PointDataTreeT &tree, const std::vector< Name > &names)
Drops attributes from the VDB tree.
Definition: PointAttribute.h:415
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition: AttributeArray.h:2231
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
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202