GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/tools/ParticlesToLevelSet.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 251 273 91.9%
Functions: 69 69 100.0%
Branches: 223 944 23.6%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @author Ken Museth
5 ///
6 /// @file tools/ParticlesToLevelSet.h
7 ///
8 /// @brief Rasterize particles with position, radius and velocity
9 /// into either a boolean mask grid or a narrow-band level set grid.
10 ///
11 /// @details Optionally, arbitrary attributes on the particles can be transferred,
12 /// resulting in additional output grids with the same topology as the main grid.
13 ///
14 /// @note Particle to level set conversion is intended to be combined with
15 /// some kind of surface postprocessing, using
16 /// @vdblink::tools::LevelSetFilter LevelSetFilter@endlink, for example.
17 /// Without such postprocessing the generated surface is typically too noisy and blobby.
18 /// However, it serves as a great and fast starting point for subsequent
19 /// level set surface processing and convolution.
20 ///
21 /// @details For particle access, any class with the following interface may be used
22 /// (see the unit test or the From Particles Houdini SOP for practical examples):
23 /// @code
24 /// struct ParticleList
25 /// {
26 /// // Return the total number of particles in the list.
27 /// // Always required!
28 /// size_t size() const;
29 ///
30 /// // Get the world-space position of the nth particle.
31 /// // Required by rasterizeSpheres().
32 /// void getPos(size_t n, Vec3R& xyz) const;
33 ///
34 /// // Get the world-space position and radius of the nth particle.
35 /// // Required by rasterizeSpheres().
36 /// void getPosRad(size_t n, Vec3R& xyz, Real& radius) const;
37 ///
38 /// // Get the world-space position, radius and velocity of the nth particle.
39 /// // Required by rasterizeTrails().
40 /// void getPosRadVel(size_t n, Vec3R& xyz, Real& radius, Vec3R& velocity) const;
41 ///
42 /// // Get the value of the nth particle's user-defined attribute (of type @c AttributeType).
43 /// // Required only if attribute transfer is enabled in ParticlesToLevelSet.
44 /// void getAtt(size_t n, AttributeType& att) const;
45 /// };
46 /// @endcode
47 ///
48 /// Some functions accept an interrupter argument. This refers to any class
49 /// with the following interface:
50 /// @code
51 /// struct Interrupter
52 /// {
53 /// void start(const char* name = nullptr) // called when computations begin
54 /// void end() // called when computations end
55 /// bool wasInterrupted(int percent=-1) // return true to abort computation
56 /// };
57 /// @endcode
58 ///
59 /// The default interrupter is @vdblink::util::NullInterrupter NullInterrupter@endlink,
60 /// for which all calls are no-ops that incur no computational overhead.
61
62 #ifndef OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
63 #define OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
64
65 #include "openvdb/Types.h"
66 #include "openvdb/Grid.h"
67 #include "openvdb/math/Math.h"
68 #include "openvdb/math/Transform.h"
69 #include "openvdb/tree/LeafManager.h"
70 #include "openvdb/util/logging.h"
71 #include "openvdb/util/NullInterrupter.h"
72 #include "openvdb/thread/Threading.h"
73
74 #include "Composite.h" // for csgUnion()
75 #include "PointPartitioner.h"
76 #include "Prune.h"
77 #include "SignedFloodFill.h"
78
79 #include <tbb/parallel_reduce.h>
80 #include <tbb/blocked_range.h>
81
82 #include <functional>
83 #include <iostream>
84 #include <type_traits>
85 #include <vector>
86
87
88 namespace openvdb {
89 OPENVDB_USE_VERSION_NAMESPACE
90 namespace OPENVDB_VERSION_NAME {
91 namespace tools {
92
93 /// @brief Populate a scalar, floating-point grid with CSG-unioned level set spheres
94 /// described by the given particle positions and radii.
95 /// @details For more control over the output, including attribute transfer,
96 /// use the ParticlesToLevelSet class directly.
97 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
98 inline void particlesToSdf(const ParticleListT&, GridT&, InterrupterT* = nullptr);
99
100 /// @brief Populate a scalar, floating-point grid with fixed-size, CSG-unioned
101 /// level set spheres described by the given particle positions and the specified radius.
102 /// @details For more control over the output, including attribute transfer,
103 /// use the ParticlesToLevelSet class directly.
104 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
105 inline void particlesToSdf(const ParticleListT&, GridT&, Real radius, InterrupterT* = nullptr);
106
107 /// @brief Populate a scalar, floating-point grid with CSG-unioned trails
108 /// of level set spheres with decreasing radius, where the starting position and radius
109 /// and the direction of each trail is given by particle attributes.
110 /// @details For more control over the output, including attribute transfer,
111 /// use the ParticlesToLevelSet class directly.
112 /// @note The @a delta parameter controls the distance between spheres in a trail.
113 /// Be careful not to use too small a value.
114 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
115 inline void particleTrailsToSdf(const ParticleListT&, GridT&, Real delta=1, InterrupterT* =nullptr);
116
117 /// @brief Activate a boolean grid wherever it intersects the spheres
118 /// described by the given particle positions and radii.
119 /// @details For more control over the output, including attribute transfer,
120 /// use the ParticlesToLevelSet class directly.
121 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
122 inline void particlesToMask(const ParticleListT&, GridT&, InterrupterT* = nullptr);
123
124 /// @brief Activate a boolean grid wherever it intersects the fixed-size spheres
125 /// described by the given particle positions and the specified radius.
126 /// @details For more control over the output, including attribute transfer,
127 /// use the ParticlesToLevelSet class directly.
128 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
129 inline void particlesToMask(const ParticleListT&, GridT&, Real radius, InterrupterT* = nullptr);
130
131 /// @brief Activate a boolean grid wherever it intersects trails of spheres
132 /// with decreasing radius, where the starting position and radius and the direction
133 /// of each trail is given by particle attributes.
134 /// @details For more control over the output, including attribute transfer,
135 /// use the ParticlesToLevelSet class directly.
136 /// @note The @a delta parameter controls the distance between spheres in a trail.
137 /// Be careful not to use too small a value.
138 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
139 inline void particleTrailsToMask(const ParticleListT&, GridT&,Real delta=1,InterrupterT* =nullptr);
140
141
142 ////////////////////////////////////////
143
144 /// @cond OPENVDB_DOCS_INTERNAL
145
146 namespace p2ls_internal {
147 // This is a simple type that combines a distance value and a particle
148 // attribute. It's required for attribute transfer which is performed
149 // in the ParticlesToLevelSet::Raster member class defined below.
150 /// @private
151 template<typename VisibleT, typename BlindT> class BlindData;
152 }
153
154 /// @endcond
155
156 template<typename SdfGridT,
157 typename AttributeT = void,
158 typename InterrupterT = util::NullInterrupter>
159 class ParticlesToLevelSet
160 {
161 public:
162 using DisableT = typename std::is_void<AttributeT>::type;
163 using InterrupterType = InterrupterT;
164
165 using SdfGridType = SdfGridT;
166 using SdfType = typename SdfGridT::ValueType;
167
168 using AttType = typename std::conditional<DisableT::value, size_t, AttributeT>::type;
169 using AttGridType = typename SdfGridT::template ValueConverter<AttType>::Type;
170
171 static const bool OutputIsMask = std::is_same<SdfType, bool>::value;
172
173 /// @brief Constructor using an existing boolean or narrow-band level set grid
174 ///
175 /// @param grid grid into which particles are rasterized
176 /// @param interrupt callback to interrupt a long-running process
177 ///
178 /// @details If the input grid is already populated with signed distances,
179 /// particles are unioned onto the existing level set surface.
180 ///
181 /// @details The width in voxel units of the generated narrow band level set
182 /// is given by 2&times;<I>background</I>/<I>dx</I>, where @a background
183 /// is the background value stored in the grid and @a dx is the voxel size
184 /// derived from the transform associated with the grid.
185 /// Also note that &minus;<I>background</I> corresponds to the constant value
186 /// inside the generated narrow-band level set.
187 ///
188 /// @note If attribute transfer is enabled, i.e., if @c AttributeT is not @c void,
189 /// attributes are generated only for voxels that overlap with particles,
190 /// not for any other preexisting voxels (for which no attributes exist!).
191 explicit ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupt = nullptr);
192
193
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
24 ~ParticlesToLevelSet() { delete mBlindGrid; }
194
195 /// @brief This method syncs up the level set and attribute grids
196 /// and therefore needs to be called before any of those grids are
197 /// used and after the last call to any of the rasterizer methods.
198 /// @details It has no effect or overhead if attribute transfer is disabled
199 /// (i.e., if @c AttributeT is @c void) and @a prune is @c false.
200 ///
201 /// @note Avoid calling this method more than once, and call it only after
202 /// all the particles have been rasterized.
203 void finalize(bool prune = false);
204
205 /// @brief Return a pointer to the grid containing the optional user-defined attribute.
206 /// @warning If attribute transfer is disabled (i.e., if @c AttributeT is @c void)
207 /// or if @link finalize() finalize@endlink is not called, the pointer will be null.
208 typename AttGridType::Ptr attributeGrid() { return mAttGrid; }
209
210 /// @brief Return the size of a voxel in world units.
211 Real getVoxelSize() const { return mDx; }
212
213 /// @brief Return the half-width of the narrow band in voxel units.
214 Real getHalfWidth() const { return mHalfWidth; }
215
216 /// @brief Return the smallest radius allowed in voxel units.
217 Real getRmin() const { return mRmin; }
218 /// @brief Set the smallest radius allowed in voxel units.
219 void setRmin(Real Rmin) { mRmin = math::Max(Real(0),Rmin); }
220
221 /// @brief Return the largest radius allowed in voxel units.
222 Real getRmax() const { return mRmax; }
223 /// @brief Set the largest radius allowed in voxel units.
224 void setRmax(Real Rmax) { mRmax = math::Max(mRmin,Rmax); }
225
226 /// @brief Return @c true if any particles were ignored due to their size.
227 bool ignoredParticles() const { return mMinCount>0 || mMaxCount>0; }
228 /// @brief Return the number of particles that were ignored because they were
229 /// smaller than the minimum radius.
230 size_t getMinCount() const { return mMinCount; }
231 /// @brief Return the number of particles that were ignored because they were
232 /// larger than the maximum radius.
233 size_t getMaxCount() const { return mMaxCount; }
234
235 /// @brief Return the grain size used for threading
236 int getGrainSize() const { return mGrainSize; }
237 /// @brief Set the grain size used for threading.
238 /// @note A grain size of zero or less disables threading.
239
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 void setGrainSize(int grainSize) { mGrainSize = grainSize; }
240
241 /// @brief Rasterize each particle as a sphere with the particle's position and radius.
242 /// @details For level set output, all spheres are CSG-unioned.
243 template<typename ParticleListT>
244 void rasterizeSpheres(const ParticleListT& pa);
245
246 /// @brief Rasterize each particle as a sphere with the particle's position
247 /// and a fixed radius.
248 /// @details For level set output, all spheres are CSG-unioned.
249 ///
250 /// @param pa particles with positions
251 /// @param radius fixed sphere radius in world units.
252 template<typename ParticleListT>
253 void rasterizeSpheres(const ParticleListT& pa, Real radius);
254
255 /// @brief Rasterize each particle as a trail comprising the CSG union
256 /// of spheres of decreasing radius.
257 ///
258 /// @param pa particles with position, radius and velocity.
259 /// @param delta controls the distance between sphere instances
260 ///
261 /// @warning Be careful not to use too small values for @a delta,
262 /// since this can lead to excessive computation per trail (which the
263 /// interrupter can't stop).
264 ///
265 /// @note The direction of a trail is opposite to that of the velocity vector,
266 /// and its length is given by the magnitude of the velocity.
267 /// The radius at the head of the trail is given by the radius of the particle,
268 /// and the radius at the tail is @a Rmin voxel units, which has
269 /// a default value of 1.5 corresponding to the Nyquist frequency!
270 template<typename ParticleListT>
271 void rasterizeTrails(const ParticleListT& pa, Real delta=1.0);
272
273 private:
274 using BlindType = p2ls_internal::BlindData<SdfType, AttType>;
275 using BlindGridType = typename SdfGridT::template ValueConverter<BlindType>::Type;
276
277 /// Class with multi-threaded implementation of particle rasterization
278 template<typename ParticleListT, typename GridT> struct Raster;
279
280 SdfGridType* mSdfGrid;
281 typename AttGridType::Ptr mAttGrid;
282 BlindGridType* mBlindGrid;
283 InterrupterT* mInterrupter;
284 Real mDx, mHalfWidth;
285 Real mRmin, mRmax; // ignore particles outside this range of radii in voxel
286 size_t mMinCount, mMaxCount; // counters for ignored particles
287 int mGrainSize;
288 }; // class ParticlesToLevelSet
289
290
291 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
292 24 inline ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
293 ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupter) :
294 mSdfGrid(&grid),
295 mBlindGrid(nullptr),
296 mInterrupter(interrupter),
297 24 mDx(grid.voxelSize()[0]),
298 24 mHalfWidth(grid.background()/mDx),
299 mRmin(1.5),// corresponds to the Nyquist grid sampling frequency
300 mRmax(100.0),// corresponds to a huge particle (probably too large!)
301 mMinCount(0),
302 mMaxCount(0),
303
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
48 mGrainSize(1)
304 {
305
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
24 if (!mSdfGrid->hasUniformVoxels()) {
306 OPENVDB_THROW(RuntimeError, "ParticlesToLevelSet only supports uniform voxels!");
307 }
308 if (!DisableT::value) {
309
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 mBlindGrid = new BlindGridType(BlindType(grid.background()));
310
2/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8 mBlindGrid->setTransform(mSdfGrid->transform().copy());
311 }
312 24 }
313
314 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
315 template<typename ParticleListT>
316 12 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
317 rasterizeSpheres(const ParticleListT& pa)
318 {
319 if (DisableT::value) {
320 12 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
321
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 r.rasterizeSpheres();
322 } else {
323 12 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
324
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 r.rasterizeSpheres();
325 }
326 12 }
327
328 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
329 template<typename ParticleListT>
330 4 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
331 rasterizeSpheres(const ParticleListT& pa, Real radius)
332 {
333 if (DisableT::value) {
334 8 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
335
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 r.rasterizeSpheres(radius/mDx);
336 } else {
337 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
338 r.rasterizeSpheres(radius/mDx);
339 }
340 4 }
341
342 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
343 template<typename ParticleListT>
344 8 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
345 rasterizeTrails(const ParticleListT& pa, Real delta)
346 {
347 if (DisableT::value) {
348 12 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
349
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 r.rasterizeTrails(delta);
350 } else {
351 4 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
352
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 r.rasterizeTrails(delta);
353 }
354 8 }
355
356
357 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
358 inline void
359 10 ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::finalize(bool prune)
360 {
361 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
362
363
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
10 if (!mBlindGrid) {
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (prune) {
365 if (OutputIsMask) {
366 tools::prune(mSdfGrid->tree());
367 } else {
368 tools::pruneLevelSet(mSdfGrid->tree());
369 }
370 }
371 2 return;
372 }
373
374
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 if (prune) tools::prune(mBlindGrid->tree());
375
376 using AttTreeT = typename AttGridType::TreeType;
377 using AttLeafT = typename AttTreeT::LeafNodeType;
378 using BlindTreeT = typename BlindGridType::TreeType;
379 using BlindLeafIterT = typename BlindTreeT::LeafCIter;
380 using BlindLeafT = typename BlindTreeT::LeafNodeType;
381 using SdfTreeT = typename SdfGridType::TreeType;
382 using SdfLeafT = typename SdfTreeT::LeafNodeType;
383
384 // Use topology copy constructors since output grids have the same topology as mBlindDataGrid
385
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 const BlindTreeT& blindTree = mBlindGrid->tree();
386
387 // Create the output attribute grid.
388
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
16 typename AttTreeT::Ptr attTree(new AttTreeT(
389 blindTree, blindTree.background().blind(), openvdb::TopologyCopy()));
390 // Note this overwrites any existing attribute grids!
391
4/8
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
24 mAttGrid = typename AttGridType::Ptr(new AttGridType(attTree));
392
2/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8 mAttGrid->setTransform(mBlindGrid->transform().copy());
393
394 8 typename SdfTreeT::Ptr sdfTree; // the output mask or level set tree
395
396 // Extract the attribute grid and the mask or level set grid from mBlindDataGrid.
397 if (OutputIsMask) {
398
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
2 sdfTree.reset(new SdfTreeT(blindTree,
399 /*off=*/SdfType(0), /*on=*/SdfType(1), TopologyCopy()));
400
401 // Copy leaf voxels in parallel.
402
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
4 tree::LeafManager<AttTreeT> leafNodes(*attTree);
403
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
314 leafNodes.foreach([&](AttLeafT& attLeaf, size_t /*leafIndex*/) {
404
1/2
✓ Branch 0 taken 312 times.
✗ Branch 1 not taken.
312 if (const auto* blindLeaf = blindTree.probeConstLeaf(attLeaf.origin())) {
405
2/2
✓ Branch 0 taken 53454 times.
✓ Branch 1 taken 312 times.
53766 for (auto iter = attLeaf.beginValueOn(); iter; ++iter) {
406 const auto pos = iter.pos();
407 53454 attLeaf.setValueOnly(pos, blindLeaf->getValue(pos).blind());
408 }
409 }
410 });
411 // Copy tiles serially.
412
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 const auto blindAcc = mBlindGrid->getConstAccessor();
413 auto iter = attTree->beginValueOn();
414 2 iter.setMaxDepth(AttTreeT::ValueOnIter::LEAF_DEPTH - 1);
415
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
74 for ( ; iter; ++iter) {
416
2/6
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
108 iter.modifyValue([&](AttType& v) { v = blindAcc.getValue(iter.getCoord()).blind(); });
417 }
418 } else {
419 // Here we exploit the fact that by design level sets have no active tiles.
420 // Only leaf voxels can be active.
421
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
6 sdfTree.reset(new SdfTreeT(blindTree, blindTree.background().visible(), TopologyCopy()));
422
2/2
✓ Branch 0 taken 566 times.
✓ Branch 1 taken 3 times.
1138 for (BlindLeafIterT n = blindTree.cbeginLeaf(); n; ++n) {
423 const BlindLeafT& leaf = *n;
424 1132 const openvdb::Coord xyz = leaf.origin();
425 // Get leafnodes that were allocated during topology construction!
426 SdfLeafT* sdfLeaf = sdfTree->probeLeaf(xyz);
427 AttLeafT* attLeaf = attTree->probeLeaf(xyz);
428 // Use linear offset (vs coordinate) access for better performance!
429 typename BlindLeafT::ValueOnCIter m=leaf.cbeginValueOn();
430
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 566 times.
1132 if (!m) {//no active values in leaf node so copy everything
431 for (openvdb::Index k = 0; k!=BlindLeafT::SIZE; ++k) {
432 const BlindType& v = leaf.getValue(k);
433 sdfLeaf->setValueOnly(k, v.visible());
434 attLeaf->setValueOnly(k, v.blind());
435 }
436 } else {//only copy active values (using flood fill for the inactive values)
437
2/2
✓ Branch 0 taken 97854 times.
✓ Branch 1 taken 566 times.
196840 for(; m; ++m) {
438 const openvdb::Index k = m.pos();
439 const BlindType& v = *m;
440 195708 sdfLeaf->setValueOnly(k, v.visible());
441 195708 attLeaf->setValueOnly(k, v.blind());
442 }
443 }
444 }
445
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 tools::signedFloodFill(*sdfTree);//required since we only transferred active voxels!
446 }
447
448
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
8 if (mSdfGrid->empty()) {
449
1/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
16 mSdfGrid->setTree(sdfTree);
450 } else {
451 if (OutputIsMask) {
452 mSdfGrid->tree().topologyUnion(*sdfTree);
453 tools::prune(mSdfGrid->tree());
454 } else {
455 tools::csgUnion(mSdfGrid->tree(), *sdfTree, /*prune=*/true);
456 }
457 }
458
459 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
460 }
461
462
463 ///////////////////////////////////////////////////////////
464
465
466 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
467 template<typename ParticleListT, typename GridT>
468 struct ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::Raster
469 {
470 using DisableT = typename std::is_void<AttributeT>::type;
471 using ParticlesToLevelSetT = ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>;
472 using SdfT = typename ParticlesToLevelSetT::SdfType; // type of signed distance values
473 using AttT = typename ParticlesToLevelSetT::AttType; // type of particle attribute
474 using ValueT = typename GridT::ValueType;
475 using AccessorT = typename GridT::Accessor;
476 using TreeT = typename GridT::TreeType;
477 using LeafNodeT = typename TreeT::LeafNodeType;
478 using PointPartitionerT = PointPartitioner<Index32, LeafNodeT::LOG2DIM>;
479
480 static const bool
481 OutputIsMask = std::is_same<SdfT, bool>::value,
482 DoAttrXfer = !DisableT::value;
483
484 /// @brief Main constructor
485 24 Raster(ParticlesToLevelSetT& parent, GridT* grid, const ParticleListT& particles)
486 : mParent(parent)
487 , mParticles(particles)
488 , mGrid(grid)
489 24 , mMap(*(mGrid->transform().baseMap()))
490 , mMinCount(0)
491 , mMaxCount(0)
492
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
48 , mIsCopy(false)
493 {
494
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 mPointPartitioner = new PointPartitionerT;
495
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 mPointPartitioner->construct(particles, mGrid->transform());
496 24 }
497
498 /// @brief Copy constructor called by tbb threads
499 56 Raster(Raster& other, tbb::split)
500 56 : mParent(other.mParent)
501 56 , mParticles(other.mParticles)
502
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
56 , mGrid(new GridT(*other.mGrid, openvdb::ShallowCopy()))
503 56 , mMap(other.mMap)
504 , mMinCount(0)
505 , mMaxCount(0)
506 56 , mTask(other.mTask)
507 , mIsCopy(true)
508
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
112 , mPointPartitioner(other.mPointPartitioner)
509 {
510
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
56 mGrid->newTree();
511 56 }
512
513 80 virtual ~Raster()
514 {
515 // Copy-constructed Rasters own temporary grids that have to be deleted,
516 // while the original has ownership of the bucket array.
517 80 if (mIsCopy) {
518
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
56 delete mGrid;
519 } else {
520
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 delete mPointPartitioner;
521 }
522 }
523
524 12 void rasterizeSpheres()
525 {
526 12 mMinCount = mMaxCount = 0;
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if (mParent.mInterrupter) {
528 mParent.mInterrupter->start("Rasterizing particles to level set using spheres");
529 }
530 12 mTask = std::bind(&Raster::rasterSpheres, std::placeholders::_1, std::placeholders::_2);
531 12 this->cook();
532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if (mParent.mInterrupter) mParent.mInterrupter->end();
533 12 }
534
535 4 void rasterizeSpheres(Real radius)
536 {
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 mMinCount = radius < mParent.mRmin ? mParticles.size() : 0;
538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 mMaxCount = radius > mParent.mRmax ? mParticles.size() : 0;
539
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (mMinCount>0 || mMaxCount>0) {//skipping all particles!
540 mParent.mMinCount = mMinCount;
541 mParent.mMaxCount = mMaxCount;
542 } else {
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 if (mParent.mInterrupter) {
544 mParent.mInterrupter->start(
545 "Rasterizing particles to level set using const spheres");
546 }
547 4 mTask = std::bind(&Raster::rasterFixedSpheres,
548 std::placeholders::_1, std::placeholders::_2, radius);
549 4 this->cook();
550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 if (mParent.mInterrupter) mParent.mInterrupter->end();
551 }
552 4 }
553
554 8 void rasterizeTrails(Real delta=1.0)
555 {
556 8 mMinCount = mMaxCount = 0;
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 if (mParent.mInterrupter) {
558 mParent.mInterrupter->start("Rasterizing particles to level set using trails");
559 }
560 8 mTask = std::bind(&Raster::rasterTrails,
561 std::placeholders::_1, std::placeholders::_2, delta);
562 8 this->cook();
563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 if (mParent.mInterrupter) mParent.mInterrupter->end();
564 8 }
565
566 /// @brief Kick off the optionally multithreaded computation.
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
190 void operator()(const tbb::blocked_range<size_t>& r)
568 {
569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
190 assert(mTask);
570 190 mTask(this, r);
571 190 mParent.mMinCount = mMinCount;
572 190 mParent.mMaxCount = mMaxCount;
573 190 }
574
575 /// @brief Required by tbb::parallel_reduce
576 11 void join(Raster& other)
577 {
578 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
579 if (OutputIsMask) {
580 if (DoAttrXfer) {
581 4 tools::compMax(*mGrid, *other.mGrid);
582 } else {
583 11 mGrid->topologyUnion(*other.mGrid);
584 }
585 } else {
586 13 tools::csgUnion(*mGrid, *other.mGrid, /*prune=*/true);
587 }
588 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
589 28 mMinCount += other.mMinCount;
590 28 mMaxCount += other.mMaxCount;
591 17 }
592
593 private:
594 /// Disallow assignment since some of the members are references
595 Raster& operator=(const Raster&) { return *this; }
596
597 /// @return true if the particle is too small or too large
598 bool ignoreParticle(Real R)
599 {
600 95 if (R < mParent.mRmin) {// below the cutoff radius
601 8 ++mMinCount;
602 return true;
603 }
604
7/14
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 22 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 22 times.
87 if (R > mParent.mRmax) {// above the cutoff radius
605 ++mMaxCount;
606 return true;
607 }
608 return false;
609 }
610
611 /// @brief Threaded rasterization of particles as spheres with variable radius
612 /// @param r range of indices into the list of particles
613 96 void rasterSpheres(const tbb::blocked_range<size_t>& r)
614 {
615 96 AccessorT acc = mGrid->getAccessor(); // local accessor
616 bool run = true;
617 96 const Real invDx = 1 / mParent.mDx;
618 AttT att;
619 Vec3R pos;
620 Real rad;
621
622 // Loop over buckets
623
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 48 times.
192 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
624 // Loop over particles in bucket n.
625 96 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
626
3/4
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 48 times.
228 for ( ; run && iter; ++iter) {
627 const Index32& id = *iter;
628
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 62 times.
132 mParticles.getPosRad(id, pos, rad);
629
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 62 times.
132 const Real R = invDx * rad;// in voxel units
630 8 if (this->ignoreParticle(R)) continue;
631
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
124 const Vec3R P = mMap.applyInverseMap(pos);
632
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
62 this->getAtt<DisableT>(id, att);
633
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
124 run = this->makeSphere(P, R, att, acc);
634 }//end loop over particles
635 }//end loop over buckets
636 96 }
637
638 /// @brief Threaded rasterization of particles as spheres with a fixed radius
639 /// @param r range of indices into the list of particles
640 /// @param R radius of fixed-size spheres
641 40 void rasterFixedSpheres(const tbb::blocked_range<size_t>& r, Real R)
642 {
643 40 AccessorT acc = mGrid->getAccessor(); // local accessor
644 AttT att;
645 Vec3R pos;
646
647 // Loop over buckets
648
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
80 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
649 // Loop over particles in bucket n.
650
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
80 for (auto iter = mPointPartitioner->indices(n); iter; ++iter) {
651 const Index32& id = *iter;
652 40 this->getAtt<DisableT>(id, att);
653
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 mParticles.getPos(id, pos);
654
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 const Vec3R P = mMap.applyInverseMap(pos);
655
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 this->makeSphere(P, R, att, acc);
656 }
657 }
658 40 }
659
660 /// @brief Threaded rasterization of particles as spheres with velocity trails
661 /// @param r range of indices into the list of particles
662 /// @param delta inter-sphere spacing
663 54 void rasterTrails(const tbb::blocked_range<size_t>& r, Real delta)
664 {
665 54 AccessorT acc = mGrid->getAccessor(); // local accessor
666 bool run = true;
667 AttT att;
668 Vec3R pos, vel;
669 Real rad;
670
1/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
54 const Vec3R origin = mMap.applyInverseMap(Vec3R(0,0,0));
671 54 const Real Rmin = mParent.mRmin, invDx = 1 / mParent.mDx;
672
673 // Loop over buckets
674
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
108 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
675 // Loop over particles in bucket n.
676 54 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
677
3/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 27 times.
112 for ( ; run && iter; ++iter) {
678 const Index32& id = *iter;
679 58 mParticles.getPosRadVel(id, pos, rad, vel);
680
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 25 times.
58 const Real R0 = invDx * rad;
681 8 if (this->ignoreParticle(R0)) continue;
682
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 this->getAtt<DisableT>(id, att);
683
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 const Vec3R P0 = mMap.applyInverseMap(pos);
684
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 const Vec3R V = mMap.applyInverseMap(vel) - origin; // exclude translation
685 50 const Real speed = V.length(), invSpeed = 1.0 / speed;
686 const Vec3R Nrml = -V * invSpeed; // inverse normalized direction
687 50 Vec3R P = P0; // local position of instance
688 Real R = R0, d = 0; // local radius and length of trail
689
3/4
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
✓ Branch 3 taken 25 times.
388 for (size_t m = 0; run && d <= speed ; ++m) {
690
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
338 run = this->makeSphere(P, R, att, acc);
691 338 P += 0.5 * delta * R * Nrml; // adaptive offset along inverse velocity direction
692 d = (P - P0).length(); // current length of trail
693 338 R = R0 - (R0 - Rmin) * d * invSpeed; // R = R0 -> mRmin(e.g. 1.5)
694 }//end loop over sphere instances
695 }//end loop over particles
696 }//end loop over buckets
697 54 }
698
699 24 void cook()
700 {
701 // parallelize over the point buckets
702
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 const Index32 bucketCount = Index32(mPointPartitioner->size());
703
704
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 if (mParent.mGrainSize>0) {
705 24 tbb::parallel_reduce(
706 tbb::blocked_range<size_t>(0, bucketCount, mParent.mGrainSize), *this);
707 } else {
708 (*this)(tbb::blocked_range<size_t>(0, bucketCount));
709 }
710 24 }
711
712 /// @brief Rasterize sphere at position P and radius R into
713 /// a narrow-band level set with half-width, mHalfWidth.
714 /// @return @c false if rasterization was interrupted
715 ///
716 /// @param P coordinates of the particle position in voxel units
717 /// @param R radius of particle in voxel units
718 /// @param att an optional user-defined attribute value to be associated with voxels
719 /// @param acc grid accessor with a private copy of the grid
720 ///
721 /// @note For best performance all computations are performed in voxel space,
722 /// with the important exception of the final level set value that is converted
723 /// to world units (the grid stores the closest Euclidean signed distances
724 /// measured in world units). Also note we use the convention of positive distances
725 /// outside the surface and negative distances inside the surface.
726 template <bool IsMaskT = OutputIsMask>
727 typename std::enable_if<!IsMaskT, bool>::type
728 362 makeSphere(const Vec3R& P, Real R, const AttT& att, AccessorT& acc)
729 {
730 const Real
731 362 dx = mParent.mDx,
732 362 w = mParent.mHalfWidth,
733
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 65 times.
362 max = R + w, // maximum distance in voxel units
734 max2 = math::Pow2(max), // square of maximum distance in voxel units
735
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 65 times.
594 min2 = math::Pow2(math::Max(Real(0), R - w)); // square of minimum distance
736 // Bounding box of the sphere
737 const Coord
738 362 lo(math::Floor(P[0]-max),math::Floor(P[1]-max),math::Floor(P[2]-max)),
739 362 hi(math::Ceil( P[0]+max),math::Ceil( P[1]+max),math::Ceil( P[2]+max));
740 362 const ValueT inside = -mGrid->background();
741
742 ValueT v;
743 size_t count = 0;
744
2/2
✓ Branch 0 taken 2887 times.
✓ Branch 1 taken 181 times.
6136 for (Coord c = lo; c.x() <= hi.x(); ++c.x()) {
745 //only check interrupter every 32'th scan in x
746
3/4
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 2697 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 190 times.
5774 if (!(count++ & ((1<<5)-1)) && util::wasInterrupted(mParent.mInterrupter)) {
747 thread::cancelGroupExecution();
748 return false;
749 }
750 5774 const Real x2 = math::Pow2(c.x() - P[0]);
751
2/2
✓ Branch 0 taken 57756 times.
✓ Branch 1 taken 2887 times.
121286 for (c.y() = lo.y(); c.y() <= hi.y(); ++c.y()) {
752 115512 const Real x2y2 = x2 + math::Pow2(c.y() - P[1]);
753
2/2
✓ Branch 0 taken 1462318 times.
✓ Branch 1 taken 57756 times.
3040148 for (c.z() = lo.z(); c.z() <= hi.z(); ++c.z()) {
754
2/2
✓ Branch 0 taken 603545 times.
✓ Branch 1 taken 858773 times.
2924636 const Real x2y2z2 = x2y2 + math::Pow2(c.z()-P[2]); // squared dist from c to P
755 #if defined __INTEL_COMPILER
756 _Pragma("warning (push)")
757 _Pragma("warning (disable:186)") // "pointless comparison of unsigned integer with zero"
758 #endif
759
6/6
✓ Branch 0 taken 603545 times.
✓ Branch 1 taken 858773 times.
✓ Branch 3 taken 515884 times.
✓ Branch 4 taken 87661 times.
✓ Branch 5 taken 17768 times.
✓ Branch 6 taken 358667 times.
2924636 if (x2y2z2 >= max2 || (!acc.probeValue(c, v) && (v < ValueT(0))))
760 2008020 continue;//outside narrow band of the particle or inside existing level set
761 #if defined __INTEL_COMPILER
762 _Pragma("warning (pop)")
763 #endif
764
2/2
✓ Branch 0 taken 123879 times.
✓ Branch 1 taken 458308 times.
1164374 if (x2y2z2 <= min2) {//inside narrow band of the particle.
765 247758 acc.setValueOff(c, inside);
766 247758 continue;
767 }
768 // convert signed distance from voxel units to world units
769 //const ValueT d=dx*(math::Sqrt(x2y2z2) - R);
770 916616 const ValueT d = Merge(static_cast<SdfT>(dx*(math::Sqrt(x2y2z2)-R)), att);
771
2/2
✓ Branch 0 taken 294126 times.
✓ Branch 1 taken 36167 times.
888456 if (d < v) acc.setValue(c, d);//CSG union
772 }//end loop over z
773 }//end loop over y
774 }//end loop over x
775 362 return true;
776 }
777
778 /// @brief Rasterize a sphere of radius @a r at position @a p into a boolean mask grid.
779 /// @return @c false if rasterization was interrupted
780 template <bool IsMaskT = OutputIsMask>
781 typename std::enable_if<IsMaskT, bool>::type
782 140 makeSphere(const Vec3R& p, Real r, const AttT& att, AccessorT& acc)
783 {
784 const Real
785 140 rSquared = r * r, // sphere radius squared, in voxel units
786 140 inW = r / math::Sqrt(6.0); // half the width in voxel units of an inscribed cube
787 const Coord
788 // Bounding box of the sphere
789 140 outLo(math::Floor(p[0] - r), math::Floor(p[1] - r), math::Floor(p[2] - r)),
790 140 outHi(math::Ceil(p[0] + r), math::Ceil(p[1] + r), math::Ceil(p[2] + r)),
791 // Bounds of the inscribed cube
792 140 inLo(math::Ceil(p[0] - inW), math::Ceil(p[1] - inW), math::Ceil(p[2] - inW)),
793 140 inHi(math::Floor(p[0] + inW), math::Floor(p[1] + inW), math::Floor(p[2] + inW));
794 // Bounding boxes of regions comprising out - in
795 /// @todo These could be divided further into sparsely- and densely-filled subregions.
796 140 const std::vector<CoordBBox> padding{
797 CoordBBox(outLo.x(), outLo.y(), outLo.z(), inLo.x()-1, outHi.y(), outHi.z()),
798 CoordBBox(inHi.x()+1, outLo.y(), outLo.z(), outHi.x(), outHi.y(), outHi.z()),
799 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), inLo.y()-1, outHi.z()),
800 CoordBBox(outLo.x(), inHi.y()+1, outLo.z(), outHi.x(), outHi.y(), outHi.z()),
801 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), outHi.y(), inLo.z()-1),
802 CoordBBox(outLo.x(), outLo.y(), inHi.z()+1, outHi.x(), outHi.y(), outHi.z()),
803 };
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
140 const ValueT onValue = Merge(SdfT(1), att);
805
806 // Sparsely fill the inscribed cube.
807 /// @todo Use sparse fill only if 2r > leaf width?
808
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
140 acc.tree().sparseFill(CoordBBox(inLo, inHi), onValue);
809
810 // Densely fill the remaining regions.
811
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 70 times.
980 for (const auto& bbox: padding) {
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 420 times.
840 if (util::wasInterrupted(mParent.mInterrupter)) {
813 thread::cancelGroupExecution();
814 return false;
815 }
816 const Coord &bmin = bbox.min(), &bmax = bbox.max();
817 Coord c;
818 Real cx, cy, cz;
819
2/2
✓ Branch 0 taken 5356 times.
✓ Branch 1 taken 420 times.
11552 for (c = bmin, cx = c.x(); c.x() <= bmax.x(); ++c.x(), cx += 1) {
820 10712 const Real x2 = math::Pow2(cx - p[0]);
821
2/2
✓ Branch 0 taken 81991 times.
✓ Branch 1 taken 5356 times.
174694 for (c.y() = bmin.y(), cy = c.y(); c.y() <= bmax.y(); ++c.y(), cy += 1) {
822 163982 const Real x2y2 = x2 + math::Pow2(cy - p[1]);
823
2/2
✓ Branch 0 taken 1219482 times.
✓ Branch 1 taken 81991 times.
2602946 for (c.z() = bmin.z(), cz = c.z(); c.z() <= bmax.z(); ++c.z(), cz += 1) {
824
2/2
✓ Branch 0 taken 331909 times.
✓ Branch 1 taken 887573 times.
2438964 const Real x2y2z2 = x2y2 + math::Pow2(cz - p[2]);
825
2/2
✓ Branch 0 taken 331909 times.
✓ Branch 1 taken 887573 times.
2438964 if (x2y2z2 < rSquared) {
826
1/2
✓ Branch 1 taken 331909 times.
✗ Branch 2 not taken.
663818 acc.setValue(c, onValue);
827 }
828 }
829 }
830 }
831 }
832 140 return true;
833 }
834
835 using FuncType = typename std::function<void (Raster*, const tbb::blocked_range<size_t>&)>;
836
837 template<typename DisableType>
838 typename std::enable_if<DisableType::value>::type
839 getAtt(size_t, AttT&) const {}
840
841 template<typename DisableType>
842 typename std::enable_if<!DisableType::value>::type
843 getAtt(size_t n, AttT& a) const { mParticles.getAtt(n, a); }
844
845 template<typename T>
846 typename std::enable_if<std::is_same<T, ValueT>::value, ValueT>::type
847 Merge(T s, const AttT&) const { return s; }
848
849 template<typename T>
850 typename std::enable_if<!std::is_same<T, ValueT>::value, ValueT>::type
851 128024 Merge(T s, const AttT& a) const { return ValueT(s,a); }
852
853 ParticlesToLevelSetT& mParent;
854 const ParticleListT& mParticles;//list of particles
855 GridT* mGrid;
856 const math::MapBase& mMap;
857 size_t mMinCount, mMaxCount;//counters for ignored particles!
858 FuncType mTask;
859 const bool mIsCopy;
860 PointPartitionerT* mPointPartitioner;
861 }; // struct ParticlesToLevelSet::Raster
862
863
864 ///////////////////// YOU CAN SAFELY IGNORE THIS SECTION /////////////////////
865
866 /// @cond OPENVDB_DOCS_INTERNAL
867
868 namespace p2ls_internal {
869
870 // This is a simple type that combines a distance value and a particle
871 // attribute. It's required for attribute transfer which is defined in the
872 // Raster class above.
873 /// @private
874 template<typename VisibleT, typename BlindT>
875 class BlindData
876 {
877 public:
878 using type = VisibleT;
879 using VisibleType = VisibleT;
880 using BlindType = BlindT;
881
882
4/16
✓ Branch 0 taken 370 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 303 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 300017 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
301597 BlindData() {}
883
3/56
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ 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 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 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 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✓ Branch 79 taken 6 times.
✗ Branch 80 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✓ Branch 95 taken 1 times.
✗ Branch 96 not taken.
✓ Branch 99 taken 3 times.
✗ Branch 100 not taken.
50 explicit BlindData(VisibleT v) : mVisible(v), mBlind(zeroVal<BlindType>()) {}
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
10 BlindData(VisibleT v, BlindT b) : mVisible(v), mBlind(b) {}
885 BlindData(const BlindData&) = default;
886 BlindData& operator=(const BlindData&) = default;
887
2/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 7 taken 97854 times.
✗ 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.
97857 const VisibleT& visible() const { return mVisible; }
888
3/14
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 11 taken 97854 times.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
151312 const BlindT& blind() const { return mBlind; }
889 OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN
890
4/108
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ 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.
✗ 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 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 taken 1 times.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✓ Branch 104 taken 1 times.
✗ Branch 105 not taken.
✓ Branch 106 taken 69 times.
✗ Branch 107 not taken.
78 bool operator==(const BlindData& rhs) const { return mVisible == rhs.mVisible; }
891 OPENVDB_NO_FP_EQUALITY_WARNING_END
892
20/250
✗ 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 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 24300 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 24264 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 655340 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 196602 times.
✓ Branch 20 taken 1305 times.
✓ Branch 21 taken 4839 times.
✗ 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 taken 71564 times.
✓ Branch 31 taken 572868 times.
✗ 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 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 taken 34 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 17340 times.
✗ Branch 72 not taken.
✓ Branch 73 taken 17340 times.
✗ Branch 74 not taken.
✓ Branch 75 taken 272 times.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✓ Branch 79 taken 272 times.
✗ 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 taken 34 times.
✗ 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.
✗ Branch 186 not taken.
✗ Branch 187 not taken.
✗ Branch 188 not taken.
✗ Branch 189 not taken.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 192 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✓ Branch 195 taken 17374 times.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 198 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 201 not taken.
✗ Branch 202 not taken.
✗ Branch 203 not taken.
✗ Branch 204 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 207 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 210 not taken.
✗ Branch 211 not taken.
✗ Branch 212 not taken.
✗ Branch 213 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 216 not taken.
✗ Branch 217 not taken.
✗ Branch 218 not taken.
✗ Branch 219 not taken.
✗ Branch 220 not taken.
✗ Branch 221 not taken.
✗ Branch 222 not taken.
✗ Branch 223 not taken.
✗ Branch 224 not taken.
✗ Branch 225 not taken.
✗ Branch 226 not taken.
✗ Branch 227 not taken.
✗ Branch 228 not taken.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 231 not taken.
✗ Branch 232 not taken.
✗ Branch 233 not taken.
✗ Branch 234 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 237 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
✗ Branch 240 not taken.
✗ Branch 241 not taken.
✗ Branch 242 not taken.
✗ Branch 243 not taken.
✗ Branch 244 not taken.
✗ Branch 245 not taken.
✓ Branch 246 taken 3590 times.
✓ Branch 247 taken 135859 times.
✓ Branch 248 taken 113935 times.
✓ Branch 249 taken 14080 times.
1870953 bool operator< (const BlindData& rhs) const { return mVisible < rhs.mVisible; }
893
4/54
✗ 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 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 24300 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 655340 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 10 times.
✗ 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 taken 17374 times.
✗ 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.
697024 bool operator> (const BlindData& rhs) const { return mVisible > rhs.mVisible; }
894 1 BlindData operator+(const BlindData& rhs) const { return BlindData(mVisible + rhs.mVisible); }
895
2/72
✓ Branch 0 taken 86966 times.
✓ Branch 1 taken 15767 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ 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.
✗ 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 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.
102733 BlindData operator-(const BlindData& rhs) const { return BlindData(mVisible - rhs.mVisible); }
896
4/32
✓ Branch 0 taken 15767 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 10 times.
✗ 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.
15877 BlindData operator-() const { return BlindData(-mVisible, mBlind); }
897
898 protected:
899 VisibleT mVisible;
900 BlindT mBlind;
901 };
902
903 /// @private
904 // Required by several of the tree nodes
905 template<typename VisibleT, typename BlindT>
906 inline std::ostream& operator<<(std::ostream& ostr, const BlindData<VisibleT, BlindT>& rhs)
907 {
908 ostr << rhs.visible();
909 return ostr;
910 }
911
912 /// @private
913 // Required by math::Abs
914 template<typename VisibleT, typename BlindT>
915 inline BlindData<VisibleT, BlindT> Abs(const BlindData<VisibleT, BlindT>& x)
916 {
917 return BlindData<VisibleT, BlindT>(math::Abs(x.visible()), x.blind());
918 }
919
920 /// @private
921 // Required to support the (zeroVal<BlindData>() + val) idiom.
922 template<typename VisibleT, typename BlindT, typename T>
923 inline BlindData<VisibleT, BlindT>
924 operator+(const BlindData<VisibleT, BlindT>& x, const T& rhs)
925 {
926 2 return BlindData<VisibleT, BlindT>(x.visible() + static_cast<VisibleT>(rhs), x.blind());
927 }
928
929 } // namespace p2ls_internal
930
931 /// @endcond
932
933 //////////////////////////////////////////////////////////////////////////////
934
935
936 // The following are convenience functions for common use cases.
937
938 template<typename GridT, typename ParticleListT, typename InterrupterT>
939 inline void
940 1 particlesToSdf(const ParticleListT& plist, GridT& grid, InterrupterT* interrupt)
941 {
942 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
943 "particlesToSdf requires an SDF grid with floating-point values");
944
945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (grid.getGridClass() != GRID_LEVEL_SET) {
946 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
947 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
948 }
949
950 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
951
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeSpheres(plist);
952
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::pruneLevelSet(grid.tree());
953 1 }
954
955 template<typename GridT, typename ParticleListT, typename InterrupterT>
956 inline void
957 1 particlesToSdf(const ParticleListT& plist, GridT& grid, Real radius, InterrupterT* interrupt)
958 {
959 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
960 "particlesToSdf requires an SDF grid with floating-point values");
961
962
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (grid.getGridClass() != GRID_LEVEL_SET) {
963 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
964 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
965 }
966
967 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
968
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeSpheres(plist, radius);
969
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::pruneLevelSet(grid.tree());
970 1 }
971
972 template<typename GridT, typename ParticleListT, typename InterrupterT>
973 inline void
974 1 particleTrailsToSdf(const ParticleListT& plist, GridT& grid, Real delta, InterrupterT* interrupt)
975 {
976 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
977 "particleTrailsToSdf requires an SDF grid with floating-point values");
978
979
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (grid.getGridClass() != GRID_LEVEL_SET) {
980 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
981 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
982 }
983
984 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
985
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeTrails(plist, delta);
986
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::pruneLevelSet(grid.tree());
987 1 }
988
989 template<typename GridT, typename ParticleListT, typename InterrupterT>
990 inline void
991 1 particlesToMask(const ParticleListT& plist, GridT& grid, InterrupterT* interrupt)
992 {
993 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
994 "particlesToMask requires a boolean-valued grid");
995 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
996
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeSpheres(plist);
997
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::prune(grid.tree());
998 1 }
999
1000 template<typename GridT, typename ParticleListT, typename InterrupterT>
1001 inline void
1002 1 particlesToMask(const ParticleListT& plist, GridT& grid, Real radius, InterrupterT* interrupt)
1003 {
1004 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1005 "particlesToMask requires a boolean-valued grid");
1006 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
1007
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeSpheres(plist, radius);
1008
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::prune(grid.tree());
1009 1 }
1010
1011 template<typename GridT, typename ParticleListT, typename InterrupterT>
1012 inline void
1013 1 particleTrailsToMask(const ParticleListT& plist, GridT& grid, Real delta, InterrupterT* interrupt)
1014 {
1015 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1016 "particleTrailsToMask requires a boolean-valued grid");
1017 2 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
1018
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 p2ls.rasterizeTrails(plist, delta);
1019
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tools::prune(grid.tree());
1020 1 }
1021
1022 } // namespace tools
1023 } // namespace OPENVDB_VERSION_NAME
1024 } // namespace openvdb
1025
1026 #endif // OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
1027