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) 2012-2018 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 <algorithm>
50 #include <random>
51 #include <string>
52 #include <vector>
53 
54 namespace openvdb {
56 namespace OPENVDB_VERSION_NAME {
57 namespace points {
58 
59 /// @brief Delete any group that is not present in the Descriptor.
60 ///
61 /// @param groups the vector of group names.
62 /// @param descriptor the descriptor that holds the group map.
63 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
64  const AttributeSet::Descriptor& descriptor);
65 
66 /// @brief Appends a new empty group to the VDB tree.
67 ///
68 /// @param tree the PointDataTree to be appended to.
69 /// @param group name of the new group.
70 template <typename PointDataTree>
71 inline void appendGroup(PointDataTree& tree,
72  const Name& group);
73 
74 /// @brief Appends new empty groups to the VDB tree.
75 ///
76 /// @param tree the PointDataTree to be appended to.
77 /// @param groups names of the new groups.
78 template <typename PointDataTree>
79 inline void appendGroups(PointDataTree& tree,
80  const std::vector<Name>& groups);
81 
82 /// @brief Drops an existing group from the VDB tree.
83 ///
84 /// @param tree the PointDataTree to be dropped from.
85 /// @param group name of the group.
86 /// @param compact compact attributes if possible to reduce memory - if dropping
87 /// more than one group, compacting once at the end will be faster
88 template <typename PointDataTree>
89 inline void dropGroup( PointDataTree& tree,
90  const Name& group,
91  const bool compact = true);
92 
93 /// @brief Drops existing groups from the VDB tree, the tree is compacted after dropping.
94 ///
95 /// @param tree the PointDataTree to be dropped from.
96 /// @param groups names of the groups.
97 template <typename PointDataTree>
98 inline void dropGroups( PointDataTree& tree,
99  const std::vector<Name>& groups);
100 
101 /// @brief Drops all existing groups from the VDB tree, the tree is compacted after dropping.
102 ///
103 /// @param tree the PointDataTree to be dropped from.
104 template <typename PointDataTree>
105 inline void dropGroups( PointDataTree& tree);
106 
107 /// @brief Compacts existing groups of a VDB Tree to use less memory if possible.
108 ///
109 /// @param tree the PointDataTree to be compacted.
110 template <typename PointDataTree>
111 inline void compactGroups(PointDataTree& tree);
112 
113 /// @brief Sets group membership from a PointIndexTree-ordered vector.
114 ///
115 /// @param tree the PointDataTree.
116 /// @param indexTree the PointIndexTree.
117 /// @param membership @c 1 if the point is in the group, 0 otherwise.
118 /// @param group the name of the group.
119 /// @param remove if @c true also perform removal of points from the group.
120 ///
121 /// @note vector<bool> is not thread-safe on concurrent write, so use vector<short> instead
122 template <typename PointDataTree, typename PointIndexTree>
123 inline void setGroup( PointDataTree& tree,
124  const PointIndexTree& indexTree,
125  const std::vector<short>& membership,
126  const Name& group,
127  const bool remove = false);
128 
129 /// @brief Sets membership for the specified group for all points (on/off).
130 ///
131 /// @param tree the PointDataTree.
132 /// @param group the name of the group.
133 /// @param member true / false for membership of the group.
134 template <typename PointDataTree>
135 inline void setGroup( PointDataTree& tree,
136  const Name& group,
137  const bool member = true);
138 
139 /// @brief Sets group membership based on a provided filter.
140 ///
141 /// @param tree the PointDataTree.
142 /// @param group the name of the group.
143 /// @param filter filter data that is used to create a per-leaf filter
144 template <typename PointDataTree, typename FilterT>
145 inline void setGroupByFilter( PointDataTree& tree,
146  const Name& group,
147  const FilterT& filter);
148 
149 
150 ////////////////////////////////////////
151 
152 
153 namespace point_group_internal {
154 
155 
156 /// Copy a group attribute value from one group offset to another
157 template<typename PointDataTreeType>
158 struct CopyGroupOp {
159 
161  using LeafRangeT = typename LeafManagerT::LeafRange;
162  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
163 
164  CopyGroupOp(const GroupIndex& targetIndex,
165  const GroupIndex& sourceIndex)
166  : mTargetIndex(targetIndex)
167  , mSourceIndex(sourceIndex) { }
168 
169  void operator()(const typename LeafManagerT::LeafRange& range) const {
170 
171  for (auto leaf = range.begin(); leaf; ++leaf) {
172 
173  GroupHandle sourceGroup = leaf->groupHandle(mSourceIndex);
174  GroupWriteHandle targetGroup = leaf->groupWriteHandle(mTargetIndex);
175 
176  for (auto iter = leaf->beginIndexAll(); iter; ++iter) {
177  const bool groupOn = sourceGroup.get(*iter);
178  targetGroup.set(*iter, groupOn);
179  }
180  }
181  }
182 
183  //////////
184 
187 };
188 
189 
190 /// Set membership on or off for the specified group
191 template <typename PointDataTree, bool Member>
193 {
195  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
196 
197  SetGroupOp(const AttributeSet::Descriptor::GroupIndex& index)
198  : mIndex(index) { }
199 
200  void operator()(const typename LeafManagerT::LeafRange& range) const
201  {
202  for (auto leaf = range.begin(); leaf; ++leaf) {
203 
204  // obtain the group attribute array
205 
206  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
207 
208  // set the group value
209 
210  group.collapse(Member);
211  }
212  }
213 
214  //////////
215 
217 }; // struct SetGroupOp
218 
219 
220 template <typename PointDataTree, typename PointIndexTree, bool Remove>
222 {
224  using LeafRangeT = typename LeafManagerT::LeafRange;
225  using PointIndexLeafNode = typename PointIndexTree::LeafNodeType;
227  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
228  using MembershipArray = std::vector<short>;
229 
231  const MembershipArray& membership,
232  const GroupIndex& index)
233  : mIndexTree(indexTree)
234  , mMembership(membership)
235  , mIndex(index) { }
236 
237  void operator()(const typename LeafManagerT::LeafRange& range) const
238  {
239  for (auto leaf = range.begin(); leaf; ++leaf) {
240 
241  // obtain the PointIndexLeafNode (using the origin of the current leaf)
242 
243  const PointIndexLeafNode* pointIndexLeaf = mIndexTree.probeConstLeaf(leaf->origin());
244 
245  if (!pointIndexLeaf) continue;
246 
247  // obtain the group attribute array
248 
249  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
250 
251  // initialise the attribute storage
252 
253  Index64 index = 0;
254 
255  const IndexArray& indices = pointIndexLeaf->indices();
256 
257  for (const Index64 i: indices) {
258  if (Remove) {
259  group.set(static_cast<Index>(index), mMembership[i]);
260  } else if (mMembership[i] == short(1)) {
261  group.set(static_cast<Index>(index), short(1));
262  }
263  index++;
264  }
265 
266  // attempt to compact the array
267 
268  group.compact();
269  }
270  }
271 
272  //////////
273 
277 }; // struct SetGroupFromIndexOp
278 
279 
280 template <typename PointDataTree, typename FilterT, typename IterT = typename PointDataTree::LeafNodeType::ValueAllCIter>
282 {
284  using LeafRangeT = typename LeafManagerT::LeafRange;
286  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
287 
288  SetGroupByFilterOp( const GroupIndex& index, const FilterT& filter)
289  : mIndex(index)
290  , mFilter(filter) { }
291 
292  void operator()(const typename LeafManagerT::LeafRange& range) const
293  {
294  for (auto leaf = range.begin(); leaf; ++leaf) {
295 
296  // obtain the group attribute array
297 
298  GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
299 
300  auto iter = leaf->template beginIndex<IterT, FilterT>(mFilter);
301 
302  for (; iter; ++iter) {
303  group.set(*iter, true);
304  }
305 
306  // attempt to compact the array
307 
308  group.compact();
309  }
310  }
311 
312  //////////
313 
315  const FilterT& mFilter; // beginIndex takes a copy of mFilter
316 }; // struct SetGroupByFilterOp
317 
318 
319 ////////////////////////////////////////
320 
321 
322 /// Convenience class with methods for analyzing group data
324 {
325 public:
327 
328  GroupInfo(const AttributeSet& attributeSet)
329  : mAttributeSet(attributeSet) { }
330 
331  /// Return the number of bits in a group (typically 8)
332  static size_t groupBits() { return sizeof(GroupType) * CHAR_BIT; }
333 
334  /// Return the number of empty group slots which correlates to the number of groups
335  /// that can be stored without increasing the number of group attribute arrays
336  size_t unusedGroups() const
337  {
338  const Descriptor& descriptor = mAttributeSet.descriptor();
339 
340  // compute total slots (one slot per bit of the group attributes)
341 
342  const size_t groupAttributes = descriptor.count(GroupAttributeArray::attributeType());
343 
344  if (groupAttributes == 0) return 0;
345 
346  const size_t totalSlots = groupAttributes * this->groupBits();
347 
348  // compute slots in use
349 
350  const AttributeSet::Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
351  const size_t usedSlots = groupMap.size();
352 
353  return totalSlots - usedSlots;
354  }
355 
356  /// Return @c true if there are sufficient empty slots to allow compacting
357  bool canCompactGroups() const
358  {
359  // can compact if more unused groups than in one group attribute array
360 
361  return this->unusedGroups() >= this->groupBits();
362  }
363 
364  /// Return the next empty group slot
365  size_t nextUnusedOffset() const
366  {
367  const Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
368 
369  // build a list of group indices
370 
371  std::vector<size_t> indices;
372  indices.reserve(groupMap.size());
373  for (const auto& namePos : groupMap) {
374  indices.push_back(namePos.second);
375  }
376 
377  std::sort(indices.begin(), indices.end());
378 
379  // return first index not present
380 
381  size_t offset = 0;
382  for (const size_t& index : indices) {
383  if (index != offset) break;
384  offset++;
385  }
386 
387  return offset;
388  }
389 
390  /// Return vector of indices correlating to the group attribute arrays
391  std::vector<size_t> populateGroupIndices() const
392  {
393  std::vector<size_t> indices;
394 
395  const Descriptor::NameToPosMap& map = mAttributeSet.descriptor().map();
396 
397  for (const auto& namePos : map) {
398  const AttributeArray* array = mAttributeSet.getConst(namePos.first);
399  if (isGroup(*array)) {
400  indices.push_back(namePos.second);
401  }
402  }
403 
404  return indices;
405  }
406 
407  /// Determine if a move is required to efficiently compact the data and store the
408  /// source name, offset and the target offset in the input parameters
409  bool requiresMove(Name& sourceName, size_t& sourceOffset, size_t& targetOffset) const {
410 
411  targetOffset = this->nextUnusedOffset();
412 
413  const Descriptor::NameToPosMap& groupMap = mAttributeSet.descriptor().groupMap();
414 
415  for (const auto& namePos : groupMap) {
416 
417  // move only required if source comes after the target
418 
419  if (namePos.second >= targetOffset) {
420  sourceName = namePos.first;
421  sourceOffset = namePos.second;
422  return true;
423  }
424  }
425 
426  return false;
427  }
428 
429 private:
430  const AttributeSet& mAttributeSet;
431 }; // class GroupInfo
432 
433 
434 } // namespace point_group_internal
435 
436 
437 ////////////////////////////////////////
438 
439 
440 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
441  const AttributeSet::Descriptor& descriptor)
442 {
443  for (auto it = groups.begin(); it != groups.end();) {
444  if (!descriptor.hasGroup(*it)) it = groups.erase(it);
445  else ++it;
446  }
447 }
448 
449 
450 ////////////////////////////////////////
451 
452 
453 template <typename PointDataTree>
454 inline void appendGroup(PointDataTree& tree, const Name& group)
455 {
456  using Descriptor = AttributeSet::Descriptor;
457  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
458 
461 
462  if (group.empty()) {
463  OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
464  }
465 
466  auto iter = tree.cbeginLeaf();
467 
468  if (!iter) return;
469 
470  const AttributeSet& attributeSet = iter->attributeSet();
471  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
472  GroupInfo groupInfo(attributeSet);
473 
474  // don't add if group already exists
475 
476  if (descriptor->hasGroup(group)) return;
477 
478  const bool hasUnusedGroup = groupInfo.unusedGroups() > 0;
479 
480  // add a new group attribute if there are no unused groups
481 
482  if (!hasUnusedGroup) {
483 
484  // find a new internal group name
485 
486  const Name groupName = descriptor->uniqueName("__group");
487 
488  descriptor = descriptor->duplicateAppend(groupName, GroupAttributeArray::attributeType());
489 
490  const size_t pos = descriptor->find(groupName);
491 
492  // insert new group attribute
493 
494  AppendAttributeOp<PointDataTree> append(descriptor, pos);
495  LeafManagerT leafManager(tree);
496  tbb::parallel_for(leafManager.leafRange(), append);
497  }
498  else {
499  // make the descriptor unique before we modify the group map
500 
501  makeDescriptorUnique(tree);
502  descriptor = attributeSet.descriptorPtr();
503  }
504 
505  // ensure that there are now available groups
506 
507  assert(groupInfo.unusedGroups() > 0);
508 
509  // find next unused offset
510 
511  const size_t offset = groupInfo.nextUnusedOffset();
512 
513  // add the group mapping to the descriptor
514 
515  descriptor->setGroup(group, offset);
516 
517  // if there was an unused group then we did not need to append a new attribute, so
518  // we must manually clear membership in the new group as its bits may have been
519  // previously set
520 
521  if (hasUnusedGroup) setGroup(tree, group, false);
522 }
523 
524 
525 ////////////////////////////////////////
526 
527 
528 template <typename PointDataTree>
529 inline void appendGroups(PointDataTree& tree,
530  const std::vector<Name>& groups)
531 {
532  // TODO: could be more efficient by appending multiple groups at once
533  // instead of one-by-one, however this is likely not that common a use case
534 
535  for (const Name& name : groups) {
536  appendGroup(tree, name);
537  }
538 }
539 
540 
541 ////////////////////////////////////////
542 
543 
544 template <typename PointDataTree>
545 inline void dropGroup(PointDataTree& tree, const Name& group, const bool compact)
546 {
547  using Descriptor = AttributeSet::Descriptor;
548 
549  if (group.empty()) {
550  OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
551  }
552 
553  auto iter = tree.cbeginLeaf();
554 
555  if (!iter) return;
556 
557  const AttributeSet& attributeSet = iter->attributeSet();
558 
559  // make the descriptor unique before we modify the group map
560 
561  makeDescriptorUnique(tree);
562  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
563 
564  // now drop the group
565 
566  descriptor->dropGroup(group);
567 
568  if (compact) {
569  compactGroups(tree);
570  }
571 }
572 
573 
574 ////////////////////////////////////////
575 
576 
577 template <typename PointDataTree>
578 inline void dropGroups( PointDataTree& tree,
579  const std::vector<Name>& groups)
580 {
581  for (const Name& name : groups) {
582  dropGroup(tree, name, /*compact=*/false);
583  }
584 
585  // compaction done once for efficiency
586 
587  compactGroups(tree);
588 }
589 
590 
591 ////////////////////////////////////////
592 
593 
594 template <typename PointDataTree>
595 inline void dropGroups( PointDataTree& tree)
596 {
597  using Descriptor = AttributeSet::Descriptor;
598 
600 
601  auto iter = tree.cbeginLeaf();
602 
603  if (!iter) return;
604 
605  const AttributeSet& attributeSet = iter->attributeSet();
606  GroupInfo groupInfo(attributeSet);
607 
608  // make the descriptor unique before we modify the group map
609 
610  makeDescriptorUnique(tree);
611  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
612 
613  descriptor->clearGroups();
614 
615  // find all indices for group attribute arrays
616 
617  std::vector<size_t> indices = groupInfo.populateGroupIndices();
618 
619  // drop these attributes arrays
620 
621  dropAttributes(tree, indices);
622 }
623 
624 
625 ////////////////////////////////////////
626 
627 
628 template <typename PointDataTree>
629 inline void compactGroups(PointDataTree& tree)
630 {
631  using Descriptor = AttributeSet::Descriptor;
632  using GroupIndex = Descriptor::GroupIndex;
633  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
634 
637 
638  auto iter = tree.cbeginLeaf();
639 
640  if (!iter) return;
641 
642  const AttributeSet& attributeSet = iter->attributeSet();
643  GroupInfo groupInfo(attributeSet);
644 
645  // early exit if not possible to compact
646 
647  if (!groupInfo.canCompactGroups()) return;
648 
649  // make the descriptor unique before we modify the group map
650 
651  makeDescriptorUnique(tree);
652  Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
653 
654  // generate a list of group offsets and move them (one-by-one)
655  // TODO: improve this algorithm to move multiple groups per array at once
656  // though this is likely not that common a use case
657 
658  Name sourceName;
659  size_t sourceOffset, targetOffset;
660 
661  while (groupInfo.requiresMove(sourceName, sourceOffset, targetOffset)) {
662 
663  const GroupIndex sourceIndex = attributeSet.groupIndex(sourceOffset);
664  const GroupIndex targetIndex = attributeSet.groupIndex(targetOffset);
665 
666  CopyGroupOp<PointDataTree> copy(targetIndex, sourceIndex);
667  LeafManagerT leafManager(tree);
668  tbb::parallel_for(leafManager.leafRange(), copy);
669 
670  descriptor->setGroup(sourceName, targetOffset);
671  }
672 
673  // drop unused attribute arrays
674 
675  std::vector<size_t> indices = groupInfo.populateGroupIndices();
676 
677  const size_t totalAttributesToDrop = groupInfo.unusedGroups() / groupInfo.groupBits();
678 
679  assert(totalAttributesToDrop <= indices.size());
680 
681  std::vector<size_t> indicesToDrop(indices.end() - totalAttributesToDrop, indices.end());
682 
683  dropAttributes(tree, indicesToDrop);
684 }
685 
686 
687 ////////////////////////////////////////
688 
689 
690 template <typename PointDataTree, typename PointIndexTree>
691 inline void setGroup( PointDataTree& tree,
692  const PointIndexTree& indexTree,
693  const std::vector<short>& membership,
694  const Name& group,
695  const bool remove)
696 {
697  using Descriptor = AttributeSet::Descriptor;
698  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
699 
700  if (membership.size() != pointCount(tree)) {
701  OPENVDB_THROW(LookupError, "Membership vector size must match number of points.");
702  }
703 
705 
706  auto iter = tree.cbeginLeaf();
707 
708  if (!iter) return;
709 
710  const AttributeSet& attributeSet = iter->attributeSet();
711  const Descriptor& descriptor = attributeSet.descriptor();
712 
713  if (!descriptor.hasGroup(group)) {
714  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
715  }
716 
717  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
718  LeafManagerT leafManager(tree);
719 
720  // set membership
721 
722  if (remove) {
723  SetGroupFromIndexOp<PointDataTree,
724  PointIndexTree, false> set(indexTree, membership, index);
725  tbb::parallel_for(leafManager.leafRange(), set);
726  }
727  else {
728  SetGroupFromIndexOp<PointDataTree,
729  PointIndexTree, true> set(indexTree, membership, index);
730  tbb::parallel_for(leafManager.leafRange(), set);
731  }
732 }
733 
734 
735 ////////////////////////////////////////
736 
737 
738 template <typename PointDataTree>
739 inline void setGroup( PointDataTree& tree,
740  const Name& group,
741  const bool member)
742 {
743  using Descriptor = AttributeSet::Descriptor;
744  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
745 
747 
748  auto iter = tree.cbeginLeaf();
749 
750  if (!iter) return;
751 
752  const AttributeSet& attributeSet = iter->attributeSet();
753  const Descriptor& descriptor = attributeSet.descriptor();
754 
755  if (!descriptor.hasGroup(group)) {
756  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
757  }
758 
759  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
760  LeafManagerT leafManager(tree);
761 
762  // set membership based on member variable
763 
764  if (member) tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTree, true>(index));
765  else tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTree, false>(index));
766 }
767 
768 
769 ////////////////////////////////////////
770 
771 
772 template <typename PointDataTree, typename FilterT>
773 inline void setGroupByFilter( PointDataTree& tree,
774  const Name& group,
775  const FilterT& filter)
776 {
777  using Descriptor = AttributeSet::Descriptor;
778  using LeafManagerT = typename tree::template LeafManager<PointDataTree>;
779 
781 
782  auto iter = tree.cbeginLeaf();
783 
784  if (!iter) return;
785 
786  const AttributeSet& attributeSet = iter->attributeSet();
787  const Descriptor& descriptor = attributeSet.descriptor();
788 
789  if (!descriptor.hasGroup(group)) {
790  OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
791  }
792 
793  const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
794 
795  // set membership using filter
796 
797  SetGroupByFilterOp<PointDataTree, FilterT> set(index, filter);
798  LeafManagerT leafManager(tree);
799 
800  tbb::parallel_for(leafManager.leafRange(), set);
801 }
802 
803 
804 ////////////////////////////////////////
805 
806 
807 template <typename PointDataTree>
809  const Name& group,
810  const Index64 targetPoints,
811  const unsigned int seed = 0)
812 {
814 
815  RandomFilter filter(tree, targetPoints, seed);
816 
817  setGroupByFilter<PointDataTree, RandomFilter>(tree, group, filter);
818 }
819 
820 
821 ////////////////////////////////////////
822 
823 
824 template <typename PointDataTree>
826  const Name& group,
827  const float percentage = 10.0f,
828  const unsigned int seed = 0)
829 {
831 
832  const int currentPoints = static_cast<int>(pointCount(tree));
833  const int targetPoints = int(math::Round((percentage * currentPoints)/100.0f));
834 
835  RandomFilter filter(tree, targetPoints, seed);
836 
837  setGroupByFilter<PointDataTree, RandomFilter>(tree, group, filter);
838 }
839 
840 
841 ////////////////////////////////////////
842 
843 
844 } // namespace points
845 } // namespace OPENVDB_VERSION_NAME
846 } // namespace openvdb
847 
848 
849 #endif // OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
850 
851 // Copyright (c) 2012-2018 DreamWorks Animation LLC
852 // All rights reserved. This software is distributed under the
853 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
CopyGroupOp(const GroupIndex &targetIndex, const GroupIndex &sourceIndex)
Definition: PointGroup.h:164
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
SetGroupFromIndexOp(const PointIndexTree &indexTree, const MembershipArray &membership, const GroupIndex &index)
Definition: PointGroup.h:230
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:121
Util::GroupIndex groupIndex(const Name &groupName) const
Return the group index from the name of the group.
GLsizei GLenum const void * indices
Definition: glcorearb.h:405
GLenum GLint * range
Definition: glcorearb.h:1924
void dropGroup(PointDataTree &tree, const Name &group, const bool compact=true)
Drops an existing group from the VDB tree.
Definition: PointGroup.h:545
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:288
static size_t groupBits()
Return the number of bits in a group (typically 8)
Definition: PointGroup.h:332
Copy a group attribute value from one group offset to another.
Definition: PointGroup.h:158
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
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:808
Set membership on or off for the specified group.
Definition: PointGroup.h:192
png_uint_32 i
Definition: png.h:2877
void setGroupByRandomPercentage(PointDataTree &tree, const Name &group, const float percentage=10.0f, const unsigned int seed=0)
Definition: PointGroup.h:825
bool isGroup(const AttributeArray &array)
Convenience class with methods for analyzing group data.
Definition: PointGroup.h:323
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:169
void deleteMissingPointGroups(std::vector< std::string > &groups, const AttributeSet::Descriptor &descriptor)
Delete any group that is not present in the Descriptor.
Definition: PointGroup.h:440
GLfloat f
Definition: glcorearb.h:1925
Base class for storing attribute data.
Methods for counting points in VDB Point grids.
bool requiresMove(Name &sourceName, size_t &sourceOffset, size_t &targetOffset) const
Definition: PointGroup.h:409
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:773
void appendGroups(PointDataTree &tree, const std::vector< Name > &groups)
Appends new empty groups to the VDB tree.
Definition: PointGroup.h:529
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:200
static const NamePair & attributeType()
Return the name of this attribute's type (includes codec)
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...
bool collapse(bool on)
Set membership for the whole array and attempt to collapse.
GLintptr offset
Definition: glcorearb.h:664
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
void dropAttributes(PointDataTreeT &tree, const std::vector< size_t > &indices)
Drops attributes from the VDB tree.
typename tree::LeafManager< PointDataTree > LeafManagerT
Definition: PointGroup.h:194
Index Iterators.
std::vector< size_t > populateGroupIndices() const
Return vector of indices correlating to the group attribute arrays.
Definition: PointGroup.h:391
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
GLuint const GLchar * name
Definition: glcorearb.h:785
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:292
Point attribute manipulation in a VDB Point Grid.
typename tree::LeafManager< PointDataTreeType > LeafManagerT
Definition: PointGroup.h:160
size_t nextUnusedOffset() const
Return the next empty group slot.
Definition: PointGroup.h:365
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
typedef int
Definition: png.h:1175
Set of Attribute Arrays which tracks metadata about each array.
SetGroupOp(const AttributeSet::Descriptor::GroupIndex &index)
Definition: PointGroup.h:197
GLuint index
Definition: glcorearb.h:785
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointGroup.h:237
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:578
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:691
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.
Definition: PointGroup.h:454
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:135
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:357
DescriptorPtr descriptorPtr() const
Return a pointer to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:127
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:629
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296
void setGroupByFilter(PointDataTree &tree, const Name &group, const FilterT &filter)
Sets group membership based on a provided filter.
Definition: PointGroup.h:773