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×<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 −<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 |