OpenVDB  12.0.0
Interpolation.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 Interpolation.h
5 ///
6 /// Sampler classes such as PointSampler and BoxSampler that are intended for use
7 /// with tools::GridTransformer should operate in voxel space and must adhere to
8 /// the interface described in the example below:
9 /// @code
10 /// struct MySampler
11 /// {
12 /// // Return a short name that can be used to identify this sampler
13 /// // in error messages and elsewhere.
14 /// const char* name() { return "mysampler"; }
15 ///
16 /// // Return the radius of the sampling kernel in voxels, not including
17 /// // the center voxel. This is the number of voxels of padding that
18 /// // are added to all sides of a volume as a result of resampling.
19 /// int radius() { return 2; }
20 ///
21 /// // Return true if scaling by a factor smaller than 0.5 (along any axis)
22 /// // should be handled via a mipmapping-like scheme of successive halvings
23 /// // of a grid's resolution, until the remaining scale factor is
24 /// // greater than or equal to 1/2. Set this to false only when high-quality
25 /// // scaling is not required.
26 /// bool mipmap() { return true; }
27 ///
28 /// // Specify if sampling at a location that is collocated with a grid point
29 /// // is guaranteed to return the exact value at that grid point.
30 /// // For most sampling kernels, this should be false.
31 /// bool consistent() { return false; }
32 ///
33 /// // Sample the tree at the given coordinates and return the result in val.
34 /// // Return true if the sampled value is active.
35 /// template<class TreeT>
36 /// bool sample(const TreeT& tree, const Vec3R& coord, typename TreeT::ValueType& val);
37 /// };
38 /// @endcode
39 
40 #ifndef OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED
41 #define OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED
42 
43 #include <openvdb/version.h> // for OPENVDB_VERSION_NAME
44 #include <openvdb/Platform.h> // for round()
45 #include <openvdb/math/Math.h>// for SmoothUnitStep
46 #include <openvdb/math/Transform.h> // for Transform
47 #include <openvdb/Grid.h>
49 #include <openvdb/util/Assert.h>
50 #include <cmath>
51 #include <type_traits>
52 
53 namespace openvdb {
55 namespace OPENVDB_VERSION_NAME {
56 namespace tools {
57 
58 /// @brief Provises a unified interface for sampling, i.e. interpolation.
59 /// @details Order = 0: closest point
60 /// Order = 1: tri-linear
61 /// Order = 2: tri-quadratic
62 /// Staggered: Set to true for MAC grids
63 template <size_t Order, bool Staggered = false>
64 struct Sampler
65 {
66  static_assert(Order < 3, "Samplers of order higher than 2 are not supported");
67  static const char* name();
68  static int radius();
69  static bool mipmap();
70  static bool consistent();
71  static bool staggered();
72  static size_t order();
73 
74  /// @brief Sample @a inTree at the floating-point index coordinate @a inCoord
75  /// and store the result in @a result.
76  ///
77  /// @return @c true if the sampled value is active.
78  template<class TreeT>
79  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
80  typename TreeT::ValueType& result);
81 
82  /// @brief Sample @a inTree at the floating-point index coordinate @a inCoord.
83  ///
84  /// @return the reconstructed value
85  template<class TreeT>
86  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
87 };
88 
89 //////////////////////////////////////// Non-Staggered Samplers
90 
91 // The following samplers operate in voxel space.
92 // When the samplers are applied to grids holding vector or other non-scalar data,
93 // the data is assumed to be collocated. For example, using the BoxSampler on a grid
94 // with ValueType Vec3f assumes that all three elements in a vector can be assigned
95 // the same physical location. Consider using the GridSampler below instead.
96 
98 {
99  static const char* name() { return "point"; }
100  static int radius() { return 0; }
101  static bool mipmap() { return false; }
102  static bool consistent() { return true; }
103  static bool staggered() { return false; }
104  static size_t order() { return 0; }
105 
106  /// @brief Sample @a inTree at the nearest neighbor to @a inCoord
107  /// and store the result in @a result.
108  /// @return @c true if the sampled value is active.
109  template<class TreeT>
110  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
111  typename TreeT::ValueType& result);
112 
113  /// @brief Sample @a inTree at the nearest neighbor to @a inCoord
114  /// @return the reconstructed value
115  template<class TreeT>
116  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
117 };
118 
119 
121 {
122  static const char* name() { return "box"; }
123  static int radius() { return 1; }
124  static bool mipmap() { return true; }
125  static bool consistent() { return true; }
126  static bool staggered() { return false; }
127  static size_t order() { return 1; }
128 
129  /// @brief Trilinearly reconstruct @a inTree at @a inCoord
130  /// and store the result in @a result.
131  /// @return @c true if any one of the sampled values is active.
132  template<class TreeT>
133  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
134  typename TreeT::ValueType& result);
135 
136  /// @brief Trilinearly reconstruct @a inTree at @a inCoord.
137  /// @return the reconstructed value
138  template<class TreeT>
139  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
140 
141  /// @brief Import all eight values from @a inTree to support
142  /// tri-linear interpolation.
143  template<class ValueT, class TreeT, size_t N>
144  static inline void getValues(ValueT (&data)[N][N][N], const TreeT& inTree, Coord ijk);
145 
146  /// @brief Import all eight values from @a inTree to support
147  /// tri-linear interpolation.
148  /// @return @c true if any of the eight values are active
149  template<class ValueT, class TreeT, size_t N>
150  static inline bool probeValues(ValueT (&data)[N][N][N], const TreeT& inTree, Coord ijk);
151 
152  /// @brief Find the minimum and maximum values of the eight cell
153  /// values in @ data.
154  template<class ValueT, size_t N>
155  static inline void extrema(ValueT (&data)[N][N][N], ValueT& vMin, ValueT& vMax);
156 
157  /// @return the tri-linear interpolation with the unit cell coordinates @a uvw
158  template<class ValueT, size_t N>
159  static inline ValueT trilinearInterpolation(ValueT (&data)[N][N][N], const Vec3R& uvw);
160 };
161 
162 
164 {
165  static const char* name() { return "quadratic"; }
166  static int radius() { return 1; }
167  static bool mipmap() { return true; }
168  static bool consistent() { return false; }
169  static bool staggered() { return false; }
170  static size_t order() { return 2; }
171 
172  /// @brief Triquadratically reconstruct @a inTree at @a inCoord
173  /// and store the result in @a result.
174  /// @return @c true if any one of the sampled values is active.
175  template<class TreeT>
176  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
177  typename TreeT::ValueType& result);
178 
179  /// @brief Triquadratically reconstruct @a inTree at to @a inCoord.
180  /// @return the reconstructed value
181  template<class TreeT>
182  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
183 
184  template<class ValueT, size_t N>
185  static inline ValueT triquadraticInterpolation(ValueT (&data)[N][N][N], const Vec3R& uvw);
186 };
187 
188 
189 //////////////////////////////////////// Staggered Samplers
190 
191 
192 // The following samplers operate in voxel space and are designed for Vec3
193 // staggered grid data (e.g., fluid simulations using the Marker-and-Cell approach
194 // associate elements of the velocity vector with different physical locations:
195 // the faces of a cube).
196 
198 {
199  static const char* name() { return "point"; }
200  static int radius() { return 0; }
201  static bool mipmap() { return false; }
202  static bool consistent() { return false; }
203  static bool staggered() { return true; }
204  static size_t order() { return 0; }
205 
206  /// @brief Sample @a inTree at the nearest neighbor to @a inCoord
207  /// and store the result in @a result.
208  /// @return true if the sampled value is active.
209  template<class TreeT>
210  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
211  typename TreeT::ValueType& result);
212 
213  /// @brief Sample @a inTree at the nearest neighbor to @a inCoord
214  /// @return the reconstructed value
215  template<class TreeT>
216  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
217 };
218 
219 
221 {
222  static const char* name() { return "box"; }
223  static int radius() { return 1; }
224  static bool mipmap() { return true; }
225  static bool consistent() { return false; }
226  static bool staggered() { return true; }
227  static size_t order() { return 1; }
228 
229  /// @brief Trilinearly reconstruct @a inTree at @a inCoord
230  /// and store the result in @a result.
231  /// @return true if any one of the sampled value is active.
232  template<class TreeT>
233  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
234  typename TreeT::ValueType& result);
235 
236  /// @brief Trilinearly reconstruct @a inTree at @a inCoord.
237  /// @return the reconstructed value
238  template<class TreeT>
239  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
240 };
241 
242 
244 {
245  static const char* name() { return "quadratic"; }
246  static int radius() { return 1; }
247  static bool mipmap() { return true; }
248  static bool consistent() { return false; }
249  static bool staggered() { return true; }
250  static size_t order() { return 2; }
251 
252  /// @brief Triquadratically reconstruct @a inTree at @a inCoord
253  /// and store the result in @a result.
254  /// @return true if any one of the sampled values is active.
255  template<class TreeT>
256  static bool sample(const TreeT& inTree, const Vec3R& inCoord,
257  typename TreeT::ValueType& result);
258 
259  /// @brief Triquadratically reconstruct @a inTree at to @a inCoord.
260  /// @return the reconstructed value
261  template<class TreeT>
262  static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord);
263 };
264 
265 
266 //////////////////////////////////////// GridSampler
267 
268 
269 /// @brief Class that provides the interface for continuous sampling
270 /// of values in a tree.
271 ///
272 /// @details Since trees support only discrete voxel sampling, TreeSampler
273 /// must be used to sample arbitrary continuous points in (world or
274 /// index) space.
275 ///
276 /// @warning This implementation of the GridSampler stores a pointer
277 /// to a Tree for value access. While this is thread-safe it is
278 /// uncached and hence slow compared to using a
279 /// ValueAccessor. Consequently it is normally advisable to use the
280 /// template specialization below that employs a
281 /// ValueAccessor. However, care must be taken when dealing with
282 /// multi-threading (see warning below).
283 template<typename GridOrTreeType, typename SamplerType>
285 {
286 public:
288  using ValueType = typename GridOrTreeType::ValueType;
292 
293  /// @param grid a grid to be sampled
294  explicit GridSampler(const GridType& grid)
295  : mTree(&(grid.tree())), mTransform(&(grid.transform())) {}
296 
297  /// @param tree a tree to be sampled, or a ValueAccessor for the tree
298  /// @param transform is used when sampling world space locations.
299  GridSampler(const TreeType& tree, const math::Transform& transform)
300  : mTree(&tree), mTransform(&transform) {}
301 
302  const math::Transform& transform() const { return *mTransform; }
303 
304  /// @brief Sample a point in index space in the grid.
305  /// @param x Fractional x-coordinate of point in index-coordinates of grid
306  /// @param y Fractional y-coordinate of point in index-coordinates of grid
307  /// @param z Fractional z-coordinate of point in index-coordinates of grid
308  template<typename RealType>
309  ValueType sampleVoxel(const RealType& x, const RealType& y, const RealType& z) const
310  {
311  return this->isSample(Vec3d(x,y,z));
312  }
313 
314  /// @brief Sample value in integer index space
315  /// @param i Integer x-coordinate in index space
316  /// @param j Integer y-coordinate in index space
317  /// @param k Integer x-coordinate in index space
318  ValueType sampleVoxel(typename Coord::ValueType i,
319  typename Coord::ValueType j,
320  typename Coord::ValueType k) const
321  {
322  return this->isSample(Coord(i,j,k));
323  }
324 
325  /// @brief Sample value in integer index space
326  /// @param ijk the location in index space
327  ValueType isSample(const Coord& ijk) const { return mTree->getValue(ijk); }
328 
329  /// @brief Sample in fractional index space
330  /// @param ispoint the location in index space
331  ValueType isSample(const Vec3d& ispoint) const
332  {
333  ValueType result = zeroVal<ValueType>();
334  SamplerType::sample(*mTree, ispoint, result);
335  return result;
336  }
337 
338  /// @brief Sample in world space
339  /// @param wspoint the location in world space
340  ValueType wsSample(const Vec3d& wspoint) const
341  {
342  ValueType result = zeroVal<ValueType>();
343  SamplerType::sample(*mTree, mTransform->worldToIndex(wspoint), result);
344  return result;
345  }
346 
347 private:
348  const TreeType* mTree;
349  const math::Transform* mTransform;
350 }; // class GridSampler
351 
352 
353 /// @brief Specialization of GridSampler for construction from a ValueAccessor type
354 ///
355 /// @note This version should normally be favored over the one above
356 /// that takes a Grid or Tree. The reason is this version uses a
357 /// ValueAccessor that performs fast (cached) access where the
358 /// tree-based flavor performs slower (uncached) access.
359 ///
360 /// @warning Since this version stores a pointer to an (externally
361 /// allocated) value accessor it is not threadsafe. Hence each thread
362 /// should have its own instance of a GridSampler constructed from a
363 /// local ValueAccessor. Alternatively the Grid/Tree-based GridSampler
364 /// is threadsafe, but also slower.
365 template<typename TreeT, typename SamplerType>
366 class GridSampler<tree::ValueAccessor<TreeT>, SamplerType>
367 {
368 public:
370  using ValueType = typename TreeT::ValueType;
371  using TreeType = TreeT;
374 
375  /// @param acc a ValueAccessor to be sampled
376  /// @param transform is used when sampling world space locations.
378  const math::Transform& transform)
379  : mAccessor(&acc), mTransform(&transform) {}
380 
381  const math::Transform& transform() const { return *mTransform; }
382 
383  /// @brief Sample a point in index space in the grid.
384  /// @param x Fractional x-coordinate of point in index-coordinates of grid
385  /// @param y Fractional y-coordinate of point in index-coordinates of grid
386  /// @param z Fractional z-coordinate of point in index-coordinates of grid
387  template<typename RealType>
388  ValueType sampleVoxel(const RealType& x, const RealType& y, const RealType& z) const
389  {
390  return this->isSample(Vec3d(x,y,z));
391  }
392 
393  /// @brief Sample value in integer index space
394  /// @param i Integer x-coordinate in index space
395  /// @param j Integer y-coordinate in index space
396  /// @param k Integer x-coordinate in index space
397  ValueType sampleVoxel(typename Coord::ValueType i,
398  typename Coord::ValueType j,
399  typename Coord::ValueType k) const
400  {
401  return this->isSample(Coord(i,j,k));
402  }
403 
404  /// @brief Sample value in integer index space
405  /// @param ijk the location in index space
406  ValueType isSample(const Coord& ijk) const { return mAccessor->getValue(ijk); }
407 
408  /// @brief Sample in fractional index space
409  /// @param ispoint the location in index space
410  ValueType isSample(const Vec3d& ispoint) const
411  {
412  ValueType result = zeroVal<ValueType>();
413  SamplerType::sample(*mAccessor, ispoint, result);
414  return result;
415  }
416 
417  /// @brief Sample in world space
418  /// @param wspoint the location in world space
419  ValueType wsSample(const Vec3d& wspoint) const
420  {
421  ValueType result = zeroVal<ValueType>();
422  SamplerType::sample(*mAccessor, mTransform->worldToIndex(wspoint), result);
423  return result;
424  }
425 
426 private:
427  const AccessorType* mAccessor;//not thread-safe!
428  const math::Transform* mTransform;
429 };//Specialization of GridSampler
430 
431 
432 //////////////////////////////////////// DualGridSampler
433 
434 
435 /// @brief This is a simple convenience class that allows for sampling
436 /// from a source grid into the index space of a target grid. At
437 /// construction the source and target grids are checked for alignment
438 /// which potentially renders interpolation unnecessary. Else
439 /// interpolation is performed according to the templated Sampler
440 /// type.
441 ///
442 /// @warning For performance reasons the check for alignment of the
443 /// two grids is only performed at construction time!
444 template<typename GridOrTreeT,
445  typename SamplerT>
447 {
448 public:
449  using ValueType = typename GridOrTreeT::ValueType;
451  using TreeType = typename TreeAdapter<GridOrTreeT>::TreeType;
453 
454  /// @brief Grid and transform constructor.
455  /// @param sourceGrid Source grid.
456  /// @param targetXform Transform of the target grid.
457  DualGridSampler(const GridType& sourceGrid,
458  const math::Transform& targetXform)
459  : mSourceTree(&(sourceGrid.tree()))
460  , mSourceXform(&(sourceGrid.transform()))
461  , mTargetXform(&targetXform)
462  , mAligned(targetXform == *mSourceXform)
463  {
464  }
465  /// @brief Tree and transform constructor.
466  /// @param sourceTree Source tree.
467  /// @param sourceXform Transform of the source grid.
468  /// @param targetXform Transform of the target grid.
469  DualGridSampler(const TreeType& sourceTree,
470  const math::Transform& sourceXform,
471  const math::Transform& targetXform)
472  : mSourceTree(&sourceTree)
473  , mSourceXform(&sourceXform)
474  , mTargetXform(&targetXform)
475  , mAligned(targetXform == sourceXform)
476  {
477  }
478  /// @brief Return the value of the source grid at the index
479  /// coordinates, ijk, relative to the target grid (or its tranform).
480  inline ValueType operator()(const Coord& ijk) const
481  {
482  if (mAligned) return mSourceTree->getValue(ijk);
483  const Vec3R world = mTargetXform->indexToWorld(ijk);
484  return SamplerT::sample(*mSourceTree, mSourceXform->worldToIndex(world));
485  }
486  /// @brief Return true if the two grids are aligned.
487  inline bool isAligned() const { return mAligned; }
488 private:
489  const TreeType* mSourceTree;
490  const math::Transform* mSourceXform;
491  const math::Transform* mTargetXform;
492  const bool mAligned;
493 };// DualGridSampler
494 
495 /// @brief Specialization of DualGridSampler for construction from a ValueAccessor type.
496 template<typename TreeT,
497  typename SamplerT>
498 class DualGridSampler<tree::ValueAccessor<TreeT>, SamplerT>
499 {
500  public:
501  using ValueType = typename TreeT::ValueType;
502  using TreeType = TreeT;
505 
506  /// @brief ValueAccessor and transform constructor.
507  /// @param sourceAccessor ValueAccessor into the source grid.
508  /// @param sourceXform Transform for the source grid.
509  /// @param targetXform Transform for the target grid.
510  DualGridSampler(const AccessorType& sourceAccessor,
511  const math::Transform& sourceXform,
512  const math::Transform& targetXform)
513  : mSourceAcc(&sourceAccessor)
514  , mSourceXform(&sourceXform)
515  , mTargetXform(&targetXform)
516  , mAligned(targetXform == sourceXform)
517  {
518  }
519  /// @brief Return the value of the source grid at the index
520  /// coordinates, ijk, relative to the target grid.
521  inline ValueType operator()(const Coord& ijk) const
522  {
523  if (mAligned) return mSourceAcc->getValue(ijk);
524  const Vec3R world = mTargetXform->indexToWorld(ijk);
525  return SamplerT::sample(*mSourceAcc, mSourceXform->worldToIndex(world));
526  }
527  /// @brief Return true if the two grids are aligned.
528  inline bool isAligned() const { return mAligned; }
529 private:
530  const AccessorType* mSourceAcc;
531  const math::Transform* mSourceXform;
532  const math::Transform* mTargetXform;
533  const bool mAligned;
534 };//Specialization of DualGridSampler
535 
536 //////////////////////////////////////// AlphaMask
537 
538 
539 // Class to derive the normalized alpha mask
540 template <typename GridT,
541  typename MaskT,
542  typename SamplerT = tools::BoxSampler,
543  typename FloatT = float>
545 {
546 public:
547  static_assert(std::is_floating_point<FloatT>::value,
548  "AlphaMask requires a floating-point value type");
549  using GridType = GridT;
550  using MaskType = MaskT;
551  using SamlerType = SamplerT;
552  using FloatType = FloatT;
553 
554  AlphaMask(const GridT& grid, const MaskT& mask, FloatT min, FloatT max, bool invert)
555  : mAcc(mask.tree())
556  , mSampler(mAcc, mask.transform() , grid.transform())
557  , mMin(min)
558  , mInvNorm(1/(max-min))
559  , mInvert(invert)
560  {
561  OPENVDB_ASSERT(min < max);
562  }
563 
564  inline bool operator()(const Coord& xyz, FloatT& a, FloatT& b) const
565  {
566  a = math::SmoothUnitStep( (mSampler(xyz) - mMin) * mInvNorm );//smooth mapping to 0->1
567  b = 1 - a;
568  if (mInvert) std::swap(a,b);
569  return a>0;
570  }
571 
572 protected:
573  using AccT = typename MaskType::ConstAccessor;
576  const FloatT mMin, mInvNorm;
577  const bool mInvert;
578 };// AlphaMask
579 
580 ////////////////////////////////////////
581 
582 namespace local_util {
583 
584 inline Vec3i
585 floorVec3(const Vec3R& v)
586 {
587  return Vec3i(int(std::floor(v(0))), int(std::floor(v(1))), int(std::floor(v(2))));
588 }
589 
590 
591 inline Vec3i
592 ceilVec3(const Vec3R& v)
593 {
594  return Vec3i(int(std::ceil(v(0))), int(std::ceil(v(1))), int(std::ceil(v(2))));
595 }
596 
597 
598 inline Vec3i
599 roundVec3(const Vec3R& v)
600 {
601  return Vec3i(int(::round(v(0))), int(::round(v(1))), int(::round(v(2))));
602 }
603 
604 } // namespace local_util
605 
606 
607 //////////////////////////////////////// PointSampler
608 
609 
610 template<class TreeT>
611 inline bool
612 PointSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
613  typename TreeT::ValueType& result)
614 {
615  return inTree.probeValue(Coord(local_util::roundVec3(inCoord)), result);
616 }
617 
618 template<class TreeT>
619 inline typename TreeT::ValueType
620 PointSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
621 {
622  return inTree.getValue(Coord(local_util::roundVec3(inCoord)));
623 }
624 
625 
626 //////////////////////////////////////// BoxSampler
627 
628 template<class ValueT, class TreeT, size_t N>
629 inline void
630 BoxSampler::getValues(ValueT (&data)[N][N][N], const TreeT& inTree, Coord ijk)
631 {
632  data[0][0][0] = inTree.getValue(ijk); // i, j, k
633 
634  ijk[2] += 1;
635  data[0][0][1] = inTree.getValue(ijk); // i, j, k + 1
636 
637  ijk[1] += 1;
638  data[0][1][1] = inTree.getValue(ijk); // i, j+1, k + 1
639 
640  ijk[2] -= 1;
641  data[0][1][0] = inTree.getValue(ijk); // i, j+1, k
642 
643  ijk[0] += 1;
644  ijk[1] -= 1;
645  data[1][0][0] = inTree.getValue(ijk); // i+1, j, k
646 
647  ijk[2] += 1;
648  data[1][0][1] = inTree.getValue(ijk); // i+1, j, k + 1
649 
650  ijk[1] += 1;
651  data[1][1][1] = inTree.getValue(ijk); // i+1, j+1, k + 1
652 
653  ijk[2] -= 1;
654  data[1][1][0] = inTree.getValue(ijk); // i+1, j+1, k
655 }
656 
657 template<class ValueT, class TreeT, size_t N>
658 inline bool
659 BoxSampler::probeValues(ValueT (&data)[N][N][N], const TreeT& inTree, Coord ijk)
660 {
661  bool hasActiveValues = false;
662  hasActiveValues |= inTree.probeValue(ijk, data[0][0][0]); // i, j, k
663 
664  ijk[2] += 1;
665  hasActiveValues |= inTree.probeValue(ijk, data[0][0][1]); // i, j, k + 1
666 
667  ijk[1] += 1;
668  hasActiveValues |= inTree.probeValue(ijk, data[0][1][1]); // i, j+1, k + 1
669 
670  ijk[2] -= 1;
671  hasActiveValues |= inTree.probeValue(ijk, data[0][1][0]); // i, j+1, k
672 
673  ijk[0] += 1;
674  ijk[1] -= 1;
675  hasActiveValues |= inTree.probeValue(ijk, data[1][0][0]); // i+1, j, k
676 
677  ijk[2] += 1;
678  hasActiveValues |= inTree.probeValue(ijk, data[1][0][1]); // i+1, j, k + 1
679 
680  ijk[1] += 1;
681  hasActiveValues |= inTree.probeValue(ijk, data[1][1][1]); // i+1, j+1, k + 1
682 
683  ijk[2] -= 1;
684  hasActiveValues |= inTree.probeValue(ijk, data[1][1][0]); // i+1, j+1, k
685 
686  return hasActiveValues;
687 }
688 
689 template<class ValueT, size_t N>
690 inline void
691 BoxSampler::extrema(ValueT (&data)[N][N][N], ValueT& vMin, ValueT &vMax)
692 {
693  vMin = vMax = data[0][0][0];
694  vMin = math::Min(vMin, data[0][0][1]);
695  vMax = math::Max(vMax, data[0][0][1]);
696  vMin = math::Min(vMin, data[0][1][0]);
697  vMax = math::Max(vMax, data[0][1][0]);
698  vMin = math::Min(vMin, data[0][1][1]);
699  vMax = math::Max(vMax, data[0][1][1]);
700  vMin = math::Min(vMin, data[1][0][0]);
701  vMax = math::Max(vMax, data[1][0][0]);
702  vMin = math::Min(vMin, data[1][0][1]);
703  vMax = math::Max(vMax, data[1][0][1]);
704  vMin = math::Min(vMin, data[1][1][0]);
705  vMax = math::Max(vMax, data[1][1][0]);
706  vMin = math::Min(vMin, data[1][1][1]);
707  vMax = math::Max(vMax, data[1][1][1]);
708 }
709 
710 
711 template<class ValueT, size_t N>
712 inline ValueT
713 BoxSampler::trilinearInterpolation(ValueT (&data)[N][N][N], const Vec3R& uvw)
714 {
715  auto _interpolate = [](const ValueT& a, const ValueT& b, double weight)
716  {
718  const auto temp = (b - a) * weight;
720  return static_cast<ValueT>(a + ValueT(temp));
721  };
722 
723  // Trilinear interpolation:
724  // The eight surrounding latice values are used to construct the result. \n
725  // result(x,y,z) =
726  // v000 (1-x)(1-y)(1-z) + v001 (1-x)(1-y)z + v010 (1-x)y(1-z) + v011 (1-x)yz
727  // + v100 x(1-y)(1-z) + v101 x(1-y)z + v110 xy(1-z) + v111 xyz
728 
729  return _interpolate(
730  _interpolate(
731  _interpolate(data[0][0][0], data[0][0][1], uvw[2]),
732  _interpolate(data[0][1][0], data[0][1][1], uvw[2]),
733  uvw[1]),
734  _interpolate(
735  _interpolate(data[1][0][0], data[1][0][1], uvw[2]),
736  _interpolate(data[1][1][0], data[1][1][1], uvw[2]),
737  uvw[1]),
738  uvw[0]);
739 }
740 
741 
742 template<class TreeT>
743 inline bool
744 BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
745  typename TreeT::ValueType& result)
746 {
747  using ValueT = typename TreeT::ValueType;
748 
749  const Vec3i inIdx = local_util::floorVec3(inCoord);
750  const Vec3R uvw = inCoord - inIdx;
751 
752  // Retrieve the values of the eight voxels surrounding the
753  // fractional source coordinates.
754  ValueT data[2][2][2];
755 
756  const bool hasActiveValues = BoxSampler::probeValues(data, inTree, Coord(inIdx));
757 
758  result = BoxSampler::trilinearInterpolation(data, uvw);
759 
760  return hasActiveValues;
761 }
762 
763 
764 template<class TreeT>
765 inline typename TreeT::ValueType
766 BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
767 {
768  using ValueT = typename TreeT::ValueType;
769 
770  const Vec3i inIdx = local_util::floorVec3(inCoord);
771  const Vec3R uvw = inCoord - inIdx;
772 
773  // Retrieve the values of the eight voxels surrounding the
774  // fractional source coordinates.
775  ValueT data[2][2][2];
776 
777  BoxSampler::getValues(data, inTree, Coord(inIdx));
778 
779  return BoxSampler::trilinearInterpolation(data, uvw);
780 }
781 
782 
783 //////////////////////////////////////// QuadraticSampler
784 
785 template<class ValueT, size_t N>
786 inline ValueT
787 QuadraticSampler::triquadraticInterpolation(ValueT (&data)[N][N][N], const Vec3R& uvw)
788 {
789  auto _interpolate = [](const ValueT* value, double weight)
790  {
792  const ValueT
793  a = static_cast<ValueT>(0.5 * (value[0] + value[2]) - value[1]),
794  b = static_cast<ValueT>(0.5 * (value[2] - value[0])),
795  c = static_cast<ValueT>(value[1]);
796  const auto temp = weight * (weight * a + b) + c;
798  return static_cast<ValueT>(temp);
799  };
800 
801  /// @todo For vector types, interpolate over each component independently.
802  ValueT vx[3];
803  for (int dx = 0; dx < 3; ++dx) {
804  ValueT vy[3];
805  for (int dy = 0; dy < 3; ++dy) {
806  // Fit a parabola to three contiguous samples in z
807  // (at z=-1, z=0 and z=1), then evaluate the parabola at z',
808  // where z' is the fractional part of inCoord.z, i.e.,
809  // inCoord.z - inIdx.z. The coefficients come from solving
810  //
811  // | (-1)^2 -1 1 || a | | v0 |
812  // | 0 0 1 || b | = | v1 |
813  // | 1^2 1 1 || c | | v2 |
814  //
815  // for a, b and c.
816  const ValueT* vz = &data[dx][dy][0];
817  vy[dy] = _interpolate(vz, uvw.z());
818  }//loop over y
819  // Fit a parabola to three interpolated samples in y, then
820  // evaluate the parabola at y', where y' is the fractional
821  // part of inCoord.y.
822  vx[dx] = _interpolate(vy, uvw.y());
823  }//loop over x
824  // Fit a parabola to three interpolated samples in x, then
825  // evaluate the parabola at the fractional part of inCoord.x.
826  return _interpolate(vx, uvw.x());
827 }
828 
829 template<class TreeT>
830 inline bool
831 QuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
832  typename TreeT::ValueType& result)
833 {
834  using ValueT = typename TreeT::ValueType;
835 
836  const Vec3i inIdx = local_util::floorVec3(inCoord), inLoIdx = inIdx - Vec3i(1, 1, 1);
837  const Vec3R uvw = inCoord - inIdx;
838 
839  // Retrieve the values of the 27 voxels surrounding the
840  // fractional source coordinates.
841  bool active = false;
842  ValueT data[3][3][3];
843  for (int dx = 0, ix = inLoIdx.x(); dx < 3; ++dx, ++ix) {
844  for (int dy = 0, iy = inLoIdx.y(); dy < 3; ++dy, ++iy) {
845  for (int dz = 0, iz = inLoIdx.z(); dz < 3; ++dz, ++iz) {
846  if (inTree.probeValue(Coord(ix, iy, iz), data[dx][dy][dz])) active = true;
847  }
848  }
849  }
850 
851  result = QuadraticSampler::triquadraticInterpolation(data, uvw);
852 
853  return active;
854 }
855 
856 template<class TreeT>
857 inline typename TreeT::ValueType
858 QuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
859 {
860  using ValueT = typename TreeT::ValueType;
861 
862  const Vec3i inIdx = local_util::floorVec3(inCoord), inLoIdx = inIdx - Vec3i(1, 1, 1);
863  const Vec3R uvw = inCoord - inIdx;
864 
865  // Retrieve the values of the 27 voxels surrounding the
866  // fractional source coordinates.
867  ValueT data[3][3][3];
868  for (int dx = 0, ix = inLoIdx.x(); dx < 3; ++dx, ++ix) {
869  for (int dy = 0, iy = inLoIdx.y(); dy < 3; ++dy, ++iy) {
870  for (int dz = 0, iz = inLoIdx.z(); dz < 3; ++dz, ++iz) {
871  data[dx][dy][dz] = inTree.getValue(Coord(ix, iy, iz));
872  }
873  }
874  }
875 
876  return QuadraticSampler::triquadraticInterpolation(data, uvw);
877 }
878 
879 
880 //////////////////////////////////////// StaggeredPointSampler
881 
882 
883 template<class TreeT>
884 inline bool
885 StaggeredPointSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
886  typename TreeT::ValueType& result)
887 {
888  using ValueType = typename TreeT::ValueType;
889 
890  ValueType tempX, tempY, tempZ;
891  bool active = false;
892 
893  active = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active;
894  active = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active;
895  active = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active;
896 
897  result.x() = tempX.x();
898  result.y() = tempY.y();
899  result.z() = tempZ.z();
900 
901  return active;
902 }
903 
904 template<class TreeT>
905 inline typename TreeT::ValueType
906 StaggeredPointSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
907 {
908  using ValueT = typename TreeT::ValueType;
909 
910  const ValueT tempX = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0.0, 0.0));
911  const ValueT tempY = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.5, 0.0));
912  const ValueT tempZ = PointSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.0, 0.5));
913 
914  return ValueT(tempX.x(), tempY.y(), tempZ.z());
915 }
916 
917 
918 //////////////////////////////////////// StaggeredBoxSampler
919 
920 
921 template<class TreeT>
922 inline bool
923 StaggeredBoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
924  typename TreeT::ValueType& result)
925 {
926  using ValueType = typename TreeT::ValueType;
927 
928  ValueType tempX, tempY, tempZ;
929  tempX = tempY = tempZ = zeroVal<ValueType>();
930  bool active = false;
931 
932  active = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active;
933  active = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active;
934  active = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active;
935 
936  result.x() = tempX.x();
937  result.y() = tempY.y();
938  result.z() = tempZ.z();
939 
940  return active;
941 }
942 
943 template<class TreeT>
944 inline typename TreeT::ValueType
945 StaggeredBoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
946 {
947  using ValueT = typename TreeT::ValueType;
948 
949  const ValueT tempX = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0.0, 0.0));
950  const ValueT tempY = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.5, 0.0));
951  const ValueT tempZ = BoxSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.0, 0.5));
952 
953  return ValueT(tempX.x(), tempY.y(), tempZ.z());
954 }
955 
956 
957 //////////////////////////////////////// StaggeredQuadraticSampler
958 
959 
960 template<class TreeT>
961 inline bool
962 StaggeredQuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
963  typename TreeT::ValueType& result)
964 {
965  using ValueType = typename TreeT::ValueType;
966 
967  ValueType tempX, tempY, tempZ;
968  bool active = false;
969 
970  active = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active;
971  active = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active;
972  active = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active;
973 
974  result.x() = tempX.x();
975  result.y() = tempY.y();
976  result.z() = tempZ.z();
977 
978  return active;
979 }
980 
981 template<class TreeT>
982 inline typename TreeT::ValueType
983 StaggeredQuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
984 {
985  using ValueT = typename TreeT::ValueType;
986 
987  const ValueT tempX = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.5, 0.0, 0.0));
988  const ValueT tempY = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.5, 0.0));
989  const ValueT tempZ = QuadraticSampler::sample<TreeT>(inTree, inCoord + Vec3R(0.0, 0.0, 0.5));
990 
991  return ValueT(tempX.x(), tempY.y(), tempZ.z());
992 }
993 
994 //////////////////////////////////////// Sampler
995 
996 template <>
997 struct Sampler<0, false> : public PointSampler {};
998 
999 template <>
1000 struct Sampler<1, false> : public BoxSampler {};
1001 
1002 template <>
1003 struct Sampler<2, false> : public QuadraticSampler {};
1004 
1005 template <>
1006 struct Sampler<0, true> : public StaggeredPointSampler {};
1007 
1008 template <>
1009 struct Sampler<1, true> : public StaggeredBoxSampler {};
1010 
1011 template <>
1012 struct Sampler<2, true> : public StaggeredQuadraticSampler {};
1013 
1014 } // namespace tools
1015 } // namespace OPENVDB_VERSION_NAME
1016 } // namespace openvdb
1017 
1018 #endif // OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
Bracket code with OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN/_END, to inhibit warnings about type conve...
Definition: Platform.h:221
T & y()
Definition: Vec3.h:87
static int radius()
Definition: Interpolation.h:200
Definition: Interpolation.h:163
static const char * name()
Definition: Interpolation.h:245
static bool consistent()
Definition: Interpolation.h:168
static bool mipmap()
Definition: Interpolation.h:247
typename tree::ValueAccessor< TreeT > AccessorType
Definition: Interpolation.h:504
This is a simple convenience class that allows for sampling from a source grid into the index space o...
Definition: Interpolation.h:446
typename tree::ValueAccessor< TreeT > AccessorType
Definition: Interpolation.h:373
Vec3i roundVec3(const Vec3R &v)
Definition: Interpolation.h:599
GridSampler(const AccessorType &acc, const math::Transform &transform)
Definition: Interpolation.h:377
Vec3i floorVec3(const Vec3R &v)
Definition: Interpolation.h:585
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
static bool consistent()
Definition: Interpolation.h:102
static bool staggered()
Definition: Interpolation.h:226
static const char * name()
Definition: Interpolation.h:222
DualGridSampler(const AccessorType &sourceAccessor, const math::Transform &sourceXform, const math::Transform &targetXform)
ValueAccessor and transform constructor.
Definition: Interpolation.h:510
Definition: Interpolation.h:197
static size_t order()
Definition: Interpolation.h:104
static int radius()
Definition: Interpolation.h:246
ValueType operator()(const Coord &ijk) const
Return the value of the source grid at the index coordinates, ijk, relative to the target grid (or it...
Definition: Interpolation.h:480
ValueType wsSample(const Vec3d &wspoint) const
Sample in world space.
Definition: Interpolation.h:419
AlphaMask(const GridT &grid, const MaskT &mask, FloatT min, FloatT max, bool invert)
Definition: Interpolation.h:554
static bool staggered()
Definition: Interpolation.h:203
static int radius()
Definition: Interpolation.h:166
const math::Transform & transform() const
Definition: Interpolation.h:302
ValueType isSample(const Coord &ijk) const
Sample value in integer index space.
Definition: Interpolation.h:327
static bool staggered()
Definition: Interpolation.h:169
Class that provides the interface for continuous sampling of values in a tree.
Definition: Interpolation.h:284
static bool mipmap()
Definition: Interpolation.h:201
static const char * name()
Definition: Interpolation.h:99
static const char * name()
Definition: Interpolation.h:122
ValueType sampleVoxel(const RealType &x, const RealType &y, const RealType &z) const
Sample a point in index space in the grid.
Definition: Interpolation.h:388
T & z()
Definition: Vec3.h:88
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition: Math.h:595
typename TreeAdapter< GridOrTreeType >::GridType GridType
Definition: Interpolation.h:289
ValueType isSample(const Coord &ijk) const
Sample value in integer index space.
Definition: Interpolation.h:406
typename MaskType::ConstAccessor AccT
Definition: Interpolation.h:573
DualGridSampler(const TreeType &sourceTree, const math::Transform &sourceXform, const math::Transform &targetXform)
Tree and transform constructor.
Definition: Interpolation.h:469
static size_t order()
Definition: Interpolation.h:127
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
Definition: Math.h:656
static const char * name()
Definition: Interpolation.h:199
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
typename TreeT::ValueType ValueType
Definition: Interpolation.h:501
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition: Platform.h:222
MaskT MaskType
Definition: Interpolation.h:550
_TreeType TreeType
Definition: Grid.h:1061
static int radius()
Definition: Interpolation.h:223
const FloatT mMin
Definition: Interpolation.h:576
Definition: Interpolation.h:120
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:86
typename TreeT::ValueType ValueType
Definition: Interpolation.h:370
const math::Transform & transform() const
Definition: Interpolation.h:381
Type SmoothUnitStep(Type x)
Return 0 if x < 0, 1 if x > 1 or else (3 − 2 x) x².
Definition: Math.h:287
const bool mInvert
Definition: Interpolation.h:577
GridSampler(const GridType &grid)
Definition: Interpolation.h:294
std::shared_ptr< T > SharedPtr
Definition: Types.h:114
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
typename TreeAdapter< GridOrTreeType >::TreeType TreeType
Definition: Interpolation.h:290
ValueType isSample(const Vec3d &ispoint) const
Sample in fractional index space.
Definition: Interpolation.h:331
static bool mipmap()
Definition: Interpolation.h:101
ValueType isSample(const Vec3d &ispoint) const
Sample in fractional index space.
Definition: Interpolation.h:410
SamplerT SamlerType
Definition: Interpolation.h:551
static bool mipmap()
Definition: Interpolation.h:224
SharedPtr< GridSampler > Ptr
Definition: Interpolation.h:287
Provises a unified interface for sampling, i.e. interpolation.
Definition: Interpolation.h:64
static size_t order()
Definition: Interpolation.h:170
static int radius()
Definition: Interpolation.h:100
ValueType wsSample(const Vec3d &wspoint) const
Sample in world space.
Definition: Interpolation.h:340
static int radius()
Definition: Interpolation.h:123
Definition: Exceptions.h:13
static bool consistent()
Definition: Interpolation.h:225
ValueType sampleVoxel(typename Coord::ValueType i, typename Coord::ValueType j, typename Coord::ValueType k) const
Sample value in integer index space.
Definition: Interpolation.h:397
static bool staggered()
Definition: Interpolation.h:249
tools::DualGridSampler< AccT, SamplerT > mSampler
Definition: Interpolation.h:575
GridT GridType
Definition: Interpolation.h:549
Vec3i ceilVec3(const Vec3R &v)
Definition: Interpolation.h:592
static bool consistent()
Definition: Interpolation.h:125
math::Extrema extrema(const IterT &iter, bool threaded=true)
Iterate over a scalar grid and compute extrema (min/max) of the values of the voxels that are visited...
Definition: Statistics.h:354
DualGridSampler(const GridType &sourceGrid, const math::Transform &targetXform)
Grid and transform constructor.
Definition: Interpolation.h:457
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
static const char * name()
Definition: Interpolation.h:165
ValueType operator()(const Coord &ijk) const
Return the value of the source grid at the index coordinates, ijk, relative to the target grid...
Definition: Interpolation.h:521
static size_t order()
Definition: Interpolation.h:204
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels >> ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition: ValueAccessor.h:88
static bool staggered()
Definition: Interpolation.h:103
static size_t order()
Definition: Interpolation.h:227
static size_t order()
Definition: Interpolation.h:250
Definition: Interpolation.h:544
SharedPtr< GridSampler > Ptr
Definition: Interpolation.h:369
static bool consistent()
Definition: Interpolation.h:248
Definition: Transform.h:39
ValueType sampleVoxel(typename Coord::ValueType i, typename Coord::ValueType j, typename Coord::ValueType k) const
Sample value in integer index space.
Definition: Interpolation.h:318
Definition: Interpolation.h:220
FloatT FloatType
Definition: Interpolation.h:552
typename tree::ValueAccessor< TreeType > AccessorType
Definition: Grid.h:1072
static bool staggered()
Definition: Interpolation.h:126
typename GridOrTreeType::ValueType ValueType
Definition: Interpolation.h:288
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
typename TreeAdapter< AccT >::GridType GridType
Definition: Interpolation.h:450
static bool mipmap()
Definition: Interpolation.h:167
typename AccT::ValueType ValueType
Definition: Interpolation.h:449
typename TreeAdapter< GridType >::AccessorType AccessorType
Definition: Interpolation.h:452
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
Vec3< int32_t > Vec3i
Definition: Vec3.h:662
bool operator()(const Coord &xyz, FloatT &a, FloatT &b) const
Definition: Interpolation.h:564
AccT mAcc
Definition: Interpolation.h:574
GridSampler(const TreeType &tree, const math::Transform &transform)
Definition: Interpolation.h:299
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
math::Vec3< Real > Vec3R
Definition: Types.h:72
ValueType sampleVoxel(const RealType &x, const RealType &y, const RealType &z) const
Sample a point in index space in the grid.
Definition: Interpolation.h:309
bool isAligned() const
Return true if the two grids are aligned.
Definition: Interpolation.h:528
bool isAligned() const
Return true if the two grids are aligned.
Definition: Interpolation.h:487
static bool consistent()
Definition: Interpolation.h:202
Definition: Interpolation.h:97
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
typename TreeAdapter< GridOrTreeType >::AccessorType AccessorType
Definition: Interpolation.h:291
static bool mipmap()
Definition: Interpolation.h:124