22#ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
23#define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
29#include <tbb/parallel_sort.h>
30#include <tbb/parallel_for.h>
41template<
typename PointAccessorType,
42 typename RandomGenerator,
43 typename InterruptType = util::NullInterrupter>
44class BasePointScatter;
84template<
typename PointAccessorType,
85 typename RandomGenerator,
86 typename InterruptType = util::NullInterrupter>
96 RandomGenerator& randGen,
98 InterruptType* interrupt =
nullptr)
99 :
BaseT(points, randGen, spread, interrupt)
100 , mTargetPointCount(pointCount)
101 , mPointsPerVolume(0.0f)
105 float pointsPerVolume,
106 RandomGenerator& randGen,
108 InterruptType* interrupt =
nullptr)
109 :
BaseT(points, randGen, spread, interrupt)
110 , mTargetPointCount(0)
111 , mPointsPerVolume(pointsPerVolume)
116 template<
typename Gr
idT>
119 mVoxelCount = grid.activeVoxelCount();
120 if (mVoxelCount == 0)
return false;
122 const auto voxelVolume = grid.transform().voxelVolume();
123 if (mPointsPerVolume > 0) {
124 BaseT::start(
"Uniform scattering with fixed point density");
125 mTargetPointCount =
Index64(mPointsPerVolume * voxelVolume *
double(mVoxelCount));
126 }
else if (mTargetPointCount > 0) {
127 BaseT::start(
"Uniform scattering with fixed point count");
128 mPointsPerVolume = float(mTargetPointCount) / float(voxelVolume *
double(mVoxelCount));
133 std::unique_ptr<Index64[]> idList{
new Index64[mTargetPointCount]};
135 for (
Index64 i=0; i<mTargetPointCount; ++i) idList[i] = rand();
136 tbb::parallel_sort(idList.get(), idList.get() + mTargetPointCount);
139 const Vec3R offset(0.5, 0.5, 0.5);
140 typename GridT::ValueOnCIter valueIter = grid.cbeginValueOn();
142 for (
Index64 i=0, n=valueIter.getVoxelCount() ; i != mTargetPointCount; ++i) {
143 if (BaseT::interrupt())
return false;
144 const Index64 voxelId = idList[i];
145 while ( n <= voxelId ) {
147 n += valueIter.getVoxelCount();
149 if (valueIter.isVoxelValue()) {
150 BaseT::addPoint(grid, valueIter.getCoord() - offset);
152 valueIter.getBoundingBox(bbox);
153 BaseT::addPoint(grid, bbox.
min() - offset, bbox.
extents());
164 void print(
const std::string &name, std::ostream& os = std::cout)
const
166 os <<
"Uniformly scattered " << mPointCount <<
" points into " << mVoxelCount
167 <<
" active voxels in \"" << name <<
"\" corresponding to "
168 << mPointsPerVolume <<
" points per volume." << std::endl;
176 using BaseT::mPointCount;
177 using BaseT::mVoxelCount;
179 float mPointsPerVolume;
185template<
typename PointAccessorType,
186 typename RandomGenerator,
196 float pointsPerVoxel,
197 RandomGenerator& randGen,
199 InterruptType* interrupt =
nullptr)
200 :
BaseT(points, randGen, spread, interrupt)
201 , mPointsPerVoxel(pointsPerVoxel)
206 template<
typename Gr
idT>
209 using ValueIter =
typename GridT::ValueOnCIter;
210 if (mPointsPerVoxel < 1.0e-6)
return false;
211 mVoxelCount = grid.activeVoxelCount();
212 if (mVoxelCount == 0)
return false;
213 BaseT::start(
"Dense uniform scattering with fixed point count");
215 const Vec3R offset(0.5, 0.5, 0.5);
217 const int ppv = math::Floor(mPointsPerVoxel);
218 const double delta = mPointsPerVoxel - float(ppv);
219 const bool fractional = !math::isApproxZero(delta, 1.0e-6);
221 for (ValueIter iter = grid.cbeginValueOn(); iter; ++iter) {
222 if (BaseT::interrupt())
return false;
223 if (iter.isVoxelValue()) {
224 const Vec3R dmin = iter.getCoord() - offset;
225 for (
int n = 0; n != ppv; ++n) BaseT::addPoint(grid, dmin);
226 if (fractional && BaseT::getRand01() < delta) BaseT::addPoint(grid, dmin);
228 iter.getBoundingBox(bbox);
230 const Vec3R dmin = bbox.
min() - offset;
231 const double d = mPointsPerVoxel * float(iter.getVoxelCount());
232 const int m = math::Floor(d);
233 for (
int n = 0; n != m; ++n) BaseT::addPoint(grid, dmin, size);
234 if (BaseT::getRand01() < d - m) BaseT::addPoint(grid, dmin, size);
244 void print(
const std::string &name, std::ostream& os = std::cout)
const
246 os <<
"Dense uniformly scattered " << mPointCount <<
" points into " << mVoxelCount
247 <<
" active voxels in \"" << name <<
"\" corresponding to "
248 << mPointsPerVoxel <<
" points per voxel." << std::endl;
254 using BaseT::mPointCount;
255 using BaseT::mVoxelCount;
256 float mPointsPerVoxel;
267template<
typename PointAccessorType,
268 typename RandomGenerator,
278 float pointsPerVolume,
279 RandomGenerator& randGen,
281 InterruptType* interrupt =
nullptr)
282 :
BaseT(points, randGen, spread, interrupt)
283 , mPointsPerVolume(pointsPerVolume)
289 template<
typename Gr
idT>
292 if (mPointsPerVolume <= 0.0f)
return false;
293 mVoxelCount = grid.activeVoxelCount();
294 if (mVoxelCount == 0)
return false;
295 BaseT::start(
"Non-uniform scattering with local point density");
296 const Vec3d dim = grid.voxelSize();
297 const double volumePerVoxel = dim[0]*dim[1]*dim[2],
298 pointsPerVoxel = mPointsPerVolume * volumePerVoxel;
300 const Vec3R offset(0.5, 0.5, 0.5);
301 for (
typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) {
302 if (BaseT::interrupt())
return false;
303 const double d = double(*iter) * pointsPerVoxel * double(iter.getVoxelCount());
304 const int n = int(d);
305 if (iter.isVoxelValue()) {
306 const Vec3R dmin =iter.getCoord() - offset;
307 for (
int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin);
308 if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin);
310 iter.getBoundingBox(bbox);
312 const Vec3R dmin = bbox.
min() - offset;
313 for (
int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin, size);
314 if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin, size);
323 void print(
const std::string &name, std::ostream& os = std::cout)
const
325 os <<
"Non-uniformly scattered " << mPointCount <<
" points into " << mVoxelCount
326 <<
" active voxels in \"" << name <<
"\"." << std::endl;
332 using BaseT::mPointCount;
333 using BaseT::mVoxelCount;
334 float mPointsPerVolume;
339template<
typename PointAccessorType,
340 typename RandomGenerator,
341 typename InterruptType>
361 RandomGenerator& randGen,
363 InterruptType* interrupt =
nullptr)
365 , mInterrupter(interrupt)
369 , mSpread(math::Clamp01(spread))
376 if (mInterrupter) mInterrupter->start(name);
381 if (mInterrupter) mInterrupter->end();
387 return !(mInterruptCount++ & ((1<<5)-1)) && util::wasInterrupted(mInterrupter);
394 inline double getRand() {
return 0.5 + mSpread * (mRand01() - 0.5); }
396 template <
typename Gr
idT>
399 const Vec3R pos(dmin[0] + this->getRand(),
400 dmin[1] + this->getRand(),
401 dmin[2] + this->getRand());
402 mPoints.add(grid.indexToWorld(pos));
406 template <
typename Gr
idT>
409 const Vec3R pos(dmin[0] + size[0]*this->getRand(),
410 dmin[1] + size[1]*this->getRand(),
411 dmin[2] + size[2]*this->getRand());
412 mPoints.add(grid.indexToWorld(pos));
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:249
Coord extents() const
Definition Coord.h:382
const Coord & min() const
Definition Coord.h:321
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:25
Simple generator of random numbers over the range [0, 1)
Definition Math.h:167
Simple random integer generator.
Definition Math.h:203
uint64_t Index64
Definition Types.h:53
Definition Exceptions.h:13
Base class for interrupters.
Definition NullInterrupter.h:26
#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:212