GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/tools/GridTransformer.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 214 289 74.0%
Functions: 115 597 19.3%
Branches: 182 1126 16.2%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file GridTransformer.h
5 /// @author Peter Cucka
6
7 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
8 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
9
10 #include <openvdb/Grid.h>
11 #include <openvdb/Types.h>
12 #include <openvdb/math/Math.h> // for isApproxEqual()
13 #include <openvdb/util/NullInterrupter.h>
14 #include "ChangeBackground.h"
15 #include "Interpolation.h"
16 #include "LevelSetRebuild.h" // for doLevelSetRebuild()
17 #include "SignedFloodFill.h" // for signedFloodFill
18 #include "Prune.h" // for pruneLevelSet
19 #include <openvdb/openvdb.h>
20 #include <tbb/blocked_range.h>
21 #include <tbb/parallel_reduce.h>
22 #include <cmath>
23 #include <functional>
24
25 namespace openvdb {
26 OPENVDB_USE_VERSION_NAMESPACE
27 namespace OPENVDB_VERSION_NAME {
28 namespace tools {
29
30 /// @brief Resample an input grid into an output grid of the same type such that,
31 /// after resampling, the input and output grids coincide (apart from sampling
32 /// artifacts), but the output grid's transform is unchanged.
33 /// @details Specifically, this function resamples the input grid into the output
34 /// grid's index space, using a sampling kernel like PointSampler, BoxSampler,
35 /// or QuadraticSampler.
36 /// @param inGrid the grid to be resampled
37 /// @param outGrid the grid into which to write the resampled voxel data
38 /// @param interrupter an object adhering to the util::NullInterrupter interface
39 /// @par Example:
40 /// @code
41 /// // Create an input grid with the default identity transform
42 /// // and populate it with a level-set sphere.
43 /// FloatGrid::ConstPtr src = tools::makeSphere(...);
44 /// // Create an output grid and give it a uniform-scale transform.
45 /// FloatGrid::Ptr dest = FloatGrid::create();
46 /// const float voxelSize = 0.5;
47 /// dest->setTransform(math::Transform::createLinearTransform(voxelSize));
48 /// // Resample the input grid into the output grid, reproducing
49 /// // the level-set sphere at a smaller voxel size.
50 /// MyInterrupter interrupter = ...;
51 /// tools::resampleToMatch<tools::QuadraticSampler>(*src, *dest, interrupter);
52 /// @endcode
53 template<typename Sampler, typename Interrupter, typename GridType>
54 void
55 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
56
57 /// @brief Resample an input grid into an output grid of the same type such that,
58 /// after resampling, the input and output grids coincide (apart from sampling
59 /// artifacts), but the output grid's transform is unchanged.
60 /// @details Specifically, this function resamples the input grid into the output
61 /// grid's index space, using a sampling kernel like PointSampler, BoxSampler,
62 /// or QuadraticSampler.
63 /// @param inGrid the grid to be resampled
64 /// @param outGrid the grid into which to write the resampled voxel data
65 /// @par Example:
66 /// @code
67 /// // Create an input grid with the default identity transform
68 /// // and populate it with a level-set sphere.
69 /// FloatGrid::ConstPtr src = tools::makeSphere(...);
70 /// // Create an output grid and give it a uniform-scale transform.
71 /// FloatGrid::Ptr dest = FloatGrid::create();
72 /// const float voxelSize = 0.5;
73 /// dest->setTransform(math::Transform::createLinearTransform(voxelSize));
74 /// // Resample the input grid into the output grid, reproducing
75 /// // the level-set sphere at a smaller voxel size.
76 /// tools::resampleToMatch<tools::QuadraticSampler>(*src, *dest);
77 /// @endcode
78 template<typename Sampler, typename GridType>
79 void
80 resampleToMatch(const GridType& inGrid, GridType& outGrid);
81
82
83 ////////////////////////////////////////
84
85 /// @cond OPENVDB_DOCS_INTERNAL
86
87 namespace internal {
88
89 /// @brief A TileSampler wraps a grid sampler of another type (BoxSampler,
90 /// QuadraticSampler, etc.), and for samples that fall within a given tile
91 /// of the grid, it returns a cached tile value instead of accessing the grid.
92 template<typename Sampler, typename TreeT>
93 class TileSampler: public Sampler
94 {
95 public:
96 using ValueT = typename TreeT::ValueType;
97
98 /// @param b the index-space bounding box of a particular grid tile
99 /// @param tileVal the tile's value
100 /// @param on the tile's active state
101 96 TileSampler(const CoordBBox& b, const ValueT& tileVal, bool on):
102 96 mBBox(b.min().asVec3d(), b.max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
103 {
104 96 mBBox.expand(-this->radius()); // shrink the bounding box by the sample radius
105 96 mEmpty = mBBox.empty();
106 96 }
107
108 27582384 bool sample(const TreeT& inTree, const Vec3R& inCoord, ValueT& result) const
109 {
110
3/4
✓ Branch 0 taken 13791192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4634322 times.
✓ Branch 3 taken 9156870 times.
27582384 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal; return mActive; }
111 18313740 return Sampler::sample(inTree, inCoord, result);
112 }
113
114 protected:
115 BBoxd mBBox;
116 ValueT mVal;
117 bool mActive, mEmpty;
118 };
119
120
121 /// @brief For point sampling, tree traversal is less expensive than testing
122 /// bounding box membership.
123 template<typename TreeT>
124 class TileSampler<PointSampler, TreeT>: public PointSampler {
125 public:
126 TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
127 };
128
129 /// @brief For point sampling, tree traversal is less expensive than testing
130 /// bounding box membership.
131 template<typename TreeT>
132 class TileSampler<StaggeredPointSampler, TreeT>: public StaggeredPointSampler {
133 public:
134 TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
135 };
136
137 } // namespace internal
138
139 /// @endcond
140
141
142 ////////////////////////////////////////
143
144
145 /// A GridResampler applies a geometric transformation to an
146 /// input grid using one of several sampling schemes, and stores
147 /// the result in an output grid.
148 ///
149 /// Usage:
150 /// @code
151 /// GridResampler resampler();
152 /// resampler.transformGrid<BoxSampler>(xform, inGrid, outGrid);
153 /// @endcode
154 /// where @c xform is a functor that implements the following methods:
155 /// @code
156 /// bool isAffine() const
157 /// openvdb::Vec3d transform(const openvdb::Vec3d&) const
158 /// openvdb::Vec3d invTransform(const openvdb::Vec3d&) const
159 /// @endcode
160 /// @note When the transform is affine and can be expressed as a 4 x 4 matrix,
161 /// a GridTransformer is much more efficient than a GridResampler.
162 class GridResampler
163 {
164 public:
165 using Ptr = SharedPtr<GridResampler>;
166 using InterruptFunc = std::function<bool (void)>;
167
168
0/46
✗ 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.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 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.
331848 GridResampler(): mThreaded(true), mTransformTiles(true) {}
169
11/186
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 17 taken 8 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 8 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 8 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✓ Branch 33 taken 8 times.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✓ Branch 37 taken 331776 times.
✗ 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 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 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.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 140 not taken.
✗ Branch 141 not taken.
✗ Branch 142 not taken.
✗ Branch 143 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 147 not taken.
✗ Branch 148 not taken.
✗ Branch 149 not taken.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✗ Branch 152 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 167 not taken.
✗ Branch 168 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 171 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
✗ Branch 182 not taken.
✗ Branch 183 not taken.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
331849 virtual ~GridResampler() {}
170
171 GridResampler(const GridResampler&) = default;
172 GridResampler& operator=(const GridResampler&) = default;
173
174 /// Enable or disable threading. (Threading is enabled by default.)
175 void setThreaded(bool b) { mThreaded = b; }
176 /// Return @c true if threading is enabled.
177 bool threaded() const { return mThreaded; }
178 /// Enable or disable processing of tiles. (Enabled by default, except for level set grids.)
179
9/18
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 8 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
72 void setTransformTiles(bool b) { mTransformTiles = b; }
180 /// Return @c true if tile processing is enabled.
181 bool transformTiles() const { return mTransformTiles; }
182
183 /// @brief Allow processing to be aborted by providing an interrupter object.
184 /// The interrupter will be queried periodically during processing.
185 /// @see util/NullInterrupter.h for interrupter interface requirements.
186 template<typename InterrupterType> void setInterrupter(InterrupterType&);
187
188 template<typename Sampler, typename GridT, typename Transformer>
189 void transformGrid(const Transformer&,
190 const GridT& inGrid, GridT& outGrid) const;
191
192 protected:
193 template<typename Sampler, typename GridT, typename Transformer>
194 void applyTransform(const Transformer&, const GridT& inGrid, GridT& outGrid) const;
195
196 bool interrupt() const { return mInterrupt && mInterrupt(); }
197
198 private:
199 template<typename Sampler, typename InTreeT, typename OutTreeT, typename Transformer>
200 static void transformBBox(const Transformer&, const CoordBBox& inBBox,
201 const InTreeT& inTree, OutTreeT& outTree, const InterruptFunc&,
202 const Sampler& = Sampler());
203
204 template<typename Sampler, typename TreeT, typename Transformer>
205 class RangeProcessor;
206
207 bool mThreaded, mTransformTiles;
208 InterruptFunc mInterrupt;
209 };
210
211
212 ////////////////////////////////////////
213
214
215 /// @brief A GridTransformer applies a geometric transformation to an
216 /// input grid using one of several sampling schemes, and stores
217 /// the result in an output grid.
218 ///
219 /// @note GridTransformer is optimized for affine transformations.
220 ///
221 /// Usage:
222 /// @code
223 /// Mat4R xform = ...;
224 /// GridTransformer transformer(xform);
225 /// transformer.transformGrid<BoxSampler>(inGrid, outGrid);
226 /// @endcode
227 /// or
228 /// @code
229 /// Vec3R pivot = ..., scale = ..., rotate = ..., translate = ...;
230 /// GridTransformer transformer(pivot, scale, rotate, translate);
231 /// transformer.transformGrid<QuadraticSampler>(inGrid, outGrid);
232 /// @endcode
233 class GridTransformer: public GridResampler
234 {
235 public:
236 using Ptr = SharedPtr<GridTransformer>;
237
238 GridTransformer(const Mat4R& xform);
239 GridTransformer(
240 const Vec3R& pivot,
241 const Vec3R& scale,
242 const Vec3R& rotate,
243 const Vec3R& translate,
244 const std::string& xformOrder = "tsr",
245 const std::string& rotationOrder = "zyx");
246 ~GridTransformer() override = default;
247
248 GridTransformer(const GridTransformer&) = default;
249 GridTransformer& operator=(const GridTransformer&) = default;
250
251 const Mat4R& getTransform() const { return mTransform; }
252
253 template<class Sampler, class GridT>
254 void transformGrid(const GridT& inGrid, GridT& outGrid) const;
255
256 private:
257 struct MatrixTransform;
258
259 inline void init(const Vec3R& pivot, const Vec3R& scale,
260 const Vec3R& rotate, const Vec3R& translate,
261 const std::string& xformOrder, const std::string& rotOrder);
262
263 Vec3R mPivot;
264 Vec3i mMipLevels;
265 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
266 };
267
268
269 ////////////////////////////////////////
270
271
272 namespace local_util {
273
274 enum { DECOMP_INVALID = 0, DECOMP_VALID = 1, DECOMP_UNIQUE = 2 };
275
276 /// @brief Decompose an affine transform into scale, rotation (XYZ order),
277 /// and translation components.
278 /// @return DECOMP_INVALID if the given matrix is not affine or cannot
279 /// be decomposed, DECOMP_UNIQUE if the matrix has a unique decomposition,
280 /// DECOMP_VALID otherwise
281 template<typename T>
282 int
283
1/2
✓ Branch 0 taken 663555 times.
✗ Branch 1 not taken.
663555 decompose(const math::Mat4<T>& m, math::Vec3<T>& scale,
284 math::Vec3<T>& rotate, math::Vec3<T>& translate)
285 {
286 if (!math::isAffine(m)) return DECOMP_INVALID;
287
288 // This is the translation in world space
289 663554 translate = m.getTranslation();
290 // Extract translation.
291 const math::Mat3<T> xform = m.getMat3();
292
293 const math::Vec3<T> unsignedScale(
294 663554 (math::Vec3<T>(1, 0, 0) * xform).length(),
295 663554 (math::Vec3<T>(0, 1, 0) * xform).length(),
296 1327108 (math::Vec3<T>(0, 0, 1) * xform).length());
297
298 663554 const bool hasUniformScale = unsignedScale.eq(math::Vec3<T>(unsignedScale[0]));
299
300 bool hasRotation = false;
301 bool validDecomposition = false;
302
303 T minAngle = std::numeric_limits<T>::max();
304
305 // If the transformation matrix contains a reflection, test different negative scales
306 // to find a decomposition that favors the optimal resampling algorithm.
307
2/2
✓ Branch 0 taken 4720322 times.
✓ Branch 1 taken 558720 times.
5279042 for (size_t n = 0; n < 8; ++n) {
308 6897024 const math::Vec3<T> signedScale(
309
2/2
✓ Branch 0 taken 2333952 times.
✓ Branch 1 taken 2386370 times.
4720322 n & 0x1 ? -unsignedScale.x() : unsignedScale.x(),
310
2/2
✓ Branch 0 taken 2289312 times.
✓ Branch 1 taken 2431010 times.
4720322 n & 0x2 ? -unsignedScale.y() : unsignedScale.y(),
311
2/2
✓ Branch 0 taken 2273760 times.
✓ Branch 1 taken 2446562 times.
4720322 n & 0x4 ? -unsignedScale.z() : unsignedScale.z());
312
313 // Extract scale and potentially reflection.
314 4720322 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
315
2/2
✓ Branch 0 taken 2333952 times.
✓ Branch 1 taken 2386370 times.
4720322 if (mat.det() < T(0.0)) continue; // Skip if mat contains a reflection.
316
317 2386370 const math::Vec3<T> tmpAngle = math::eulerAngles(mat, math::XYZ_ROTATION);
318
319 const math::Mat3<T> rebuild =
320
1/2
✓ Branch 1 taken 2386370 times.
✗ Branch 2 not taken.
2386370 math::rotation<math::Mat3<T> >(math::Vec3<T>(0, 0, 1), tmpAngle.z()) *
321
1/2
✓ Branch 1 taken 2386370 times.
✗ Branch 2 not taken.
4772740 math::rotation<math::Mat3<T> >(math::Vec3<T>(0, 1, 0), tmpAngle.y()) *
322
1/2
✓ Branch 1 taken 2386370 times.
✗ Branch 2 not taken.
4772740 math::rotation<math::Mat3<T> >(math::Vec3<T>(1, 0, 0), tmpAngle.x()) *
323 2386370 math::scale<math::Mat3<T> >(signedScale);
324
325
2/2
✓ Branch 0 taken 326594 times.
✓ Branch 1 taken 2059776 times.
2386370 if (xform.eq(rebuild)) {
326
327
2/2
✓ Branch 0 taken 164160 times.
✓ Branch 1 taken 162434 times.
326594 const T maxAngle = std::max(std::abs(tmpAngle[0]),
328
2/2
✓ Branch 0 taken 191880 times.
✓ Branch 1 taken 134714 times.
326594 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
329
330
2/2
✓ Branch 0 taken 269570 times.
✓ Branch 1 taken 57024 times.
326594 if (!(minAngle < maxAngle)) { // Update if less or equal.
331
332 minAngle = maxAngle;
333 269570 rotate = tmpAngle;
334
2/2
✓ Branch 0 taken 164736 times.
✓ Branch 1 taken 104834 times.
269570 scale = signedScale;
335
336 269570 hasRotation = !rotate.eq(math::Vec3<T>::zero());
337 validDecomposition = true;
338
339
2/2
✓ Branch 0 taken 164736 times.
✓ Branch 1 taken 104834 times.
269570 if (hasUniformScale || !hasRotation) {
340 // Current decomposition is optimal.
341 break;
342 }
343 }
344 }
345 }
346
347
2/2
✓ Branch 0 taken 148610 times.
✓ Branch 1 taken 514944 times.
663554 if (!validDecomposition) {
348 // The decomposition is invalid if the transformation matrix contains shear.
349 return DECOMP_INVALID;
350 }
351
2/2
✓ Branch 0 taken 43776 times.
✓ Branch 1 taken 104834 times.
148610 if (hasRotation && !hasUniformScale) {
352 // No unique decomposition if scale is nonuniform and rotation is nonzero.
353 43776 return DECOMP_VALID;
354 }
355 return DECOMP_UNIQUE;
356 }
357
358 } // namespace local_util
359
360
361 ////////////////////////////////////////
362
363
364 /// This class implements the Transformer functor interface (specifically,
365 /// the isAffine(), transform() and invTransform() methods) for a transform
366 /// that is expressed as a 4 x 4 matrix.
367 struct GridTransformer::MatrixTransform
368 {
369 MatrixTransform(): mat(Mat4R::identity()), invMat(Mat4R::identity()) {}
370 73 MatrixTransform(const Mat4R& xform): mat(xform), invMat(xform.inverse()) {}
371
372 bool isAffine() const { return math::isAffine(mat); }
373
374 7080 Vec3R transform(const Vec3R& pos) const { return mat.transformH(pos); }
375
376 708 Vec3R invTransform(const Vec3R& pos) const { return invMat.transformH(pos); }
377
378 Mat4R mat, invMat;
379 };
380
381
382 ////////////////////////////////////////
383
384
385 /// @brief This class implements the Transformer functor interface (specifically,
386 /// the isAffine(), transform() and invTransform() methods) for a transform
387 /// that maps an A grid into a B grid's index space such that, after resampling,
388 /// A's index space and transform match B's index space and transform.
389 class ABTransform
390 {
391 public:
392 /// @param aXform the A grid's transform
393 /// @param bXform the B grid's transform
394 8 ABTransform(const math::Transform& aXform, const math::Transform& bXform):
395 mAXform(aXform),
396 mBXform(bXform),
397
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
398
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 7 times.
16 mIsIdentity(mIsAffine && mAXform == mBXform)
399 8 {}
400
401 1 bool isAffine() const { return mIsAffine; }
402
403 8 bool isIdentity() const { return mIsIdentity; }
404
405 openvdb::Vec3R transform(const openvdb::Vec3R& pos) const
406 {
407 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
408 }
409
410 openvdb::Vec3R invTransform(const openvdb::Vec3R& pos) const
411 {
412 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
413 }
414
415 1 const math::Transform& getA() const { return mAXform; }
416 1 const math::Transform& getB() const { return mBXform; }
417
418 private:
419 const math::Transform &mAXform, &mBXform;
420 const bool mIsAffine;
421 const bool mIsIdentity;
422 };
423
424
425 /// The normal entry points for resampling are the resampleToMatch() functions,
426 /// which correctly handle level set grids under scaling and shearing.
427 /// doResampleToMatch() is mainly for internal use but is typically faster
428 /// for level sets, and correct provided that no scaling or shearing is needed.
429 ///
430 /// @warning Do not use this function to scale or shear a level set grid.
431 template<typename Sampler, typename Interrupter, typename GridType>
432 void
433 10 doResampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
434 {
435 10 ABTransform xform(inGrid.transform(), outGrid.transform());
436
437
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
10 if (Sampler::consistent() && xform.isIdentity()) {
438 // If the transforms of the input and output are identical, the
439 // output tree is simply a deep copy of the input tree.
440
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
16 outGrid.setTree(inGrid.tree().copy());
441
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 } else if (xform.isAffine()) {
442 // If the input and output transforms are both affine, create an
443 // input to output transform (in:index-to-world * out:world-to-index)
444 // and use the fast GridTransformer API.
445
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
4 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
446
4/12
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
6 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
447
448 2 GridTransformer transformer(mat);
449
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 transformer.setInterrupter(interrupter);
450
451 // Transform the input grid and store the result in the output grid.
452
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 transformer.transformGrid<Sampler>(inGrid, outGrid);
453 } else {
454 // If either the input or the output transform is non-affine,
455 // use the slower GridResampler API.
456 GridResampler resampler;
457 resampler.setInterrupter(interrupter);
458
459 resampler.transformGrid<Sampler>(xform, inGrid, outGrid);
460 }
461 10 }
462
463
464 template<typename ValueType>
465 struct HalfWidthOp {
466 static ValueType eval(const ValueType& background, const Vec3d& voxelSize)
467 {
468 OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
469 ValueType result(background * (1.0 / voxelSize[0]));
470 OPENVDB_NO_TYPE_CONVERSION_WARNING_END
471 return result;
472 }
473 }; // struct HalfWidthOp
474
475 template<>
476 struct HalfWidthOp<bool> {
477 static bool eval(const bool& background, const Vec3d& /*voxelSize*/)
478 {
479 return background;
480 }
481 }; // struct HalfWidthOp<bool>
482
483
484 template<typename Sampler, typename Interrupter, typename GridType>
485 void
486 10 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
487 {
488
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
10 if (inGrid.getGridClass() == GRID_LEVEL_SET) {
489 // If the input grid is a level set, resample it using the level set rebuild tool.
490
491 if (inGrid.constTransform() == outGrid.constTransform()) {
492 // If the transforms of the input and output grids are identical,
493 // the output tree is simply a deep copy of the input tree.
494 outGrid.setTree(inGrid.tree().copy());
495 return;
496 }
497
498 // If the output grid is a level set, resample the input grid to have the output grid's
499 // background value. Otherwise, preserve the input grid's background value.
500 using ValueT = typename GridType::ValueType;
501 const bool outIsLevelSet = outGrid.getGridClass() == openvdb::GRID_LEVEL_SET;
502
503 const ValueT halfWidth = outIsLevelSet
504 ? HalfWidthOp<ValueT>::eval(outGrid.background(), outGrid.voxelSize())
505 : HalfWidthOp<ValueT>::eval(inGrid.background(), inGrid.voxelSize());
506
507 typename GridType::Ptr tempGrid;
508 try {
509 tempGrid = doLevelSetRebuild(inGrid, /*iso=*/zeroVal<ValueT>(),
510 /*exWidth=*/halfWidth, /*inWidth=*/halfWidth,
511 &outGrid.constTransform(), &interrupter);
512 } catch (TypeError&) {
513 // The input grid is classified as a level set, but it has a value type
514 // that is not supported by the level set rebuild tool. Fall back to
515 // using the generic resampler.
516 tempGrid.reset();
517 }
518 if (tempGrid) {
519 outGrid.setTree(tempGrid->treePtr());
520 return;
521 }
522 }
523
524 // If the input grid is not a level set, use the generic resampler.
525 10 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
526 }
527
528
529 template<typename Sampler, typename GridType>
530 void
531 8 resampleToMatch(const GridType& inGrid, GridType& outGrid)
532 {
533 8 util::NullInterrupter interrupter;
534 8 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
535 8 }
536
537
538 ////////////////////////////////////////
539
540
541 inline
542 331777 GridTransformer::GridTransformer(const Mat4R& xform):
543 mPivot(0, 0, 0),
544 mMipLevels(0, 0, 0),
545 mTransform(xform),
546 331777 mPreScaleTransform(Mat4R::identity()),
547 331777 mPostScaleTransform(Mat4R::identity())
548 {
549 Vec3R scale, rotate, translate;
550
3/4
✓ Branch 1 taken 331777 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 74305 times.
✓ Branch 4 taken 257472 times.
331777 if (local_util::decompose(mTransform, scale, rotate, translate)) {
551 // If the transform can be decomposed into affine components,
552 // use them to set up a mipmapping-like scheme for downsampling.
553
3/6
✓ Branch 1 taken 74305 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74305 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 74305 times.
✗ Branch 8 not taken.
148610 init(mPivot, scale, rotate, translate, "rst", "zyx");
554 }
555 331777 }
556
557
558 inline
559 72 GridTransformer::GridTransformer(
560 const Vec3R& pivot, const Vec3R& scale,
561 const Vec3R& rotate, const Vec3R& translate,
562 72 const std::string& xformOrder, const std::string& rotOrder):
563 mPivot(0, 0, 0),
564 mMipLevels(0, 0, 0),
565 72 mPreScaleTransform(Mat4R::identity()),
566 72 mPostScaleTransform(Mat4R::identity())
567 {
568
1/2
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
72 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
569 72 }
570
571
572 ////////////////////////////////////////
573
574
575 inline void
576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74377 times.
74377 GridTransformer::init(
577 const Vec3R& pivot, const Vec3R& scale,
578 const Vec3R& rotate, const Vec3R& translate,
579 const std::string& xformOrder, const std::string& rotOrder)
580 {
581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74377 times.
74377 if (xformOrder.size() != 3) {
582 OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
583 }
584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74377 times.
74377 if (rotOrder.size() != 3) {
585 OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
586 }
587
588 74377 mPivot = pivot;
589
590 // Scaling is handled via a mipmapping-like scheme of successive
591 // halvings of the tree resolution, until the remaining scale
592 // factor is greater than or equal to 1/2.
593 74377 Vec3R scaleRemainder = scale;
594
2/2
✓ Branch 0 taken 223131 times.
✓ Branch 1 taken 74377 times.
297508 for (int i = 0; i < 3; ++i) {
595 223131 double s = std::fabs(scale(i));
596
2/2
✓ Branch 0 taken 74304 times.
✓ Branch 1 taken 148827 times.
223131 if (s < 0.5) {
597 74304 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
598 74304 scaleRemainder(i) = scale(i) * (1 << mMipLevels(i));
599 }
600 }
601
602 // Build pre-scale and post-scale transform matrices based on
603 // the user-specified order of operations.
604 // Note that we iterate over the transform order string in reverse order
605 // (e.g., "t", "r", "s", given "srt"). This is because math::Mat matrices
606 // postmultiply row vectors rather than premultiplying column vectors.
607 74377 mTransform = mPreScaleTransform = mPostScaleTransform = Mat4R::identity();
608 74377 Mat4R* remainder = &mPostScaleTransform;
609 int rpos, spos, tpos;
610 rpos = spos = tpos = 3;
611
2/2
✓ Branch 0 taken 223131 times.
✓ Branch 1 taken 74377 times.
297508 for (int ix = 2; ix >= 0; --ix) { // reverse iteration
612
3/4
✓ Branch 0 taken 74377 times.
✓ Branch 1 taken 74377 times.
✓ Branch 2 taken 74377 times.
✗ Branch 3 not taken.
223131 switch (xformOrder[ix]) {
613
614 74377 case 'r':
615 rpos = ix;
616 74377 mTransform.preTranslate(pivot);
617 74377 remainder->preTranslate(pivot);
618
619 int xpos, ypos, zpos;
620 xpos = ypos = zpos = 3;
621
2/2
✓ Branch 0 taken 223131 times.
✓ Branch 1 taken 74377 times.
297508 for (int ir = 2; ir >= 0; --ir) {
622
3/4
✓ Branch 0 taken 74377 times.
✓ Branch 1 taken 74377 times.
✓ Branch 2 taken 74377 times.
✗ Branch 3 not taken.
223131 switch (rotOrder[ir]) {
623 74377 case 'x':
624 xpos = ir;
625 74377 mTransform.preRotate(math::X_AXIS, rotate.x());
626 74377 remainder->preRotate(math::X_AXIS, rotate.x());
627 74377 break;
628 74377 case 'y':
629 ypos = ir;
630 74377 mTransform.preRotate(math::Y_AXIS, rotate.y());
631 74377 remainder->preRotate(math::Y_AXIS, rotate.y());
632 74377 break;
633 74377 case 'z':
634 zpos = ir;
635 74377 mTransform.preRotate(math::Z_AXIS, rotate.z());
636 74377 remainder->preRotate(math::Z_AXIS, rotate.z());
637 74377 break;
638 }
639 }
640 // Reject rotation order strings that don't contain exactly one
641 // instance of "x", "y" and "z".
642
2/4
✓ Branch 0 taken 74377 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74377 times.
74377 if (xpos > 2 || ypos > 2 || zpos > 2) {
643 OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
644 }
645
646 74377 mTransform.preTranslate(-pivot);
647 74377 remainder->preTranslate(-pivot);
648 74377 break;
649
650 74377 case 's':
651 spos = ix;
652 74377 mTransform.preTranslate(pivot);
653 74377 mTransform.preScale(scale);
654 74377 mTransform.preTranslate(-pivot);
655
656 74377 remainder->preTranslate(pivot);
657 74377 remainder->preScale(scaleRemainder);
658 74377 remainder->preTranslate(-pivot);
659 74377 remainder = &mPreScaleTransform;
660 74377 break;
661
662 74377 case 't':
663 tpos = ix;
664 74377 mTransform.preTranslate(translate);
665 74377 remainder->preTranslate(translate);
666 break;
667 }
668 }
669 // Reject transform order strings that don't contain exactly one
670 // instance of "t", "r" and "s".
671
2/4
✓ Branch 0 taken 74377 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74377 times.
74377 if (tpos > 2 || rpos > 2 || spos > 2) {
672 OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
673 }
674 74377 }
675
676
677 ////////////////////////////////////////
678
679
680 template<typename InterrupterType>
681 void
682 1 GridResampler::setInterrupter(InterrupterType& interrupter)
683 {
684 1 mInterrupt = std::bind(&InterrupterType::wasInterrupted,
685 /*this=*/&interrupter, /*percent=*/-1);
686 1 }
687
688
689 template<typename Sampler, typename GridT, typename Transformer>
690 void
691 GridResampler::transformGrid(const Transformer& xform,
692 const GridT& inGrid, GridT& outGrid) const
693 {
694 tools::changeBackground(outGrid.tree(), inGrid.background());
695 applyTransform<Sampler>(xform, inGrid, outGrid);
696 }
697
698
699 template<class Sampler, class GridT>
700 void
701 146 GridTransformer::transformGrid(const GridT& inGrid, GridT& outGrid) const
702 {
703 146 tools::changeBackground(outGrid.tree(), inGrid.background());
704
705 if (!Sampler::mipmap() || mMipLevels == Vec3i::zero()) {
706 // Skip the mipmapping step.
707 146 const MatrixTransform xform(mTransform);
708 146 applyTransform<Sampler>(xform, inGrid, outGrid);
709
710 } else {
711 bool firstPass = true;
712 const typename GridT::ValueType background = inGrid.background();
713 typename GridT::Ptr tempGrid = GridT::create(background);
714
715 if (!mPreScaleTransform.eq(Mat4R::identity())) {
716 firstPass = false;
717 // Apply the pre-scale transform to the input grid
718 // and store the result in a temporary grid.
719 const MatrixTransform xform(mPreScaleTransform);
720 applyTransform<Sampler>(xform, inGrid, *tempGrid);
721 }
722
723 // While the scale factor along one or more axes is less than 1/2,
724 // scale the grid by half along those axes.
725 Vec3i count = mMipLevels; // # of halvings remaining per axis
726 while (count != Vec3i::zero()) {
727 MatrixTransform xform;
728 xform.mat.setTranslation(mPivot);
729 xform.mat.preScale(Vec3R(
730 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
731 xform.mat.preTranslate(-mPivot);
732 xform.invMat = xform.mat.inverse();
733
734 if (firstPass) {
735 firstPass = false;
736 // Scale the input grid and store the result in a temporary grid.
737 applyTransform<Sampler>(xform, inGrid, *tempGrid);
738 } else {
739 // Scale the temporary grid and store the result in a transient grid,
740 // then swap the two and discard the transient grid.
741 typename GridT::Ptr destGrid = GridT::create(background);
742 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
743 tempGrid.swap(destGrid);
744 }
745 // (3, 2, 1) -> (2, 1, 0) -> (1, 0, 0) -> (0, 0, 0), etc.
746 count = math::maxComponent(count - 1, Vec3i::zero());
747 }
748
749 // Apply the post-scale transform and store the result in the output grid.
750 if (!mPostScaleTransform.eq(Mat4R::identity())) {
751 const MatrixTransform xform(mPostScaleTransform);
752 applyTransform<Sampler>(xform, *tempGrid, outGrid);
753 } else {
754 outGrid.setTree(tempGrid->treePtr());
755 }
756 }
757 146 }
758
759
760 ////////////////////////////////////////
761
762
763 template<class Sampler, class TreeT, typename Transformer>
764 class GridResampler::RangeProcessor
765 {
766 public:
767 using LeafIterT = typename TreeT::LeafCIter;
768 using TileIterT = typename TreeT::ValueAllCIter;
769 using LeafRange = typename tree::IteratorRange<LeafIterT>;
770 using TileRange = typename tree::IteratorRange<TileIterT>;
771 using InTreeAccessor = typename tree::ValueAccessor<const TreeT>;
772 using OutTreeAccessor = typename tree::ValueAccessor<TreeT>;
773
774 292 RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inT, TreeT& outT):
775 mIsRoot(true), mXform(xform), mBBox(b),
776
1/2
✓ Branch 2 taken 146 times.
✗ Branch 3 not taken.
292 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
777 292 {}
778
779 RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inTree):
780 mIsRoot(false), mXform(xform), mBBox(b),
781 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
782 mInAcc(mInTree), mOutAcc(*mOutTree)
783 {}
784
785
3/4
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 444 times.
✗ Branch 3 not taken.
1180 ~RangeProcessor() { if (!mIsRoot) delete mOutTree; }
786
787 /// Splitting constructor: don't copy the original processor's output tree
788 888 RangeProcessor(RangeProcessor& other, tbb::split):
789 mIsRoot(false),
790 mXform(other.mXform),
791 mBBox(other.mBBox),
792 888 mInTree(other.mInTree),
793 888 mOutTree(new TreeT(mInTree.background())),
794 mInAcc(mInTree),
795
1/2
✓ Branch 1 taken 444 times.
✗ Branch 2 not taken.
888 mOutAcc(*mOutTree),
796
1/2
✓ Branch 3 taken 444 times.
✗ Branch 4 not taken.
2664 mInterrupt(other.mInterrupt)
797 888 {}
798
799 146 void setInterrupt(const InterruptFunc& f) { mInterrupt = f; }
800
801 /// Transform each leaf node in the given range.
802 160 void operator()(LeafRange& r)
803 {
804 for ( ; r; ++r) {
805 if (interrupt()) break;
806 LeafIterT i = r.iterator();
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 632 times.
1264 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
808 if (!mBBox.empty()) {
809 // Intersect the leaf node's bounding box with mBBox.
810 bbox = CoordBBox(
811 Coord::maxComponent(bbox.min(), mBBox.min()),
812 Coord::minComponent(bbox.max(), mBBox.max()));
813 }
814 if (!bbox.empty()) {
815 1264 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
816 }
817 }
818 160 }
819
820 /// Transform each non-background tile in the given range.
821 24882 void operator()(TileRange& r)
822 {
823 for ( ; r; ++r) {
824 if (interrupt()) break;
825
826 5380734 TileIterT i = r.iterator();
827 // Skip voxels and background tiles.
828 5380582 if (!i.isTileValue()) continue;
829
4/4
✓ Branch 0 taken 2690323 times.
✓ Branch 1 taken 44 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 2690291 times.
5380734 if (!i.isValueOn() && math::isApproxEqual(*i, mOutTree->background())) continue;
830
831 152 CoordBBox bbox;
832 152 i.getBoundingBox(bbox);
833 if (!mBBox.empty()) {
834 // Intersect the tile's bounding box with mBBox.
835 bbox = CoordBBox(
836 Coord::maxComponent(bbox.min(), mBBox.min()),
837 Coord::minComponent(bbox.max(), mBBox.max()));
838 }
839 if (!bbox.empty()) {
840 /// @todo This samples the tile voxel-by-voxel, which is much too slow.
841 /// Instead, compute the largest axis-aligned bounding box that is
842 /// contained in the transformed tile (adjusted for the sampler radius)
843 /// and fill it with the tile value. Then transform the remaining voxels.
844 internal::TileSampler<Sampler, InTreeAccessor>
845 96 sampler(bbox, i.getValue(), i.isValueOn());
846 152 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
847 }
848 }
849 24882 }
850
851 /// Merge another processor's output tree into this processor's tree.
852
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 436 times.
888 void join(RangeProcessor& other)
853 {
854 888 if (!interrupt()) mOutTree->merge(*other.mOutTree);
855 888 }
856
857 private:
858
33/552
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 41 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 56 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 42 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 42 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 60 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 53 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✓ Branch 35 taken 8 times.
✓ Branch 36 taken 54 times.
✓ Branch 38 taken 8 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✓ Branch 41 taken 45 times.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✓ Branch 46 taken 64 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 51 taken 294840 times.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✓ Branch 56 taken 64 times.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✓ Branch 61 taken 294840 times.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✓ Branch 66 taken 64 times.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✓ Branch 71 taken 294840 times.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✓ Branch 76 taken 64 times.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✓ Branch 81 taken 294840 times.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✓ Branch 86 taken 64 times.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✓ Branch 91 taken 294840 times.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✓ Branch 96 taken 64 times.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✓ Branch 101 taken 294840 times.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✓ Branch 106 taken 64 times.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✓ Branch 111 taken 294840 times.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✓ Branch 115 taken 56 times.
✓ Branch 116 taken 64 times.
✗ Branch 118 not taken.
✓ Branch 119 taken 56 times.
✓ Branch 120 taken 36807 times.
✓ Branch 121 taken 294840 times.
✗ Branch 123 not taken.
✓ Branch 124 taken 36807 times.
✗ Branch 125 not taken.
✓ Branch 126 taken 64 times.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✓ Branch 131 taken 294840 times.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 140 not taken.
✗ Branch 141 not taken.
✗ Branch 143 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 148 not taken.
✗ Branch 149 not taken.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 168 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 171 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
✗ Branch 183 not taken.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
✗ Branch 186 not taken.
✗ Branch 188 not taken.
✗ Branch 189 not taken.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✗ Branch 195 not taken.
✗ Branch 196 not taken.
✗ Branch 198 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 201 not taken.
✗ Branch 203 not taken.
✗ Branch 204 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 210 not taken.
✗ Branch 211 not taken.
✗ Branch 213 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 216 not taken.
✗ Branch 218 not taken.
✗ Branch 219 not taken.
✗ Branch 220 not taken.
✗ Branch 221 not taken.
✗ Branch 223 not taken.
✗ Branch 224 not taken.
✗ Branch 225 not taken.
✗ Branch 226 not taken.
✗ Branch 228 not taken.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 231 not taken.
✗ Branch 233 not taken.
✗ Branch 234 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
✗ Branch 240 not taken.
✗ Branch 241 not taken.
✗ Branch 243 not taken.
✗ Branch 244 not taken.
✗ Branch 245 not taken.
✗ Branch 246 not taken.
✗ Branch 248 not taken.
✗ Branch 249 not taken.
✗ Branch 250 not taken.
✗ Branch 251 not taken.
✗ Branch 253 not taken.
✗ Branch 254 not taken.
✗ Branch 255 not taken.
✗ Branch 256 not taken.
✗ Branch 258 not taken.
✗ Branch 259 not taken.
✗ Branch 260 not taken.
✗ Branch 261 not taken.
✗ Branch 263 not taken.
✗ Branch 264 not taken.
✗ Branch 265 not taken.
✗ Branch 266 not taken.
✗ Branch 268 not taken.
✗ Branch 269 not taken.
✗ Branch 270 not taken.
✗ Branch 271 not taken.
✗ Branch 273 not taken.
✗ Branch 274 not taken.
✗ Branch 275 not taken.
✗ Branch 276 not taken.
✗ Branch 278 not taken.
✗ Branch 279 not taken.
✗ Branch 280 not taken.
✗ Branch 281 not taken.
✗ Branch 283 not taken.
✗ Branch 284 not taken.
✗ Branch 285 not taken.
✗ Branch 286 not taken.
✗ Branch 288 not taken.
✗ Branch 289 not taken.
✗ Branch 290 not taken.
✗ Branch 291 not taken.
✗ Branch 293 not taken.
✗ Branch 294 not taken.
✗ Branch 295 not taken.
✗ Branch 296 not taken.
✗ Branch 298 not taken.
✗ Branch 299 not taken.
✗ Branch 300 not taken.
✗ Branch 301 not taken.
✗ Branch 303 not taken.
✗ Branch 304 not taken.
✗ Branch 305 not taken.
✗ Branch 306 not taken.
✗ Branch 308 not taken.
✗ Branch 309 not taken.
✗ Branch 310 not taken.
✗ Branch 311 not taken.
✗ Branch 313 not taken.
✗ Branch 314 not taken.
✗ Branch 315 not taken.
✗ Branch 316 not taken.
✗ Branch 318 not taken.
✗ Branch 319 not taken.
✗ Branch 320 not taken.
✗ Branch 321 not taken.
✗ Branch 323 not taken.
✗ Branch 324 not taken.
✗ Branch 325 not taken.
✗ Branch 326 not taken.
✗ Branch 328 not taken.
✗ Branch 329 not taken.
✗ Branch 330 not taken.
✗ Branch 331 not taken.
✗ Branch 333 not taken.
✗ Branch 334 not taken.
✗ Branch 335 not taken.
✗ Branch 336 not taken.
✗ Branch 338 not taken.
✗ Branch 339 not taken.
✗ Branch 340 not taken.
✗ Branch 341 not taken.
✗ Branch 343 not taken.
✗ Branch 344 not taken.
✗ Branch 345 not taken.
✗ Branch 346 not taken.
✗ Branch 348 not taken.
✗ Branch 349 not taken.
✗ Branch 350 not taken.
✗ Branch 351 not taken.
✗ Branch 353 not taken.
✗ Branch 354 not taken.
✗ Branch 355 not taken.
✗ Branch 356 not taken.
✗ Branch 358 not taken.
✗ Branch 359 not taken.
✗ Branch 360 not taken.
✗ Branch 361 not taken.
✗ Branch 363 not taken.
✗ Branch 364 not taken.
✗ Branch 365 not taken.
✗ Branch 366 not taken.
✗ Branch 368 not taken.
✗ Branch 369 not taken.
✗ Branch 370 not taken.
✗ Branch 371 not taken.
✗ Branch 373 not taken.
✗ Branch 374 not taken.
✗ Branch 375 not taken.
✗ Branch 376 not taken.
✗ Branch 378 not taken.
✗ Branch 379 not taken.
✗ Branch 380 not taken.
✗ Branch 381 not taken.
✗ Branch 383 not taken.
✗ Branch 384 not taken.
✗ Branch 385 not taken.
✗ Branch 386 not taken.
✗ Branch 388 not taken.
✗ Branch 389 not taken.
✗ Branch 390 not taken.
✗ Branch 391 not taken.
✗ Branch 393 not taken.
✗ Branch 394 not taken.
✗ Branch 395 not taken.
✗ Branch 396 not taken.
✗ Branch 398 not taken.
✗ Branch 399 not taken.
✗ Branch 400 not taken.
✗ Branch 401 not taken.
✗ Branch 403 not taken.
✗ Branch 404 not taken.
✗ Branch 405 not taken.
✗ Branch 406 not taken.
✗ Branch 408 not taken.
✗ Branch 409 not taken.
✗ Branch 410 not taken.
✗ Branch 411 not taken.
✗ Branch 413 not taken.
✗ Branch 414 not taken.
✗ Branch 415 not taken.
✗ Branch 416 not taken.
✗ Branch 418 not taken.
✗ Branch 419 not taken.
✗ Branch 420 not taken.
✗ Branch 421 not taken.
✗ Branch 423 not taken.
✗ Branch 424 not taken.
✗ Branch 425 not taken.
✗ Branch 426 not taken.
✗ Branch 428 not taken.
✗ Branch 429 not taken.
✗ Branch 430 not taken.
✗ Branch 431 not taken.
✗ Branch 433 not taken.
✗ Branch 434 not taken.
✗ Branch 435 not taken.
✗ Branch 436 not taken.
✗ Branch 438 not taken.
✗ Branch 439 not taken.
✗ Branch 440 not taken.
✗ Branch 441 not taken.
✗ Branch 443 not taken.
✗ Branch 444 not taken.
✗ Branch 445 not taken.
✗ Branch 446 not taken.
✗ Branch 448 not taken.
✗ Branch 449 not taken.
✗ Branch 450 not taken.
✗ Branch 451 not taken.
✗ Branch 453 not taken.
✗ Branch 454 not taken.
✗ Branch 455 not taken.
✗ Branch 456 not taken.
✗ Branch 458 not taken.
✗ Branch 459 not taken.
✗ Branch 460 not taken.
✗ Branch 461 not taken.
✗ Branch 463 not taken.
✗ Branch 464 not taken.
✗ Branch 465 not taken.
✗ Branch 466 not taken.
✗ Branch 468 not taken.
✗ Branch 469 not taken.
✗ Branch 470 not taken.
✗ Branch 471 not taken.
✗ Branch 473 not taken.
✗ Branch 474 not taken.
✗ Branch 475 not taken.
✗ Branch 476 not taken.
✗ Branch 478 not taken.
✗ Branch 479 not taken.
✗ Branch 480 not taken.
✗ Branch 481 not taken.
✗ Branch 483 not taken.
✗ Branch 484 not taken.
✗ Branch 485 not taken.
✗ Branch 486 not taken.
✗ Branch 488 not taken.
✗ Branch 489 not taken.
✗ Branch 490 not taken.
✗ Branch 491 not taken.
✗ Branch 493 not taken.
✗ Branch 494 not taken.
✗ Branch 495 not taken.
✗ Branch 496 not taken.
✗ Branch 498 not taken.
✗ Branch 499 not taken.
✗ Branch 500 not taken.
✗ Branch 501 not taken.
✗ Branch 503 not taken.
✗ Branch 504 not taken.
✗ Branch 505 not taken.
✗ Branch 506 not taken.
✗ Branch 508 not taken.
✗ Branch 509 not taken.
✗ Branch 510 not taken.
✗ Branch 511 not taken.
✗ Branch 513 not taken.
✗ Branch 514 not taken.
✗ Branch 515 not taken.
✗ Branch 516 not taken.
✗ Branch 518 not taken.
✗ Branch 519 not taken.
✗ Branch 520 not taken.
✗ Branch 521 not taken.
✗ Branch 523 not taken.
✗ Branch 524 not taken.
✗ Branch 525 not taken.
✗ Branch 526 not taken.
✗ Branch 528 not taken.
✗ Branch 529 not taken.
✗ Branch 530 not taken.
✗ Branch 531 not taken.
✗ Branch 533 not taken.
✗ Branch 534 not taken.
✗ Branch 535 not taken.
✗ Branch 536 not taken.
✗ Branch 538 not taken.
✗ Branch 539 not taken.
✗ Branch 540 not taken.
✗ Branch 541 not taken.
✗ Branch 543 not taken.
✗ Branch 544 not taken.
✗ Branch 545 not taken.
✗ Branch 546 not taken.
✗ Branch 548 not taken.
✗ Branch 549 not taken.
✗ Branch 550 not taken.
✗ Branch 551 not taken.
✗ Branch 553 not taken.
✗ Branch 554 not taken.
✗ Branch 555 not taken.
✗ Branch 556 not taken.
✗ Branch 558 not taken.
✗ Branch 559 not taken.
✗ Branch 560 not taken.
✗ Branch 561 not taken.
✗ Branch 563 not taken.
✗ Branch 564 not taken.
✗ Branch 565 not taken.
✗ Branch 566 not taken.
✗ Branch 568 not taken.
✗ Branch 569 not taken.
✗ Branch 570 not taken.
✗ Branch 571 not taken.
✗ Branch 573 not taken.
✗ Branch 574 not taken.
✗ Branch 575 not taken.
✗ Branch 576 not taken.
✗ Branch 578 not taken.
✗ Branch 579 not taken.
✗ Branch 580 not taken.
✗ Branch 581 not taken.
✗ Branch 583 not taken.
✗ Branch 584 not taken.
✗ Branch 585 not taken.
✗ Branch 586 not taken.
✗ Branch 588 not taken.
✗ Branch 589 not taken.
✗ Branch 590 not taken.
✗ Branch 591 not taken.
✗ Branch 593 not taken.
✗ Branch 594 not taken.
✗ Branch 595 not taken.
✗ Branch 596 not taken.
✗ Branch 598 not taken.
✗ Branch 599 not taken.
✗ Branch 600 not taken.
✗ Branch 601 not taken.
✗ Branch 603 not taken.
✗ Branch 604 not taken.
✗ Branch 605 not taken.
✗ Branch 606 not taken.
✗ Branch 608 not taken.
✗ Branch 609 not taken.
✗ Branch 610 not taken.
✗ Branch 611 not taken.
✗ Branch 613 not taken.
✗ Branch 614 not taken.
✗ Branch 615 not taken.
✗ Branch 616 not taken.
✗ Branch 618 not taken.
✗ Branch 619 not taken.
✗ Branch 620 not taken.
✗ Branch 621 not taken.
✗ Branch 623 not taken.
✗ Branch 624 not taken.
✗ Branch 625 not taken.
✗ Branch 626 not taken.
✗ Branch 628 not taken.
✗ Branch 629 not taken.
✗ Branch 630 not taken.
✗ Branch 631 not taken.
✗ Branch 633 not taken.
✗ Branch 634 not taken.
✗ Branch 635 not taken.
✗ Branch 636 not taken.
✗ Branch 638 not taken.
✗ Branch 639 not taken.
✗ Branch 640 not taken.
✗ Branch 641 not taken.
✗ Branch 643 not taken.
✗ Branch 644 not taken.
✗ Branch 645 not taken.
✗ Branch 646 not taken.
✗ Branch 648 not taken.
✗ Branch 649 not taken.
✗ Branch 650 not taken.
✗ Branch 651 not taken.
✗ Branch 653 not taken.
✗ Branch 654 not taken.
✗ Branch 655 not taken.
✗ Branch 656 not taken.
✗ Branch 658 not taken.
✗ Branch 659 not taken.
✗ Branch 660 not taken.
✗ Branch 661 not taken.
✗ Branch 663 not taken.
✗ Branch 664 not taken.
✗ Branch 665 not taken.
✗ Branch 666 not taken.
✗ Branch 668 not taken.
✗ Branch 669 not taken.
✗ Branch 670 not taken.
✗ Branch 671 not taken.
✗ Branch 673 not taken.
✗ Branch 674 not taken.
✗ Branch 675 not taken.
✗ Branch 676 not taken.
✗ Branch 678 not taken.
✗ Branch 679 not taken.
✗ Branch 680 not taken.
✗ Branch 681 not taken.
✗ Branch 683 not taken.
✗ Branch 684 not taken.
✗ Branch 685 not taken.
✗ Branch 686 not taken.
✗ Branch 688 not taken.
✗ Branch 689 not taken.
2691443 bool interrupt() const { return mInterrupt && mInterrupt(); }
859
860 const bool mIsRoot; // true if mOutTree is the top-level tree
861 Transformer mXform;
862 CoordBBox mBBox;
863 const TreeT& mInTree;
864 TreeT* mOutTree;
865 InTreeAccessor mInAcc;
866 OutTreeAccessor mOutAcc;
867 InterruptFunc mInterrupt;
868 };
869
870
871 ////////////////////////////////////////
872
873
874 template<class Sampler, class GridT, typename Transformer>
875 void
876 146 GridResampler::applyTransform(const Transformer& xform,
877 const GridT& inGrid, GridT& outGrid) const
878 {
879 using TreeT = typename GridT::TreeType;
880 const TreeT& inTree = inGrid.tree();
881 TreeT& outTree = outGrid.tree();
882
883 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
884
885 146 const GridClass gridClass = inGrid.getGridClass();
886
887
2/4
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
✗ Branch 3 not taken.
146 if (gridClass != GRID_LEVEL_SET && mTransformTiles) {
888 // Independently transform the tiles of the input grid.
889 // Note: Tiles in level sets can only be background tiles, and they
890 // are handled more efficiently with a signed flood fill (see below).
891
892 292 RangeProc proc(xform, CoordBBox(), inTree, outTree);
893
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
146 proc.setInterrupt(mInterrupt);
894
895 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
896 146 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1); // skip leaf nodes
897 typename RangeProc::TileRange tileRange(tileIter);
898
899
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
146 if (mThreaded) {
900
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
146 tbb::parallel_reduce(tileRange, proc);
901 } else {
902 proc(tileRange);
903 }
904 }
905
906 146 CoordBBox clipBBox;
907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
146 if (gridClass == GRID_LEVEL_SET) {
908 // Inactive voxels in level sets can only be background voxels, and they
909 // are handled more efficiently with a signed flood fill (see below).
910 clipBBox = inGrid.evalActiveVoxelBoundingBox();
911 }
912
913 // Independently transform the leaf nodes of the input grid.
914
915 292 RangeProc proc(xform, clipBBox, inTree, outTree);
916
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
146 proc.setInterrupt(mInterrupt);
917
918
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
146 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
919
920
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
146 if (mThreaded) {
921
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
146 tbb::parallel_reduce(leafRange, proc);
922 } else {
923 proc(leafRange);
924 }
925
926 // If the grid is a level set, mark inactive voxels as inside or outside.
927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
146 if (gridClass == GRID_LEVEL_SET) {
928 tools::pruneLevelSet(outTree);
929 tools::signedFloodFill(outTree);
930 }
931 146 }
932
933
934 ////////////////////////////////////////
935
936
937 //static
938 template<class Sampler, class InTreeT, class OutTreeT, class Transformer>
939 void
940 1416 GridResampler::transformBBox(
941 const Transformer& xform,
942 const CoordBBox& bbox,
943 const InTreeT& inTree,
944 OutTreeT& outTree,
945 const InterruptFunc& interrupt,
946 const Sampler& sampler)
947 {
948 using ValueT = typename OutTreeT::ValueType;
949
950 // Transform the corners of the input tree's bounding box
951 // and compute the enclosing bounding box in the output tree.
952 Vec3R
953 1416 inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
954 1416 inRMax(bbox.max().x()+1, bbox.max().y()+1, bbox.max().z()+1),
955 1416 outRMin = math::minComponent(xform.transform(inRMin), xform.transform(inRMax)),
956 1416 outRMax = math::maxComponent(xform.transform(inRMin), xform.transform(inRMax));
957
2/2
✓ Branch 0 taken 5664 times.
✓ Branch 1 taken 708 times.
12744 for (int i = 0; i < 8; ++i) {
958 33984 Vec3R corner(
959
2/2
✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 2832 times.
11328 i & 1 ? inRMax.x() : inRMin.x(),
960
2/2
✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 2832 times.
11328 i & 2 ? inRMax.y() : inRMin.y(),
961
2/2
✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 2832 times.
11328 i & 4 ? inRMax.z() : inRMin.z());
962 11328 outRMin = math::minComponent(outRMin, xform.transform(corner));
963 11328 outRMax = math::maxComponent(outRMax, xform.transform(corner));
964 }
965 Vec3i
966 1416 outMin = local_util::floorVec3(outRMin) - Sampler::radius(),
967
1/2
✓ Branch 1 taken 708 times.
✗ Branch 2 not taken.
1416 outMax = local_util::ceilVec3(outRMax) + Sampler::radius();
968
969 if (!xform.isAffine()) {
970 // If the transform is not affine, back-project each output voxel
971 // into the input tree.
972 Vec3R xyz, inXYZ;
973 Coord outXYZ;
974 int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
975 for (x = outMin.x(); x <= outMax.x(); ++x) {
976 if (interrupt && interrupt()) break;
977 xyz.x() = x;
978 for (y = outMin.y(); y <= outMax.y(); ++y) {
979 if (interrupt && interrupt()) break;
980 xyz.y() = y;
981 for (z = outMin.z(); z <= outMax.z(); ++z) {
982 xyz.z() = z;
983 inXYZ = xform.invTransform(xyz);
984 ValueT result;
985 if (sampler.sample(inTree, inXYZ, result)) {
986 outTree.setValueOn(outXYZ, result);
987 } else {
988 // Note: Don't overwrite existing active values with inactive values.
989 if (!outTree.isValueOn(outXYZ)) {
990 outTree.setValueOff(outXYZ, result);
991 }
992 }
993 }
994 }
995 }
996 } else { // affine
997 // Compute step sizes in the input tree that correspond to
998 // unit steps in x, y and z in the output tree.
999 const Vec3R
1000 1416 translation = xform.invTransform(Vec3R(0, 0, 0)),
1001 1416 deltaX = xform.invTransform(Vec3R(1, 0, 0)) - translation,
1002 1416 deltaY = xform.invTransform(Vec3R(0, 1, 0)) - translation,
1003 1416 deltaZ = xform.invTransform(Vec3R(0, 0, 1)) - translation;
1004
1005 #if defined(__ICC)
1006 /// @todo The following line is a workaround for bad code generation
1007 /// in opt-icc11.1_64 (but not debug or gcc) builds. It should be
1008 /// removed once the problem has been addressed at its source.
1009 const Vec3R dummy = deltaX;
1010 #endif
1011
1012 // Step by whole voxels through the output tree, sampling the
1013 // corresponding fractional voxels of the input tree.
1014 1416 Vec3R inStartX = xform.invTransform(Vec3R(outMin));
1015 Coord outXYZ;
1016 int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
1017
2/2
✓ Branch 0 taken 39035 times.
✓ Branch 1 taken 708 times.
79486 for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
1018
3/4
✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 37835 times.
✓ Branch 3 taken 1200 times.
✗ Branch 4 not taken.
78070 if (interrupt && interrupt()) break;
1019 78070 Vec3R inStartY = inStartX;
1020
2/2
✓ Branch 0 taken 2504467 times.
✓ Branch 1 taken 39035 times.
5087004 for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
1021
3/4
✓ Branch 0 taken 22528 times.
✓ Branch 1 taken 2481939 times.
✓ Branch 3 taken 22528 times.
✗ Branch 4 not taken.
5008934 if (interrupt && interrupt()) break;
1022 5008934 Vec3R inXYZ = inStartY;
1023
2/2
✓ Branch 0 taken 249150152 times.
✓ Branch 1 taken 2504467 times.
503309238 for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
1024 ValueT result;
1025
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 8100029 times.
✓ Branch 2 taken 241050123 times.
498300304 if (sampler.sample(inTree, inXYZ, result)) {
1026 16200058 outTree.setValueOn(outXYZ, result);
1027 } else {
1028 // Note: Don't overwrite existing active values with inactive values.
1029
2/2
✓ Branch 1 taken 241047963 times.
✓ Branch 2 taken 2160 times.
482100246 if (!outTree.isValueOn(outXYZ)) {
1030 482095926 outTree.setValueOff(outXYZ, result);
1031 }
1032 }
1033 }
1034 }
1035 }
1036 }
1037 1416 } // GridResampler::transformBBox()
1038
1039
1040 ////////////////////////////////////////
1041
1042
1043 // Explicit Template Instantiation
1044
1045 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1046
1047 #ifdef OPENVDB_INSTANTIATE_GRIDTRANSFORMER
1048 #include <openvdb/util/ExplicitInstantiation.h>
1049 #endif
1050
1051 #define _FUNCTION(TreeT) \
1052 void resampleToMatch<PointSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1053 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1054 #undef _FUNCTION
1055
1056 #define _FUNCTION(TreeT) \
1057 void resampleToMatch<BoxSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1058 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1059 #undef _FUNCTION
1060
1061 #define _FUNCTION(TreeT) \
1062 void resampleToMatch<QuadraticSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1063 OPENVDB_NUMERIC_TREE_INSTANTIATE(_FUNCTION)
1064 #undef _FUNCTION
1065
1066 #define _FUNCTION(TreeT) \
1067 void resampleToMatch<QuadraticSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1068 OPENVDB_VEC3_TREE_INSTANTIATE(_FUNCTION)
1069 #undef _FUNCTION
1070
1071 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1072
1073
1074 } // namespace tools
1075 } // namespace OPENVDB_VERSION_NAME
1076 } // namespace openvdb
1077
1078 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
1079