HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ValueTransformer.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @file ValueTransformer.h
5 ///
6 /// @author Peter Cucka
7 ///
8 /// tools::foreach() and tools::transformValues() transform the values in a grid
9 /// by iterating over the grid with a user-supplied iterator and applying a
10 /// user-supplied functor at each step of the iteration. With tools::foreach(),
11 /// the transformation is done in-place on the input grid, whereas with
12 /// tools::transformValues(), transformed values are written to an output grid
13 /// (which can, for example, have a different value type than the input grid).
14 /// Both functions can optionally transform multiple values of the grid in parallel.
15 ///
16 /// tools::accumulate() can be used to accumulate the results of applying a functor
17 /// at each step of a grid iteration. (The functor is responsible for storing and
18 /// updating intermediate results.) When the iteration is done serially the behavior is
19 /// the same as with tools::foreach(), but when multiple values are processed in parallel,
20 /// an additional step is performed: when any two threads finish processing,
21 /// @c op.join(otherOp) is called on one thread's functor to allow it to coalesce
22 /// its intermediate result with the other thread's.
23 ///
24 /// Finally, tools::setValueOnMin(), tools::setValueOnMax(), tools::setValueOnSum()
25 /// and tools::setValueOnMult() are wrappers around Tree::modifyValue() (or
26 /// ValueAccessor::modifyValue()) for some commmon in-place operations.
27 /// These are typically significantly faster than calling getValue() followed by setValue().
28 
29 #ifndef OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
30 #define OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
31 
32 #include <algorithm> // for std::min(), std::max()
33 #include <tbb/parallel_for.h>
34 #include <tbb/parallel_reduce.h>
35 #include <openvdb/Types.h>
36 #include <openvdb/Grid.h>
37 #include <openvdb/openvdb.h>
38 
39 
40 namespace openvdb {
42 namespace OPENVDB_VERSION_NAME {
43 namespace tools {
44 
45 /// Iterate over a grid and at each step call @c op(iter).
46 /// @param iter an iterator over a grid or its tree (@c Grid::ValueOnCIter,
47 /// @c Tree::NodeIter, etc.)
48 /// @param op a functor of the form <tt>void op(const IterT&)</tt>, where @c IterT is
49 /// the type of @a iter
50 /// @param threaded if true, transform multiple values of the grid in parallel
51 /// @param shareOp if true and @a threaded is true, all threads use the same functor;
52 /// otherwise, each thread gets its own copy of the @e original functor
53 ///
54 /// @par Example:
55 /// Multiply all values (both set and unset) of a scalar, floating-point grid by two.
56 /// @code
57 /// struct Local {
58 /// static inline void op(const FloatGrid::ValueAllIter& iter) {
59 /// iter.setValue(*iter * 2);
60 /// }
61 /// };
62 /// FloatGrid grid = ...;
63 /// tools::foreach(grid.beginValueAll(), Local::op);
64 /// @endcode
65 ///
66 /// @par Example:
67 /// Rotate all active vectors of a vector grid by 45 degrees about the y axis.
68 /// @code
69 /// namespace {
70 /// struct MatMul {
71 /// math::Mat3s M;
72 /// MatMul(const math::Mat3s& mat): M(mat) {}
73 /// inline void operator()(const VectorGrid::ValueOnIter& iter) const {
74 /// iter.setValue(M.transform(*iter));
75 /// }
76 /// };
77 /// }
78 /// {
79 /// VectorGrid grid = ...;
80 /// tools::foreach(grid.beginValueOn(),
81 /// MatMul(math::rotation<math::Mat3s>(math::Y, openvdb::math::pi<double>()/4.0)));
82 /// }
83 /// @endcode
84 ///
85 /// @note For more complex operations that require finer control over threading,
86 /// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction
87 /// with a tree::IteratorRange that wraps a grid or tree iterator.
88 template<typename IterT, typename XformOp>
89 inline void foreach(const IterT& iter, XformOp& op,
90  bool threaded = true, bool shareOp = true);
91 
92 template<typename IterT, typename XformOp>
93 inline void foreach(const IterT& iter, const XformOp& op,
94  bool threaded = true, bool shareOp = true);
95 
96 
97 /// Iterate over a grid and at each step call <tt>op(iter, accessor)</tt> to
98 /// populate (via the accessor) the given output grid, whose @c ValueType
99 /// need not be the same as the input grid's.
100 /// @param inIter a non-<tt>const</tt> or (preferably) @c const iterator over an
101 /// input grid or its tree (@c Grid::ValueOnCIter, @c Tree::NodeIter, etc.)
102 /// @param outGrid an empty grid to be populated
103 /// @param op a functor of the form
104 /// <tt>void op(const InIterT&, OutGridT::ValueAccessor&)</tt>,
105 /// where @c InIterT is the type of @a inIter
106 /// @param threaded if true, transform multiple values of the input grid in parallel
107 /// @param shareOp if true and @a threaded is true, all threads use the same functor;
108 /// otherwise, each thread gets its own copy of the @e original functor
109 /// @param merge how to merge intermediate results from multiple threads (see Types.h)
110 ///
111 /// @par Example:
112 /// Populate a scalar floating-point grid with the lengths of the vectors from all
113 /// active voxels of a vector-valued input grid.
114 /// @code
115 /// struct Local {
116 /// static void op(
117 /// const Vec3fGrid::ValueOnCIter& iter,
118 /// FloatGrid::ValueAccessor& accessor)
119 /// {
120 /// if (iter.isVoxelValue()) { // set a single voxel
121 /// accessor.setValue(iter.getCoord(), iter->length());
122 /// } else { // fill an entire tile
123 /// CoordBBox bbox;
124 /// iter.getBoundingBox(bbox);
125 /// accessor.getTree()->fill(bbox, iter->length());
126 /// }
127 /// }
128 /// };
129 /// Vec3fGrid inGrid = ...;
130 /// FloatGrid outGrid;
131 /// tools::transformValues(inGrid.cbeginValueOn(), outGrid, Local::op);
132 /// @endcode
133 ///
134 /// @note For more complex operations that require finer control over threading,
135 /// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction
136 /// with a tree::IteratorRange that wraps a grid or tree iterator.
137 template<typename InIterT, typename OutGridT, typename XformOp>
138 inline void transformValues(const InIterT& inIter, OutGridT& outGrid,
139  XformOp& op, bool threaded = true, bool shareOp = true,
141 
142 template<typename InIterT, typename OutGridT, typename XformOp>
143 inline void transformValues(const InIterT& inIter, OutGridT& outGrid,
144  const XformOp& op, bool threaded = true, bool shareOp = true,
146 
147 
148 /// Iterate over a grid and at each step call @c op(iter). If threading is enabled,
149 /// call @c op.join(otherOp) to accumulate intermediate results from pairs of threads.
150 /// @param iter an iterator over a grid or its tree (@c Grid::ValueOnCIter,
151 /// @c Tree::NodeIter, etc.)
152 /// @param op a functor with a join method of the form <tt>void join(XformOp&)</tt>
153 /// and a call method of the form <tt>void op(const IterT&)</tt>,
154 /// where @c IterT is the type of @a iter
155 /// @param threaded if true, transform multiple values of the grid in parallel
156 /// @note If @a threaded is true, each thread gets its own copy of the @e original functor.
157 /// The order in which threads are joined is unspecified.
158 /// @note If @a threaded is false, the join method is never called.
159 ///
160 /// @par Example:
161 /// Compute the average of the active values of a scalar, floating-point grid
162 /// using the math::Stats class.
163 /// @code
164 /// namespace {
165 /// struct Average {
166 /// math::Stats stats;
167 ///
168 /// // Accumulate voxel and tile values into this functor's Stats object.
169 /// inline void operator()(const FloatGrid::ValueOnCIter& iter) {
170 /// if (iter.isVoxelValue()) stats.add(*iter);
171 /// else stats.add(*iter, iter.getVoxelCount());
172 /// }
173 ///
174 /// // Accumulate another functor's Stats object into this functor's.
175 /// inline void join(Average& other) { stats.add(other.stats); }
176 ///
177 /// // Return the cumulative result.
178 /// inline double average() const { return stats.mean(); }
179 /// };
180 /// }
181 /// {
182 /// FloatGrid grid = ...;
183 /// Average op;
184 /// tools::accumulate(grid.cbeginValueOn(), op);
185 /// double average = op.average();
186 /// }
187 /// @endcode
188 ///
189 /// @note For more complex operations that require finer control over threading,
190 /// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction
191 /// with a tree::IteratorRange that wraps a grid or tree iterator.
192 template<typename IterT, typename XformOp>
193 inline void accumulate(const IterT& iter, XformOp& op, bool threaded = true);
194 
195 
196 /// @brief Set the value of the voxel at the given coordinates in @a tree to
197 /// the minimum of its current value and @a value, and mark the voxel as active.
198 /// @details This is typically significantly faster than calling getValue()
199 /// followed by setValueOn().
200 /// @note @a TreeT can be either a Tree or a ValueAccessor.
201 template<typename TreeT>
202 void setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value);
203 
204 /// @brief Set the value of the voxel at the given coordinates in @a tree to
205 /// the maximum of its current value and @a value, and mark the voxel as active.
206 /// @details This is typically significantly faster than calling getValue()
207 /// followed by setValueOn().
208 /// @note @a TreeT can be either a Tree or a ValueAccessor.
209 template<typename TreeT>
210 void setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value);
211 
212 /// @brief Set the value of the voxel at the given coordinates in @a tree to
213 /// the sum of its current value and @a value, and mark the voxel as active.
214 /// @details This is typically significantly faster than calling getValue()
215 /// followed by setValueOn().
216 /// @note @a TreeT can be either a Tree or a ValueAccessor.
217 template<typename TreeT>
218 void setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value);
219 
220 /// @brief Set the value of the voxel at the given coordinates in @a tree to
221 /// the product of its current value and @a value, and mark the voxel as active.
222 /// @details This is typically significantly faster than calling getValue()
223 /// followed by setValueOn().
224 /// @note @a TreeT can be either a Tree or a ValueAccessor.
225 template<typename TreeT>
226 void setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value);
227 
228 
229 ////////////////////////////////////////
230 
231 
232 namespace valxform {
233 
234 template<typename ValueType>
235 struct MinOp {
236  const ValueType val;
237  MinOp(const ValueType& v): val(v) {}
238  inline void operator()(ValueType& v) const { v = std::min<ValueType>(v, val); }
239 };
240 
241 template<typename ValueType>
242 struct MaxOp {
243  const ValueType val;
244  MaxOp(const ValueType& v): val(v) {}
245  inline void operator()(ValueType& v) const { v = std::max<ValueType>(v, val); }
246 };
247 
248 template<typename ValueType>
249 struct SumOp {
250  const ValueType val;
251  SumOp(const ValueType& v): val(v) {}
252  inline void operator()(ValueType& v) const { v += val; }
253 };
254 
255 template<>
256 struct SumOp<bool> {
257  using ValueType = bool;
258  const ValueType val;
259  SumOp(const ValueType& v): val(v) {}
260  inline void operator()(ValueType& v) const { v = v || val; }
261 };
262 
263 template<typename ValueType>
264 struct MultOp {
265  const ValueType val;
266  MultOp(const ValueType& v): val(v) {}
267  inline void operator()(ValueType& v) const { v *= val; }
268 };
269 
270 template<>
271 struct MultOp<bool> {
272  using ValueType = bool;
273  const ValueType val;
274  MultOp(const ValueType& v): val(v) {}
275  inline void operator()(ValueType& v) const { v = v && val; }
276 };
277 
278 }
279 
280 
281 template<typename TreeT>
282 void
283 setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
284 {
285  tree.modifyValue(xyz, valxform::MinOp<typename TreeT::ValueType>(value));
286 }
287 
288 
289 template<typename TreeT>
290 void
291 setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
292 {
293  tree.modifyValue(xyz, valxform::MaxOp<typename TreeT::ValueType>(value));
294 }
295 
296 
297 template<typename TreeT>
298 void
299 setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
300 {
301  tree.modifyValue(xyz, valxform::SumOp<typename TreeT::ValueType>(value));
302 }
303 
304 
305 template<typename TreeT>
306 void
307 setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
308 {
309  tree.modifyValue(xyz, valxform::MultOp<typename TreeT::ValueType>(value));
310 }
311 
312 
313 ////////////////////////////////////////
314 
315 
316 namespace valxform {
317 
318 template<typename IterT, typename OpT>
320 {
321 public:
323 
324  SharedOpApplier(const IterT& iter, OpT& op): mIter(iter), mOp(op) {}
325 
326  void process(bool threaded = true)
327  {
328  IterRange range(mIter);
329  if (threaded) {
330  tbb::parallel_for(range, *this);
331  } else {
332  (*this)(range);
333  }
334  }
335 
336  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
337 
338 private:
339  IterT mIter;
340  OpT& mOp;
341 };
342 
343 
344 template<typename IterT, typename OpT>
346 {
347 public:
349 
350  CopyableOpApplier(const IterT& iter, const OpT& op): mIter(iter), mOp(op), mOrigOp(&op) {}
351 
352  // When splitting this task, give the subtask a copy of the original functor,
353  // not of this task's functor, which might have been modified arbitrarily.
355  mIter(other.mIter), mOp(*other.mOrigOp), mOrigOp(other.mOrigOp) {}
356 
357  void process(bool threaded = true)
358  {
359  IterRange range(mIter);
360  if (threaded) {
361  tbb::parallel_for(range, *this);
362  } else {
363  (*this)(range);
364  }
365  }
366 
367  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
368 
369 private:
370  IterT mIter;
371  OpT mOp; // copy of original functor
372  OpT const * const mOrigOp; // pointer to original functor
373 };
374 
375 } // namespace valxform
376 
377 
378 template<typename IterT, typename XformOp>
379 inline void
380 foreach(const IterT& iter, XformOp& op, bool threaded, bool shared)
381 {
382  if (shared) {
383  typename valxform::SharedOpApplier<IterT, XformOp> proc(iter, op);
384  proc.process(threaded);
385  } else {
387  Processor proc(iter, op);
388  proc.process(threaded);
389  }
390 }
391 
392 template<typename IterT, typename XformOp>
393 inline void
394 foreach(const IterT& iter, const XformOp& op, bool threaded, bool /*shared*/)
395 {
396  // Const ops are shared across threads, not copied.
397  typename valxform::SharedOpApplier<IterT, const XformOp> proc(iter, op);
398  proc.process(threaded);
399 }
400 
401 
402 ////////////////////////////////////////
403 
404 
405 namespace valxform {
406 
407 template<typename InIterT, typename OutTreeT, typename OpT>
409 {
410 public:
411  using InTreeT = typename InIterT::TreeT;
413  using OutValueT = typename OutTreeT::ValueType;
414 
415  SharedOpTransformer(const InIterT& inIter, OutTreeT& outTree, OpT& op, MergePolicy merge):
416  mIsRoot(true),
417  mInputIter(inIter),
418  mInputTree(inIter.getTree()),
419  mOutputTree(&outTree),
420  mOp(op),
421  mMergePolicy(merge)
422  {
423  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
424  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
425  " to transform a grid in place");
426  }
427  }
428 
429  /// Splitting constructor
431  mIsRoot(false),
432  mInputIter(other.mInputIter),
433  mInputTree(other.mInputTree),
434  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
435  mOp(other.mOp),
436  mMergePolicy(other.mMergePolicy)
437  {}
438 
440  {
441  // Delete the output tree only if it was allocated locally
442  // (the top-level output tree was supplied by the caller).
443  if (!mIsRoot) {
444  delete mOutputTree;
445  mOutputTree = nullptr;
446  }
447  }
448 
449  void process(bool threaded = true)
450  {
451  if (!mInputTree || !mOutputTree) return;
452 
453  IterRange range(mInputIter);
454 
455  // Independently transform elements in the iterator range,
456  // either in parallel or serially.
457  if (threaded) {
458  tbb::parallel_reduce(range, *this);
459  } else {
460  (*this)(range);
461  }
462  }
463 
464  /// Transform each element in the given range.
465  void operator()(const IterRange& range) const
466  {
467  if (!mOutputTree) return;
468  IterRange r(range);
469  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
470  for ( ; r; ++r) {
471  mOp(r.iterator(), outAccessor);
472  }
473  }
474 
475  void join(const SharedOpTransformer& other)
476  {
477  if (mOutputTree && other.mOutputTree) {
478  mOutputTree->merge(*other.mOutputTree, mMergePolicy);
479  }
480  }
481 
482 private:
483  bool mIsRoot;
484  InIterT mInputIter;
485  const InTreeT* mInputTree;
486  OutTreeT* mOutputTree;
487  OpT& mOp;
488  MergePolicy mMergePolicy;
489 }; // class SharedOpTransformer
490 
491 
492 template<typename InIterT, typename OutTreeT, typename OpT>
494 {
495 public:
496  using InTreeT = typename InIterT::TreeT;
498  using OutValueT = typename OutTreeT::ValueType;
499 
500  CopyableOpTransformer(const InIterT& inIter, OutTreeT& outTree,
501  const OpT& op, MergePolicy merge):
502  mIsRoot(true),
503  mInputIter(inIter),
504  mInputTree(inIter.getTree()),
505  mOutputTree(&outTree),
506  mOp(op),
507  mOrigOp(&op),
508  mMergePolicy(merge)
509  {
510  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
511  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
512  " to transform a grid in place");
513  }
514  }
515 
516  // When splitting this task, give the subtask a copy of the original functor,
517  // not of this task's functor, which might have been modified arbitrarily.
519  mIsRoot(false),
520  mInputIter(other.mInputIter),
521  mInputTree(other.mInputTree),
522  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
523  mOp(*other.mOrigOp),
524  mOrigOp(other.mOrigOp),
525  mMergePolicy(other.mMergePolicy)
526  {}
527 
529  {
530  // Delete the output tree only if it was allocated locally
531  // (the top-level output tree was supplied by the caller).
532  if (!mIsRoot) {
533  delete mOutputTree;
534  mOutputTree = nullptr;
535  }
536  }
537 
538  void process(bool threaded = true)
539  {
540  if (!mInputTree || !mOutputTree) return;
541 
542  IterRange range(mInputIter);
543 
544  // Independently transform elements in the iterator range,
545  // either in parallel or serially.
546  if (threaded) {
547  tbb::parallel_reduce(range, *this);
548  } else {
549  (*this)(range);
550  }
551  }
552 
553  /// Transform each element in the given range.
555  {
556  if (!mOutputTree) return;
557  IterRange r(range);
558  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
559  for ( ; r; ++r) {
560  mOp(r.iterator(), outAccessor);
561  }
562  }
563 
564  void join(const CopyableOpTransformer& other)
565  {
566  if (mOutputTree && other.mOutputTree) {
567  mOutputTree->merge(*other.mOutputTree, mMergePolicy);
568  }
569  }
570 
571 private:
572  bool mIsRoot;
573  InIterT mInputIter;
574  const InTreeT* mInputTree;
575  OutTreeT* mOutputTree;
576  OpT mOp; // copy of original functor
577  OpT const * const mOrigOp; // pointer to original functor
578  MergePolicy mMergePolicy;
579 }; // class CopyableOpTransformer
580 
581 } // namespace valxform
582 
583 
584 ////////////////////////////////////////
585 
586 
587 template<typename InIterT, typename OutGridT, typename XformOp>
588 inline void
589 transformValues(const InIterT& inIter, OutGridT& outGrid, XformOp& op,
590  bool threaded, bool shared, MergePolicy merge)
591 {
592  using Adapter = TreeAdapter<OutGridT>;
593  using OutTreeT = typename Adapter::TreeType;
594  if (shared) {
596  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
597  proc.process(threaded);
598  } else {
600  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
601  proc.process(threaded);
602  }
603 }
604 
605 template<typename InIterT, typename OutGridT, typename XformOp>
606 inline void
607 transformValues(const InIterT& inIter, OutGridT& outGrid, const XformOp& op,
608  bool threaded, bool /*share*/, MergePolicy merge)
609 {
610  using Adapter = TreeAdapter<OutGridT>;
611  using OutTreeT = typename Adapter::TreeType;
612  // Const ops are shared across threads, not copied.
614  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
615  proc.process(threaded);
616 }
617 
618 
619 ////////////////////////////////////////
620 
621 
622 namespace valxform {
623 
624 template<typename IterT, typename OpT>
626 {
627 public:
629 
630  // The root task makes a const copy of the original functor (mOrigOp)
631  // and keeps a pointer to the original functor (mOp), which it then modifies.
632  // Each subtask keeps a const pointer to the root task's mOrigOp
633  // and makes and then modifies a non-const copy (mOp) of it.
634  OpAccumulator(const IterT& iter, OpT& op):
635  mIsRoot(true),
636  mIter(iter),
637  mOp(&op),
638  mOrigOp(new OpT(op))
639  {}
640 
641  // When splitting this task, give the subtask a copy of the original functor,
642  // not of this task's functor, which might have been modified arbitrarily.
644  mIsRoot(false),
645  mIter(other.mIter),
646  mOp(new OpT(*other.mOrigOp)),
647  mOrigOp(other.mOrigOp)
648  {}
649 
650  ~OpAccumulator() { if (mIsRoot) delete mOrigOp; else delete mOp; }
651 
652  void process(bool threaded = true)
653  {
654  IterRange range(mIter);
655  if (threaded) {
656  tbb::parallel_reduce(range, *this);
657  } else {
658  (*this)(range);
659  }
660  }
661 
662  void operator()(const IterRange& r) { for (IterRange it(r); it.test(); ++it) (*mOp)(it.iterator()); }
663 
664  void join(OpAccumulator& other) { mOp->join(*other.mOp); }
665 
666 private:
667  const bool mIsRoot;
668  const IterT mIter;
669  OpT* mOp; // pointer to original functor, which might get modified
670  OpT const * const mOrigOp; // const copy of original functor
671 }; // class OpAccumulator
672 
673 } // namespace valxform
674 
675 
676 ////////////////////////////////////////
677 
678 
679 template<typename IterT, typename XformOp>
680 inline void
681 accumulate(const IterT& iter, XformOp& op, bool threaded)
682 {
683  typename valxform::OpAccumulator<IterT, XformOp> proc(iter, op);
684  proc.process(threaded);
685 }
686 
687 
688 ////////////////////////////////////////
689 
690 
691 // Explicit Template Instantiation
692 
693 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
694 
695 #ifdef OPENVDB_INSTANTIATE_VALUETRANSFORMER
697 #endif
698 
699 #define _FUNCTION(TreeT) \
700  void setValueOnMin(TreeT&, const Coord&, const TreeT::ValueType&)
702 #undef _FUNCTION
703 
704 #define _FUNCTION(TreeT) \
705  void setValueOnMax(TreeT&, const Coord&, const TreeT::ValueType&)
707 #undef _FUNCTION
708 
709 #define _FUNCTION(TreeT) \
710  void setValueOnSum(TreeT&, const Coord&, const TreeT::ValueType&)
712 #undef _FUNCTION
713 
714 #define _FUNCTION(TreeT) \
715  void setValueOnMult(TreeT&, const Coord&, const TreeT::ValueType&)
717 #undef _FUNCTION
718 
719 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
720 
721 
722 } // namespace tools
723 } // namespace OPENVDB_VERSION_NAME
724 } // namespace openvdb
725 
726 #endif // OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
Definition: parallel.h:127
GLenum GLint * range
Definition: glcorearb.h:1925
const GLdouble * v
Definition: glcorearb.h:837
CopyableOpTransformer(const InIterT &inIter, OutTreeT &outTree, const OpT &op, MergePolicy merge)
void operator()(const IterRange &range) const
Transform each element in the given range.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:239
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
SharedOpTransformer(SharedOpTransformer &other, tbb::split)
Splitting constructor.
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1059
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:70
void setValueOnMax(TreeT &tree, const Coord &xyz, const typename TreeT::ValueType &value)
Set the value of the voxel at the given coordinates in tree to the maximum of its current value and v...
void setValueOnMult(TreeT &tree, const Coord &xyz, const typename TreeT::ValueType &value)
Set the value of the voxel at the given coordinates in tree to the product of its current value and v...
void setValueOnMin(TreeT &tree, const Coord &xyz, const typename TreeT::ValueType &value)
Set the value of the voxel at the given coordinates in tree to the minimum of its current value and v...
void setValueOnSum(TreeT &tree, const Coord &xyz, const typename TreeT::ValueType &value)
Set the value of the voxel at the given coordinates in tree to the sum of its current value and value...
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h:169
#define OPENVDB_LOG_INFO(mesg)
Definition: logging.h:276
void accumulate(const IterT &iter, XformOp &op, bool threaded=true)
void transformValues(const InIterT &inIter, OutGridT &outGrid, XformOp &op, bool threaded=true, bool shareOp=true, MergePolicy merge=MERGE_ACTIVE_STATES)
class OCIOEXPORT Processor
GLuint GLfloat * val
Definition: glcorearb.h:1608
Definition: core.h:1131
GLboolean r
Definition: glcorearb.h:1222
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
void operator()(const IterRange &range)
Transform each element in the given range.
SharedOpTransformer(const InIterT &inIter, OutTreeT &outTree, OpT &op, MergePolicy merge)