HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ValueTransformer.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2017 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 template<typename ValueType>
284 struct MultOp {
285  const ValueType val;
286  MultOp(const ValueType& v): val(v) {}
287  inline void operator()(ValueType& v) const { v *= val; }
288 };
289 
290 }
291 
292 
293 template<typename TreeT>
294 inline void
295 setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
296 {
297  tree.modifyValue(xyz, valxform::MinOp<typename TreeT::ValueType>(value));
298 }
299 
300 
301 template<typename TreeT>
302 inline void
303 setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
304 {
305  tree.modifyValue(xyz, valxform::MaxOp<typename TreeT::ValueType>(value));
306 }
307 
308 
309 template<typename TreeT>
310 inline void
311 setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
312 {
313  tree.modifyValue(xyz, valxform::SumOp<typename TreeT::ValueType>(value));
314 }
315 
316 
317 template<typename TreeT>
318 inline void
319 setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value)
320 {
321  tree.modifyValue(xyz, valxform::MultOp<typename TreeT::ValueType>(value));
322 }
323 
324 
325 ////////////////////////////////////////
326 
327 
328 namespace valxform {
329 
330 template<typename IterT, typename OpT>
332 {
333 public:
335 
336  SharedOpApplier(const IterT& iter, OpT& op): mIter(iter), mOp(op) {}
337 
338  void process(bool threaded = true)
339  {
340  IterRange range(mIter);
341  if (threaded) {
342  tbb::parallel_for(range, *this);
343  } else {
344  (*this)(range);
345  }
346  }
347 
348  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
349 
350 private:
351  IterT mIter;
352  OpT& mOp;
353 };
354 
355 
356 template<typename IterT, typename OpT>
358 {
359 public:
361 
362  CopyableOpApplier(const IterT& iter, const OpT& op): mIter(iter), mOp(op), mOrigOp(&op) {}
363 
364  // When splitting this task, give the subtask a copy of the original functor,
365  // not of this task's functor, which might have been modified arbitrarily.
367  mIter(other.mIter), mOp(*other.mOrigOp), mOrigOp(other.mOrigOp) {}
368 
369  void process(bool threaded = true)
370  {
371  IterRange range(mIter);
372  if (threaded) {
373  tbb::parallel_for(range, *this);
374  } else {
375  (*this)(range);
376  }
377  }
378 
379  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
380 
381 private:
382  IterT mIter;
383  OpT mOp; // copy of original functor
384  OpT const * const mOrigOp; // pointer to original functor
385 };
386 
387 } // namespace valxform
388 
389 
390 template<typename IterT, typename XformOp>
391 inline void
392 foreach(const IterT& iter, XformOp& op, bool threaded, bool shared)
393 {
394  if (shared) {
395  typename valxform::SharedOpApplier<IterT, XformOp> proc(iter, op);
396  proc.process(threaded);
397  } else {
398  typedef typename valxform::CopyableOpApplier<IterT, XformOp> Processor;
399  Processor proc(iter, op);
400  proc.process(threaded);
401  }
402 }
403 
404 template<typename IterT, typename XformOp>
405 inline void
406 foreach(const IterT& iter, const XformOp& op, bool threaded, bool /*shared*/)
407 {
408  // Const ops are shared across threads, not copied.
409  typename valxform::SharedOpApplier<IterT, const XformOp> proc(iter, op);
410  proc.process(threaded);
411 }
412 
413 
414 ////////////////////////////////////////
415 
416 
417 namespace valxform {
418 
419 template<typename InIterT, typename OutTreeT, typename OpT>
421 {
422 public:
423  typedef typename InIterT::TreeT InTreeT;
425  typedef typename OutTreeT::ValueType OutValueT;
426 
427  SharedOpTransformer(const InIterT& inIter, OutTreeT& outTree, OpT& op, MergePolicy merge):
428  mIsRoot(true),
429  mInputIter(inIter),
430  mInputTree(inIter.getTree()),
431  mOutputTree(&outTree),
432  mOp(op),
433  mMergePolicy(merge)
434  {
435  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
436  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
437  " to transform a grid in place");
438  }
439  }
440 
441  /// Splitting constructor
443  mIsRoot(false),
444  mInputIter(other.mInputIter),
445  mInputTree(other.mInputTree),
446  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
447  mOp(other.mOp),
448  mMergePolicy(other.mMergePolicy)
449  {}
450 
452  {
453  // Delete the output tree only if it was allocated locally
454  // (the top-level output tree was supplied by the caller).
455  if (!mIsRoot) {
456  delete mOutputTree;
457  mOutputTree = NULL;
458  }
459  }
460 
461  void process(bool threaded = true)
462  {
463  if (!mInputTree || !mOutputTree) return;
464 
465  IterRange range(mInputIter);
466 
467  // Independently transform elements in the iterator range,
468  // either in parallel or serially.
469  if (threaded) {
470  tbb::parallel_reduce(range, *this);
471  } else {
472  (*this)(range);
473  }
474  }
475 
476  /// Transform each element in the given range.
478  {
479  if (!mOutputTree) return;
480  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
481  for ( ; range; ++range) {
482  mOp(range.iterator(), outAccessor);
483  }
484  }
485 
486  void join(const SharedOpTransformer& other)
487  {
488  if (mOutputTree && other.mOutputTree) {
489  mOutputTree->merge(*other.mOutputTree, mMergePolicy);
490  }
491  }
492 
493 private:
494  bool mIsRoot;
495  InIterT mInputIter;
496  const InTreeT* mInputTree;
497  OutTreeT* mOutputTree;
498  OpT& mOp;
499  MergePolicy mMergePolicy;
500 }; // class SharedOpTransformer
501 
502 
503 template<typename InIterT, typename OutTreeT, typename OpT>
505 {
506 public:
507  typedef typename InIterT::TreeT InTreeT;
509  typedef typename OutTreeT::ValueType OutValueT;
510 
511  CopyableOpTransformer(const InIterT& inIter, OutTreeT& outTree,
512  const OpT& op, MergePolicy merge):
513  mIsRoot(true),
514  mInputIter(inIter),
515  mInputTree(inIter.getTree()),
516  mOutputTree(&outTree),
517  mOp(op),
518  mOrigOp(&op),
519  mMergePolicy(merge)
520  {
521  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
522  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
523  " to transform a grid in place");
524  }
525  }
526 
527  // When splitting this task, give the subtask a copy of the original functor,
528  // not of this task's functor, which might have been modified arbitrarily.
530  mIsRoot(false),
531  mInputIter(other.mInputIter),
532  mInputTree(other.mInputTree),
533  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
534  mOp(*other.mOrigOp),
535  mOrigOp(other.mOrigOp),
536  mMergePolicy(other.mMergePolicy)
537  {}
538 
540  {
541  // Delete the output tree only if it was allocated locally
542  // (the top-level output tree was supplied by the caller).
543  if (!mIsRoot) {
544  delete mOutputTree;
545  mOutputTree = NULL;
546  }
547  }
548 
549  void process(bool threaded = true)
550  {
551  if (!mInputTree || !mOutputTree) return;
552 
553  IterRange range(mInputIter);
554 
555  // Independently transform elements in the iterator range,
556  // either in parallel or serially.
557  if (threaded) {
558  tbb::parallel_reduce(range, *this);
559  } else {
560  (*this)(range);
561  }
562  }
563 
564  /// Transform each element in the given range.
566  {
567  if (!mOutputTree) return;
568  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
569  for ( ; range; ++range) {
570  mOp(range.iterator(), outAccessor);
571  }
572  }
573 
574  void join(const CopyableOpTransformer& other)
575  {
576  if (mOutputTree && other.mOutputTree) {
577  mOutputTree->merge(*other.mOutputTree, mMergePolicy);
578  }
579  }
580 
581 private:
582  bool mIsRoot;
583  InIterT mInputIter;
584  const InTreeT* mInputTree;
585  OutTreeT* mOutputTree;
586  OpT mOp; // copy of original functor
587  OpT const * const mOrigOp; // pointer to original functor
588  MergePolicy mMergePolicy;
589 }; // class CopyableOpTransformer
590 
591 } // namespace valxform
592 
593 
594 ////////////////////////////////////////
595 
596 
597 template<typename InIterT, typename OutGridT, typename XformOp>
598 inline void
599 transformValues(const InIterT& inIter, OutGridT& outGrid, XformOp& op,
600  bool threaded, bool shared, MergePolicy merge)
601 {
602  typedef TreeAdapter<OutGridT> Adapter;
603  typedef typename Adapter::TreeType OutTreeT;
604  if (shared) {
606  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
607  proc.process(threaded);
608  } else {
610  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
611  proc.process(threaded);
612  }
613 }
614 
615 #ifndef _MSC_VER
616 template<typename InIterT, typename OutGridT, typename XformOp>
617 inline void
618 transformValues(const InIterT& inIter, OutGridT& outGrid, const XformOp& op,
619  bool threaded, bool /*share*/, MergePolicy merge)
620 {
621  typedef TreeAdapter<OutGridT> Adapter;
622  typedef typename Adapter::TreeType OutTreeT;
623  // Const ops are shared across threads, not copied.
625  Processor proc(inIter, Adapter::tree(outGrid), op, merge);
626  proc.process(threaded);
627 }
628 #endif
629 
630 
631 ////////////////////////////////////////
632 
633 
634 namespace valxform {
635 
636 template<typename IterT, typename OpT>
638 {
639 public:
641 
642  // The root task makes a const copy of the original functor (mOrigOp)
643  // and keeps a pointer to the original functor (mOp), which it then modifies.
644  // Each subtask keeps a const pointer to the root task's mOrigOp
645  // and makes and then modifies a non-const copy (mOp) of it.
646  OpAccumulator(const IterT& iter, OpT& op):
647  mIsRoot(true),
648  mIter(iter),
649 ////
650  //mOp(&op),
651  //mOrigOp(new OpT(op))
652 mOp(NULL),
653 mOrigOp(NULL)
654 {
655  mOp = &op;
656  mOrigOp = new OpT(op);
657 }
658  //{}
659 ////
660 
661  // When splitting this task, give the subtask a copy of the original functor,
662  // not of this task's functor, which might have been modified arbitrarily.
663  OpAccumulator(OpAccumulator& other, tbb::split):
664  mIsRoot(false),
665  mIter(other.mIter),
666  mOp(new OpT(*other.mOrigOp)),
667  mOrigOp(other.mOrigOp)
668  {}
669 
670  ~OpAccumulator() { if (mIsRoot) delete mOrigOp; else delete mOp; }
671 
672  void process(bool threaded = true)
673  {
674  IterRange range(mIter);
675  if (threaded) {
676  tbb::parallel_reduce(range, *this);
677  } else {
678  (*this)(range);
679  }
680  }
681 
682  void operator()(IterRange& r) { for ( ; r; ++r) (*mOp)(r.iterator()); }
683 
684  void join(OpAccumulator& other) { mOp->join(*other.mOp); }
685 
686 private:
687  const bool mIsRoot;
688  const IterT mIter;
689  OpT* mOp; // pointer to original functor, which might get modified
690 ////
691  //OpT const * const mOrigOp; // const copy of original functor
692 OpT const * mOrigOp; // const copy of original functor
693 ////
694 }; // class OpAccumulator
695 
696 } // namespace valxform
697 
698 
699 ////////////////////////////////////////
700 
701 
702 template<typename IterT, typename XformOp>
703 inline void
704 accumulate(const IterT& iter, XformOp& op, bool threaded)
705 {
706  typename valxform::OpAccumulator<IterT, XformOp> proc(iter, op);
707  proc.process(threaded);
708 }
709 
710 } // namespace tools
711 } // namespace OPENVDB_VERSION_NAME
712 } // namespace openvdb
713 
714 #endif // OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
715 
716 // Copyright (c) 2012-2017 DreamWorks Animation LLC
717 // All rights reserved. This software is distributed under the
718 // 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)
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:937
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...
#define OPENVDB_VERSION_NAME
Definition: version.h:43
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:298
GLuint GLfloat * val
Definition: glcorearb.h:1607
GLboolean r
Definition: glcorearb.h:1221
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:94
SharedOpTransformer(const InIterT &inIter, OutTreeT &outTree, OpT &op, MergePolicy merge)