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