OpenVDB  1.2.0
Dense.h
Go to the documentation of this file.
1 //
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 //
35 
36 #ifndef OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED
37 #define OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED
38 
39 #include <openvdb/Types.h>
40 #include <openvdb/Grid.h>
41 #include <openvdb/Exceptions.h>
42 #include <tbb/parallel_for.h>
43 
44 namespace openvdb {
46 namespace OPENVDB_VERSION_NAME {
47 namespace tools {
48 
49 // Forward declaration (see definition below)
50 template<typename ValueT> class Dense;
51 
52 
58 template<typename GridOrTreeT>
59 void
61  const GridOrTreeT& sparse,
63  bool serial = false);
64 
65 
72 template<typename GridOrTreeT>
73 void
76  GridOrTreeT& sparse,
77  const typename GridOrTreeT::ValueType& tolerance,
78  bool serial = false);
79 
80 
82 
83 
95 template<typename ValueT>
96 class Dense
97 {
98 public:
99  typedef ValueT ValueType;
100 
105  Dense(const CoordBBox& bbox)
106  : mBBox(bbox), mArray(new ValueT[bbox.volume()]), mData(mArray.get()),
107  mY(bbox.dim()[2]), mX(mY*bbox.dim()[1])
108  {
109  if (bbox.empty()) {
110  OPENVDB_THROW(ValueError, "can't construct a dense grid with an empty bounding box");
111  }
112  }
113 
119  Dense(const CoordBBox& bbox, const ValueT& value)
120  : mBBox(bbox), mArray(new ValueT[bbox.volume()]), mData(mArray.get()),
121  mY(bbox.dim()[2]), mX(mY*bbox.dim()[1])
122  {
123  if (bbox.empty()) {
124  OPENVDB_THROW(ValueError, "can't construct a dense grid with an empty bounding box");
125  }
126  this->fill(value);
127  }
128 
137  Dense(const CoordBBox& bbox, ValueT* data)
138  : mBBox(bbox), mData(data), mY(mBBox.dim()[2]), mX(mY*mBBox.dim()[1])
139  {
140  if (mBBox.empty()) {
141  OPENVDB_THROW(ValueError, "can't construct a dense grid with an empty bounding box");
142  }
143  }
144 
150  Dense(const Coord& dim, const Coord& min = Coord(0))
151  : mBBox(min, min+dim.offsetBy(-1)), mArray(new ValueT[mBBox.volume()]),
152  mData(mArray.get()), mY(mBBox.dim()[2]), mX(mY*mBBox.dim()[1])
153  {
154  if (mBBox.empty()) {
155  OPENVDB_THROW(ValueError, "can't construct a dense grid of size zero");
156  }
157  }
158 
162  ValueT* data() { return mData; }
163 
167  const ValueT* data() const { return mData; }
168 
172  const CoordBBox& bbox() const { return mBBox; }
173 
177  size_t xStride() const { return mX; }
178 
182  size_t yStride() const { return mY; }
183 
185  size_t valueCount() const { return mBBox.volume(); }
186 
188  void setValue(size_t offset, const ValueT& value) { mData[offset] = value; }
189 
191  const ValueT& getValue(size_t offset) const { return mData[offset]; }
192 
195  void setValue(size_t i, size_t j, size_t k, const ValueT& value)
196  {
197  mData[this->coordToOffset(i,j,k)] = value;
198  }
199 
202  const ValueT& getValue(size_t i, size_t j, size_t k) const
203  {
204  return mData[this->coordToOffset(i,j,k)];
205  }
206 
209  void setValue(const Coord& xyz, const ValueT& value)
210  {
211  mData[this->coordToOffset(xyz)] = value;
212  }
213 
216  const ValueT& getValue(const Coord& xyz) const
217  {
218  return mData[this->coordToOffset(xyz)];
219  }
220 
222  void fill(const ValueT& value)
223  {
224  size_t size = this->valueCount();
225  ValueT* a = mData;
226  while(size--) *a++ = value;
227  }
228 
235  inline size_t coordToOffset(size_t i, size_t j, size_t k) const
236  {
237  return k + j*mY + i*mX;
238  }
239 
246  inline size_t coordToOffset(Coord xyz) const
247  {
248  assert(mBBox.isInside(xyz));
249  return this->coordToOffset(size_t(xyz[0]-mBBox.min()[0]),
250  size_t(xyz[1]-mBBox.min()[1]),
251  size_t(xyz[2]-mBBox.min()[2]));
252  }
253 
254  Index64 memUsage() const{ return sizeof(*this) + mBBox.volume() * sizeof(ValueType); }
255 
256 private:
257  const CoordBBox mBBox;//signed coordinates of the domain represented by the grid
258  boost::shared_array<ValueT> mArray;
259  ValueT* mData;//raw c-style pointer to values
260  const size_t mY, mX;//strides in x and y (by design it's 1 in z)
261 };// end of Dense
262 
263 
265 
266 
271 template<typename TreeT>
273 {
274 public:
275  typedef typename TreeT::ValueType ValueT;
276 
277  CopyToDense(const TreeT& tree, Dense<ValueT> &dense)
278  : mRoot(tree.root()), mDense(dense) {}
279 
280  void copy(bool serial = false) const
281  {
282  if (serial) {
283  mRoot.copyToDense(mDense.bbox(), mDense);
284  } else {
285  tbb::parallel_for(mDense.bbox(), *this);
286  }
287  }
288 
290  void operator()(const CoordBBox& bbox) const
291  {
292  mRoot.copyToDense(bbox, mDense);
293  }
294 
295 private:
296  const typename TreeT::RootNodeType &mRoot;
297  Dense<ValueT> &mDense;
298 };// CopyToDense
299 
300 
301 // Convenient wrapper function for the CopyToDense class
302 template<typename GridOrTreeT>
303 void
304 copyToDense(const GridOrTreeT& sparse, Dense<typename GridOrTreeT::ValueType>& dense, bool serial)
305 {
306  typedef TreeAdapter<GridOrTreeT> Adapter;
307  typedef typename Adapter::TreeType TreeT;
308 
309  CopyToDense<TreeT> op(Adapter::constTree(sparse), dense);
310  op.copy(serial);
311 }
312 
313 
315 
316 
326 template<typename TreeT>
328 {
329 public:
330  typedef typename TreeT::ValueType ValueT;
331  typedef typename TreeT::LeafNodeType LeafT;
332 
333  CopyFromDense(const Dense<ValueT>& dense, TreeT& tree, const ValueT& tolerance)
334  : mDense(dense), mTree(tree), mBlocks(NULL), mTolerance(tolerance)
335  {
336  }
337 
339  void copy(bool serial = false)
340  {
341  std::vector<Block> blocks;
342  mBlocks = &blocks;
343  const CoordBBox& bbox = mDense.bbox();
344  // Pre-process: Construct a list of blocks alligned with (potential) leaf nodes
345  for (CoordBBox sub=bbox; sub.min()[0] <= bbox.max()[0]; sub.min()[0] = sub.max()[0] + 1) {
346  for (sub.min()[1] = bbox.min()[1]; sub.min()[1] <= bbox.max()[1];
347  sub.min()[1] = sub.max()[1] + 1)
348  {
349  for (sub.min()[2] = bbox.min()[2]; sub.min()[2] <= bbox.max()[2];
350  sub.min()[2] = sub.max()[2] + 1)
351  {
352  sub.max() = Coord::minComponent(bbox.max(),
353  (sub.min()&(~(LeafT::DIM-1u))).offsetBy(LeafT::DIM-1u));
354  blocks.push_back(Block(sub));
355  }
356  }
357  }
358  // Multi-threaded process: Convert dense grid into leaf nodes and tiles
359  if (serial) {
360  (*this)(tbb::blocked_range<size_t>(0, blocks.size()));
361  } else {
362  tbb::parallel_for(tbb::blocked_range<size_t>(0, blocks.size()), *this);
363  }
364  // Post-process: Insert leaf nodes and tiles into the tree, and prune the tiles only!
365  tree::ValueAccessor<TreeT> acc(mTree);
366  for (size_t m=0, size = blocks.size(); m<size; ++m) {
367  Block& block = blocks[m];
368  if (block.leaf) {
369  acc.addLeaf(block.leaf);
370  } else if (block.tile.second) {//only background tiles are inactive
371  acc.addTile(1, block.bbox.min(), block.tile.first, true);//leaf tile
372  }
373  }
374  mTree.root().pruneTiles(mTolerance);
375  }
376 
378  void operator()(const tbb::blocked_range<size_t> &r) const
379  {
380  LeafT* leaf = NULL;
381 
382  for (size_t m=r.begin(), n=0, end = r.end(); m != end; ++m, ++n) {
383 
384  if (leaf == NULL) leaf = new LeafT();
385 
386  Block& block = (*mBlocks)[m];
387  const CoordBBox &bbox = block.bbox;
388 
389  leaf->copyFromDense(bbox, mDense, mTree.background(), mTolerance);
390 
391  if (!leaf->isConstant(block.tile.first, block.tile.second, mTolerance)) {
392  leaf->setOrigin(bbox.min());
393  block.leaf = leaf;
394  leaf = NULL;
395  }
396  }// loop over blocks
397 
398  delete leaf;
399  }
400 
401 private:
402  struct Block {
403  CoordBBox bbox;
404  LeafT* leaf;
405  std::pair<ValueT, bool> tile;
406  Block(const CoordBBox& b) : bbox(b), leaf(NULL) {}
407  };
408 
409  const Dense<ValueT>& mDense;
410  TreeT& mTree;
411  std::vector<Block>* mBlocks;
412  ValueT mTolerance;
413 };// CopyFromDense
414 
415 
416 // Convenient wrapper function for the CopyFromDense class
417 template<typename GridOrTreeT>
418 void
419 copyFromDense(const Dense<typename GridOrTreeT::ValueType>& dense, GridOrTreeT& sparse,
420  const typename GridOrTreeT::ValueType& tolerance, bool serial)
421 {
422  typedef TreeAdapter<GridOrTreeT> Adapter;
423  typedef typename Adapter::TreeType TreeT;
424 
425  CopyFromDense<TreeT> op(dense, Adapter::tree(sparse), tolerance);
426  op.copy(serial);
427 }
428 
429 } // namespace tools
430 } // namespace OPENVDB_VERSION_NAME
431 } // namespace openvdb
432 
433 #endif // OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED
434 
435 // Copyright (c) 2012-2013 DreamWorks Animation LLC
436 // All rights reserved. This software is distributed under the
437 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )