| Line | Branch | Exec | Source |
|---|---|---|---|
| 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 { | ||
| 41 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 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, M_PI_4))); | ||
| 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, | ||
| 140 | MergePolicy merge = MERGE_ACTIVE_STATES); | ||
| 141 | |||
| 142 | #ifndef _WIN32 | ||
| 143 | template<typename InIterT, typename OutGridT, typename XformOp> | ||
| 144 | inline void transformValues(const InIterT& inIter, OutGridT& outGrid, | ||
| 145 | const XformOp& op, bool threaded = true, bool shareOp = true, | ||
| 146 | MergePolicy merge = MERGE_ACTIVE_STATES); | ||
| 147 | #endif | ||
| 148 | |||
| 149 | |||
| 150 | /// Iterate over a grid and at each step call @c op(iter). If threading is enabled, | ||
| 151 | /// call @c op.join(otherOp) to accumulate intermediate results from pairs of threads. | ||
| 152 | /// @param iter an iterator over a grid or its tree (@c Grid::ValueOnCIter, | ||
| 153 | /// @c Tree::NodeIter, etc.) | ||
| 154 | /// @param op a functor with a join method of the form <tt>void join(XformOp&)</tt> | ||
| 155 | /// and a call method of the form <tt>void op(const IterT&)</tt>, | ||
| 156 | /// where @c IterT is the type of @a iter | ||
| 157 | /// @param threaded if true, transform multiple values of the grid in parallel | ||
| 158 | /// @note If @a threaded is true, each thread gets its own copy of the @e original functor. | ||
| 159 | /// The order in which threads are joined is unspecified. | ||
| 160 | /// @note If @a threaded is false, the join method is never called. | ||
| 161 | /// | ||
| 162 | /// @par Example: | ||
| 163 | /// Compute the average of the active values of a scalar, floating-point grid | ||
| 164 | /// using the math::Stats class. | ||
| 165 | /// @code | ||
| 166 | /// namespace { | ||
| 167 | /// struct Average { | ||
| 168 | /// math::Stats stats; | ||
| 169 | /// | ||
| 170 | /// // Accumulate voxel and tile values into this functor's Stats object. | ||
| 171 | /// inline void operator()(const FloatGrid::ValueOnCIter& iter) { | ||
| 172 | /// if (iter.isVoxelValue()) stats.add(*iter); | ||
| 173 | /// else stats.add(*iter, iter.getVoxelCount()); | ||
| 174 | /// } | ||
| 175 | /// | ||
| 176 | /// // Accumulate another functor's Stats object into this functor's. | ||
| 177 | /// inline void join(Average& other) { stats.add(other.stats); } | ||
| 178 | /// | ||
| 179 | /// // Return the cumulative result. | ||
| 180 | /// inline double average() const { return stats.mean(); } | ||
| 181 | /// }; | ||
| 182 | /// } | ||
| 183 | /// { | ||
| 184 | /// FloatGrid grid = ...; | ||
| 185 | /// Average op; | ||
| 186 | /// tools::accumulate(grid.cbeginValueOn(), op); | ||
| 187 | /// double average = op.average(); | ||
| 188 | /// } | ||
| 189 | /// @endcode | ||
| 190 | /// | ||
| 191 | /// @note For more complex operations that require finer control over threading, | ||
| 192 | /// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction | ||
| 193 | /// with a tree::IteratorRange that wraps a grid or tree iterator. | ||
| 194 | template<typename IterT, typename XformOp> | ||
| 195 | inline void accumulate(const IterT& iter, XformOp& op, bool threaded = true); | ||
| 196 | |||
| 197 | |||
| 198 | /// @brief Set the value of the voxel at the given coordinates in @a tree to | ||
| 199 | /// the minimum of its current value and @a value, and mark the voxel as active. | ||
| 200 | /// @details This is typically significantly faster than calling getValue() | ||
| 201 | /// followed by setValueOn(). | ||
| 202 | /// @note @a TreeT can be either a Tree or a ValueAccessor. | ||
| 203 | template<typename TreeT> | ||
| 204 | void setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); | ||
| 205 | |||
| 206 | /// @brief Set the value of the voxel at the given coordinates in @a tree to | ||
| 207 | /// the maximum of its current value and @a value, and mark the voxel as active. | ||
| 208 | /// @details This is typically significantly faster than calling getValue() | ||
| 209 | /// followed by setValueOn(). | ||
| 210 | /// @note @a TreeT can be either a Tree or a ValueAccessor. | ||
| 211 | template<typename TreeT> | ||
| 212 | void setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); | ||
| 213 | |||
| 214 | /// @brief Set the value of the voxel at the given coordinates in @a tree to | ||
| 215 | /// the sum of its current value and @a value, and mark the voxel as active. | ||
| 216 | /// @details This is typically significantly faster than calling getValue() | ||
| 217 | /// followed by setValueOn(). | ||
| 218 | /// @note @a TreeT can be either a Tree or a ValueAccessor. | ||
| 219 | template<typename TreeT> | ||
| 220 | void setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); | ||
| 221 | |||
| 222 | /// @brief Set the value of the voxel at the given coordinates in @a tree to | ||
| 223 | /// the product of its current value and @a value, and mark the voxel as active. | ||
| 224 | /// @details This is typically significantly faster than calling getValue() | ||
| 225 | /// followed by setValueOn(). | ||
| 226 | /// @note @a TreeT can be either a Tree or a ValueAccessor. | ||
| 227 | template<typename TreeT> | ||
| 228 | void setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); | ||
| 229 | |||
| 230 | |||
| 231 | //////////////////////////////////////// | ||
| 232 | |||
| 233 | |||
| 234 | namespace valxform { | ||
| 235 | |||
| 236 | template<typename ValueType> | ||
| 237 | struct MinOp { | ||
| 238 | const ValueType val; | ||
| 239 | 2 | MinOp(const ValueType& v): val(v) {} | |
| 240 |
4/66✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
|
7 | inline void operator()(ValueType& v) const { v = std::min<ValueType>(v, val); } |
| 241 | }; | ||
| 242 | |||
| 243 | template<typename ValueType> | ||
| 244 | struct MaxOp { | ||
| 245 | const ValueType val; | ||
| 246 | 520028190 | MaxOp(const ValueType& v): val(v) {} | |
| 247 |
6/76✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✓ Branch 58 taken 5 times.
✓ Branch 59 taken 1 times.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✓ Branch 74 taken 10491837 times.
✓ Branch 75 taken 509536345 times.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
|
530520033 | inline void operator()(ValueType& v) const { v = std::max<ValueType>(v, val); } |
| 248 | }; | ||
| 249 | |||
| 250 | template<typename ValueType> | ||
| 251 | struct SumOp { | ||
| 252 | const ValueType val; | ||
| 253 |
0/44✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
|
19853882 | SumOp(const ValueType& v): val(v) {} |
| 254 | 7685484 | inline void operator()(ValueType& v) const { v += val; } | |
| 255 | }; | ||
| 256 | |||
| 257 | template<> | ||
| 258 | struct SumOp<bool> { | ||
| 259 | using ValueType = bool; | ||
| 260 | const ValueType val; | ||
| 261 |
0/12✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
29 | SumOp(const ValueType& v): val(v) {} |
| 262 |
6/32✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
|
29 | inline void operator()(ValueType& v) const { v = v || val; } |
| 263 | }; | ||
| 264 | |||
| 265 | template<typename ValueType> | ||
| 266 | struct MultOp { | ||
| 267 | const ValueType val; | ||
| 268 | ✗ | MultOp(const ValueType& v): val(v) {} | |
| 269 | ✗ | inline void operator()(ValueType& v) const { v *= val; } | |
| 270 | }; | ||
| 271 | |||
| 272 | template<> | ||
| 273 | struct MultOp<bool> { | ||
| 274 | using ValueType = bool; | ||
| 275 | const ValueType val; | ||
| 276 | ✗ | MultOp(const ValueType& v): val(v) {} | |
| 277 | ✗ | inline void operator()(ValueType& v) const { v = v && val; } | |
| 278 | }; | ||
| 279 | |||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | template<typename TreeT> | ||
| 284 | void | ||
| 285 | 3 | setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) | |
| 286 | { | ||
| 287 | 3 | tree.modifyValue(xyz, valxform::MinOp<typename TreeT::ValueType>(value)); | |
| 288 | 3 | } | |
| 289 | |||
| 290 | |||
| 291 | template<typename TreeT> | ||
| 292 | void | ||
| 293 | 3 | setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) | |
| 294 | { | ||
| 295 | 3 | tree.modifyValue(xyz, valxform::MaxOp<typename TreeT::ValueType>(value)); | |
| 296 | 3 | } | |
| 297 | |||
| 298 | |||
| 299 | template<typename TreeT> | ||
| 300 | void | ||
| 301 | 3 | setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) | |
| 302 | { | ||
| 303 | 3 | tree.modifyValue(xyz, valxform::SumOp<typename TreeT::ValueType>(value)); | |
| 304 | 3 | } | |
| 305 | |||
| 306 | |||
| 307 | template<typename TreeT> | ||
| 308 | void | ||
| 309 | ✗ | setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) | |
| 310 | { | ||
| 311 | ✗ | tree.modifyValue(xyz, valxform::MultOp<typename TreeT::ValueType>(value)); | |
| 312 | } | ||
| 313 | |||
| 314 | |||
| 315 | //////////////////////////////////////// | ||
| 316 | |||
| 317 | |||
| 318 | namespace valxform { | ||
| 319 | |||
| 320 | template<typename IterT, typename OpT> | ||
| 321 | 59968 | class SharedOpApplier | |
| 322 | { | ||
| 323 | public: | ||
| 324 | using IterRange = typename tree::IteratorRange<IterT>; | ||
| 325 | |||
| 326 | 1610 | SharedOpApplier(const IterT& iter, OpT& op): mIter(iter), mOp(op) {} | |
| 327 | |||
| 328 | 3228 | void process(bool threaded = true) | |
| 329 | { | ||
| 330 | 3228 | IterRange range(mIter); | |
| 331 |
2/2✓ Branch 0 taken 1610 times.
✓ Branch 1 taken 4 times.
|
3228 | if (threaded) { |
| 332 | 3220 | tbb::parallel_for(range, *this); | |
| 333 | } else { | ||
| 334 | 8 | (*this)(range); | |
| 335 | } | ||
| 336 | 3228 | } | |
| 337 | |||
| 338 | 609426240 | void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); } | |
| 339 | |||
| 340 | private: | ||
| 341 | IterT mIter; | ||
| 342 | OpT& mOp; | ||
| 343 | }; | ||
| 344 | |||
| 345 | |||
| 346 | template<typename IterT, typename OpT> | ||
| 347 | ✗ | class CopyableOpApplier | |
| 348 | { | ||
| 349 | public: | ||
| 350 | using IterRange = typename tree::IteratorRange<IterT>; | ||
| 351 | |||
| 352 | 23 | CopyableOpApplier(const IterT& iter, const OpT& op): mIter(iter), mOp(op), mOrigOp(&op) {} | |
| 353 | |||
| 354 | // When splitting this task, give the subtask a copy of the original functor, | ||
| 355 | // not of this task's functor, which might have been modified arbitrarily. | ||
| 356 | 930 | CopyableOpApplier(const CopyableOpApplier& other): | |
| 357 | 930 | mIter(other.mIter), mOp(*other.mOrigOp), mOrigOp(other.mOrigOp) {} | |
| 358 | |||
| 359 | 46 | void process(bool threaded = true) | |
| 360 | { | ||
| 361 | 46 | IterRange range(mIter); | |
| 362 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
46 | if (threaded) { |
| 363 | 46 | tbb::parallel_for(range, *this); | |
| 364 | } else { | ||
| 365 | ✗ | (*this)(range); | |
| 366 | } | ||
| 367 | 46 | } | |
| 368 | |||
| 369 | 9192184 | void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); } | |
| 370 | |||
| 371 | private: | ||
| 372 | IterT mIter; | ||
| 373 | OpT mOp; // copy of original functor | ||
| 374 | OpT const * const mOrigOp; // pointer to original functor | ||
| 375 | }; | ||
| 376 | |||
| 377 | } // namespace valxform | ||
| 378 | |||
| 379 | |||
| 380 | template<typename IterT, typename XformOp> | ||
| 381 | inline void | ||
| 382 | 63 | foreach(const IterT& iter, XformOp& op, bool threaded, bool shared) | |
| 383 | { | ||
| 384 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23 times.
|
63 | if (shared) { |
| 385 | typename valxform::SharedOpApplier<IterT, XformOp> proc(iter, op); | ||
| 386 | 17 | proc.process(threaded); | |
| 387 | } else { | ||
| 388 | using Processor = typename valxform::CopyableOpApplier<IterT, XformOp>; | ||
| 389 | Processor proc(iter, op); | ||
| 390 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
46 | proc.process(threaded); |
| 391 | } | ||
| 392 | 63 | } | |
| 393 | |||
| 394 | template<typename IterT, typename XformOp> | ||
| 395 | inline void | ||
| 396 | 8 | foreach(const IterT& iter, const XformOp& op, bool threaded, bool /*shared*/) | |
| 397 | { | ||
| 398 | // Const ops are shared across threads, not copied. | ||
| 399 | typename valxform::SharedOpApplier<IterT, const XformOp> proc(iter, op); | ||
| 400 |
15/30✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
|
1609 | proc.process(threaded); |
| 401 | 8 | } | |
| 402 | |||
| 403 | |||
| 404 | //////////////////////////////////////// | ||
| 405 | |||
| 406 | |||
| 407 | namespace valxform { | ||
| 408 | |||
| 409 | template<typename InIterT, typename OutTreeT, typename OpT> | ||
| 410 | class SharedOpTransformer | ||
| 411 | { | ||
| 412 | public: | ||
| 413 | using InTreeT = typename InIterT::TreeT; | ||
| 414 | using IterRange = typename tree::IteratorRange<InIterT>; | ||
| 415 | using OutValueT = typename OutTreeT::ValueType; | ||
| 416 | |||
| 417 | 1 | SharedOpTransformer(const InIterT& inIter, OutTreeT& outTree, OpT& op, MergePolicy merge): | |
| 418 | mIsRoot(true), | ||
| 419 | mInputIter(inIter), | ||
| 420 | mInputTree(inIter.getTree()), | ||
| 421 | mOutputTree(&outTree), | ||
| 422 | mOp(op), | ||
| 423 | 1 | mMergePolicy(merge) | |
| 424 | { | ||
| 425 | if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) { | ||
| 426 | OPENVDB_LOG_INFO("use tools::foreach(), not transformValues()," | ||
| 427 | " to transform a grid in place"); | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Splitting constructor | ||
| 432 | 5 | SharedOpTransformer(SharedOpTransformer& other, tbb::split): | |
| 433 | mIsRoot(false), | ||
| 434 | 5 | mInputIter(other.mInputIter), | |
| 435 | 5 | mInputTree(other.mInputTree), | |
| 436 | 5 | mOutputTree(new OutTreeT(zeroVal<OutValueT>())), | |
| 437 | 5 | mOp(other.mOp), | |
| 438 | 5 | mMergePolicy(other.mMergePolicy) | |
| 439 | 5 | {} | |
| 440 | |||
| 441 | ~SharedOpTransformer() | ||
| 442 | { | ||
| 443 | // Delete the output tree only if it was allocated locally | ||
| 444 | // (the top-level output tree was supplied by the caller). | ||
| 445 |
2/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
6 | if (!mIsRoot) { |
| 446 |
1/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
5 | delete mOutputTree; |
| 447 | mOutputTree = nullptr; | ||
| 448 | } | ||
| 449 | 5 | } | |
| 450 | |||
| 451 | 1 | void process(bool threaded = true) | |
| 452 | { | ||
| 453 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!mInputTree || !mOutputTree) return; |
| 454 | |||
| 455 | 1 | IterRange range(mInputIter); | |
| 456 | |||
| 457 | // Independently transform elements in the iterator range, | ||
| 458 | // either in parallel or serially. | ||
| 459 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (threaded) { |
| 460 | 1 | tbb::parallel_reduce(range, *this); | |
| 461 | } else { | ||
| 462 | ✗ | (*this)(range); | |
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | /// Transform each element in the given range. | ||
| 467 | 137 | void operator()(IterRange& range) const | |
| 468 | { | ||
| 469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
|
137 | if (!mOutputTree) return; |
| 470 | typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree); | ||
| 471 | for ( ; range; ++range) { | ||
| 472 |
1/2✓ Branch 1 taken 15628 times.
✗ Branch 2 not taken.
|
15628 | mOp(range.iterator(), outAccessor); |
| 473 | } | ||
| 474 | } | ||
| 475 | |||
| 476 | void join(const SharedOpTransformer& other) | ||
| 477 | { | ||
| 478 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | if (mOutputTree && other.mOutputTree) { |
| 479 | 5 | mOutputTree->merge(*other.mOutputTree, mMergePolicy); | |
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | private: | ||
| 484 | bool mIsRoot; | ||
| 485 | InIterT mInputIter; | ||
| 486 | const InTreeT* mInputTree; | ||
| 487 | OutTreeT* mOutputTree; | ||
| 488 | OpT& mOp; | ||
| 489 | MergePolicy mMergePolicy; | ||
| 490 | }; // class SharedOpTransformer | ||
| 491 | |||
| 492 | |||
| 493 | template<typename InIterT, typename OutTreeT, typename OpT> | ||
| 494 | class CopyableOpTransformer | ||
| 495 | { | ||
| 496 | public: | ||
| 497 | using InTreeT = typename InIterT::TreeT; | ||
| 498 | using IterRange = typename tree::IteratorRange<InIterT>; | ||
| 499 | using OutValueT = typename OutTreeT::ValueType; | ||
| 500 | |||
| 501 | 1 | CopyableOpTransformer(const InIterT& inIter, OutTreeT& outTree, | |
| 502 | const OpT& op, MergePolicy merge): | ||
| 503 | mIsRoot(true), | ||
| 504 | mInputIter(inIter), | ||
| 505 | mInputTree(inIter.getTree()), | ||
| 506 | mOutputTree(&outTree), | ||
| 507 | mOp(op), | ||
| 508 | mOrigOp(&op), | ||
| 509 | 1 | mMergePolicy(merge) | |
| 510 | { | ||
| 511 | if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) { | ||
| 512 | OPENVDB_LOG_INFO("use tools::foreach(), not transformValues()," | ||
| 513 | " to transform a grid in place"); | ||
| 514 | } | ||
| 515 | 1 | } | |
| 516 | |||
| 517 | // When splitting this task, give the subtask a copy of the original functor, | ||
| 518 | // not of this task's functor, which might have been modified arbitrarily. | ||
| 519 | 3 | CopyableOpTransformer(CopyableOpTransformer& other, tbb::split): | |
| 520 | mIsRoot(false), | ||
| 521 | 3 | mInputIter(other.mInputIter), | |
| 522 | 3 | mInputTree(other.mInputTree), | |
| 523 | 3 | mOutputTree(new OutTreeT(zeroVal<OutValueT>())), | |
| 524 | 3 | mOp(*other.mOrigOp), | |
| 525 | 3 | mOrigOp(other.mOrigOp), | |
| 526 | 3 | mMergePolicy(other.mMergePolicy) | |
| 527 | 3 | {} | |
| 528 | |||
| 529 | ~CopyableOpTransformer() | ||
| 530 | { | ||
| 531 | // Delete the output tree only if it was allocated locally | ||
| 532 | // (the top-level output tree was supplied by the caller). | ||
| 533 |
2/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
4 | if (!mIsRoot) { |
| 534 |
1/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
3 | delete mOutputTree; |
| 535 | mOutputTree = nullptr; | ||
| 536 | } | ||
| 537 | 3 | } | |
| 538 | |||
| 539 | 1 | void process(bool threaded = true) | |
| 540 | { | ||
| 541 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!mInputTree || !mOutputTree) return; |
| 542 | |||
| 543 | 1 | IterRange range(mInputIter); | |
| 544 | |||
| 545 | // Independently transform elements in the iterator range, | ||
| 546 | // either in parallel or serially. | ||
| 547 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (threaded) { |
| 548 | 1 | tbb::parallel_reduce(range, *this); | |
| 549 | } else { | ||
| 550 | ✗ | (*this)(range); | |
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 554 | /// Transform each element in the given range. | ||
| 555 | 140 | void operator()(IterRange& range) | |
| 556 | { | ||
| 557 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | if (!mOutputTree) return; |
| 558 | typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree); | ||
| 559 | for ( ; range; ++range) { | ||
| 560 |
1/2✓ Branch 1 taken 15628 times.
✗ Branch 2 not taken.
|
15628 | mOp(range.iterator(), outAccessor); |
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | void join(const CopyableOpTransformer& other) | ||
| 565 | { | ||
| 566 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | if (mOutputTree && other.mOutputTree) { |
| 567 | 3 | 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 | 2 | 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 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (shared) { |
| 595 | using Processor = typename valxform::SharedOpTransformer<InIterT, OutTreeT, XformOp>; | ||
| 596 | Processor proc(inIter, Adapter::tree(outGrid), op, merge); | ||
| 597 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | proc.process(threaded); |
| 598 | } else { | ||
| 599 | using Processor = typename valxform::CopyableOpTransformer<InIterT, OutTreeT, XformOp>; | ||
| 600 | 1 | Processor proc(inIter, Adapter::tree(outGrid), op, merge); | |
| 601 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | proc.process(threaded); |
| 602 | } | ||
| 603 | 2 | } | |
| 604 | |||
| 605 | #ifndef _WIN32 | ||
| 606 | template<typename InIterT, typename OutGridT, typename XformOp> | ||
| 607 | inline void | ||
| 608 | transformValues(const InIterT& inIter, OutGridT& outGrid, const XformOp& op, | ||
| 609 | bool threaded, bool /*share*/, MergePolicy merge) | ||
| 610 | { | ||
| 611 | using Adapter = TreeAdapter<OutGridT>; | ||
| 612 | using OutTreeT = typename Adapter::TreeType; | ||
| 613 | // Const ops are shared across threads, not copied. | ||
| 614 | using Processor = typename valxform::SharedOpTransformer<InIterT, OutTreeT, const XformOp>; | ||
| 615 | Processor proc(inIter, Adapter::tree(outGrid), op, merge); | ||
| 616 | proc.process(threaded); | ||
| 617 | } | ||
| 618 | #endif | ||
| 619 | |||
| 620 | |||
| 621 | //////////////////////////////////////// | ||
| 622 | |||
| 623 | |||
| 624 | namespace valxform { | ||
| 625 | |||
| 626 | template<typename IterT, typename OpT> | ||
| 627 | class OpAccumulator | ||
| 628 | { | ||
| 629 | public: | ||
| 630 | using IterRange = typename tree::IteratorRange<IterT>; | ||
| 631 | |||
| 632 | // The root task makes a const copy of the original functor (mOrigOp) | ||
| 633 | // and keeps a pointer to the original functor (mOp), which it then modifies. | ||
| 634 | // Each subtask keeps a const pointer to the root task's mOrigOp | ||
| 635 | // and makes and then modifies a non-const copy (mOp) of it. | ||
| 636 | 96 | OpAccumulator(const IterT& iter, OpT& op): | |
| 637 | mIsRoot(true), | ||
| 638 | mIter(iter), | ||
| 639 | mOp(&op), | ||
| 640 |
1/2✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
|
97 | mOrigOp(new OpT(op)) |
| 641 | 95 | {} | |
| 642 | |||
| 643 | // When splitting this task, give the subtask a copy of the original functor, | ||
| 644 | // not of this task's functor, which might have been modified arbitrarily. | ||
| 645 | 255 | OpAccumulator(OpAccumulator& other, tbb::split): | |
| 646 | mIsRoot(false), | ||
| 647 | 252 | mIter(other.mIter), | |
| 648 |
1/2✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
|
258 | mOp(new OpT(*other.mOrigOp)), |
| 649 | 255 | mOrigOp(other.mOrigOp) | |
| 650 | 252 | {} | |
| 651 | |||
| 652 |
4/6✓ Branch 0 taken 51 times.
✓ Branch 1 taken 129 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 129 times.
✗ Branch 6 not taken.
|
559 | ~OpAccumulator() { if (mIsRoot) delete mOrigOp; else delete mOp; } |
| 653 | |||
| 654 | 97 | void process(bool threaded = true) | |
| 655 | { | ||
| 656 | 95 | IterRange range(mIter); | |
| 657 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 19 times.
|
97 | if (threaded) { |
| 658 | 59 | tbb::parallel_reduce(range, *this); | |
| 659 | } else { | ||
| 660 | 38 | (*this)(range); | |
| 661 | } | ||
| 662 | 97 | } | |
| 663 | |||
| 664 | 28735990 | void operator()(IterRange& r) { for ( ; r; ++r) (*mOp)(r.iterator()); } | |
| 665 | |||
| 666 |
7/16✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 9 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 times.
|
129 | void join(OpAccumulator& other) { mOp->join(*other.mOp); } |
| 667 | |||
| 668 | private: | ||
| 669 | const bool mIsRoot; | ||
| 670 | const IterT mIter; | ||
| 671 | OpT* mOp; // pointer to original functor, which might get modified | ||
| 672 | OpT const * const mOrigOp; // const copy of original functor | ||
| 673 | }; // class OpAccumulator | ||
| 674 | |||
| 675 | } // namespace valxform | ||
| 676 | |||
| 677 | |||
| 678 | //////////////////////////////////////// | ||
| 679 | |||
| 680 | |||
| 681 | template<typename IterT, typename XformOp> | ||
| 682 | inline void | ||
| 683 | 97 | accumulate(const IterT& iter, XformOp& op, bool threaded) | |
| 684 | { | ||
| 685 | 192 | typename valxform::OpAccumulator<IterT, XformOp> proc(iter, op); | |
| 686 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
97 | proc.process(threaded); |
| 687 | 97 | } | |
| 688 | |||
| 689 | |||
| 690 | //////////////////////////////////////// | ||
| 691 | |||
| 692 | |||
| 693 | // Explicit Template Instantiation | ||
| 694 | |||
| 695 | #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 696 | |||
| 697 | #ifdef OPENVDB_INSTANTIATE_VALUETRANSFORMER | ||
| 698 | #include <openvdb/util/ExplicitInstantiation.h> | ||
| 699 | #endif | ||
| 700 | |||
| 701 | #define _FUNCTION(TreeT) \ | ||
| 702 | void setValueOnMin(TreeT&, const Coord&, const TreeT::ValueType&) | ||
| 703 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 704 | #undef _FUNCTION | ||
| 705 | |||
| 706 | #define _FUNCTION(TreeT) \ | ||
| 707 | void setValueOnMax(TreeT&, const Coord&, const TreeT::ValueType&) | ||
| 708 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 709 | #undef _FUNCTION | ||
| 710 | |||
| 711 | #define _FUNCTION(TreeT) \ | ||
| 712 | void setValueOnSum(TreeT&, const Coord&, const TreeT::ValueType&) | ||
| 713 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 714 | #undef _FUNCTION | ||
| 715 | |||
| 716 | #define _FUNCTION(TreeT) \ | ||
| 717 | void setValueOnMult(TreeT&, const Coord&, const TreeT::ValueType&) | ||
| 718 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 719 | #undef _FUNCTION | ||
| 720 | |||
| 721 | #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 722 | |||
| 723 | |||
| 724 | } // namespace tools | ||
| 725 | } // namespace OPENVDB_VERSION_NAME | ||
| 726 | } // namespace openvdb | ||
| 727 | |||
| 728 | #endif // OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED | ||
| 729 |