HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IndexFilter.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 /// @file points/IndexFilter.h
32 ///
33 /// @author Dan Bailey
34 ///
35 /// @brief Index filters primarily designed to be used with a FilterIndexIter.
36 ///
37 /// Filters must adhere to the interface described in the example below:
38 /// @code
39 /// struct MyFilter
40 /// {
41 /// // Return true when the filter has been initialized for first use
42 /// bool initialized() { return true; }
43 ///
44 /// // Return index::ALL if all points are valid, index::NONE if no points are valid
45 /// // and index::PARTIAL if some points are valid
46 /// index::State state() { return index::PARTIAL; }
47 ///
48 /// // Return index::ALL if all points in this leaf are valid, index::NONE if no points
49 /// // in this leaf are valid and index::PARTIAL if some points in this leaf are valid
50 /// template <typename LeafT>
51 /// index::State state(const LeafT&) { return index::PARTIAL; }
52 ///
53 /// // Resets the filter to refer to the specified leaf, all subsequent valid() calls
54 /// // will be relative to this leaf until reset() is called with a different leaf.
55 /// // Although a required method, many filters will provide an empty implementation if
56 /// // there is no leaf-specific logic needed.
57 /// template <typename LeafT> void reset(const LeafT&) { }
58 ///
59 /// // Returns true if the filter is valid for the supplied iterator
60 /// template <typename IterT> bool valid(const IterT&) { return true; }
61 /// };
62 /// @endcode
63 
64 #ifndef OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
65 #define OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
66 
67 #include <openvdb/version.h>
68 #include <openvdb/Types.h>
69 
70 #include <openvdb/math/Transform.h>
72 
73 #include "IndexIterator.h"
74 #include "AttributeArray.h"
75 #include "AttributeGroup.h"
76 #include "AttributeSet.h"
77 
78 #include <hboost/ptr_container/ptr_vector.hpp>
79 
80 #include <random> // std::mt19937
81 #include <numeric> // std::iota
82 
83 
84 class TestIndexFilter;
85 
86 namespace openvdb {
88 namespace OPENVDB_VERSION_NAME {
89 namespace points {
90 
91 
92 ////////////////////////////////////////
93 
94 
95 
96 namespace index_filter_internal {
97 
98 
99 // generate a random subset of n indices from the range [0:m]
100 template <typename RandGenT, typename IntType>
101 std::vector<IntType>
102 generateRandomSubset(const unsigned int seed, const IntType n, const IntType m)
103 {
104  if (n <= 0) return std::vector<IntType>();
105 
106  // fill vector with ascending indices
107  std::vector<IntType> values(m);
108  std::iota(values.begin(), values.end(), 0);
109  if (n >= m) return values;
110 
111  // shuffle indices using random generator
112 
113  RandGenT randGen(seed);
114  std::shuffle(values.begin(), values.end(), randGen);
115 
116  // resize the container to n elements
117  values.resize(n);
118 
119  // sort the subset of the indices vector that will be used
120  std::sort(values.begin(), values.end());
121 
122  return values;
123 }
124 
125 
126 } // namespace index_filter_internal
127 
128 
129 /// Index filtering on active / inactive state of host voxel
130 template <bool On>
132 {
133 public:
134  static bool initialized() { return true; }
135  static index::State state() { return index::PARTIAL; }
136  template <typename LeafT>
137  static index::State state(const LeafT& leaf)
138  {
139  if (leaf.isDense()) return On ? index::ALL : index::NONE;
140  else if (leaf.isEmpty()) return On ? index::NONE : index::ALL;
141  return index::PARTIAL;
142  }
143 
144  template <typename LeafT>
145  void reset(const LeafT&) { }
146 
147  template <typename IterT>
148  bool valid(const IterT& iter) const
149  {
150  const bool valueOn = iter.isValueOn();
151  return On ? valueOn : !valueOn;
152  }
153 };
154 
155 
158 
159 
160 /// Index filtering on multiple group membership for inclusion and exclusion
161 ///
162 /// @note include filters are applied first, then exclude filters
164 {
165 public:
166  using NameVector = std::vector<Name>;
167  using IndexVector = std::vector<AttributeSet::Descriptor::GroupIndex>;
168  using HandleVector = std::vector<GroupHandle>;
169 
170 private:
171  static IndexVector namesToIndices(const AttributeSet& attributeSet, const NameVector& names) {
173  for (const auto& name : names) {
174  try {
175  indices.emplace_back(attributeSet.groupIndex(name));
176  } catch (LookupError&) {
177  // silently drop group names that don't exist
178  }
179  }
180  return indices;
181  }
182 
183 public:
184  MultiGroupFilter( const NameVector& include,
185  const NameVector& exclude,
186  const AttributeSet& attributeSet)
187  : mInclude(MultiGroupFilter::namesToIndices(attributeSet, include))
188  , mExclude(MultiGroupFilter::namesToIndices(attributeSet, exclude)) { }
189 
190  MultiGroupFilter( const IndexVector& include,
191  const IndexVector& exclude)
192  : mInclude(include)
193  , mExclude(exclude) { }
194 
196  : mInclude(filter.mInclude)
197  , mExclude(filter.mExclude)
198  , mIncludeHandles(filter.mIncludeHandles)
199  , mExcludeHandles(filter.mExcludeHandles)
200  , mInitialized(filter.mInitialized) { }
201 
202  inline bool initialized() const { return mInitialized; }
203 
204  inline index::State state() const
205  {
206  return (mInclude.empty() && mExclude.empty()) ? index::ALL : index::PARTIAL;
207  }
208 
209  template <typename LeafT>
210  static index::State state(const LeafT&) { return index::PARTIAL; }
211 
212  template <typename LeafT>
213  void reset(const LeafT& leaf) {
214  mIncludeHandles.clear();
215  mExcludeHandles.clear();
216  for (const auto& i : mInclude) {
217  mIncludeHandles.emplace_back(leaf.groupHandle(i));
218  }
219  for (const auto& i : mExclude) {
220  mExcludeHandles.emplace_back(leaf.groupHandle(i));
221  }
222  mInitialized = true;
223  }
224 
225  template <typename IterT>
226  bool valid(const IterT& iter) const {
227  assert(mInitialized);
228  // accept no include filters as valid
229  bool includeValid = mIncludeHandles.empty();
230  for (const GroupHandle& handle : mIncludeHandles) {
231  if (handle.getUnsafe(*iter)) {
232  includeValid = true;
233  break;
234  }
235  }
236  if (!includeValid) return false;
237  for (const GroupHandle& handle : mExcludeHandles) {
238  if (handle.getUnsafe(*iter)) return false;
239  }
240  return true;
241  }
242 
243 private:
244  IndexVector mInclude;
245  IndexVector mExclude;
246  HandleVector mIncludeHandles;
247  HandleVector mExcludeHandles;
248  bool mInitialized = false;
249 }; // class MultiGroupFilter
250 
251 
252 // Random index filtering per leaf
253 template <typename PointDataTreeT, typename RandGenT>
255 {
256 public:
257  using SeedCountPair = std::pair<Index, Index>;
258  using LeafMap = std::map<openvdb::Coord, SeedCountPair>;
259 
260  RandomLeafFilter( const PointDataTreeT& tree,
261  const Index64 targetPoints,
262  const unsigned int seed = 0) {
263  Index64 currentPoints = 0;
264  for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
265  currentPoints += iter->pointCount();
266  }
267 
268  const float factor = targetPoints > currentPoints ? 1.0f : float(targetPoints) / float(currentPoints);
269 
270  std::mt19937 generator(seed);
271  std::uniform_int_distribution<unsigned int> dist(0, std::numeric_limits<unsigned int>::max() - 1);
272 
273  Index32 leafCounter = 0;
274  float totalPointsFloat = 0.0f;
275  int totalPoints = 0;
276  for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
277  // for the last leaf - use the remaining points to reach the target points
278  if (leafCounter + 1 == tree.leafCount()) {
279  const int leafPoints = static_cast<int>(targetPoints) - totalPoints;
280  mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints);
281  break;
282  }
283  totalPointsFloat += factor * iter->pointCount();
284  const auto leafPoints = static_cast<int>(math::Floor(totalPointsFloat));
285  totalPointsFloat -= static_cast<float>(leafPoints);
286  totalPoints += leafPoints;
287 
288  mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints);
289 
290  leafCounter++;
291  }
292  }
293 
294  inline bool initialized() const { return mNextIndex == -1; }
295 
296  static index::State state() { return index::PARTIAL; }
297  template <typename LeafT>
298  static index::State state(const LeafT&) { return index::PARTIAL; }
299 
300  template <typename LeafT>
301  void reset(const LeafT& leaf) {
303 
304  auto it = mLeafMap.find(leaf.origin());
305  if (it == mLeafMap.end()) {
306  OPENVDB_THROW(openvdb::KeyError,
307  "Cannot find leaf origin in map for random filter - " << leaf.origin());
308  }
309 
310  const SeedCountPair& value = it->second;
311  const unsigned int seed = static_cast<unsigned int>(value.first);
312  const auto total = static_cast<Index>(leaf.pointCount());
313  mCount = std::min(value.second, total);
314 
315  mIndices = generateRandomSubset<RandGenT, int>(seed, mCount, total);
316 
317  mSubsetOffset = -1;
318  mNextIndex = -1;
319  }
320 
321  inline void next() const {
322  mSubsetOffset++;
323  mNextIndex = mSubsetOffset >= mCount ?
325  mIndices[mSubsetOffset];
326  }
327 
328  template <typename IterT>
329  bool valid(const IterT& iter) const {
330  const int index = *iter;
331  while (mNextIndex < index) this->next();
332  return mNextIndex == index;
333  }
334 
335 protected:
336  friend class ::TestIndexFilter;
337 
338 private:
339  LeafMap mLeafMap;
340  std::vector<int> mIndices;
341  int mCount = 0;
342  mutable int mSubsetOffset = -1;
343  mutable int mNextIndex = -1;
344 }; // class RandomLeafFilter
345 
346 
347 // Hash attribute value for deterministic, but approximate filtering
348 template <typename RandGenT, typename IntType>
350 {
351 public:
353 
355  const double percentage,
356  const unsigned int seed = 0)
357  : mIndex(index)
358  , mFactor(percentage / 100.0)
359  , mSeed(seed) { }
360 
362  : mIndex(filter.mIndex)
363  , mFactor(filter.mFactor)
364  , mSeed(filter.mSeed)
365  {
366  if (filter.mIdHandle) mIdHandle.reset(new Handle(*filter.mIdHandle));
367  }
368 
369  inline bool initialized() const { return bool(mIdHandle); }
370 
371  static index::State state() { return index::PARTIAL; }
372  template <typename LeafT>
373  static index::State state(const LeafT&) { return index::PARTIAL; }
374 
375  template <typename LeafT>
376  void reset(const LeafT& leaf) {
377  assert(leaf.hasAttribute(mIndex));
378  mIdHandle.reset(new Handle(leaf.constAttributeArray(mIndex)));
379  }
380 
381  template <typename IterT>
382  bool valid(const IterT& iter) const {
383  assert(mIdHandle);
384  const IntType id = mIdHandle->get(*iter);
385  const unsigned int seed = mSeed + static_cast<unsigned int>(id);
386  RandGenT generator(seed);
387  std::uniform_real_distribution<double> dist(0.0, 1.0);
388  return dist(generator) < mFactor;
389  }
390 
391 private:
392  const size_t mIndex;
393  const double mFactor;
394  const unsigned int mSeed;
395  typename Handle::UniquePtr mIdHandle;
396 }; // class AttributeHashFilter
397 
398 
399 template <typename LevelSetGridT>
401 {
402 public:
403  using ValueT = typename LevelSetGridT::ValueType;
405 
406  LevelSetFilter( const LevelSetGridT& grid,
407  const math::Transform& transform,
408  const ValueT min,
409  const ValueT max)
410  : mAccessor(grid.getConstAccessor())
411  , mLevelSetTransform(grid.transform())
412  , mTransform(transform)
413  , mMin(min)
414  , mMax(max) { }
415 
417  : mAccessor(filter.mAccessor)
418  , mLevelSetTransform(filter.mLevelSetTransform)
419  , mTransform(filter.mTransform)
420  , mMin(filter.mMin)
421  , mMax(filter.mMax)
422  {
423  if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle));
424  }
425 
426  inline bool initialized() const { return bool(mPositionHandle); }
427 
428  static index::State state() { return index::PARTIAL; }
429  template <typename LeafT>
430  static index::State state(const LeafT&) { return index::PARTIAL; }
431 
432  template <typename LeafT>
433  void reset(const LeafT& leaf) {
434  mPositionHandle.reset(new Handle(leaf.constAttributeArray("P")));
435  }
436 
437  template <typename IterT>
438  bool valid(const IterT& iter) const {
439  assert(mPositionHandle);
440  assert(iter);
441 
442  const openvdb::Coord ijk = iter.getCoord();
443  const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d();
444 
445  // Retrieve point position in voxel space
446  const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter);
447 
448  // Compute point position in index space
449  const openvdb::Vec3f pointWorldSpace = mTransform.indexToWorld(pointVoxelSpace + voxelIndexSpace);
450  const openvdb::Vec3f pointIndexSpace = mLevelSetTransform.worldToIndex(pointWorldSpace);
451 
452  // Perform level-set sampling
453  const typename LevelSetGridT::ValueType value = tools::BoxSampler::sample(mAccessor, pointIndexSpace);
454 
455  // if min is greater than max, we invert so that values are valid outside of the range (not inside)
456  const bool invert = mMin > mMax;
457 
458  return invert ? (value < mMax || value > mMin) : (value < mMax && value > mMin);
459  }
460 
461 private:
462  // not a reference to ensure const-accessor is unique per-thread
463  const typename LevelSetGridT::ConstAccessor mAccessor;
464  const math::Transform& mLevelSetTransform;
465  const math::Transform& mTransform;
466  const ValueT mMin;
467  const ValueT mMax;
468  Handle::UniquePtr mPositionHandle;
469 }; // class LevelSetFilter
470 
471 
472 // BBox index filtering
474 {
475 public:
477 
478  BBoxFilter(const openvdb::math::Transform& transform,
479  const openvdb::BBoxd& bboxWS)
480  : mTransform(transform)
481  , mBbox(transform.worldToIndex(bboxWS)) { }
482 
484  : mTransform(filter.mTransform)
485  , mBbox(filter.mBbox)
486  {
487  if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle));
488  }
489 
490  inline bool initialized() const { return bool(mPositionHandle); }
491 
492  inline index::State state() const
493  {
494  return mBbox.empty() ? index::NONE : index::PARTIAL;
495  }
496  template <typename LeafT>
497  static index::State state(const LeafT&) { return index::PARTIAL; }
498 
499  template <typename LeafT>
500  void reset(const LeafT& leaf) {
501  mPositionHandle.reset(new Handle(leaf.constAttributeArray("P")));
502  }
503 
504  template <typename IterT>
505  bool valid(const IterT& iter) const {
506  assert(mPositionHandle);
507 
508  const openvdb::Coord ijk = iter.getCoord();
509  const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d();
510 
511  // Retrieve point position in voxel space
512  const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter);
513 
514  // Compute point position in index space
515  const openvdb::Vec3f pointIndexSpace = pointVoxelSpace + voxelIndexSpace;
516 
517  return mBbox.isInside(pointIndexSpace);
518  }
519 
520 private:
521  const openvdb::math::Transform& mTransform;
522  const openvdb::BBoxd mBbox;
523  Handle::UniquePtr mPositionHandle;
524 }; // class BBoxFilter
525 
526 
527 // Index filtering based on evaluating both sub-filters
528 template <typename T1, typename T2, bool And = true>
530 {
531 public:
532  BinaryFilter( const T1& filter1,
533  const T2& filter2)
534  : mFilter1(filter1)
535  , mFilter2(filter2) { }
536 
537  inline bool initialized() const { return mFilter1.initialized() && mFilter2.initialized(); }
538 
539  inline index::State state() const
540  {
541  return this->computeState(mFilter1.state(), mFilter2.state());
542  }
543  template <typename LeafT>
544  inline index::State state(const LeafT& leaf) const
545  {
546  return this->computeState(mFilter1.state(leaf), mFilter2.state(leaf));
547  }
548 
549  template <typename LeafT>
550  void reset(const LeafT& leaf) {
551  mFilter1.reset(leaf);
552  mFilter2.reset(leaf);
553  }
554 
555  template <typename IterT>
556  bool valid(const IterT& iter) const {
557  if (And) return mFilter1.valid(iter) && mFilter2.valid(iter);
558  return mFilter1.valid(iter) || mFilter2.valid(iter);
559  }
560 
561 private:
562  inline index::State computeState( index::State state1,
563  index::State state2) const
564  {
565  if (And) {
566  if (state1 == index::NONE || state2 == index::NONE) return index::NONE;
567  else if (state1 == index::ALL && state2 == index::ALL) return index::ALL;
568  } else {
569  if (state1 == index::NONE && state2 == index::NONE) return index::NONE;
570  else if (state1 == index::ALL && state2 == index::ALL) return index::ALL;
571  }
572  return index::PARTIAL;
573  }
574 
575  T1 mFilter1;
576  T2 mFilter2;
577 }; // class BinaryFilter
578 
579 
580 ////////////////////////////////////////
581 
582 
583 template<typename T>
584 struct FilterTraits {
585  static const bool RequiresCoord = false;
586 };
587 template<>
589  static const bool RequiresCoord = true;
590 };
591 template <typename T>
593  static const bool RequiresCoord = true;
594 };
595 template <typename T0, typename T1, bool And>
596 struct FilterTraits<BinaryFilter<T0, T1, And>> {
599 };
600 
601 
602 ////////////////////////////////////////
603 
604 
605 } // namespace points
606 } // namespace OPENVDB_VERSION_NAME
607 } // namespace openvdb
608 
609 #endif // OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
610 
611 // Copyright (c) 2012-2018 DreamWorks Animation LLC
612 // All rights reserved. This software is distributed under the
613 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
GA_API const UT_StringHolder dist
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
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
GLboolean invert
Definition: glcorearb.h:548
RandomLeafFilter(const PointDataTreeT &tree, const Index64 targetPoints, const unsigned int seed=0)
Definition: IndexFilter.h:260
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
Index filtering on active / inactive state of host voxel.
Definition: IndexFilter.h:131
png_uint_32 i
Definition: png.h:2877
MultiGroupFilter(const MultiGroupFilter &filter)
Definition: IndexFilter.h:195
GLuint id
Definition: glcorearb.h:654
AttributeHandle< openvdb::Vec3f > Handle
Definition: IndexFilter.h:476
static index::State state(const LeafT &)
Definition: IndexFilter.h:430
GLdouble n
Definition: glcorearb.h:2007
static index::State state(const LeafT &)
Definition: IndexFilter.h:497
typename LevelSetGridT::ValueType ValueT
Definition: IndexFilter.h:403
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
MultiGroupFilter(const NameVector &include, const NameVector &exclude, const AttributeSet &attributeSet)
Definition: IndexFilter.h:184
Index Iterators.
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1601
GLuint const GLchar * name
Definition: glcorearb.h:785
GA_API const UT_StringHolder transform
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Trilinearly reconstruct inTree at inCoord and store the result in result.
static index::State state(const LeafT &leaf)
Definition: IndexFilter.h:137
GLsizei const GLfloat * value
Definition: glcorearb.h:823
AttributeHashFilter(const size_t index, const double percentage, const unsigned int seed=0)
Definition: IndexFilter.h:354
BinaryFilter(const T1 &filter1, const T2 &filter2)
Definition: IndexFilter.h:532
Set of Attribute Arrays which tracks metadata about each array.
Attribute Group access and filtering for iteration.
AttributeHandle< openvdb::Vec3f > Handle
Definition: IndexFilter.h:404
GLuint index
Definition: glcorearb.h:785
std::map< openvdb::Coord, SeedCountPair > LeafMap
Definition: IndexFilter.h:258
math::BBox< Vec3d > BBoxd
Definition: Types.h:91
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
int Floor(float x)
Return the floor of x.
Definition: Math.h:802
std::vector< IntType > generateRandomSubset(const unsigned int seed, const IntType n, const IntType m)
Definition: IndexFilter.h:102
index::State state(const LeafT &leaf) const
Definition: IndexFilter.h:544
LevelSetFilter(const LevelSetGridT &grid, const math::Transform &transform, const ValueT min, const ValueT max)
Definition: IndexFilter.h:406
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:137
BBoxFilter(const openvdb::math::Transform &transform, const openvdb::BBoxd &bboxWS)
Definition: IndexFilter.h:478
Attribute Array storage templated on type and compression codec.
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
AttributeHashFilter(const AttributeHashFilter &filter)
Definition: IndexFilter.h:361
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:135
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
MultiGroupFilter(const IndexVector &include, const IndexVector &exclude)
Definition: IndexFilter.h:190
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296
std::vector< AttributeSet::Descriptor::GroupIndex > IndexVector
Definition: IndexFilter.h:167
math::Vec3< float > Vec3f
Definition: Types.h:81