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