OpenVDB  6.2.0
tools/PointScatter.h
Go to the documentation of this file.
1 //
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 //
30 //
48 
49 #ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
50 #define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
51 
52 #include <openvdb/Types.h>
53 #include <openvdb/Grid.h>
54 #include <openvdb/math/Math.h>
56 #include <tbb/parallel_sort.h>
57 #include <tbb/parallel_for.h>
58 #include <iostream>
59 #include <memory>
60 #include <string>
61 
62 namespace openvdb {
64 namespace OPENVDB_VERSION_NAME {
65 namespace tools {
66 
68 template<typename PointAccessorType,
69  typename RandomGenerator,
70  typename InterruptType = util::NullInterrupter>
72 
102 
103 
111 template<typename PointAccessorType,
112  typename RandomGenerator,
113  typename InterruptType = util::NullInterrupter>
114 class UniformPointScatter : public BasePointScatter<PointAccessorType,
115  RandomGenerator,
116  InterruptType>
117 {
118 public:
120 
121  UniformPointScatter(PointAccessorType& points,
123  RandomGenerator& randGen,
124  double spread = 1.0,
125  InterruptType* interrupt = nullptr)
126  : BaseT(points, randGen, spread, interrupt)
127  , mTargetPointCount(pointCount)
128  , mPointsPerVolume(0.0f)
129  {
130  }
131  UniformPointScatter(PointAccessorType& points,
132  float pointsPerVolume,
133  RandomGenerator& randGen,
134  double spread = 1.0,
135  InterruptType* interrupt = nullptr)
136  : BaseT(points, randGen, spread, interrupt)
137  , mTargetPointCount(0)
138  , mPointsPerVolume(pointsPerVolume)
139  {
140  }
141 
143  template<typename GridT>
144  bool operator()(const GridT& grid)
145  {
146  mVoxelCount = grid.activeVoxelCount();
147  if (mVoxelCount == 0) return false;
148 
149  const auto voxelVolume = grid.transform().voxelVolume();
150  if (mPointsPerVolume > 0) {
151  BaseT::start("Uniform scattering with fixed point density");
152  mTargetPointCount = Index64(mPointsPerVolume * voxelVolume * double(mVoxelCount));
153  } else if (mTargetPointCount > 0) {
154  BaseT::start("Uniform scattering with fixed point count");
155  mPointsPerVolume = float(mTargetPointCount) / float(voxelVolume * double(mVoxelCount));
156  } else {
157  return false;
158  }
159 
160  std::unique_ptr<Index64[]> idList{new Index64[mTargetPointCount]};
161  math::RandInt<Index64, RandomGenerator> rand(BaseT::mRand01.engine(), 0, mVoxelCount-1);
162  for (Index64 i=0; i<mTargetPointCount; ++i) idList[i] = rand();
163  tbb::parallel_sort(idList.get(), idList.get() + mTargetPointCount);
164 
165  CoordBBox bbox;
166  const Vec3R offset(0.5, 0.5, 0.5);
167  typename GridT::ValueOnCIter valueIter = grid.cbeginValueOn();
168 
169  for (Index64 i=0, n=valueIter.getVoxelCount() ; i != mTargetPointCount; ++i) {
170  if (BaseT::interrupt()) return false;
171  const Index64 voxelId = idList[i];
172  while ( n <= voxelId ) {
173  ++valueIter;
174  n += valueIter.getVoxelCount();
175  }
176  if (valueIter.isVoxelValue()) {// a majority is expected to be voxels
177  BaseT::addPoint(grid, valueIter.getCoord() - offset);
178  } else {// tiles contain multiple (virtual) voxels
179  valueIter.getBoundingBox(bbox);
180  BaseT::addPoint(grid, bbox.min() - offset, bbox.extents());
181  }
182  }//loop over all the active voxels and tiles
183  //}
184 
185  BaseT::end();
186  return true;
187  }
188 
189  // The following methods should only be called after the
190  // the operator() method was called
191  void print(const std::string &name, std::ostream& os = std::cout) const
192  {
193  os << "Uniformly scattered " << mPointCount << " points into " << mVoxelCount
194  << " active voxels in \"" << name << "\" corresponding to "
195  << mPointsPerVolume << " points per volume." << std::endl;
196  }
197 
198  float getPointsPerVolume() const { return mPointsPerVolume; }
199  Index64 getTargetPointCount() const { return mTargetPointCount; }
200 
201 private:
202 
203  using BaseT::mPointCount;
204  using BaseT::mVoxelCount;
205  Index64 mTargetPointCount;
206  float mPointsPerVolume;
207 
208 }; // class UniformPointScatter
209 
212 template<typename PointAccessorType,
213  typename RandomGenerator,
214  typename InterruptType = util::NullInterrupter>
215 class DenseUniformPointScatter : public BasePointScatter<PointAccessorType,
216  RandomGenerator,
217  InterruptType>
218 {
219 public:
221 
222  DenseUniformPointScatter(PointAccessorType& points,
223  float pointsPerVoxel,
224  RandomGenerator& randGen,
225  double spread = 1.0,
226  InterruptType* interrupt = nullptr)
227  : BaseT(points, randGen, spread, interrupt)
228  , mPointsPerVoxel(pointsPerVoxel)
229  {
230  }
231 
233  template<typename GridT>
234  bool operator()(const GridT& grid)
235  {
236  using ValueIter = typename GridT::ValueOnCIter;
237  if (mPointsPerVoxel < 1.0e-6) return false;
238  mVoxelCount = grid.activeVoxelCount();
239  if (mVoxelCount == 0) return false;
240  BaseT::start("Dense uniform scattering with fixed point count");
241  CoordBBox bbox;
242  const Vec3R offset(0.5, 0.5, 0.5);
243 
244  const int ppv = math::Floor(mPointsPerVoxel);
245  const double delta = mPointsPerVoxel - float(ppv);
246  const bool fractional = !math::isApproxZero(delta, 1.0e-6);
247 
248  for (ValueIter iter = grid.cbeginValueOn(); iter; ++iter) {
249  if (BaseT::interrupt()) return false;
250  if (iter.isVoxelValue()) {// a majority is expected to be voxels
251  const Vec3R dmin = iter.getCoord() - offset;
252  for (int n = 0; n != ppv; ++n) BaseT::addPoint(grid, dmin);
253  if (fractional && BaseT::getRand01() < delta) BaseT::addPoint(grid, dmin);
254  } else {// tiles contain multiple (virtual) voxels
255  iter.getBoundingBox(bbox);
256  const Coord size(bbox.extents());
257  const Vec3R dmin = bbox.min() - offset;
258  const double d = mPointsPerVoxel * float(iter.getVoxelCount());
259  const int m = math::Floor(d);
260  for (int n = 0; n != m; ++n) BaseT::addPoint(grid, dmin, size);
261  if (BaseT::getRand01() < d - m) BaseT::addPoint(grid, dmin, size);
262  }
263  }//loop over all the active voxels and tiles
264  //}
265  BaseT::end();
266  return true;
267  }
268 
269  // The following methods should only be called after the
270  // the operator() method was called
271  void print(const std::string &name, std::ostream& os = std::cout) const
272  {
273  os << "Dense uniformly scattered " << mPointCount << " points into " << mVoxelCount
274  << " active voxels in \"" << name << "\" corresponding to "
275  << mPointsPerVoxel << " points per voxel." << std::endl;
276  }
277 
278  float getPointsPerVoxel() const { return mPointsPerVoxel; }
279 
280 private:
281  using BaseT::mPointCount;
282  using BaseT::mVoxelCount;
283  float mPointsPerVoxel;
284 }; // class DenseUniformPointScatter
285 
294 template<typename PointAccessorType,
295  typename RandomGenerator,
296  typename InterruptType = util::NullInterrupter>
297 class NonUniformPointScatter : public BasePointScatter<PointAccessorType,
298  RandomGenerator,
299  InterruptType>
300 {
301 public:
303 
304  NonUniformPointScatter(PointAccessorType& points,
305  float pointsPerVolume,
306  RandomGenerator& randGen,
307  double spread = 1.0,
308  InterruptType* interrupt = nullptr)
309  : BaseT(points, randGen, spread, interrupt)
310  , mPointsPerVolume(pointsPerVolume)//note this is merely a
311  //multiplier for the local point density
312  {
313  }
314 
316  template<typename GridT>
317  bool operator()(const GridT& grid)
318  {
319  if (mPointsPerVolume <= 0.0f) return false;
320  mVoxelCount = grid.activeVoxelCount();
321  if (mVoxelCount == 0) return false;
322  BaseT::start("Non-uniform scattering with local point density");
323  const Vec3d dim = grid.voxelSize();
324  const double volumePerVoxel = dim[0]*dim[1]*dim[2],
325  pointsPerVoxel = mPointsPerVolume * volumePerVoxel;
326  CoordBBox bbox;
327  const Vec3R offset(0.5, 0.5, 0.5);
328  for (typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) {
329  if (BaseT::interrupt()) return false;
330  const double d = double(*iter) * pointsPerVoxel * double(iter.getVoxelCount());
331  const int n = int(d);
332  if (iter.isVoxelValue()) { // a majority is expected to be voxels
333  const Vec3R dmin =iter.getCoord() - offset;
334  for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin);
335  if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin);
336  } else { // tiles contain multiple (virtual) voxels
337  iter.getBoundingBox(bbox);
338  const Coord size(bbox.extents());
339  const Vec3R dmin = bbox.min() - offset;
340  for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin, size);
341  if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin, size);
342  }
343  }//loop over all the active voxels and tiles
344  BaseT::end();
345  return true;
346  }
347 
348  // The following methods should only be called after the
349  // the operator() method was called
350  void print(const std::string &name, std::ostream& os = std::cout) const
351  {
352  os << "Non-uniformly scattered " << mPointCount << " points into " << mVoxelCount
353  << " active voxels in \"" << name << "\"." << std::endl;
354  }
355 
356  float getPointPerVolume() const { return mPointsPerVolume; }
357 
358 private:
359  using BaseT::mPointCount;
360  using BaseT::mVoxelCount;
361  float mPointsPerVolume;
362 
363 }; // class NonUniformPointScatter
364 
366 template<typename PointAccessorType,
367  typename RandomGenerator,
368  typename InterruptType>
369 class BasePointScatter
370 {
371 public:
372 
373  Index64 getPointCount() const { return mPointCount; }
374  Index64 getVoxelCount() const { return mVoxelCount; }
375 
376 protected:
377 
378  PointAccessorType& mPoints;
379  InterruptType* mInterrupter;
383  const double mSpread;
385 
387  BasePointScatter(PointAccessorType& points,
388  RandomGenerator& randGen,
389  double spread,
390  InterruptType* interrupt = nullptr)
391  : mPoints(points)
392  , mInterrupter(interrupt)
393  , mPointCount(0)
394  , mVoxelCount(0)
395  , mInterruptCount(0)
396  , mSpread(math::Clamp01(spread))
397  , mRand01(randGen)
398  {
399  }
400 
401  inline void start(const char* name)
402  {
403  if (mInterrupter) mInterrupter->start(name);
404  }
405 
406  inline void end()
407  {
408  if (mInterrupter) mInterrupter->end();
409  }
410 
411  inline bool interrupt()
412  {
413  //only check interrupter for every 32'th call
414  return !(mInterruptCount++ & ((1<<5)-1)) && util::wasInterrupted(mInterrupter);
415  }
416 
418  inline double getRand01() { return mRand01(); }
419 
421  inline double getRand() { return 0.5 + mSpread * (mRand01() - 0.5); }
422 
423  template <typename GridT>
424  inline void addPoint(const GridT &grid, const Vec3R &dmin)
425  {
426  const Vec3R pos(dmin[0] + this->getRand(),
427  dmin[1] + this->getRand(),
428  dmin[2] + this->getRand());
429  mPoints.add(grid.indexToWorld(pos));
430  ++mPointCount;
431  }
432 
433  template <typename GridT>
434  inline void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size)
435  {
436  const Vec3R pos(dmin[0] + size[0]*this->getRand(),
437  dmin[1] + size[1]*this->getRand(),
438  dmin[2] + size[2]*this->getRand());
439  mPoints.add(grid.indexToWorld(pos));
440  ++mPointCount;
441  }
442 };// class BasePointScatter
443 
444 } // namespace tools
445 } // namespace OPENVDB_VERSION_NAME
446 } // namespace openvdb
447 
448 #endif // OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
449 
450 // Copyright (c) DreamWorks Animation LLC
451 // All rights reserved. This software is distributed under the
452 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
Forward declaration of base class.
Definition: tools/PointScatter.h:71
Index64 getPointCount() const
Definition: tools/PointScatter.h:373
Index64 getVoxelCount() const
Definition: tools/PointScatter.h:374
NonUniformPointScatter(PointAccessorType &points, float pointsPerVolume, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition: tools/PointScatter.h:304
void addPoint(const GridT &grid, const Vec3R &dmin)
Definition: tools/PointScatter.h:424
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size)
Definition: tools/PointScatter.h:434
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition: tools/PointScatter.h:317
void start(const char *name)
Definition: tools/PointScatter.h:401
const double mSpread
Definition: tools/PointScatter.h:383
bool interrupt()
Definition: tools/PointScatter.h:411
Non-uniform scatters of point in the active voxels. The local point count is implicitly defined as a ...
Definition: tools/PointScatter.h:297
Simple random integer generator.
Definition: Math.h:171
UniformPointScatter(PointAccessorType &points, Index64 pointCount, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition: tools/PointScatter.h:121
Vec3< double > Vec3d
Definition: Vec3.h:689
PointAccessorType & mPoints
Definition: tools/PointScatter.h:378
InterruptType * mInterrupter
Definition: tools/PointScatter.h:379
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition: tools/PointScatter.h:234
void print(const std::string &name, std::ostream &os=std::cout) const
Definition: tools/PointScatter.h:350
Scatters a fixed (and integer) number of points in all active voxels and tiles.
Definition: tools/PointScatter.h:215
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:128
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
Definition: Math.h:320
void print(const std::string &name, std::ostream &os=std::cout) const
Definition: tools/PointScatter.h:191
math::Rand01< double, RandomGenerator > mRand01
Definition: tools/PointScatter.h:384
Index64 mInterruptCount
Definition: tools/PointScatter.h:382
Definition: Exceptions.h:40
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
uint64_t Index64
Definition: Types.h:60
double getRand01()
Return a random floating point number between zero and one.
Definition: tools/PointScatter.h:418
double getRand()
Return a random floating point number between 0.5 -+ mSpread/2.
Definition: tools/PointScatter.h:421
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:115
Index64 mPointCount
Definition: tools/PointScatter.h:380
UniformPointScatter(PointAccessorType &points, float pointsPerVolume, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition: tools/PointScatter.h:131
Index64 getTargetPointCount() const
Definition: tools/PointScatter.h:199
BasePointScatter(PointAccessorType &points, RandomGenerator &randGen, double spread, InterruptType *interrupt=nullptr)
This is a base class so the constructor is protected.
Definition: tools/PointScatter.h:387
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition: tools/PointScatter.h:144
Index64 mVoxelCount
Definition: tools/PointScatter.h:381
float getPointPerVolume() const
Definition: tools/PointScatter.h:356
Type Clamp01(Type x)
Return x clamped to [0, 1].
Definition: Math.h:240
void print(const std::string &name, std::ostream &os=std::cout) const
Definition: tools/PointScatter.h:271
DenseUniformPointScatter(PointAccessorType &points, float pointsPerVoxel, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition: tools/PointScatter.h:222
void end()
Definition: tools/PointScatter.h:406
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:180
float getPointsPerVolume() const
Definition: tools/PointScatter.h:198
The two point scatters UniformPointScatter and NonUniformPointScatter depend on the following two cla...
Definition: tools/PointScatter.h:114
int Floor(float x)
Return the floor of x.
Definition: Math.h:822
float getPointsPerVoxel() const
Definition: tools/PointScatter.h:278
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76