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