OpenVDB  12.0.0
PointAttributeImpl.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 /// @author Dan Bailey, Khang Ngo
5 ///
6 /// @file PointAttributeImpl.h
7 ///
8 
9 #ifndef OPENVDB_POINTS_POINT_ATTRIBUTE_IMPL_HAS_BEEN_INCLUDED
10 #define OPENVDB_POINTS_POINT_ATTRIBUTE_IMPL_HAS_BEEN_INCLUDED
11 
12 namespace openvdb {
14 namespace OPENVDB_VERSION_NAME {
15 namespace points {
16 
17 /// @cond OPENVDB_DOCS_INTERNAL
18 
19 namespace point_attribute_internal {
20 
21 
22 template <typename ValueType>
23 inline void collapseAttribute(AttributeArray& array,
24  const AttributeSet::Descriptor&, const ValueType& uniformValue)
25 {
26  AttributeWriteHandle<ValueType> handle(array);
27  handle.collapse(uniformValue);
28 }
29 
30 
31 inline void collapseAttribute(AttributeArray& array,
32  const AttributeSet::Descriptor& descriptor, const Name& uniformValue)
33 {
34  StringAttributeWriteHandle handle(array, descriptor.getMetadata());
35  handle.collapse(uniformValue);
36 }
37 
38 
39 ////////////////////////////////////////
40 
41 
42 template <typename ValueType, typename CodecType>
43 struct AttributeTypeConversion
44 {
45  static const NamePair& type() {
46  return TypedAttributeArray<ValueType, CodecType>::attributeType();
47  }
48 };
49 
50 
51 template <typename CodecType>
52 struct AttributeTypeConversion<Name, CodecType>
53 {
54  static const NamePair& type() { return StringAttributeArray::attributeType(); }
55 };
56 
57 
58 ////////////////////////////////////////
59 
60 
61 template <typename PointDataTreeT, typename ValueType>
62 struct MetadataStorage
63 {
64  static void add(PointDataTreeT&, const ValueType&) {}
65 
66  template<typename AttributeListType>
67  static void add(PointDataTreeT&, const AttributeListType&) {}
68 };
69 
70 
71 template <typename PointDataTreeT>
72 struct MetadataStorage<PointDataTreeT, Name>
73 {
74  static void add(PointDataTreeT& tree, const Name& uniformValue) {
75  MetaMap& metadata = makeDescriptorUnique(tree)->getMetadata();
76  StringMetaInserter inserter(metadata);
77  inserter.insert(uniformValue);
78  }
79 
80  template<typename AttributeListType>
81  static void add(PointDataTreeT& tree, const AttributeListType& data) {
82  MetaMap& metadata = makeDescriptorUnique(tree)->getMetadata();
83  StringMetaInserter inserter(metadata);
84  Name value;
85 
86  for (size_t i = 0; i < data.size(); i++) {
87  data.get(value, i);
88  inserter.insert(value);
89  }
90  }
91 };
92 
93 
94 } // namespace point_attribute_internal
95 
96 /// @endcond
97 
98 
99 ////////////////////////////////////////
100 
101 
102 template <typename PointDataTreeT>
103 inline void appendAttribute(PointDataTreeT& tree,
104  const Name& name,
105  const NamePair& type,
106  const Index strideOrTotalSize,
107  const bool constantStride,
108  const Metadata* defaultValue,
109  const bool hidden,
110  const bool transient)
111 {
112  auto iter = tree.cbeginLeaf();
113 
114  if (!iter) return;
115 
116  // do not append a non-unique attribute
117 
118  const auto& descriptor = iter->attributeSet().descriptor();
119  const size_t index = descriptor.find(name);
120 
121  if (index != AttributeSet::INVALID_POS) {
123  "Cannot append an attribute with a non-unique name - " << name << ".");
124  }
125 
126  // create a new attribute descriptor
127 
128  auto newDescriptor = descriptor.duplicateAppend(name, type);
129 
130  // store the attribute default value in the descriptor metadata
131 
132  if (defaultValue) {
133  newDescriptor->setDefaultValue(name, *defaultValue);
134  }
135 
136  // extract new pos
137 
138  const size_t pos = newDescriptor->find(name);
139 
140  // acquire registry lock to avoid locking when appending attributes in parallel
141 
143 
144  // insert attributes using the new descriptor
145 
146  tree::LeafManager<PointDataTreeT> leafManager(tree);
147  leafManager.foreach(
148  [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
149  auto expected = leaf.attributeSet().descriptorPtr();
150 
151  auto attribute = leaf.appendAttribute(*expected, newDescriptor,
152  pos, strideOrTotalSize, constantStride, defaultValue,
153  &lock);
154 
155  if (hidden) attribute->setHidden(true);
156  if (transient) attribute->setTransient(true);
157  }, /*threaded=*/ true
158  );
159 }
160 
161 
162 ////////////////////////////////////////
163 
164 
165 template <typename ValueType, typename CodecType, typename PointDataTreeT>
166 inline void appendAttribute(PointDataTreeT& tree,
167  const std::string& name,
168  const ValueType& uniformValue,
169  const Index strideOrTotalSize,
170  const bool constantStride,
171  const TypedMetadata<ValueType>* defaultValue,
172  const bool hidden,
173  const bool transient)
174 {
175  static_assert(!std::is_base_of<AttributeArray, ValueType>::value,
176  "ValueType must not be derived from AttributeArray");
177 
178  using point_attribute_internal::AttributeTypeConversion;
180  using point_attribute_internal::MetadataStorage;
181 
182  appendAttribute(tree, name, AttributeTypeConversion<ValueType, CodecType>::type(),
183  strideOrTotalSize, constantStride, defaultValue, hidden, transient);
184 
185  // if the uniform value is equal to either the default value provided
186  // through the metadata argument or the default value for this value type,
187  // it is not necessary to perform the collapse
188 
189  const bool uniformIsDefault = math::isExactlyEqual(uniformValue,
190  bool(defaultValue) ? defaultValue->value() : Default<ValueType>::value());
191  if (!uniformIsDefault) {
192  MetadataStorage<PointDataTreeT, ValueType>::add(tree, uniformValue);
193  collapseAttribute<ValueType>(tree, name, uniformValue);
194  }
195 }
196 
197 
198 ////////////////////////////////////////
199 
200 
201 template <typename ValueType, typename PointDataTreeT>
202 inline void collapseAttribute( PointDataTreeT& tree,
203  const Name& name,
204  const ValueType& uniformValue)
205 {
206  static_assert(!std::is_base_of<AttributeArray, ValueType>::value,
207  "ValueType must not be derived from AttributeArray");
208 
209  auto iter = tree.cbeginLeaf();
210 
211  if (!iter) return;
212 
213  const auto& descriptor = iter->attributeSet().descriptor();
214 
215  // throw if attribute name does not exist
216 
217  const size_t index = descriptor.find(name);
218  if (index == AttributeSet::INVALID_POS) {
219  OPENVDB_THROW(KeyError, "Cannot find attribute name in PointDataTree.");
220  }
221 
222  tree::LeafManager<PointDataTreeT> leafManager(tree);
223  leafManager.foreach(
224  [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
225  OPENVDB_ASSERT(leaf.hasAttribute(index));
226  AttributeArray& array = leaf.attributeArray(index);
228  array, descriptor, uniformValue);
229  }, /*threaded=*/true
230  );
231 }
232 
233 
234 ////////////////////////////////////////
235 
236 
237 template <typename PointDataTreeT>
238 inline void dropAttributes( PointDataTreeT& tree,
239  const std::vector<size_t>& indices)
240 {
241  auto iter = tree.cbeginLeaf();
242 
243  if (!iter) return;
244 
245  const auto& descriptor = iter->attributeSet().descriptor();
246 
247  // throw if position index present in the indices as this attribute is mandatory
248 
249  const size_t positionIndex = descriptor.find("P");
250  if (positionIndex!= AttributeSet::INVALID_POS &&
251  std::find(indices.begin(), indices.end(), positionIndex) != indices.end()) {
252  OPENVDB_THROW(KeyError, "Cannot drop mandatory position attribute.");
253  }
254 
255  // insert attributes using the new descriptor
256 
257  auto newDescriptor = descriptor.duplicateDrop(indices);
258 
259  tree::LeafManager<PointDataTreeT> leafManager(tree);
260  leafManager.foreach(
261  [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
262  auto expected = leaf.attributeSet().descriptorPtr();
263  leaf.dropAttributes(indices, *expected, newDescriptor);
264  }, /*threaded=*/true
265  );
266 }
267 
268 
269 ////////////////////////////////////////
270 
271 
272 template <typename PointDataTreeT>
273 inline void dropAttributes( PointDataTreeT& tree,
274  const std::vector<Name>& names)
275 {
276  auto iter = tree.cbeginLeaf();
277 
278  if (!iter) return;
279 
280  const AttributeSet& attributeSet = iter->attributeSet();
281  const AttributeSet::Descriptor& descriptor = attributeSet.descriptor();
282 
283  std::vector<size_t> indices;
284 
285  for (const Name& name : names) {
286  const size_t index = descriptor.find(name);
287 
288  // do not attempt to drop an attribute that does not exist
289  if (index == AttributeSet::INVALID_POS) {
291  "Cannot drop an attribute that does not exist - " << name << ".");
292  }
293 
294  indices.push_back(index);
295  }
296 
297  dropAttributes(tree, indices);
298 }
299 
300 
301 ////////////////////////////////////////
302 
303 
304 template <typename PointDataTreeT>
305 inline void dropAttribute( PointDataTreeT& tree,
306  const size_t& index)
307 {
308  std::vector<size_t> indices{index};
309  dropAttributes(tree, indices);
310 }
311 
312 
313 template <typename PointDataTreeT>
314 inline void dropAttribute( PointDataTreeT& tree,
315  const Name& name)
316 {
317  std::vector<Name> names{name};
318  dropAttributes(tree, names);
319 }
320 
321 
322 ////////////////////////////////////////
323 
324 
325 template <typename PointDataTreeT>
326 inline void renameAttributes( PointDataTreeT& tree,
327  const std::vector<Name>& oldNames,
328  const std::vector<Name>& newNames)
329 {
330  if (oldNames.size() != newNames.size()) {
331  OPENVDB_THROW(ValueError, "Mis-matching sizes of name vectors, cannot rename attributes.");
332  }
333 
334  using Descriptor = AttributeSet::Descriptor;
335 
336  auto iter = tree.beginLeaf();
337 
338  if (!iter) return;
339 
340  const AttributeSet& attributeSet = iter->attributeSet();
341  const Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
342  auto newDescriptor = std::make_shared<Descriptor>(*descriptor);
343 
344  for (size_t i = 0; i < oldNames.size(); i++) {
345  const Name& oldName = oldNames[i];
346  if (descriptor->find(oldName) == AttributeSet::INVALID_POS) {
347  OPENVDB_THROW(KeyError, "Cannot find requested attribute - " << oldName << ".");
348  }
349 
350  const Name& newName = newNames[i];
351  if (descriptor->find(newName) != AttributeSet::INVALID_POS) {
353  "Cannot rename attribute as new name already exists - " << newName << ".");
354  }
355 
356  const AttributeArray* array = attributeSet.getConst(oldName);
357  OPENVDB_ASSERT(array);
358 
359  if (isGroup(*array)) {
360  OPENVDB_THROW(KeyError, "Cannot rename group attribute - " << oldName << ".");
361  }
362 
363  newDescriptor->rename(oldName, newName);
364  }
365 
366  for (; iter; ++iter) {
367  iter->renameAttributes(*descriptor, newDescriptor);
368  }
369 }
370 
371 
372 template <typename PointDataTreeT>
373 inline void renameAttribute(PointDataTreeT& tree,
374  const Name& oldName,
375  const Name& newName)
376 {
377  renameAttributes(tree, {oldName}, {newName});
378 }
379 
380 
381 ////////////////////////////////////////
382 
383 
384 template <typename PointDataTreeT>
385 inline void compactAttributes(PointDataTreeT& tree)
386 {
387  auto iter = tree.beginLeaf();
388  if (!iter) return;
389 
390  tree::LeafManager<PointDataTreeT> leafManager(tree);
391  leafManager.foreach(
392  [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
393  leaf.compactAttributes();
394  }, /*threaded=*/ true
395  );
396 }
397 
398 
399 ////////////////////////////////////////
400 
401 
402 } // namespace points
403 } // namespace OPENVDB_VERSION_NAME
404 } // namespace openvdb
405 
406 #endif // OPENVDB_POINTS_POINT_ATTRIBUTE_IMPL_HAS_BEEN_INCLUDED
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:443
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void renameAttributes(PointDataTreeT &tree, const std::vector< Name > &oldNames, const std::vector< Name > &newNames)
Rename attributes in a VDB tree.
Definition: PointAttributeImpl.h:326
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:64
void compactAttributes(PointDataTreeT &tree)
Compact attributes in a VDB tree (if possible).
Definition: PointAttributeImpl.h:385
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
Definition: PointDataGrid.h:1586
void dropAttribute(PointDataTreeT &tree, const size_t &index)
Drop one attribute from the VDB tree (convenience method).
Definition: PointAttributeImpl.h:305
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...
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
Definition: PointAttributeImpl.h:238
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: PointAttributeImpl.h:103
Index32 Index
Definition: Types.h:54
Definition: Exceptions.h:65
Base class for storing metadata information in a grid.
Definition: Metadata.h:24
void collapseAttribute(PointDataTreeT &tree, const Name &name, const ValueType &uniformValue=point_attribute_internal::Default< ValueType >::value())
Collapse the attribute into a uniform value.
Definition: PointAttributeImpl.h:202
void renameAttribute(PointDataTreeT &tree, const Name &oldName, const Name &newName)
Rename an attribute in a VDB tree.
Definition: PointAttributeImpl.h:373
Templated metadata class to hold specific types.
Definition: Metadata.h:122
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:109
Definition: Exceptions.h:13
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:40
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:484
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
Descriptor & descriptor()
Return a reference to this attribute set&#39;s descriptor, which might be shared with other sets...
Definition: AttributeSet.h:103
std::string Name
Definition: Name.h:19
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:39
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
T & value()
Return this metadata&#39;s value.
Definition: Metadata.h:250
Definition: Exceptions.h:59
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
Base class for storing attribute data.
Definition: AttributeArray.h:93