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