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