OpenVDB  9.0.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
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:444
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
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:108
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
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:102
Definition: AttributeArrayString.h:186
Definition: Exceptions.h:65
Base class for storing attribute data.
Definition: AttributeArray.h:92
T & value()
Return this metadata&#39;s value.
Definition: Metadata.h:249
Index insert(const Name &name, Index hint=Index(0))
Insert the string into the metadata using the hint if non-zero.
Definition: Exceptions.h:59
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...
Base class for storing metadata information in a grid.
Definition: Metadata.h:23
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:19
std::string Name
Definition: Name.h:17
Templated metadata class to hold specific types.
Definition: Metadata.h:121
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
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
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1577
static ValueType value()
Definition: PointAttribute.h:31
Index32 Index
Definition: Types.h:54
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttribute.h:527
Write-able version of AttributeHandle.
Definition: AttributeArray.h:881
Definition: AttributeArray.h:457
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:63
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:39
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.
Class to help with insertion of keyed string values into metadata.
Definition: AttributeArrayString.h:88
void collapse()
Set membership for the whole array and attempt to collapse.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
Typed class for storing attribute data.
Definition: AttributeArray.h:532
Set of Attribute Arrays which tracks metadata about each array.
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition: AttributeArray.h:2224
void dropAttributes(PointDataTreeT &tree, const std::vector< Name > &names)
Drops attributes from the VDB tree.
Definition: PointAttribute.h:415
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