OpenVDB  0.104.0
PointScatter.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012 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 //
32 
33 #ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
34 #define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
35 
36 #include <openvdb/Types.h>
37 #include <openvdb/Grid.h>
38 #include <openvdb/util/NullInterrupter.h>
39 #include <boost/random/uniform_01.hpp>
40 
41 namespace openvdb {
43 namespace OPENVDB_VERSION_NAME {
44 namespace tools {
45 
75 
76 
84 template<
85  typename PointAccessorType,
86  typename RandomGenerator,
87  typename InterruptType = openvdb::util::NullInterrupter>
89 {
90 protected:
91  PointAccessorType& mPoints;
92  InterruptType* mInterrupter;
96  RandomGenerator& mRandomGen;
97  boost::uniform_01<double> mRandom;
98 
99  double getRand() { return mRandom(mRandomGen); }
100 
101  template <typename GridT>
102  inline void addPoint(const GridT &grid, const openvdb::Vec3R &pos, const openvdb::Vec3R &delta)
103  {
104  mPoints.add(grid.indexToWorld(pos + delta));
105  ++mPointCount;
106  }
107  template <typename GridT>
108  inline void addPoint(const GridT &grid, const openvdb::Vec3R &dmin)
109  {
110  this->addPoint(grid, dmin, openvdb::Vec3R(getRand(),getRand(),getRand()));
111  }
112  template <typename GridT>
113  inline void addPoint(const GridT &grid, const openvdb::Vec3R &dmin, const openvdb::Coord &size)
114  {
115  const openvdb::Vec3R d(size.x()*getRand(),size.y()*getRand(),size.z()*getRand());
116  this->addPoint(grid, dmin, d);
117  }
118 
119 public:
120  UniformPointScatter(PointAccessorType& points,
121  int pointCount,
122  RandomGenerator& randGen,
123  InterruptType* interrupt = NULL):
124  mPoints(points),
125  mInterrupter(interrupt),
126  mPointCount(pointCount),
127  mPointsPerVolume(0.0f),
128  mVoxelCount(0),
129  mRandomGen(randGen)
130  {
131  }
132  UniformPointScatter(PointAccessorType& points,
133  float pointsPerVolume,
134  RandomGenerator& randGen,
135  InterruptType* interrupt = NULL):
136  mPoints(points),
137  mInterrupter(interrupt),
138  mPointCount(0),
139  mPointsPerVolume(pointsPerVolume),
140  mVoxelCount(0),
141  mRandomGen(randGen)
142  {
143  }
144 
146  template<typename GridT>
147  void operator()(const GridT& grid)
148  {
149  mVoxelCount = grid.activeVoxelCount();
150  if (mVoxelCount == 0) throw std::runtime_error("No voxels in which to scatter points!");
151  const openvdb::Index64 voxelId = mVoxelCount - 1;
152  const openvdb::Vec3d dim = grid.voxelSize();
153  if (mPointsPerVolume>0) {
154  if (mInterrupter) mInterrupter->start("Uniform scattering with fixed point density");
155  mPointCount = int(mPointsPerVolume * dim[0]*dim[1]*dim[2] * mVoxelCount);
156  } else if (mPointCount>0) {
157  if (mInterrupter) mInterrupter->start("Uniform scattering with fixed point count");
158  mPointsPerVolume = mPointCount/float(dim[0]*dim[1]*dim[2] * mVoxelCount);
159  } else {
160  throw std::runtime_error("Invalid point count and point density");
161  }
162  openvdb::CoordBBox bbox;
164  std::multiset<openvdb::Index64> mVoxelSet;
165  for (int i=0, chunks=100000; i<mPointCount; i += chunks) {
166  if (mInterrupter && mInterrupter->wasInterrupted()) {
167  throw std::runtime_error("processing was interrupted");
168  }
170  for (int j=i, end=std::min(i+chunks, mPointCount); j<end; ++j) {
171  mVoxelSet.insert(openvdb::Index64(voxelId*getRand()));
172  }
173  }
174  std::multiset<openvdb::Index64>::iterator voxelIter =
175  mVoxelSet.begin(), voxelEnd = mVoxelSet.end();
176  typename GridT::ValueOnCIter valueIter = grid.cbeginValueOn();
177  mPointCount = 0;
178  for (openvdb::Index64 i=valueIter.getVoxelCount(); voxelIter != voxelEnd; ++voxelIter) {
179  if (mInterrupter && mInterrupter->wasInterrupted()) {
180  throw std::runtime_error("processing was interrupted");
181  }
182  while ( i <= *voxelIter ) {
183  ++valueIter;
184  i += valueIter.getVoxelCount();
185  }
186  if (valueIter.isVoxelValue()) {// a majorty is expected to be voxels
187  const openvdb::Coord min = valueIter.getCoord();
188  const openvdb::Vec3R dmin(min.x()-0.5, min.y()-0.5, min.z()-0.5);
189  this->addPoint(grid, dmin);
190  } else {// tiles contain multiple (virtual) voxels
191  valueIter.getBoundingBox(bbox);
192  const openvdb::Coord size(bbox.extents());
193  const openvdb::Vec3R dmin(bbox.min().x()-0.5,
194  bbox.min().y()-0.5,
195  bbox.min().z()-0.5);
196  this->addPoint(grid, dmin, size);
197  }
198  }
199  if (mInterrupter) mInterrupter->end();
200  }
201 
202  // The following methods should only be called after the
203  // the operator() method was called
204  void print(const std::string &name, std::ostream& os = std::cout) const
205  {
206  os << "Uniformely scattered " << mPointCount << " points into " << mVoxelCount
207  << " active voxels in \"" << name << "\" corresponding to "
208  << mPointsPerVolume << " points per volume." << std::endl;
209  }
210 
211  int getPointCount() const { return mPointCount; }
212  float getPointsPerVolume() const { return mPointsPerVolume; }
213  openvdb::Index64 getVoxelCount() const { return mVoxelCount; }
214 }; // class UniformPointScatter
215 
216 
224 template<
225  typename PointAccessorType,
226  typename RandomGenerator,
227  typename InterruptType = openvdb::util::NullInterrupter>
229 {
230 protected:
231  PointAccessorType& mPoints;
232  InterruptType* mInterrupter;
236  RandomGenerator& mRandomGen;
237  boost::uniform_01<double> mRandom;
238 
239  double getRand() { return mRandom(mRandomGen); }
240 
241  template <typename GridT>
242  inline void addPoint(const GridT &grid, const openvdb::Vec3R &pos, const openvdb::Vec3R &delta)
243  {
244  mPoints.add(grid.indexToWorld(pos + delta));
245  ++mPointCount;
246  }
247  template <typename GridT>
248  inline void addPoint(const GridT &grid, const openvdb::Vec3R &dmin)
249  {
250  this->addPoint(grid, dmin, openvdb::Vec3R(getRand(),getRand(),getRand()));
251  }
252  template <typename GridT>
253  inline void addPoint(const GridT &grid, const openvdb::Vec3R &dmin, const openvdb::Coord &size)
254  {
255  const openvdb::Vec3R d(size.x()*getRand(),size.y()*getRand(),size.z()*getRand());
256  this->addPoint(grid, dmin, d);
257  }
258 
259 public:
260  NonUniformPointScatter(PointAccessorType& points,
261  float pointsPerVolume,
262  RandomGenerator& randGen,
263  InterruptType* interrupt = NULL):
264  mPoints(points),
265  mInterrupter(interrupt),
266  mPointCount(0),
267  mPointsPerVolume(pointsPerVolume),//note this is NOT the local point density
268  mVoxelCount(0),
269  mRandomGen(randGen)
270  {
271  }
272 
274  template<typename GridT>
275  void operator()(const GridT& grid)
276  {
277  mVoxelCount = grid.activeVoxelCount();
278  if (mVoxelCount == 0) throw std::runtime_error("No voxels in which to scatter points!");
279  if (mInterrupter) mInterrupter->start("Non-uniform scattering with local point density");
280  const openvdb::Vec3d dim = grid.voxelSize();
281  const double volumePerVoxel = dim[0]*dim[1]*dim[2],
282  pointsPerVoxel = mPointsPerVolume * volumePerVoxel;
283  openvdb::CoordBBox bbox;
284  for (typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) {
285  if (mInterrupter && mInterrupter->wasInterrupted()) {
286  throw std::runtime_error("processing was interrupted");
287  }
288  const double d = (*iter) * pointsPerVoxel * iter.getVoxelCount();
289  const int n = int(d);
290  if (iter.isVoxelValue()) { // a majorty is expected to be voxels
291  const openvdb::Coord min = iter.getCoord();
292  const openvdb::Vec3R dmin(min.x()-0.5, min.y()-0.5, min.z()-0.5);
293  for (int i = 0; i < n; ++i) this->addPoint(grid, dmin);
294  if (getRand() < (d - n)) this->addPoint(grid, dmin);
295  } else { // tiles contain multiple (virtual) voxels
296  iter.getBoundingBox(bbox);
297  const openvdb::Coord size(bbox.extents());
298  const openvdb::Vec3R dmin(bbox.min().x()-0.5,
299  bbox.min().y()-0.5,
300  bbox.min().z()-0.5);
301  for (int i = 0; i < n; ++i) this->addPoint(grid, dmin, size);
302  if (getRand() < (d - n)) this->addPoint(grid, dmin, size);
303  }
304  }
305  if (mInterrupter) mInterrupter->end();
306  }
307 
308  // The following methods should only be called after the
309  // the operator() method was called
310  void print(const std::string &name, std::ostream& os = std::cout) const
311  {
312  os << "Non-uniformely scattered " << mPointCount << " points into " << mVoxelCount
313  << " active voxels in \"" << name << "\"." << std::endl;
314  }
315 
316  int getPointCount() const { return mPointCount; }
317  openvdb::Index64 getVoxelCount() const { return mVoxelCount; }
318 }; // class NonUniformPointScatter
319 
320 } // namespace tools
321 } // namespace OPENVDB_VERSION_NAME
322 } // namespace openvdb
323 
324 #endif // OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED
325 
326 // Copyright (c) 2012 DreamWorks Animation LLC
327 // All rights reserved. This software is distributed under the
328 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )