HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointGroup.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
29 ///////////////////////////////////////////////////////////////////////////
30 
31 /// @author Dan Bailey
32 ///
33 /// @file points/PointGroup.h
34 ///
35 /// @brief Point group manipulation in a VDB Point Grid.
36 
37 #ifndef OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
38 #define OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
39 
40 #include <openvdb/openvdb.h>
41 
42 #include "IndexIterator.h" // FilterTraits
43 #include "IndexFilter.h" // FilterTraits
44 #include "AttributeSet.h"
45 #include "PointDataGrid.h"
46 #include "PointAttribute.h"
47 #include "PointCount.h"
48 
49 #include <tbb/parallel_reduce.h>
50 
51 #include <algorithm>
52 #include <random>
53 #include <string>
54 #include <vector>
55 
56 namespace openvdb {
58 namespace OPENVDB_VERSION_NAME {
59 namespace points {
60 
61 /// @brief Delete any group that is not present in the Descriptor.
62 ///
63 /// @param groups the vector of group names.
64 /// @param descriptor the descriptor that holds the group map.
65 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
66  const AttributeSet::Descriptor& descriptor);
67 
68 /// @brief Appends a new empty group to the VDB tree.
69 ///
70 /// @param tree the PointDataTree to be appended to.
71 /// @param group name of the new group.
72 template <typename PointDataTree>
73 inline void appendGroup(PointDataTree& tree,
74  const Name& group);
75 
76 /// @brief Appends new empty groups to the VDB tree.
77 ///
78 /// @param tree the PointDataTree to be appended to.
79 /// @param groups names of the new groups.
80 template <typename PointDataTree>
81 inline void appendGroups(PointDataTree& tree,
82  const std::vector<Name>& groups);
83 
84 /// @brief Drops an existing group from the VDB tree.
85 ///
86 /// @param tree the PointDataTree to be dropped from.
87 /// @param group name of the group.
88 /// @param compact compact attributes if possible to reduce memory - if dropping
89 /// more than one group, compacting once at the end will be faster
90 template <typename PointDataTree>
91 inline void dropGroup( PointDataTree& tree,
92  const Name& group,
93  const bool compact = true);
94 
95 /// @brief Drops existing groups from the VDB tree, the tree is compacted after dropping.
96 ///
97 /// @param tree the PointDataTree to be dropped from.
98 /// @param groups names of the groups.
99 template <typename PointDataTree>
100 inline void dropGroups( PointDataTree& tree,
101  const std::vector<Name>& groups);
102 
103 /// @brief Drops all existing groups from the VDB tree, the tree is compacted after dropping.
104 ///
105 /// @param tree the PointDataTree to be dropped from.
106 template <typename PointDataTree>
107 inline void dropGroups( PointDataTree& tree);
108 
109 /// @brief Compacts existing groups of a VDB Tree to use less memory if possible.
110 ///
111 /// @param tree the PointDataTree to be compacted.
112 template <typename PointDataTree>
113 inline void compactGroups(PointDataTree& tree);
114 
115 /// @brief Sets group membership from a PointIndexTree-ordered vector.
116 ///
117 /// @param tree the PointDataTree.
118 /// @param indexTree the PointIndexTree.
119 /// @param membership @c 1 if the point is in the group, 0 otherwise.
120 /// @param group the name of the group.
121 /// @param remove if @c true also perform removal of points from the group.
122 ///
123 /// @note vector<bool> is not thread-safe on concurrent write, so use vector<short> instead
124 template <typename PointDataTree, typename PointIndexTree>
125 inline void setGroup( PointDataTree& tree,
126  const PointIndexTree& indexTree,
127  const std::vector<short>& membership,
128  const Name& group,
129  const bool remove = false);
130 
131 /// @brief Sets membership for the specified group for all points (on/off).
132 ///
133 /// @param tree the PointDataTree.
134 /// @param group the name of the group.
135 /// @param member true / false for membership of the group.
136 template <typename PointDataTree>
137 inline void setGroup( PointDataTree& tree,
138  const Name& group,
139  const bool member = true);
140 
141 /// @brief Sets group membership based on a provided filter.
142 ///
143 /// @param tree the PointDataTree.
144 /// @param group the name of the group.
145 /// @param filter filter data that is used to create a per-leaf filter
146 template <typename PointDataTree, typename FilterT>
147 inline void setGroupByFilter( PointDataTree& tree,
148  const Name& group,
149  const FilterT& filter);
150 
151 
152 ////////////////////////////////////////
153 
154 
155 namespace point_group_internal {
156 
157 
158 /// Copy a group attribute value from one group offset to another
159 template<typename PointDataTreeType>
160 struct CopyGroupOp {
161 
163  using LeafRangeT = typename LeafManagerT::LeafRange;
164  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
165 
166  CopyGroupOp(const GroupIndex& targetIndex,
167  const GroupIndex& sourceIndex)
168  : mTargetIndex(targetIndex)
169  , mSourceIndex(sourceIndex) { }
170 
171  void operator()(const typename LeafManagerT::LeafRange& range) const {
172 
173  for (auto leaf = range.begin(); leaf; ++leaf) {
174 
175  GroupHandle sourceGroup = leaf->groupHandle(mSourceIndex);
176  GroupWriteHandle targetGroup = leaf->groupWriteHandle(mTargetIndex);
177 
178  for (auto iter = leaf->beginIndexAll(); iter; ++iter) {
179  const bool groupOn = sourceGroup.get(*iter);
180  targetGroup.set(*iter, groupOn);
181  }
182  }
183  }
184 
185  //////////
186 
189 };
190 
191 
192 /// Set membership on or off for the specified group
193 template <typename PointDataTree, bool Member>
195 {
197  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
198 
199  SetGroupOp(const AttributeSet::Descriptor::GroupIndex& index)
200  : mIndex(index) { }
201 
202  void operator()(const typename LeafManagerT::LeafRange& range) const
203  {
204  for (auto leaf = range.begin(); leaf; ++leaf) {
205 
206  // obtain the group attribute array
207 
208  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
209 
210  // set the group value
211 
212  group.collapse(Member);
213  }
214  }
215 
216  //////////
217 
219 }; // struct SetGroupOp
220 
221 
222 template <typename PointDataTree, typename PointIndexTree, bool Remove>
224 {
226  using LeafRangeT = typename LeafManagerT::LeafRange;
227  using PointIndexLeafNode = typename PointIndexTree::LeafNodeType;
229  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
230  using MembershipArray = std::vector<short>;
231 
233  const MembershipArray& membership,
234  const GroupIndex& index)
235  : mIndexTree(indexTree)
236  , mMembership(membership)
237  , mIndex(index) { }
238 
239  void operator()(const typename LeafManagerT::LeafRange& range) const
240  {
241  for (auto leaf = range.begin(); leaf; ++leaf) {
242 
243  // obtain the PointIndexLeafNode (using the origin of the current leaf)
244 
245  const PointIndexLeafNode* pointIndexLeaf = mIndexTree.probeConstLeaf(leaf->origin());
246 
247  if (!pointIndexLeaf) continue;
248 
249  // obtain the group attribute array
250 
251  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
252 
253  // initialise the attribute storage
254 
255  Index64 index = 0;
256 
257  const IndexArray& indices = pointIndexLeaf->indices();
258 
259  for (const Index64 i: indices) {
260  if (Remove) {
261  group.set(static_cast<Index>(index), mMembership[i]);
262  } else if (mMembership[i] == short(1)) {
263  group.set(static_cast<Index>(index), short(1));
264  }
265  index++;
266  }
267 
268  // attempt to compact the array
269 
270  group.compact();
271  }
272  }
273 
274  //////////
275 
279 }; // struct SetGroupFromIndexOp
280 
281 
282 template <typename PointDataTree, typename FilterT, typename IterT = typename PointDataTree::LeafNodeType::ValueAllCIter>
284 {
286  using LeafRangeT = typename LeafManagerT::LeafRange;
288  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
289 
290  SetGroupByFilterOp( const GroupIndex& index, const FilterT& filter)
291  : mIndex(index)
292  , mFilter(filter) { }
293 
294  void operator()(const typename LeafManagerT::LeafRange& range) const
295  {
296  for (auto leaf = range.begin(); leaf; ++leaf) {
297 
298  // obtain the group attribute array
299 
300  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
301 
302  auto iter = leaf->template beginIndex<IterT, FilterT>(mFilter);
303 
304  for (; iter; ++iter) {
305  group.set(*iter, true);
306  }
307 
308  // attempt to compact the array
309 
310  group.compact();
311  }
312  }
313 
314  //////////
315 
317  const FilterT& mFilter; // beginIndex takes a copy of mFilter
318 }; // struct SetGroupByFilterOp
319 
320 
321 ////////////////////////////////////////
322 
323 
324 /// Convenience class with methods for analyzing group data
326 {
327 public:
329 
330  GroupInfo(const AttributeSet& attributeSet)
331  : mAttributeSet(attributeSet) { }
332 
333  /// Return the number of bits in a group (typically 8)
334  static size_t groupBits() { return sizeof(GroupType) * CHAR_BIT; }
335 
336  /// Return the number of empty group slots which correlates to the number of groups
337  /// that can be stored without increasing the number of group attribute arrays
338  size_t unusedGroups() const
339  {
340  const Descriptor& descriptor = mAttributeSet.descriptor();
341 
342  // compute total slots (one slot per bit of the group attributes)
343 
344  const size_t groupAttributes = descriptor.count(GroupAttributeArray::attributeType());
345 
346  if (groupAttributes == 0) return 0;
347 
348  const size_t totalSlots = groupAttributes * this->groupBits();
349 
350  // compute slots in use
351 
352  const AttributeSet::Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
353  const size_t usedSlots = groupMap.size();
354 
355  return totalSlots - usedSlots;
356  }
357 
358  /// Return @c true if there are sufficient empty slots to allow compacting
359  bool canCompactGroups() const
360  {
361  // can compact if more unused groups than in one group attribute array
362 
363  return this->unusedGroups() >= this->groupBits();
364  }
365 
366  /// Return the next empty group slot
367  size_t nextUnusedOffset() const
368  {
369  const Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
370 
371  // build a list of group indices
372 
373  std::vector<size_t> indices;
374  indices.reserve(groupMap.size());
375  for (const auto& namePos : groupMap) {
376  indices.push_back(namePos.second);
377  }
378 
379  std::sort(indices.begin(), indices.end());
380 
381  // return first index not present
382 
383  size_t offset = 0;
384  for (const size_t& index : indices) {
385  if (index != offset) break;
386  offset++;
387  }
388 
389  return offset;
390  }
391 
392  /// Return vector of indices correlating to the group attribute arrays
393  std::vector<size_t> populateGroupIndices() const
394  {
395  std::vector<size_t> indices;
396 
397  const Descriptor::NameToPosMap& map = mAttributeSet.descriptor().map();
398 
399  for (const auto& namePos : map) {
400  const AttributeArray* array = mAttributeSet.getConst(namePos.first);
401  if (isGroup(*array)) {
402  indices.push_back(namePos.second);
403  }
404  }
405 
406  return indices;
407  }
408 
409  /// Determine if a move is required to efficiently compact the data and store the
410  /// source name, offset and the target offset in the input parameters
411  bool requiresMove(Name& sourceName, size_t& sourceOffset, size_t& targetOffset) const {
412 
413  targetOffset = this->nextUnusedOffset();
414 
415  const Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
416 
417  for (const auto& namePos : groupMap) {
418 
419  // move only required if source comes after the target
420 
421  if (namePos.second >= targetOffset) {
422  sourceName = namePos.first;
423  sourceOffset = namePos.second;
424  return true;
425  }
426  }
427 
428  return false;
429  }
430 
431 private:
432  const AttributeSet& mAttributeSet;
433 }; // class GroupInfo
434 
435 
436 } // namespace point_group_internal
437 
438 
439 ////////////////////////////////////////
440 
441 
442 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
443  const AttributeSet::Descriptor& descriptor)
444 {
445  for (auto it = groups.begin(); it != groups.end();) {
446  if (!descriptor.hasGroup(*it)) it = groups.erase(it);
447  else ++it;
448  }
449 }
450 
451 
452 ////////////////////////////////////////
453 
454 
455 template <typename PointDataTreeT>
456 inline void appendGroup(PointDataTreeT& tree, const Name& group)
457 {
459 
460  if (group.empty()) {
461  OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
462  }
463 
464  auto iter = tree.cbeginLeaf();
465 
466  if (!iter) return;
467 
468  const AttributeSet& attributeSet = iter->attributeSet();
469  auto descriptor = attributeSet.descriptorPtr();
470  GroupInfo groupInfo(attributeSet);
471 
472  // don't add if group already exists
473 
474  if (descriptor->hasGroup(group)) return;
475 
476  const bool hasUnusedGroup = groupInfo.unusedGroups() > 0;
477 
478  // add a new group attribute if there are no unused groups
479 
480  if (!hasUnusedGroup) {
481 
482  // find a new internal group name
483 
484  const Name groupName = descriptor->uniqueName("__group");
485 
486  descriptor = descriptor->duplicateAppend(groupName, GroupAttributeArray::attributeType());
487  const size_t pos = descriptor->find(groupName);
488 
489  // insert new group attribute
490 
491  tree::LeafManager<PointDataTreeT> leafManager(tree);
492  leafManager.foreach(
493  [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
494  auto expected = leaf.attributeSet().descriptorPtr();
495  leaf.appendAttribute(*expected, descriptor, pos);
496  }, /*threaded=*/true
497  );
498  }
499  else {
500  // make the descriptor unique before we modify the group map
501 
502  makeDescriptorUnique(tree);
503  descriptor = attributeSet.descriptorPtr();
504  }
505 
506  // ensure that there are now available groups
507 
508  assert(groupInfo.unusedGroups() > 0);
509 
510  // find next unused offset
511 
512  const size_t offset = groupInfo.nextUnusedOffset();
513 
514  // add the group mapping to the descriptor
515 
516  descriptor->setGroup(group, offset);
517 
518  // if there was an unused group then we did not need to append a new attribute, so
519  // we must manually clear membership in the new group as its bits may have been
520  // previously set
521 
522  if (hasUnusedGroup) setGroup(tree, group, false);
523 }
524 
525 
526 ////////////////////////////////////////
527 
528 
529 template <typename PointDataTree>
530 inline void appendGroups(PointDataTree& tree,
531  const std::vector<Name>& groups)
532 {
533  // TODO: could be more efficient by appending multiple groups at once
534  // instead of one-by-one, however this is likely not that common a use case
535 
536  for (const Name& name : groups) {
537  appendGroup(tree, name);
538  }
539 }
540 
541 
542 ////////////////////////////////////////
543 
544 
545 template <typename PointDataTree>
546 inline void dropGroup(PointDataTree& tree, const Name& group, const bool compact)
547 {
548  using Descriptor = AttributeSet::Descriptor;
549 
550  if (group.empty()) {
551  OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
552  }
553 
554  auto iter = tree.cbeginLeaf();
555 
556  if (!iter) return;
557 
558  const AttributeSet& attributeSet = iter->attributeSet();
559 
560  // make the descriptor unique before we modify the group map
561 
562  makeDescriptorUnique(tree);
563  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
564 
565  // now drop the group
566 
567  descriptor->dropGroup(group);
568 
569  if (compact) {
570  compactGroups(tree);
571  }
572 }
573 
574 
575 ////////////////////////////////////////
576 
577 
578 template <typename PointDataTree>
579 inline void dropGroups( PointDataTree& tree,
580  const std::vector<Name>& groups)
581 {
582  for (const Name& name : groups) {
583  dropGroup(tree, name, /*compact=*/false);
584  }
585 
586  // compaction done once for efficiency
587 
588  compactGroups(tree);
589 }
590 
591 
592 ////////////////////////////////////////
593 
594 
595 template <typename PointDataTree>
596 inline void dropGroups( PointDataTree& tree)
597 {
598  using Descriptor = AttributeSet::Descriptor;
599 
601 
602  auto iter = tree.cbeginLeaf();
603 
604  if (!iter) return;
605 
606  const AttributeSet& attributeSet = iter->attributeSet();
607  GroupInfo groupInfo(attributeSet);
608 
609  // make the descriptor unique before we modify the group map
610 
611  makeDescriptorUnique(tree);
612  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
613 
614  descriptor->clearGroups();
615 
616  // find all indices for group attribute arrays
617 
618  std::vector<size_t> indices = groupInfo.populateGroupIndices();
619 
620  // drop these attributes arrays
621 
622  dropAttributes(tree, indices);
623 }
624 
625 
626 ////////////////////////////////////////
627 
628 
629 template <typename PointDataTree>
630 inline void compactGroups(PointDataTree& tree)
631 {
632  using Descriptor = AttributeSet::Descriptor;
633  using GroupIndex = Descriptor::GroupIndex;
634  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
635 
638 
639  auto iter = tree.cbeginLeaf();
640 
641  if (!iter) return;
642 
643  const AttributeSet& attributeSet = iter->attributeSet();
644  GroupInfo groupInfo(attributeSet);
645 
646  // early exit if not possible to compact
647 
648  if (!groupInfo.canCompactGroups()) return;
649 
650  // make the descriptor unique before we modify the group map
651 
652  makeDescriptorUnique(tree);
653  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
654 
655  // generate a list of group offsets and move them (one-by-one)
656  // TODO: improve this algorithm to move multiple groups per array at once
657  // though this is likely not that common a use case
658 
659  Name sourceName;
660  size_t sourceOffset, targetOffset;
661 
662  while (groupInfo.requiresMove(sourceName, sourceOffset, targetOffset)) {
663 
664  const GroupIndex sourceIndex = attributeSet.groupIndex(sourceOffset);
665  const GroupIndex targetIndex = attributeSet.groupIndex(targetOffset);
666 
667  CopyGroupOp<PointDataTree> copy(targetIndex, sourceIndex);
668  LeafManagerT leafManager(tree);
669  tbb::parallel_for(leafManager.leafRange(), copy);
670 
671  descriptor->setGroup(sourceName, targetOffset);
672  }
673 
674  // drop unused attribute arrays
675 
676  std::vector<size_t> indices = groupInfo.populateGroupIndices();
677 
678  const size_t totalAttributesToDrop = groupInfo.unusedGroups() / groupInfo.groupBits();
679 
680  assert(totalAttributesToDrop <= indices.size());
681 
682  std::vector<size_t> indicesToDrop(indices.end() - totalAttributesToDrop, indices.end());
683 
684  dropAttributes(tree, indicesToDrop);
685 }
686 
687 
688 ////////////////////////////////////////
689 
690 
691 template <typename PointDataTree, typename PointIndexTree>
692 inline void setGroup( PointDataTree& tree,
693  const PointIndexTree& indexTree,
694  const std::vector<short>& membership,
695  const Name& group,
696  const bool remove)
697 {
698  using Descriptor = AttributeSet::Descriptor;
699  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
701 
702  auto iter = tree.cbeginLeaf();
703  if (!iter) return;
704 
705  const AttributeSet& attributeSet = iter->attributeSet();
706  const Descriptor& descriptor = attributeSet.descriptor();
707 
708  if (!descriptor.hasGroup(group)) {
709  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
710  }
711 
712  {
713  // Check that that the largest index in the PointIndexTree is smaller than the size
714  // of the membership vector. The index tree will be used to lookup membership
715  // values. If the index tree was constructed with nan positions, this index will
716  // differ from the PointDataTree count
717 
718  using IndexTreeManager = tree::LeafManager<const PointIndexTree>;
719  IndexTreeManager leafManager(indexTree);
720 
721  const int64_t max = tbb::parallel_reduce(leafManager.leafRange(), -1,
722  [](const typename IndexTreeManager::LeafRange& range, int64_t value) -> int64_t {
723  for (auto leaf = range.begin(); leaf; ++leaf) {
724  auto it = std::max_element(leaf->indices().begin(), leaf->indices().end());
725  value = std::max(value, static_cast<int64_t>(*it));
726  }
727  return value;
728  },
729  [](const int64_t a, const int64_t b) {
730  return std::max(a, b);
731  }
732  );
733 
734  if (max != -1 && membership.size() <= static_cast<size_t>(max)) {
735  OPENVDB_THROW(IndexError, "Group membership vector size must be larger than "
736  " the maximum index within the provided index tree.");
737  }
738  }
739 
740  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
741  LeafManagerT leafManager(tree);
742 
743  // set membership
744 
745  if (remove) {
746  SetGroupFromIndexOp<PointDataTree, PointIndexTree, true>
747  set(indexTree, membership, index);
748  tbb::parallel_for(leafManager.leafRange(), set);
749  }
750  else {
751  SetGroupFromIndexOp<PointDataTree, PointIndexTree, false>
752  set(indexTree, membership, index);
753  tbb::parallel_for(leafManager.leafRange(), set);
754  }
755 }
756 
757 
758 ////////////////////////////////////////
759 
760 
761 template <typename PointDataTree>
762 inline void setGroup( PointDataTree& tree,
763  const Name& group,
764  const bool member)
765 {
766  using Descriptor = AttributeSet::Descriptor;
767  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
768 
770 
771  auto iter = tree.cbeginLeaf();
772 
773  if (!iter) return;
774 
775  const AttributeSet& attributeSet = iter->attributeSet();
776  const Descriptor& descriptor = attributeSet.descriptor();
777 
778  if (!descriptor.hasGroup(group)) {
779  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
780  }
781 
782  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
783  LeafManagerT leafManager(tree);
784 
785  // set membership based on member variable
786 
787  if (member) tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTree, true>(index));
788  else tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTree, false>(index));
789 }
790 
791 
792 ////////////////////////////////////////
793 
794 
795 template <typename PointDataTree, typename FilterT>
796 inline void setGroupByFilter( PointDataTree& tree,
797  const Name& group,
798  const FilterT& filter)
799 {
800  using Descriptor = AttributeSet::Descriptor;
801  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
802 
804 
805  auto iter = tree.cbeginLeaf();
806 
807  if (!iter) return;
808 
809  const AttributeSet& attributeSet = iter->attributeSet();
810  const Descriptor& descriptor = attributeSet.descriptor();
811 
812  if (!descriptor.hasGroup(group)) {
813  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
814  }
815 
816  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
817 
818  // set membership using filter
819 
820  SetGroupByFilterOp<PointDataTree, FilterT> set(index, filter);
821  LeafManagerT leafManager(tree);
822 
823  tbb::parallel_for(leafManager.leafRange(), set);
824 }
825 
826 
827 ////////////////////////////////////////
828 
829 
830 template <typename PointDataTree>
832  const Name& group,
833  const Index64 targetPoints,
834  const unsigned int seed = 0)
835 {
837 
838  RandomFilter filter(tree, targetPoints, seed);
839 
840  setGroupByFilter<PointDataTree, RandomFilter>(tree, group, filter);
841 }
842 
843 
844 ////////////////////////////////////////
845 
846 
847 template <typename PointDataTree>
849  const Name& group,
850  const float percentage = 10.0f,
851  const unsigned int seed = 0)
852 {
854 
855  const int currentPoints = static_cast<int>(pointCount(tree));
856  const int targetPoints = int(math::Round((percentage * float(currentPoints))/100.0f));
857 
858  RandomFilter filter(tree, targetPoints, seed);
859 
860  setGroupByFilter<PointDataTree, RandomFilter>(tree, group, filter);
861 }
862 
863 
864 ////////////////////////////////////////
865 
866 
867 } // namespace points
868 } // namespace OPENVDB_VERSION_NAME
869 } // namespace openvdb
870 
871 
872 #endif // OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
873 
874 // Copyright (c) DreamWorks Animation LLC
875 // All rights reserved. This software is distributed under the
876 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
CopyGroupOp(const GroupIndex &targetIndex, const GroupIndex &sourceIndex)
Definition: PointGroup.h:166
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
vint4 max(const vint4 &a, const vint4 &b)
Definition: simd.h:4703
SetGroupFromIndexOp(const PointIndexTree &indexTree, const MembershipArray &membership, const GroupIndex &index)
Definition: PointGroup.h:232
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
Definition: parallel.h:153
GLenum GLint * range
Definition: glew.h:3500
Definition: ImfName.h:53
Descriptor & descriptor()
Return a reference to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:125
Util::GroupIndex groupIndex(const Name &groupName) const
Return the group index from the name of the group.
GLuint const GLchar * name
Definition: glew.h:1814
void dropGroup(PointDataTree &tree, const Name &group, const bool compact=true)
Drops an existing group from the VDB tree.
Definition: PointGroup.h:546
LeafCIter cbeginLeaf() const
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1181
SetGroupByFilterOp(const GroupIndex &index, const FilterT &filter)
Definition: PointGroup.h:290
GLuint index
Definition: glew.h:1814
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:9477
static size_t groupBits()
Return the number of bits in a group (typically 8)
Definition: PointGroup.h:334
Copy a group attribute value from one group offset to another.
Definition: PointGroup.h:160
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:200
Index filters primarily designed to be used with a FilterIndexIter.
void setGroupByRandomTarget(PointDataTree &tree, const Name &group, const Index64 targetPoints, const unsigned int seed=0)
Definition: PointGroup.h:831
GLsizei GLuint * groups
Definition: glew.h:2744
Set membership on or off for the specified group.
Definition: PointGroup.h:194
void setGroupByRandomPercentage(PointDataTree &tree, const Name &group, const float percentage=10.0f, const unsigned int seed=0)
Definition: PointGroup.h:848
bool isGroup(const AttributeArray &array)
Convenience class with methods for analyzing group data.
Definition: PointGroup.h:325
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:171
void deleteMissingPointGroups(std::vector< std::string > &groups, const AttributeSet::Descriptor &descriptor)
Delete any group that is not present in the Descriptor.
Definition: PointGroup.h:442
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
Base class for storing attribute data.
Methods for counting points in VDB Point grids.
GLclampf f
Definition: glew.h:3499
bool requiresMove(Name &sourceName, size_t &sourceOffset, size_t &targetOffset) const
Definition: PointGroup.h:411
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:793
void appendGroups(PointDataTree &tree, const std::vector< Name > &groups)
Appends new empty groups to the VDB tree.
Definition: PointGroup.h:530
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:202
GLuint GLuint GLsizei GLenum const void * indices
Definition: glew.h:1253
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...
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
typename tree::LeafManager< PointDataTree > LeafManagerT
Definition: PointGroup.h:196
Index Iterators.
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
std::vector< size_t > populateGroupIndices() const
Return vector of indices correlating to the group attribute arrays.
Definition: PointGroup.h:393
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:115
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:523
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:294
Point attribute manipulation in a VDB Point Grid.
GLdouble GLdouble GLdouble b
Definition: glew.h:9122
typename tree::LeafManager< PointDataTreeType > LeafManagerT
Definition: PointGroup.h:162
size_t nextUnusedOffset() const
Return the next empty group slot.
Definition: PointGroup.h:367
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
Set of Attribute Arrays which tracks metadata about each array.
SetGroupOp(const AttributeSet::Descriptor::GroupIndex &index)
Definition: PointGroup.h:199
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:239
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3446
OIIO_API bool copy(string_view from, string_view to, std::string &err)
void dropGroups(PointDataTree &tree, const std::vector< Name > &groups)
Drops existing groups from the VDB tree, the tree is compacted after dropping.
Definition: PointGroup.h:579
void setGroup(PointDataTree &tree, const PointIndexTree &indexTree, const std::vector< short > &membership, const Name &group, const bool remove=false)
Sets group membership from a PointIndexTree-ordered vector.
Definition: PointGroup.h:692
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
void appendGroup(PointDataTree &tree, const Name &group)
Appends a new empty group to the VDB tree.
GLenum array
Definition: glew.h:9066
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointDataLeafNode< PointDataIndex32, 3 >, 4 >, 5 >>> PointDataTree
Point index tree configured to match the default VDB configurations.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:146
GLsizei const GLfloat * value
Definition: glew.h:1849
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
bool canCompactGroups() const
Return true if there are sufficient empty slots to allow compacting.
Definition: PointGroup.h:359
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:131
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointIndexLeafNode< PointIndex32, 3 >, 4 >, 5 >>> PointIndexTree
Point index tree configured to match the default OpenVDB tree configuration.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
void compactGroups(PointDataTree &tree)
Compacts existing groups of a VDB Tree to use less memory if possible.
Definition: PointGroup.h:630
GLboolean GLuint group
Definition: glew.h:2745
GLintptr offset
Definition: glew.h:1682
void setGroupByFilter(PointDataTree &tree, const Name &group, const FilterT &filter)
Sets group membership based on a provided filter.
Definition: PointGroup.h:796