Loading...
Searching...
No Matches
PointScatter.h
Go to the documentation of this file.
// Copyright Contributors to the OpenVDB Project
// SPDX-License-Identifier: MPL-2.0
//
/// @author Ken Museth
///
/// @file tools/PointScatter.h
///
/// @brief We offer three different algorithms (each in its own class)
/// for scattering of points in active voxels:
///
/// 1) UniformPointScatter. Has two modes: Either randomly distributes
/// a fixed number of points into the active voxels, or the user can
/// specify a fixed probability of having a points per unit of volume.
///
/// 2) DenseUniformPointScatter. Randomly distributes points into active
/// voxels using a fixed number of points per voxel.
///
/// 3) NonIniformPointScatter. Define the local probability of having
/// a point in a voxel as the product of a global density and the
/// value of the voxel itself.
#ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
#define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
#include <openvdb/Types.h>
#include <openvdb/Grid.h>
#include <openvdb/math/Math.h>
#include <openvdb/util/NullInterrupter.h>
#include <tbb/parallel_sort.h>
#include <tbb/parallel_for.h>
#include <iostream>
#include <memory>
#include <string>
namespace openvdb {
OPENVDB_USE_VERSION_NAMESPACE
namespace OPENVDB_VERSION_NAME {
namespace tools {
/// Forward declaration of base class
template<typename PointAccessorType,
typename RandomGenerator,
typename InterruptType = util::NullInterrupter>
class BasePointScatter;
/// @brief The two point scatters UniformPointScatter and
/// NonUniformPointScatter depend on the following two classes:
///
/// The @c PointAccessorType template argument below refers to any class
/// with the following interface:
/// @code
/// class PointAccessor {
/// ...
/// public:
/// void add(const openvdb::Vec3R &pos);// appends point with world positions pos
/// };
/// @endcode
///
///
/// The @c InterruptType template argument below refers to any class
/// with the following interface:
/// @code
/// class Interrupter {
/// ...
/// public:
/// void start(const char* name = nullptr) // called when computations begin
/// void end() // called when computations end
/// bool wasInterrupted(int percent=-1) // return true to break computation
///};
/// @endcode
///
/// @note If no template argument is provided for this InterruptType
/// the util::NullInterrupter is used which implies that all
/// interrupter calls are no-ops (i.e. incurs no computational overhead).
/// @brief Uniformly scatters points in the active voxels.
/// The point count is either explicitly defined or implicitly
/// through the specification of a global density (=points-per-volume)
///
/// @note This uniform scattering technique assumes that the number of
/// points is generally smaller than the number of active voxels
/// (including virtual active voxels in active tiles).
template<typename PointAccessorType,
typename RandomGenerator,
typename InterruptType = util::NullInterrupter>
class UniformPointScatter : public BasePointScatter<PointAccessorType,
RandomGenerator,
InterruptType>
{
public:
using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>;
UniformPointScatter(PointAccessorType& points,
Index64 pointCount,
RandomGenerator& randGen,
double spread = 1.0,
InterruptType* interrupt = nullptr)
: BaseT(points, randGen, spread, interrupt)
, mTargetPointCount(pointCount)
, mPointsPerVolume(0.0f)
{
}
UniformPointScatter(PointAccessorType& points,
float pointsPerVolume,
RandomGenerator& randGen,
double spread = 1.0,
InterruptType* interrupt = nullptr)
: BaseT(points, randGen, spread, interrupt)
, mTargetPointCount(0)
, mPointsPerVolume(pointsPerVolume)
{
}
/// This is the main functor method implementing the actual scattering of points.
template<typename GridT>
bool operator()(const GridT& grid)
{
mVoxelCount = grid.activeVoxelCount();
if (mVoxelCount == 0) return false;
const auto voxelVolume = grid.transform().voxelVolume();
if (mPointsPerVolume > 0) {
BaseT::start("Uniform scattering with fixed point density");
mTargetPointCount = Index64(mPointsPerVolume * voxelVolume * double(mVoxelCount));
} else if (mTargetPointCount > 0) {
BaseT::start("Uniform scattering with fixed point count");
mPointsPerVolume = float(mTargetPointCount) / float(voxelVolume * double(mVoxelCount));
} else {
return false;
}
std::unique_ptr<Index64[]> idList{new Index64[mTargetPointCount]};
math::RandInt<Index64, RandomGenerator> rand(BaseT::mRand01.engine(), 0, mVoxelCount-1);
for (Index64 i=0; i<mTargetPointCount; ++i) idList[i] = rand();
tbb::parallel_sort(idList.get(), idList.get() + mTargetPointCount);
CoordBBox bbox;
const Vec3R offset(0.5, 0.5, 0.5);
typename GridT::ValueOnCIter valueIter = grid.cbeginValueOn();
for (Index64 i=0, n=valueIter.getVoxelCount() ; i != mTargetPointCount; ++i) {
if (BaseT::interrupt()) return false;
const Index64 voxelId = idList[i];
while ( n <= voxelId ) {
++valueIter;
n += valueIter.getVoxelCount();
}
if (valueIter.isVoxelValue()) {// a majority is expected to be voxels
BaseT::addPoint(grid, valueIter.getCoord() - offset);
} else {// tiles contain multiple (virtual) voxels
valueIter.getBoundingBox(bbox);
BaseT::addPoint(grid, bbox.min() - offset, bbox.extents());
}
}//loop over all the active voxels and tiles
//}
BaseT::end();
return true;
}
// The following methods should only be called after the
// the operator() method was called
void print(const std::string &name, std::ostream& os = std::cout) const
{
os << "Uniformly scattered " << mPointCount << " points into " << mVoxelCount
<< " active voxels in \"" << name << "\" corresponding to "
<< mPointsPerVolume << " points per volume." << std::endl;
}
float getPointsPerVolume() const { return mPointsPerVolume; }
Index64 getTargetPointCount() const { return mTargetPointCount; }
private:
using BaseT::mPointCount;
using BaseT::mVoxelCount;
Index64 mTargetPointCount;
float mPointsPerVolume;
}; // class UniformPointScatter
/// @brief Scatters a fixed (and integer) number of points in all
/// active voxels and tiles.
template<typename PointAccessorType,
typename RandomGenerator,
typename InterruptType = util::NullInterrupter>
class DenseUniformPointScatter : public BasePointScatter<PointAccessorType,
RandomGenerator,
InterruptType>
{
public:
using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>;
DenseUniformPointScatter(PointAccessorType& points,
float pointsPerVoxel,
RandomGenerator& randGen,
double spread = 1.0,
InterruptType* interrupt = nullptr)
: BaseT(points, randGen, spread, interrupt)
, mPointsPerVoxel(pointsPerVoxel)
{
}
/// This is the main functor method implementing the actual scattering of points.
template<typename GridT>
bool operator()(const GridT& grid)
{
using ValueIter = typename GridT::ValueOnCIter;
if (mPointsPerVoxel < 1.0e-6) return false;
mVoxelCount = grid.activeVoxelCount();
if (mVoxelCount == 0) return false;
BaseT::start("Dense uniform scattering with fixed point count");
CoordBBox bbox;
const Vec3R offset(0.5, 0.5, 0.5);
const int ppv = math::Floor(mPointsPerVoxel);
const double delta = mPointsPerVoxel - float(ppv);
const bool fractional = !math::isApproxZero(delta, 1.0e-6);
for (ValueIter iter = grid.cbeginValueOn(); iter; ++iter) {
if (BaseT::interrupt()) return false;
if (iter.isVoxelValue()) {// a majority is expected to be voxels
const Vec3R dmin = iter.getCoord() - offset;
for (int n = 0; n != ppv; ++n) BaseT::addPoint(grid, dmin);
if (fractional && BaseT::getRand01() < delta) BaseT::addPoint(grid, dmin);
} else {// tiles contain multiple (virtual) voxels
iter.getBoundingBox(bbox);
const Coord size(bbox.extents());
const Vec3R dmin = bbox.min() - offset;
const double d = mPointsPerVoxel * float(iter.getVoxelCount());
const int m = math::Floor(d);
for (int n = 0; n != m; ++n) BaseT::addPoint(grid, dmin, size);
if (BaseT::getRand01() < d - m) BaseT::addPoint(grid, dmin, size);
}
}//loop over all the active voxels and tiles
//}
BaseT::end();
return true;
}
// The following methods should only be called after the
// the operator() method was called
void print(const std::string &name, std::ostream& os = std::cout) const
{
os << "Dense uniformly scattered " << mPointCount << " points into " << mVoxelCount
<< " active voxels in \"" << name << "\" corresponding to "
<< mPointsPerVoxel << " points per voxel." << std::endl;
}
float getPointsPerVoxel() const { return mPointsPerVoxel; }
private:
using BaseT::mPointCount;
using BaseT::mVoxelCount;
float mPointsPerVoxel;
}; // class DenseUniformPointScatter
/// @brief Non-uniform scatters of point in the active voxels.
/// The local point count is implicitly defined as a product of
/// of a global density (called pointsPerVolume) and the local voxel
/// (or tile) value.
///
/// @note This scattering technique can be significantly slower
/// than a uniform scattering since its computational complexity
/// is proportional to the active voxel (and tile) count.
template<typename PointAccessorType,
typename RandomGenerator,
typename InterruptType = util::NullInterrupter>
class NonUniformPointScatter : public BasePointScatter<PointAccessorType,
RandomGenerator,
InterruptType>
{
public:
using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>;
NonUniformPointScatter(PointAccessorType& points,
float pointsPerVolume,
RandomGenerator& randGen,
double spread = 1.0,
InterruptType* interrupt = nullptr)
: BaseT(points, randGen, spread, interrupt)
, mPointsPerVolume(pointsPerVolume)//note this is merely a
//multiplier for the local point density
{
}
/// This is the main functor method implementing the actual scattering of points.
template<typename GridT>
bool operator()(const GridT& grid)
{
if (mPointsPerVolume <= 0.0f) return false;
mVoxelCount = grid.activeVoxelCount();
if (mVoxelCount == 0) return false;
BaseT::start("Non-uniform scattering with local point density");
const Vec3d dim = grid.voxelSize();
const double volumePerVoxel = dim[0]*dim[1]*dim[2],
pointsPerVoxel = mPointsPerVolume * volumePerVoxel;
CoordBBox bbox;
const Vec3R offset(0.5, 0.5, 0.5);
for (typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) {
if (BaseT::interrupt()) return false;
const double d = double(*iter) * pointsPerVoxel * double(iter.getVoxelCount());
const int n = int(d);
if (iter.isVoxelValue()) { // a majority is expected to be voxels
const Vec3R dmin =iter.getCoord() - offset;
for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin);
if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin);
} else { // tiles contain multiple (virtual) voxels
iter.getBoundingBox(bbox);
const Coord size(bbox.extents());
const Vec3R dmin = bbox.min() - offset;
for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin, size);
if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin, size);
}
}//loop over all the active voxels and tiles
BaseT::end();
return true;
}
// The following methods should only be called after the
// the operator() method was called
void print(const std::string &name, std::ostream& os = std::cout) const
{
os << "Non-uniformly scattered " << mPointCount << " points into " << mVoxelCount
<< " active voxels in \"" << name << "\"." << std::endl;
}
float getPointPerVolume() const { return mPointsPerVolume; }
private:
using BaseT::mPointCount;
using BaseT::mVoxelCount;
float mPointsPerVolume;
}; // class NonUniformPointScatter
/// Base class of all the point scattering classes defined above
template<typename PointAccessorType,
typename RandomGenerator,
typename InterruptType>
class BasePointScatter
{
public:
Index64 getPointCount() const { return mPointCount; }
Index64 getVoxelCount() const { return mVoxelCount; }
protected:
PointAccessorType& mPoints;
InterruptType* mInterrupter;
Index64 mPointCount;
Index64 mVoxelCount;
Index64 mInterruptCount;
const double mSpread;
math::Rand01<double, RandomGenerator> mRand01;
/// This is a base class so the constructor is protected
BasePointScatter(PointAccessorType& points,
RandomGenerator& randGen,
double spread,
InterruptType* interrupt = nullptr)
: mPoints(points)
, mInterrupter(interrupt)
, mPointCount(0)
, mVoxelCount(0)
, mInterruptCount(0)
, mSpread(math::Clamp01(spread))
, mRand01(randGen)
{
}
inline void start(const char* name)
{
if (mInterrupter) mInterrupter->start(name);
}
inline void end()
{
if (mInterrupter) mInterrupter->end();
}
inline bool interrupt()
{
//only check interrupter for every 32'th call
return !(mInterruptCount++ & ((1<<5)-1)) && util::wasInterrupted(mInterrupter);
}
/// @brief Return a random floating point number between zero and one
inline double getRand01() { return mRand01(); }
/// @brief Return a random floating point number between 0.5 -+ mSpread/2
inline double getRand() { return 0.5 + mSpread * (mRand01() - 0.5); }
template <typename GridT>
inline void addPoint(const GridT &grid, const Vec3R &dmin)
{
const Vec3R pos(dmin[0] + this->getRand(),
dmin[1] + this->getRand(),
dmin[2] + this->getRand());
mPoints.add(grid.indexToWorld(pos));
++mPointCount;
}
template <typename GridT>
inline void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size)
{
const Vec3R pos(dmin[0] + size[0]*this->getRand(),
dmin[1] + size[1]*this->getRand(),
dmin[2] + size[2]*this->getRand());
mPoints.add(grid.indexToWorld(pos));
++mPointCount;
}
};// class BasePointScatter
} // namespace tools
} // namespace OPENVDB_VERSION_NAME
} // namespace openvdb
#endif // OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
Grid.h
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
NullInterrupter.h
Types.h
openvdb::v11_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:251
openvdb::v11_0::math::CoordBBox::extents
Coord extents() const
Definition Coord.h:384
openvdb::v11_0::math::CoordBBox::min
const Coord & min() const
Definition Coord.h:323
openvdb::v11_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:25
openvdb::v11_0::math::Rand01
Simple generator of random numbers over the range [0, 1)
Definition Math.h:167
openvdb::v11_0::math::RandInt
Simple random integer generator.
Definition Math.h:203
openvdb::v11_0::tools::BasePointScatter::addPoint
void addPoint(const GridT &grid, const Vec3R &dmin)
Definition PointScatter.h:397
openvdb::v11_0::tools::BasePointScatter::addPoint
void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size)
Definition PointScatter.h:407
openvdb::v11_0::tools::BasePointScatter::mInterrupter
InterruptType * mInterrupter
Definition PointScatter.h:352
openvdb::v11_0::tools::BasePointScatter::mInterruptCount
Index64 mInterruptCount
Definition PointScatter.h:355
openvdb::v11_0::tools::BasePointScatter::start
void start(const char *name)
Definition PointScatter.h:374
openvdb::v11_0::tools::BasePointScatter::mSpread
const double mSpread
Definition PointScatter.h:356
openvdb::v11_0::tools::BasePointScatter::getPointCount
Index64 getPointCount() const
Definition PointScatter.h:346
openvdb::v11_0::tools::BasePointScatter::mPoints
PointAccessorType & mPoints
Definition PointScatter.h:351
openvdb::v11_0::tools::BasePointScatter< PointAccessorType, RandomGenerator, util::NullInterrupter >::BasePointScatter
BasePointScatter(PointAccessorType &points, RandomGenerator &randGen, double spread, util::NullInterrupter *interrupt=nullptr)
Definition PointScatter.h:360
openvdb::v11_0::tools::BasePointScatter::mVoxelCount
Index64 mVoxelCount
Definition PointScatter.h:354
openvdb::v11_0::tools::BasePointScatter::mRand01
math::Rand01< double, RandomGenerator > mRand01
Definition PointScatter.h:357
openvdb::v11_0::tools::BasePointScatter::getVoxelCount
Index64 getVoxelCount() const
Definition PointScatter.h:347
openvdb::v11_0::tools::BasePointScatter::end
void end()
Definition PointScatter.h:379
openvdb::v11_0::tools::BasePointScatter::getRand01
double getRand01()
Return a random floating point number between zero and one.
Definition PointScatter.h:391
openvdb::v11_0::tools::BasePointScatter::mPointCount
Index64 mPointCount
Definition PointScatter.h:353
openvdb::v11_0::tools::BasePointScatter::getRand
double getRand()
Return a random floating point number between 0.5 -+ mSpread/2.
Definition PointScatter.h:394
openvdb::v11_0::tools::BasePointScatter< PointAccessorType, RandomGenerator, util::NullInterrupter >::interrupt
bool interrupt()
Definition PointScatter.h:384
openvdb::v11_0::tools::DenseUniformPointScatter::print
void print(const std::string &name, std::ostream &os=std::cout) const
Definition PointScatter.h:244
openvdb::v11_0::tools::DenseUniformPointScatter::BaseT
BasePointScatter< PointAccessorType, RandomGenerator, InterruptType > BaseT
Definition PointScatter.h:193
openvdb::v11_0::tools::DenseUniformPointScatter::getPointsPerVoxel
float getPointsPerVoxel() const
Definition PointScatter.h:251
openvdb::v11_0::tools::DenseUniformPointScatter::operator()
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition PointScatter.h:207
openvdb::v11_0::tools::DenseUniformPointScatter::DenseUniformPointScatter
DenseUniformPointScatter(PointAccessorType &points, float pointsPerVoxel, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition PointScatter.h:195
openvdb::v11_0::tools::NonUniformPointScatter::getPointPerVolume
float getPointPerVolume() const
Definition PointScatter.h:329
openvdb::v11_0::tools::NonUniformPointScatter::print
void print(const std::string &name, std::ostream &os=std::cout) const
Definition PointScatter.h:323
openvdb::v11_0::tools::NonUniformPointScatter::BaseT
BasePointScatter< PointAccessorType, RandomGenerator, InterruptType > BaseT
Definition PointScatter.h:275
openvdb::v11_0::tools::NonUniformPointScatter::operator()
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition PointScatter.h:290
openvdb::v11_0::tools::NonUniformPointScatter::NonUniformPointScatter
NonUniformPointScatter(PointAccessorType &points, float pointsPerVolume, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition PointScatter.h:277
openvdb::v11_0::tools::UniformPointScatter::print
void print(const std::string &name, std::ostream &os=std::cout) const
Definition PointScatter.h:164
openvdb::v11_0::tools::UniformPointScatter::getTargetPointCount
Index64 getTargetPointCount() const
Definition PointScatter.h:172
openvdb::v11_0::tools::UniformPointScatter::UniformPointScatter
UniformPointScatter(PointAccessorType &points, Index64 pointCount, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition PointScatter.h:94
openvdb::v11_0::tools::UniformPointScatter::UniformPointScatter
UniformPointScatter(PointAccessorType &points, float pointsPerVolume, RandomGenerator &randGen, double spread=1.0, InterruptType *interrupt=nullptr)
Definition PointScatter.h:104
openvdb::v11_0::tools::UniformPointScatter::BaseT
BasePointScatter< PointAccessorType, RandomGenerator, InterruptType > BaseT
Definition PointScatter.h:92
openvdb::v11_0::tools::UniformPointScatter::operator()
bool operator()(const GridT &grid)
This is the main functor method implementing the actual scattering of points.
Definition PointScatter.h:117
openvdb::v11_0::tools::UniformPointScatter::getPointsPerVolume
float getPointsPerVolume() const
Definition PointScatter.h:171
openvdb::v11_0::math
Definition Types.h:28
openvdb::v11_0::math::isApproxZero
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance.
Definition Math.h:349
openvdb::v11_0::math::Vec3d
Vec3< double > Vec3d
Definition Vec3.h:664
openvdb::v11_0::math::Floor
int Floor(float x)
Return the floor of x.
Definition Math.h:848
openvdb::v11_0::points
Definition AttributeArray.h:41
openvdb::v11_0::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
openvdb::v11_0::Vec3R
math::Vec3< Real > Vec3R
Definition Types.h:72
openvdb::v11_0::Index64
uint64_t Index64
Definition Types.h:53
openvdb
Definition Exceptions.h:13
openvdb::v11_0::util::NullInterrupter
Base class for interrupters.
Definition NullInterrupter.h:26
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212