OpenVDB  4.0.2
VolumeToSpheres.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2017 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 
34 
35 #ifndef OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
36 #define OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
37 
39 #include "Morphology.h" // for erodeVoxels()
40 #include "PointScatter.h"
41 #include "LevelSetUtil.h"
42 #include "VolumeToMesh.h"
43 
44 #include <boost/scoped_array.hpp>
45 #include <tbb/blocked_range.h>
46 #include <tbb/parallel_for.h>
47 #include <tbb/parallel_reduce.h>
48 
49 #include <limits> // std::numeric_limits
50 #include <vector>
51 
52 
53 namespace openvdb {
55 namespace OPENVDB_VERSION_NAME {
56 namespace tools {
57 
77 template<typename GridT, typename InterrupterT = util::NullInterrupter>
78 inline void
80  const GridT& grid,
81  std::vector<openvdb::Vec4s>& spheres,
82  int maxSphereCount,
83  bool overlapping = false,
84  float minRadius = 1.0,
85  float maxRadius = std::numeric_limits<float>::max(),
86  float isovalue = 0.0,
87  int instanceCount = 10000,
88  InterrupterT* interrupter = nullptr);
89 
90 
92 
93 
97 template<typename GridT>
99 {
100 public:
101  using TreeT = typename GridT::TreeType;
102  using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
103  using Index32TreeT = typename TreeT::template ValueConverter<Index32>::Type;
104  using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
105 
107 
118  template<typename InterrupterT = util::NullInterrupter>
119  bool initialize(const GridT& grid, float isovalue = 0.0, InterrupterT* interrupter = nullptr);
120 
124  bool search(const std::vector<Vec3R>& points, std::vector<float>& distances);
125 
129  bool searchAndReplace(std::vector<Vec3R>& points, std::vector<float>& distances);
130 
132  const Index32TreeT& indexTree() const { return *mIdxTreePt; }
134  const Int16TreeT& signTree() const { return *mSignTreePt; }
135 
136 private:
137  using Index32LeafT = typename Index32TreeT::LeafNodeType;
138  using IndexRange = std::pair<size_t, size_t>;
139 
140  bool mIsInitialized;
141  std::vector<Vec4R> mLeafBoundingSpheres, mNodeBoundingSpheres;
142  std::vector<IndexRange> mLeafRanges;
143  std::vector<const Index32LeafT*> mLeafNodes;
144  PointList mSurfacePointList;
145  size_t mPointListSize, mMaxNodeLeafs;
146  float mMaxRadiusSqr;
147  typename Index32TreeT::Ptr mIdxTreePt;
148  typename Int16TreeT::Ptr mSignTreePt;
149 
150  bool search(std::vector<Vec3R>&, std::vector<float>&, bool transformPoints);
151 };
152 
153 
155 
156 
157 // Internal utility methods
158 
159 namespace internal {
160 
162 {
163  PointAccessor(std::vector<Vec3R>& points)
164  : mPoints(points)
165  {
166  }
167 
168  void add(const Vec3R &pos)
169  {
170  mPoints.push_back(pos);
171  }
172 private:
173  std::vector<Vec3R>& mPoints;
174 };
175 
176 
177 template<typename Index32LeafT>
178 class LeafOp
179 {
180 public:
181 
182  LeafOp(std::vector<Vec4R>& leafBoundingSpheres,
183  const std::vector<const Index32LeafT*>& leafNodes,
184  const math::Transform& transform,
185  const PointList& surfacePointList);
186 
187  void run(bool threaded = true);
188 
189 
190  void operator()(const tbb::blocked_range<size_t>&) const;
191 
192 private:
193  std::vector<Vec4R>& mLeafBoundingSpheres;
194  const std::vector<const Index32LeafT*>& mLeafNodes;
195  const math::Transform& mTransform;
196  const PointList& mSurfacePointList;
197 };
198 
199 template<typename Index32LeafT>
201  std::vector<Vec4R>& leafBoundingSpheres,
202  const std::vector<const Index32LeafT*>& leafNodes,
203  const math::Transform& transform,
204  const PointList& surfacePointList)
205  : mLeafBoundingSpheres(leafBoundingSpheres)
206  , mLeafNodes(leafNodes)
207  , mTransform(transform)
208  , mSurfacePointList(surfacePointList)
209 {
210 }
211 
212 template<typename Index32LeafT>
213 void
215 {
216  if (threaded) {
217  tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafNodes.size()), *this);
218  } else {
219  (*this)(tbb::blocked_range<size_t>(0, mLeafNodes.size()));
220  }
221 }
222 
223 template<typename Index32LeafT>
224 void
225 LeafOp<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
226 {
227  typename Index32LeafT::ValueOnCIter iter;
228  Vec3s avg;
229 
230  for (size_t n = range.begin(); n != range.end(); ++n) {
231 
232  avg[0] = 0.0;
233  avg[1] = 0.0;
234  avg[2] = 0.0;
235 
236  int count = 0;
237  for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
238  avg += mSurfacePointList[iter.getValue()];
239  ++count;
240  }
241 
242  if (count > 1) avg *= float(1.0 / double(count));
243 
244  float maxDist = 0.0;
245 
246  for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
247  float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr();
248  if (tmpDist > maxDist) maxDist = tmpDist;
249  }
250 
251  Vec4R& sphere = mLeafBoundingSpheres[n];
252 
253  sphere[0] = avg[0];
254  sphere[1] = avg[1];
255  sphere[2] = avg[2];
256  sphere[3] = maxDist * 2.0; // padded radius
257  }
258 }
259 
260 
261 class NodeOp
262 {
263 public:
264  using IndexRange = std::pair<size_t, size_t>;
265 
266  NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
267  const std::vector<IndexRange>& leafRanges,
268  const std::vector<Vec4R>& leafBoundingSpheres);
269 
270  inline void run(bool threaded = true);
271 
272  inline void operator()(const tbb::blocked_range<size_t>&) const;
273 
274 private:
275  std::vector<Vec4R>& mNodeBoundingSpheres;
276  const std::vector<IndexRange>& mLeafRanges;
277  const std::vector<Vec4R>& mLeafBoundingSpheres;
278 };
279 
280 inline
281 NodeOp::NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
282  const std::vector<IndexRange>& leafRanges,
283  const std::vector<Vec4R>& leafBoundingSpheres)
284  : mNodeBoundingSpheres(nodeBoundingSpheres)
285  , mLeafRanges(leafRanges)
286  , mLeafBoundingSpheres(leafBoundingSpheres)
287 {
288 }
289 
290 inline void
291 NodeOp::run(bool threaded)
292 {
293  if (threaded) {
294  tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafRanges.size()), *this);
295  } else {
296  (*this)(tbb::blocked_range<size_t>(0, mLeafRanges.size()));
297  }
298 }
299 
300 inline void
301 NodeOp::operator()(const tbb::blocked_range<size_t>& range) const
302 {
303  Vec3d avg, pos;
304 
305  for (size_t n = range.begin(); n != range.end(); ++n) {
306 
307  avg[0] = 0.0;
308  avg[1] = 0.0;
309  avg[2] = 0.0;
310 
311  int count = int(mLeafRanges[n].second) - int(mLeafRanges[n].first);
312 
313  for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
314  avg[0] += mLeafBoundingSpheres[i][0];
315  avg[1] += mLeafBoundingSpheres[i][1];
316  avg[2] += mLeafBoundingSpheres[i][2];
317  }
318 
319  if (count > 1) avg *= float(1.0 / double(count));
320 
321 
322  double maxDist = 0.0;
323 
324  for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
325  pos[0] = mLeafBoundingSpheres[i][0];
326  pos[1] = mLeafBoundingSpheres[i][1];
327  pos[2] = mLeafBoundingSpheres[i][2];
328 
329  double tmpDist = (pos - avg).lengthSqr() + mLeafBoundingSpheres[i][3];
330  if (tmpDist > maxDist) maxDist = tmpDist;
331  }
332 
333  Vec4R& sphere = mNodeBoundingSpheres[n];
334 
335  sphere[0] = avg[0];
336  sphere[1] = avg[1];
337  sphere[2] = avg[2];
338  sphere[3] = maxDist * 2.0; // padded radius
339  }
340 }
341 
342 
344 
345 
346 template<typename Index32LeafT>
348 {
349 public:
350  using IndexRange = std::pair<size_t, size_t>;
351 
353  std::vector<Vec3R>& instancePoints,
354  std::vector<float>& instanceDistances,
355  const PointList& surfacePointList,
356  const std::vector<const Index32LeafT*>& leafNodes,
357  const std::vector<IndexRange>& leafRanges,
358  const std::vector<Vec4R>& leafBoundingSpheres,
359  const std::vector<Vec4R>& nodeBoundingSpheres,
360  size_t maxNodeLeafs,
361  bool transformPoints = false);
362 
363 
364  void run(bool threaded = true);
365 
366 
367  void operator()(const tbb::blocked_range<size_t>&) const;
368 
369 private:
370 
371  void evalLeaf(size_t index, const Index32LeafT& leaf) const;
372  void evalNode(size_t pointIndex, size_t nodeIndex) const;
373 
374 
375  std::vector<Vec3R>& mInstancePoints;
376  std::vector<float>& mInstanceDistances;
377 
378  const PointList& mSurfacePointList;
379 
380  const std::vector<const Index32LeafT*>& mLeafNodes;
381  const std::vector<IndexRange>& mLeafRanges;
382  const std::vector<Vec4R>& mLeafBoundingSpheres;
383  const std::vector<Vec4R>& mNodeBoundingSpheres;
384 
385  std::vector<float> mLeafDistances, mNodeDistances;
386 
387  const bool mTransformPoints;
388  size_t mClosestPointIndex;
389 };// ClosestPointDist
390 
391 
392 template<typename Index32LeafT>
394  std::vector<Vec3R>& instancePoints,
395  std::vector<float>& instanceDistances,
396  const PointList& surfacePointList,
397  const std::vector<const Index32LeafT*>& leafNodes,
398  const std::vector<IndexRange>& leafRanges,
399  const std::vector<Vec4R>& leafBoundingSpheres,
400  const std::vector<Vec4R>& nodeBoundingSpheres,
401  size_t maxNodeLeafs,
402  bool transformPoints)
403  : mInstancePoints(instancePoints)
404  , mInstanceDistances(instanceDistances)
405  , mSurfacePointList(surfacePointList)
406  , mLeafNodes(leafNodes)
407  , mLeafRanges(leafRanges)
408  , mLeafBoundingSpheres(leafBoundingSpheres)
409  , mNodeBoundingSpheres(nodeBoundingSpheres)
410  , mLeafDistances(maxNodeLeafs, 0.0)
411  , mNodeDistances(leafRanges.size(), 0.0)
412  , mTransformPoints(transformPoints)
413  , mClosestPointIndex(0)
414 {
415 }
416 
417 
418 template<typename Index32LeafT>
419 void
421 {
422  if (threaded) {
423  tbb::parallel_for(tbb::blocked_range<size_t>(0, mInstancePoints.size()), *this);
424  } else {
425  (*this)(tbb::blocked_range<size_t>(0, mInstancePoints.size()));
426  }
427 }
428 
429 template<typename Index32LeafT>
430 void
431 ClosestPointDist<Index32LeafT>::evalLeaf(size_t index, const Index32LeafT& leaf) const
432 {
433  typename Index32LeafT::ValueOnCIter iter;
434  const Vec3s center = mInstancePoints[index];
435  size_t& closestPointIndex = const_cast<size_t&>(mClosestPointIndex);
436 
437  for (iter = leaf.cbeginValueOn(); iter; ++iter) {
438 
439  const Vec3s& point = mSurfacePointList[iter.getValue()];
440  float tmpDist = (point - center).lengthSqr();
441 
442  if (tmpDist < mInstanceDistances[index]) {
443  mInstanceDistances[index] = tmpDist;
444  closestPointIndex = iter.getValue();
445  }
446  }
447 }
448 
449 
450 template<typename Index32LeafT>
451 void
452 ClosestPointDist<Index32LeafT>::evalNode(size_t pointIndex, size_t nodeIndex) const
453 {
454  if (nodeIndex >= mLeafRanges.size()) return;
455 
456  const Vec3R& pos = mInstancePoints[pointIndex];
457  float minDist = mInstanceDistances[pointIndex];
458  size_t minDistIdx = 0;
459  Vec3R center;
460  bool updatedDist = false;
461 
462  for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
463  i < mLeafRanges[nodeIndex].second; ++i, ++n)
464  {
465  float& distToLeaf = const_cast<float&>(mLeafDistances[n]);
466 
467  center[0] = mLeafBoundingSpheres[i][0];
468  center[1] = mLeafBoundingSpheres[i][1];
469  center[2] = mLeafBoundingSpheres[i][2];
470 
471  distToLeaf = float((pos - center).lengthSqr() - mLeafBoundingSpheres[i][3]);
472 
473  if (distToLeaf < minDist) {
474  minDist = distToLeaf;
475  minDistIdx = i;
476  updatedDist = true;
477  }
478  }
479 
480  if (!updatedDist) return;
481 
482  evalLeaf(pointIndex, *mLeafNodes[minDistIdx]);
483 
484  for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
485  i < mLeafRanges[nodeIndex].second; ++i, ++n)
486  {
487  if (mLeafDistances[n] < mInstanceDistances[pointIndex] && i != minDistIdx) {
488  evalLeaf(pointIndex, *mLeafNodes[i]);
489  }
490  }
491 }
492 
493 
494 template<typename Index32LeafT>
495 void
496 ClosestPointDist<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
497 {
498  Vec3R center;
499  for (size_t n = range.begin(); n != range.end(); ++n) {
500 
501  const Vec3R& pos = mInstancePoints[n];
502  float minDist = mInstanceDistances[n];
503  size_t minDistIdx = 0;
504 
505  for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
506  float& distToNode = const_cast<float&>(mNodeDistances[i]);
507 
508  center[0] = mNodeBoundingSpheres[i][0];
509  center[1] = mNodeBoundingSpheres[i][1];
510  center[2] = mNodeBoundingSpheres[i][2];
511 
512  distToNode = float((pos - center).lengthSqr() - mNodeBoundingSpheres[i][3]);
513 
514  if (distToNode < minDist) {
515  minDist = distToNode;
516  minDistIdx = i;
517  }
518  }
519 
520  evalNode(n, minDistIdx);
521 
522  for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
523  if (mNodeDistances[i] < mInstanceDistances[n] && i != minDistIdx) {
524  evalNode(n, i);
525  }
526  }
527 
528  mInstanceDistances[n] = std::sqrt(mInstanceDistances[n]);
529 
530  if (mTransformPoints) mInstancePoints[n] = mSurfacePointList[mClosestPointIndex];
531  }
532 }
533 
534 
536 {
537 public:
538  UpdatePoints(
539  const Vec4s& sphere,
540  const std::vector<Vec3R>& points,
541  std::vector<float>& distances,
542  std::vector<unsigned char>& mask,
543  bool overlapping);
544 
545  float radius() const { return mRadius; }
546  int index() const { return mIndex; }
547 
548  inline void run(bool threaded = true);
549 
550 
551  UpdatePoints(UpdatePoints&, tbb::split);
552  inline void operator()(const tbb::blocked_range<size_t>& range);
553  void join(const UpdatePoints& rhs)
554  {
555  if (rhs.mRadius > mRadius) {
556  mRadius = rhs.mRadius;
557  mIndex = rhs.mIndex;
558  }
559  }
560 
561 private:
562 
563  const Vec4s& mSphere;
564  const std::vector<Vec3R>& mPoints;
565 
566  std::vector<float>& mDistances;
567  std::vector<unsigned char>& mMask;
568 
569  bool mOverlapping;
570  float mRadius;
571  int mIndex;
572 };
573 
574 inline
576  const Vec4s& sphere,
577  const std::vector<Vec3R>& points,
578  std::vector<float>& distances,
579  std::vector<unsigned char>& mask,
580  bool overlapping)
581  : mSphere(sphere)
582  , mPoints(points)
583  , mDistances(distances)
584  , mMask(mask)
585  , mOverlapping(overlapping)
586  , mRadius(0.0)
587  , mIndex(0)
588 {
589 }
590 
591 inline
593  : mSphere(rhs.mSphere)
594  , mPoints(rhs.mPoints)
595  , mDistances(rhs.mDistances)
596  , mMask(rhs.mMask)
597  , mOverlapping(rhs.mOverlapping)
598  , mRadius(rhs.mRadius)
599  , mIndex(rhs.mIndex)
600 {
601 }
602 
603 inline void
604 UpdatePoints::run(bool threaded)
605 {
606  if (threaded) {
607  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPoints.size()), *this);
608  } else {
609  (*this)(tbb::blocked_range<size_t>(0, mPoints.size()));
610  }
611 }
612 
613 inline void
614 UpdatePoints::operator()(const tbb::blocked_range<size_t>& range)
615 {
616  Vec3s pos;
617  for (size_t n = range.begin(); n != range.end(); ++n) {
618  if (mMask[n]) continue;
619 
620  pos.x() = float(mPoints[n].x()) - mSphere[0];
621  pos.y() = float(mPoints[n].y()) - mSphere[1];
622  pos.z() = float(mPoints[n].z()) - mSphere[2];
623 
624  float dist = pos.length();
625 
626  if (dist < mSphere[3]) {
627  mMask[n] = 1;
628  continue;
629  }
630 
631  if (!mOverlapping) {
632  mDistances[n] = std::min(mDistances[n], (dist - mSphere[3]));
633  }
634 
635  if (mDistances[n] > mRadius) {
636  mRadius = mDistances[n];
637  mIndex = int(n);
638  }
639  }
640 }
641 
642 
643 } // namespace internal
644 
645 
647 
648 
649 template<typename GridT, typename InterrupterT>
650 inline void
652  const GridT& grid,
653  std::vector<openvdb::Vec4s>& spheres,
654  int maxSphereCount,
655  bool overlapping,
656  float minRadius,
657  float maxRadius,
658  float isovalue,
659  int instanceCount,
660  InterrupterT* interrupter)
661 {
662  spheres.clear();
663  spheres.reserve(maxSphereCount);
664 
665  const bool addNBPoints = grid.activeVoxelCount() < 10000;
666  int instances = std::max(instanceCount, maxSphereCount);
667 
668  using TreeT = typename GridT::TreeType;
669  using ValueT = typename GridT::ValueType;
670 
671  using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
672  using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
673 
674  using RandGen = std::mersenne_twister_engine<uint32_t, 32, 351, 175, 19,
675  0xccab8ee7, 11, 0xffffffff, 7, 0x31b6ab00, 15, 0xffe50000, 17, 1812433253>; // mt11213b
676  RandGen mtRand(/*seed=*/0);
677 
678  const TreeT& tree = grid.tree();
679  const math::Transform& transform = grid.transform();
680 
681  std::vector<Vec3R> instancePoints;
682  {
683  // Compute a mask of the voxels enclosed by the isosurface.
684  typename Grid<BoolTreeT>::Ptr interiorMaskPtr;
685  if (grid.getGridClass() == GRID_LEVEL_SET) {
686  // Clamp the isovalue to the level set's background value minus epsilon.
687  // (In a valid narrow-band level set, all voxels, including background voxels,
688  // have values less than or equal to the background value, so an isovalue
689  // greater than or equal to the background value would produce a mask with
690  // effectively infinite extent.)
691  isovalue = std::min(isovalue,
692  static_cast<float>(tree.background() - math::Tolerance<ValueT>::value()));
693  interiorMaskPtr = sdfInteriorMask(grid, ValueT(isovalue));
694  } else {
695  if (grid.getGridClass() == GRID_FOG_VOLUME) {
696  // Clamp the isovalue of a fog volume between epsilon and one,
697  // again to avoid a mask with infinite extent. (Recall that
698  // fog volume voxel values vary from zero outside to one inside.)
699  isovalue = math::Clamp(isovalue, math::Tolerance<float>::value(), 1.f);
700  }
701  // For non-level-set grids, the interior mask comprises the active voxels.
702  interiorMaskPtr = typename Grid<BoolTreeT>::Ptr(Grid<BoolTreeT>::create(false));
703  interiorMaskPtr->setTransform(transform.copy());
704  interiorMaskPtr->tree().topologyUnion(tree);
705  }
706 
707  if (interrupter && interrupter->wasInterrupted()) return;
708 
709  erodeVoxels(interiorMaskPtr->tree(), 1);
710 
711  // Scatter candidate sphere centroids (instancePoints)
712  instancePoints.reserve(instances);
713  internal::PointAccessor ptnAcc(instancePoints);
714 
716  ptnAcc, Index64(addNBPoints ? (instances / 2) : instances), mtRand, 1.0, interrupter);
717 
718  scatter(*interiorMaskPtr);
719  }
720 
721  if (interrupter && interrupter->wasInterrupted()) return;
722 
724  if (!csp.initialize(grid, isovalue, interrupter)) return;
725 
726  // Add extra instance points in the interior narrow band.
727  if (instancePoints.size() < size_t(instances)) {
728  const Int16TreeT& signTree = csp.signTree();
729  for (auto leafIt = signTree.cbeginLeaf(); leafIt; ++leafIt) {
730  for (auto it = leafIt->cbeginValueOn(); it; ++it) {
731  const int flags = int(it.getValue());
732  if (!(volume_to_mesh_internal::EDGES & flags)
733  && (volume_to_mesh_internal::INSIDE & flags))
734  {
735  instancePoints.push_back(transform.indexToWorld(it.getCoord()));
736  }
737  if (instancePoints.size() == size_t(instances)) break;
738  }
739  if (instancePoints.size() == size_t(instances)) break;
740  }
741  }
742 
743  if (interrupter && interrupter->wasInterrupted()) return;
744 
745  std::vector<float> instanceRadius;
746  if (!csp.search(instancePoints, instanceRadius)) return;
747 
748  std::vector<unsigned char> instanceMask(instancePoints.size(), 0);
749  float largestRadius = 0.0;
750  int largestRadiusIdx = 0;
751 
752  for (size_t n = 0, N = instancePoints.size(); n < N; ++n) {
753  if (instanceRadius[n] > largestRadius) {
754  largestRadius = instanceRadius[n];
755  largestRadiusIdx = int(n);
756  }
757  }
758 
759  Vec3s pos;
760  Vec4s sphere;
761  minRadius = float(minRadius * transform.voxelSize()[0]);
762  maxRadius = float(maxRadius * transform.voxelSize()[0]);
763 
764  for (size_t s = 0, S = std::min(size_t(maxSphereCount), instancePoints.size()); s < S; ++s) {
765 
766  if (interrupter && interrupter->wasInterrupted()) return;
767 
768  largestRadius = std::min(maxRadius, largestRadius);
769 
770  if (s != 0 && largestRadius < minRadius) break;
771 
772  sphere[0] = float(instancePoints[largestRadiusIdx].x());
773  sphere[1] = float(instancePoints[largestRadiusIdx].y());
774  sphere[2] = float(instancePoints[largestRadiusIdx].z());
775  sphere[3] = largestRadius;
776 
777  spheres.push_back(sphere);
778  instanceMask[largestRadiusIdx] = 1;
779 
781  sphere, instancePoints, instanceRadius, instanceMask, overlapping);
782  op.run();
783 
784  largestRadius = op.radius();
785  largestRadiusIdx = op.index();
786  }
787 } // fillWithSpheres
788 
789 
791 
792 
793 template<typename GridT>
795  : mIsInitialized(false)
796  , mPointListSize(0)
797  , mMaxNodeLeafs(0)
798  , mMaxRadiusSqr(0.0)
799  , mIdxTreePt()
800 {
801 }
802 
803 
804 template<typename GridT>
805 template<typename InterrupterT>
806 bool
808  const GridT& grid, float isovalue, InterrupterT* interrupter)
809 {
810  mIsInitialized = false;
811  using Index32LeafManagerT = tree::LeafManager<Index32TreeT>;
812  using ValueT = typename GridT::ValueType;
813 
814  const TreeT& tree = grid.tree();
815  const math::Transform& transform = grid.transform();
816 
817  { // Extract surface point cloud
818 
819  BoolTreeT mask(false);
821 
822  mSignTreePt.reset(new Int16TreeT(0));
823  mIdxTreePt.reset(new Index32TreeT(boost::integer_traits<Index32>::const_max));
824 
825 
827  *mSignTreePt, *mIdxTreePt, mask, tree, ValueT(isovalue));
828 
829  if (interrupter && interrupter->wasInterrupted()) return false;
830 
831  // count unique points
832 
833  using Int16LeafNodeType = typename Int16TreeT::LeafNodeType;
834  using Index32LeafNodeType = typename Index32TreeT::LeafNodeType;
835 
836  std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
837  mSignTreePt->getNodes(signFlagsLeafNodes);
838 
839  const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
840 
841  boost::scoped_array<Index32> leafNodeOffsets(new Index32[signFlagsLeafNodes.size()]);
842 
843  tbb::parallel_for(auxiliaryLeafNodeRange,
845  (signFlagsLeafNodes, leafNodeOffsets));
846 
847  {
848  Index32 pointCount = 0;
849  for (size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
850  const Index32 tmp = leafNodeOffsets[n];
851  leafNodeOffsets[n] = pointCount;
852  pointCount += tmp;
853  }
854 
855  mPointListSize = size_t(pointCount);
856  mSurfacePointList.reset(new Vec3s[mPointListSize]);
857  }
858 
859 
860  std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
861  mIdxTreePt->getNodes(pointIndexLeafNodes);
862 
863  tbb::parallel_for(auxiliaryLeafNodeRange, volume_to_mesh_internal::ComputePoints<TreeT>(
864  mSurfacePointList.get(), tree, pointIndexLeafNodes,
865  signFlagsLeafNodes, leafNodeOffsets, transform, ValueT(isovalue)));
866  }
867 
868  if (interrupter && interrupter->wasInterrupted()) return false;
869 
870  // estimate max sphere radius (sqr dist)
871  CoordBBox bbox = grid.evalActiveVoxelBoundingBox();
872 
873  Vec3s dim = transform.indexToWorld(bbox.min()) -
874  transform.indexToWorld(bbox.max());
875 
876  dim[0] = std::abs(dim[0]);
877  dim[1] = std::abs(dim[1]);
878  dim[2] = std::abs(dim[2]);
879 
880  mMaxRadiusSqr = std::min(std::min(dim[0], dim[1]), dim[2]);
881  mMaxRadiusSqr *= 0.51f;
882  mMaxRadiusSqr *= mMaxRadiusSqr;
883 
884 
885  Index32LeafManagerT idxLeafs(*mIdxTreePt);
886 
887  using Index32RootNodeT = typename Index32TreeT::RootNodeType;
888  using Index32NodeChainT = typename Index32RootNodeT::NodeChainType;
889  BOOST_STATIC_ASSERT(boost::mpl::size<Index32NodeChainT>::value > 1);
890  using Index32InternalNodeT =
891  typename boost::mpl::at<Index32NodeChainT, boost::mpl::int_<1> >::type;
892 
893  typename Index32TreeT::NodeCIter nIt = mIdxTreePt->cbeginNode();
894  nIt.setMinDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
895  nIt.setMaxDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
896 
897  std::vector<const Index32InternalNodeT*> internalNodes;
898 
899  const Index32InternalNodeT* node = nullptr;
900  for (; nIt; ++nIt) {
901  nIt.getNode(node);
902  if (node) internalNodes.push_back(node);
903  }
904 
905  std::vector<IndexRange>().swap(mLeafRanges);
906  mLeafRanges.resize(internalNodes.size());
907 
908  std::vector<const Index32LeafT*>().swap(mLeafNodes);
909  mLeafNodes.reserve(idxLeafs.leafCount());
910 
911  typename Index32InternalNodeT::ChildOnCIter leafIt;
912  mMaxNodeLeafs = 0;
913  for (size_t n = 0, N = internalNodes.size(); n < N; ++n) {
914 
915  mLeafRanges[n].first = mLeafNodes.size();
916 
917  size_t leafCount = 0;
918  for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) {
919  mLeafNodes.push_back(&(*leafIt));
920  ++leafCount;
921  }
922 
923  mMaxNodeLeafs = std::max(leafCount, mMaxNodeLeafs);
924 
925  mLeafRanges[n].second = mLeafNodes.size();
926  }
927 
928  std::vector<Vec4R>().swap(mLeafBoundingSpheres);
929  mLeafBoundingSpheres.resize(mLeafNodes.size());
930 
932  mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList);
933  leafBS.run();
934 
935 
936  std::vector<Vec4R>().swap(mNodeBoundingSpheres);
937  mNodeBoundingSpheres.resize(internalNodes.size());
938 
939  internal::NodeOp nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres);
940  nodeBS.run();
941  mIsInitialized = true;
942  return true;
943 } // ClosestSurfacePoint::initialize
944 
945 
946 template<typename GridT>
947 bool
948 ClosestSurfacePoint<GridT>::search(std::vector<Vec3R>& points,
949  std::vector<float>& distances, bool transformPoints)
950 {
951  if (!mIsInitialized) return false;
952 
953  distances.clear();
954  distances.resize(points.size(), mMaxRadiusSqr);
955 
956  internal::ClosestPointDist<Index32LeafT> cpd(points, distances, mSurfacePointList,
957  mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres,
958  mMaxNodeLeafs, transformPoints);
959 
960  cpd.run();
961 
962  return true;
963 }
964 
965 
966 template<typename GridT>
967 bool
968 ClosestSurfacePoint<GridT>::search(const std::vector<Vec3R>& points, std::vector<float>& distances)
969 {
970  return search(const_cast<std::vector<Vec3R>& >(points), distances, false);
971 }
972 
973 
974 template<typename GridT>
975 bool
977  std::vector<float>& distances)
978 {
979  return search(points, distances, true);
980 }
981 
982 } // namespace tools
983 } // namespace OPENVDB_VERSION_NAME
984 } // namespace openvdb
985 
986 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
987 
988 // Copyright (c) 2012-2017 DreamWorks Animation LLC
989 // All rights reserved. This software is distributed under the
990 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
Vec4< float > Vec4s
Definition: Vec4.h:587
Tolerance for floating-point comparison.
Definition: Math.h:117
int index() const
Definition: VolumeToSpheres.h:546
Definition: Mat4.h:51
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:797
float radius() const
Definition: VolumeToSpheres.h:545
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:496
Definition: VolumeToSpheres.h:261
UpdatePoints(const Vec4s &sphere, const std::vector< Vec3R > &points, std::vector< float > &distances, std::vector< unsigned char > &mask, bool overlapping)
Definition: VolumeToSpheres.h:575
const Int16TreeT & signTree() const
Tree accessor.
Definition: VolumeToSpheres.h:134
SharedPtr< Grid > Ptr
Definition: Grid.h:502
Ptr copy() const
Definition: Transform.h:77
uint32_t Index32
Definition: Types.h:55
void add(const Vec3R &pos)
Definition: VolumeToSpheres.h:168
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
typename TreeT::template ValueConverter< bool >::Type BoolTreeT
Definition: VolumeToSpheres.h:102
void identifySurfaceIntersectingVoxels(typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3349
typename TreeT::template ValueConverter< Int16 >::Type Int16TreeT
Definition: VolumeToSpheres.h:104
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
PointAccessor(std::vector< Vec3R > &points)
Definition: VolumeToSpheres.h:163
We offer three different algorithms (each in its own class) for scattering of points in active voxels...
Vec3< float > Vec3s
Definition: Vec3.h:677
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:225
The two point scatters UniformPointScatter and NonUniformPointScatter depend on the following two cla...
Definition: PointScatter.h:112
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
void computeAuxiliaryData(typename InputTreeType::template ValueConverter< Int16 >::Type &signFlagsTree, typename InputTreeType::template ValueConverter< Index32 >::Type &pointIndexTree, const typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3891
std::pair< size_t, size_t > IndexRange
Definition: VolumeToSpheres.h:350
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
uint64_t Index64
Definition: Types.h:56
Calculate an axis-aligned bounding box in index space from a bounding sphere in world space...
Definition: Transform.h:66
Extract polygonal surfaces from scalar volumes.
#define OPENVDB_VERSION_NAME
Definition: version.h:43
void fillWithSpheres(const GridT &grid, std::vector< openvdb::Vec4s > &spheres, int maxSphereCount, bool overlapping=false, float minRadius=1.0, float maxRadius=std::numeric_limits< float >::max(), float isovalue=0.0, int instanceCount=10000, InterrupterT *interrupter=nullptr)
Fill a closed level set or fog volume with adaptively-sized spheres.
Definition: VolumeToSpheres.h:651
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToSpheres.h:614
void run(bool threaded=true)
Definition: VolumeToSpheres.h:420
void run(bool threaded=true)
Definition: VolumeToSpheres.h:291
GridOrTreeType::template ValueConverter< bool >::Type::Ptr sdfInteriorMask(const GridOrTreeType &volume, typename GridOrTreeType::ValueType isovalue=lsutilGridZero< GridOrTreeType >())
Threaded method to construct a boolean mask that represents interior regions in a signed distance fie...
Definition: LevelSetUtil.h:2291
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:343
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:301
Implementation of morphological dilation and erosion.
Definition: VolumeToSpheres.h:535
Definition: Exceptions.h:39
std::pair< size_t, size_t > IndexRange
Definition: VolumeToSpheres.h:264
const Coord & max() const
Definition: Coord.h:335
void join(const UpdatePoints &rhs)
Definition: VolumeToSpheres.h:553
Vec3< double > Vec3d
Definition: Vec3.h:678
OPENVDB_IMPORT void initialize()
Global registration of basic types.
Definition: VolumeToSpheres.h:178
const Index32TreeT & indexTree() const
Tree accessor.
Definition: VolumeToSpheres.h:132
Type Clamp(Type x, Type min, Type max)
Return x clamped to [min, max].
Definition: Math.h:230
typename GridT::TreeType TreeT
Definition: VolumeToSpheres.h:101
NodeOp(std::vector< Vec4R > &nodeBoundingSpheres, const std::vector< IndexRange > &leafRanges, const std::vector< Vec4R > &leafBoundingSpheres)
Definition: VolumeToSpheres.h:281
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
ClosestSurfacePoint()
Definition: VolumeToSpheres.h:794
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
bool searchAndReplace(std::vector< Vec3R > &points, std::vector< float > &distances)
Overwrite each input point with its closest surface point.
Definition: VolumeToSpheres.h:976
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
boost::scoped_array< openvdb::Vec3s > PointList
Point and primitive list types.
Definition: VolumeToMesh.h:180
typename TreeT::template ValueConverter< Index32 >::Type Index32TreeT
Definition: VolumeToSpheres.h:103
void setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform. ...
Definition: Grid.h:1112
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
void run(bool threaded=true)
Definition: VolumeToSpheres.h:214
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
void erodeVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically erode all leaf-level active voxels in the given tree.
Definition: Morphology.h:877
void run(bool threaded=true)
Definition: VolumeToSpheres.h:604
static T value()
Definition: Math.h:117
const Coord & min() const
Definition: Coord.h:334
bool initialize(const GridT &grid, float isovalue=0.0, InterrupterT *interrupter=nullptr)
Extract surface points and construct a spatial acceleration structure.
Definition: VolumeToSpheres.h:807
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition: Transform.h:120
Definition: VolumeToSpheres.h:161
static constexpr size_t size
The size of a LeafBuffer when LeafBuffer::mOutOfCore is atomic.
Definition: LeafBuffer.h:85
Index64 pointCount(const PointDataTreeT &tree, const bool inCoreOnly=false)
Total points in the PointDataTree.
Definition: PointCount.h:198
Definition: Types.h:264
Definition: Types.h:265
bool search(const std::vector< Vec3R > &points, std::vector< float > &distances)
Compute the distance from each input point to its closest surface point.
Definition: VolumeToSpheres.h:968
ClosestPointDist(std::vector< Vec3R > &instancePoints, std::vector< float > &instanceDistances, const PointList &surfacePointList, const std::vector< const Index32LeafT *> &leafNodes, const std::vector< IndexRange > &leafRanges, const std::vector< Vec4R > &leafBoundingSpheres, const std::vector< Vec4R > &nodeBoundingSpheres, size_t maxNodeLeafs, bool transformPoints=false)
Definition: VolumeToSpheres.h:393
Accelerated closest surface point queries for narrow band level sets.
Definition: VolumeToSpheres.h:98