1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file tools/VolumeToSpheres.h
5 ///
6 /// @brief Fill a closed level set or fog volume with adaptively-sized spheres.
7 
8 #ifndef OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
9 #define OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
10 
11 #include <openvdb/tree/LeafManager.h>
12 #include <openvdb/math/Math.h>
13 #include "Morphology.h" // for erodeActiveValues()
14 #include "PointScatter.h"
15 #include "LevelSetRebuild.h"
16 #include "LevelSetUtil.h"
17 #include "VolumeToMesh.h"
18 #include <openvdb/openvdb.h>
19 
20 #include <tbb/blocked_range.h>
21 #include <tbb/parallel_for.h>
22 #include <tbb/parallel_reduce.h>
23 
24 #include <algorithm> // for std::min(), std::max()
25 #include <cmath> // for std::sqrt()
26 #include <limits> // for std::numeric_limits
27 #include <memory>
28 #include <random>
29 #include <utility> // for std::pair
30 #include <vector>
31 
32 
33 namespace openvdb {
34 OPENVDB_USE_VERSION_NAMESPACE
35 namespace OPENVDB_VERSION_NAME {
36 namespace tools {
37 
38 /// @brief Fill a closed level set or fog volume with adaptively-sized spheres.
39 ///
40 /// @param grid             a scalar grid that defines the surface to be filled with spheres
41 /// @param spheres          an output array of 4-tuples representing the fitted spheres<BR>
42 ///                         The first three components of each tuple specify the sphere center,
43 ///                         and the fourth specifies the radius.
44 ///                         The spheres are ordered by radius, from largest to smallest.
45 /// @param sphereCount      lower and upper bounds on the number of spheres to be generated<BR>
46 ///                         The actual number will be somewhere within the bounds.
47 /// @param overlapping      toggle to allow spheres to overlap/intersect
48 /// @param minRadius        the smallest allowable sphere size, in voxel units<BR>
49 /// @param maxRadius        the largest allowable sphere size, in voxel units
50 /// @param isovalue         the voxel value that determines the surface of the volume<BR>
51 ///                         The default value of zero works for signed distance fields,
52 ///                         while fog volumes require a larger positive value
53 ///                         (0.5 is a good initial guess).
54 /// @param instanceCount    the number of interior points to consider for the sphere placement<BR>
55 ///                         Increasing this count increases the chances of finding optimal
56 ///                         sphere sizes.
57 /// @param interrupter      pointer to an object adhering to the util::NullInterrupter interface
58 ///
59 /// @note The minimum sphere count takes precedence over the minimum radius.
60 template<typename GridT, typename InterrupterT = util::NullInterrupter>
61 void
62 fillWithSpheres(
63     const GridT& grid,
64     std::vector<openvdb::Vec4s>& spheres,
65     const Vec2i& sphereCount = Vec2i(1, 50),
66     bool overlapping = false,
67     float minRadius = 1.0,
68     float maxRadius = std::numeric_limits<float>::max(),
69     float isovalue = 0.0,
70     int instanceCount = 10000,
71     InterrupterT* interrupter = nullptr);
72 
73 
74 ////////////////////////////////////////
75 
76 
77 /// @brief  Accelerated closest surface point queries for narrow band level sets
78 /// @details Supports queries that originate at arbitrary world-space locations,
79 /// is not confined to the narrow band region of the input volume geometry.
80 template<typename GridT>
81 class ClosestSurfacePoint
82 {
83 public:
84     using Ptr = std::unique_ptr<ClosestSurfacePoint>;
85     using TreeT = typename GridT::TreeType;
86     using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
87     using Index32TreeT = typename TreeT::template ValueConverter<Index32>::Type;
88     using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
89 
90     /// @brief Extract surface points and construct a spatial acceleration structure.
91     ///
92     /// @return a null pointer if the initialization fails for any reason,
93     /// otherwise a unique pointer to a newly-allocated ClosestSurfacePoint object.
94     ///
95     /// @param grid         a scalar level set or fog volume
96     /// @param isovalue     the voxel value that determines the surface of the volume
97     ///                     The default value of zero works for signed distance fields,
98     ///                     while fog volumes require a larger positive value
99     ///                     (0.5 is a good initial guess).
100     /// @param interrupter  pointer to an object adhering to the util::NullInterrupter interface.
101     template<typename InterrupterT = util::NullInterrupter>
102     static Ptr create(const GridT& grid, float isovalue = 0.0,
103         InterrupterT* interrupter = nullptr);
104 
105     /// @brief Compute the distance from each input point to its closest surface point.
106     /// @param points       input list of points in world space
107     /// @param distances    output list of closest surface point distances
108     bool search(const std::vector<Vec3R>& points, std::vector<float>& distances);
109 
110     /// @brief Overwrite each input point with its closest surface point.
111     /// @param points       input/output list of points in world space
112     /// @param distances    output list of closest surface point distances
113     bool searchAndReplace(std::vector<Vec3R>& points, std::vector<float>& distances);
114 
115     /// @brief Tree accessor
indexTree()116     const Index32TreeT& indexTree() const { return *mIdxTreePt; }
117     /// @brief Tree accessor
signTree()118     const Int16TreeT& signTree() const { return *mSignTreePt; }
119 
120 private:
121     using Index32LeafT = typename Index32TreeT::LeafNodeType;
122     using IndexRange = std::pair<size_t, size_t>;
123 
124     std::vector<Vec4R> mLeafBoundingSpheres, mNodeBoundingSpheres;
125     std::vector<IndexRange> mLeafRanges;
126     std::vector<const Index32LeafT*> mLeafNodes;
127     PointList mSurfacePointList;
128     size_t mPointListSize = 0, mMaxNodeLeafs = 0;
129     typename Index32TreeT::Ptr mIdxTreePt;
130     typename Int16TreeT::Ptr mSignTreePt;
131 
132     ClosestSurfacePoint() = default;
133     template<typename InterrupterT = util::NullInterrupter>
134     bool initialize(const GridT&, float isovalue, InterrupterT*);
135     bool search(std::vector<Vec3R>&, std::vector<float>&, bool transformPoints);
136 };
137 
138 
139 ////////////////////////////////////////
140 
141 
142 // Internal utility methods
143 
144 /// @cond OPENVDB_DOCS_INTERNAL
145 
146 namespace v2s_internal {
147 
148 struct PointAccessor
149 {
PointAccessorPointAccessor150     PointAccessor(std::vector<Vec3R>& points)
151         : mPoints(points)
152     {
153     }
154 
addPointAccessor155     void add(const Vec3R &pos)
156     {
157         mPoints.push_back(pos);
158     }
159 private:
160     std::vector<Vec3R>& mPoints;
161 };
162 
163 
164 template<typename Index32LeafT>
165 class LeafOp
166 {
167 public:
168 
169     LeafOp(std::vector<Vec4R>& leafBoundingSpheres,
170         const std::vector<const Index32LeafT*>& leafNodes,
171         const math::Transform& transform,
172         const PointList& surfacePointList);
173 
174     void run(bool threaded = true);
175 
176 
177     void operator()(const tbb::blocked_range<size_t>&) const;
178 
179 private:
180     std::vector<Vec4R>& mLeafBoundingSpheres;
181     const std::vector<const Index32LeafT*>& mLeafNodes;
182     const math::Transform& mTransform;
183     const PointList& mSurfacePointList;
184 };
185 
186 template<typename Index32LeafT>
LeafOp(std::vector<Vec4R> & leafBoundingSpheres,const std::vector<const Index32LeafT * > & leafNodes,const math::Transform & transform,const PointList & surfacePointList)187 LeafOp<Index32LeafT>::LeafOp(
188     std::vector<Vec4R>& leafBoundingSpheres,
189     const std::vector<const Index32LeafT*>& leafNodes,
190     const math::Transform& transform,
191     const PointList& surfacePointList)
192     : mLeafBoundingSpheres(leafBoundingSpheres)
193     , mLeafNodes(leafNodes)
194     , mTransform(transform)
195     , mSurfacePointList(surfacePointList)
196 {
197 }
198 
199 template<typename Index32LeafT>
200 void
run(bool threaded)201 LeafOp<Index32LeafT>::run(bool threaded)
202 {
203     if (threaded) {
204         tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafNodes.size()), *this);
205     } else {
206         (*this)(tbb::blocked_range<size_t>(0, mLeafNodes.size()));
207     }
208 }
209 
210 template<typename Index32LeafT>
211 void
operator()212 LeafOp<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
213 {
214     typename Index32LeafT::ValueOnCIter iter;
215     Vec3s avg;
216 
217     for (size_t n = range.begin(); n != range.end(); ++n) {
218         avg[0] = 0.0;
219         avg[1] = 0.0;
220         avg[2] = 0.0;
221 
222         int count = 0;
223         for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
224             avg += mSurfacePointList[iter.getValue()];
225             ++count;
226         }
227         if (count > 1) avg *= float(1.0 / double(count));
228 
229         float maxDist = 0.0;
230         for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
231             float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr();
232             if (tmpDist > maxDist) maxDist = tmpDist;
233         }
234 
235         Vec4R& sphere = mLeafBoundingSpheres[n];
236         sphere[0] = avg[0];
237         sphere[1] = avg[1];
238         sphere[2] = avg[2];
239         sphere[3] = maxDist * 2.0; // padded radius
240     }
241 }
242 
243 
244 class NodeOp
245 {
246 public:
247     using IndexRange = std::pair<size_t, size_t>;
248 
249     NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
250         const std::vector<IndexRange>& leafRanges,
251         const std::vector<Vec4R>& leafBoundingSpheres);
252 
253     inline void run(bool threaded = true);
254 
255     inline void operator()(const tbb::blocked_range<size_t>&) const;
256 
257 private:
258     std::vector<Vec4R>& mNodeBoundingSpheres;
259     const std::vector<IndexRange>& mLeafRanges;
260     const std::vector<Vec4R>& mLeafBoundingSpheres;
261 };
262 
263 inline
NodeOp(std::vector<Vec4R> & nodeBoundingSpheres,const std::vector<IndexRange> & leafRanges,const std::vector<Vec4R> & leafBoundingSpheres)264 NodeOp::NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
265     const std::vector<IndexRange>& leafRanges,
266     const std::vector<Vec4R>& leafBoundingSpheres)
267     : mNodeBoundingSpheres(nodeBoundingSpheres)
268     , mLeafRanges(leafRanges)
269     , mLeafBoundingSpheres(leafBoundingSpheres)
270 {
271 }
272 
273 inline void
run(bool threaded)274 NodeOp::run(bool threaded)
275 {
276     if (threaded) {
277         tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafRanges.size()), *this);
278     } else {
279         (*this)(tbb::blocked_range<size_t>(0, mLeafRanges.size()));
280     }
281 }
282 
283 inline void
operator()284 NodeOp::operator()(const tbb::blocked_range<size_t>& range) const
285 {
286     Vec3d avg, pos;
287 
288     for (size_t n = range.begin(); n != range.end(); ++n) {
289 
290         avg[0] = 0.0;
291         avg[1] = 0.0;
292         avg[2] = 0.0;
293 
294         int count = int(mLeafRanges[n].second) - int(mLeafRanges[n].first);
295 
296         for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
297             avg[0] += mLeafBoundingSpheres[i][0];
298             avg[1] += mLeafBoundingSpheres[i][1];
299             avg[2] += mLeafBoundingSpheres[i][2];
300         }
301 
302         if (count > 1) avg *= float(1.0 / double(count));
303 
304 
305         double maxDist = 0.0;
306 
307         for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
308             pos[0] = mLeafBoundingSpheres[i][0];
309             pos[1] = mLeafBoundingSpheres[i][1];
310             pos[2] = mLeafBoundingSpheres[i][2];
311             const auto radiusSqr = mLeafBoundingSpheres[i][3];
312 
313             double tmpDist = (pos - avg).lengthSqr() + radiusSqr;
314             if (tmpDist > maxDist) maxDist = tmpDist;
315         }
316 
317         Vec4R& sphere = mNodeBoundingSpheres[n];
318 
319         sphere[0] = avg[0];
320         sphere[1] = avg[1];
321         sphere[2] = avg[2];
322         sphere[3] = maxDist * 2.0; // padded radius
323     }
324 }
325 
326 
327 ////////////////////////////////////////
328 
329 
330 template<typename Index32LeafT>
331 class ClosestPointDist
332 {
333 public:
334     using IndexRange = std::pair<size_t, size_t>;
335 
336     ClosestPointDist(
337         std::vector<Vec3R>& instancePoints,
338         std::vector<float>& instanceDistances,
339         const PointList& surfacePointList,
340         const std::vector<const Index32LeafT*>& leafNodes,
341         const std::vector<IndexRange>& leafRanges,
342         const std::vector<Vec4R>& leafBoundingSpheres,
343         const std::vector<Vec4R>& nodeBoundingSpheres,
344         size_t maxNodeLeafs,
345         bool transformPoints = false);
346 
347 
348     void run(bool threaded = true);
349 
350 
351     void operator()(const tbb::blocked_range<size_t>&) const;
352 
353 private:
354 
355     void evalLeaf(size_t index, const Index32LeafT& leaf) const;
356     void evalNode(size_t pointIndex, size_t nodeIndex) const;
357 
358 
359     std::vector<Vec3R>& mInstancePoints;
360     std::vector<float>& mInstanceDistances;
361 
362     const PointList& mSurfacePointList;
363 
364     const std::vector<const Index32LeafT*>& mLeafNodes;
365     const std::vector<IndexRange>& mLeafRanges;
366     const std::vector<Vec4R>& mLeafBoundingSpheres;
367     const std::vector<Vec4R>& mNodeBoundingSpheres;
368 
369     std::vector<float> mLeafDistances, mNodeDistances;
370 
371     const bool mTransformPoints;
372     size_t mClosestPointIndex;
373 };// ClosestPointDist
374 
375 
376 template<typename Index32LeafT>
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)377 ClosestPointDist<Index32LeafT>::ClosestPointDist(
378     std::vector<Vec3R>& instancePoints,
379     std::vector<float>& instanceDistances,
380     const PointList& surfacePointList,
381     const std::vector<const Index32LeafT*>& leafNodes,
382     const std::vector<IndexRange>& leafRanges,
383     const std::vector<Vec4R>& leafBoundingSpheres,
384     const std::vector<Vec4R>& nodeBoundingSpheres,
385     size_t maxNodeLeafs,
386     bool transformPoints)
387     : mInstancePoints(instancePoints)
388     , mInstanceDistances(instanceDistances)
389     , mSurfacePointList(surfacePointList)
390     , mLeafNodes(leafNodes)
391     , mLeafRanges(leafRanges)
392     , mLeafBoundingSpheres(leafBoundingSpheres)
393     , mNodeBoundingSpheres(nodeBoundingSpheres)
394     , mLeafDistances(maxNodeLeafs, 0.0)
395     , mNodeDistances(leafRanges.size(), 0.0)
396     , mTransformPoints(transformPoints)
397     , mClosestPointIndex(0)
398 {
399 }
400 
401 
402 template<typename Index32LeafT>
403 void
run(bool threaded)404 ClosestPointDist<Index32LeafT>::run(bool threaded)
405 {
406     if (threaded) {
407         tbb::parallel_for(tbb::blocked_range<size_t>(0, mInstancePoints.size()), *this);
408     } else {
409         (*this)(tbb::blocked_range<size_t>(0, mInstancePoints.size()));
410     }
411 }
412 
413 template<typename Index32LeafT>
414 void
evalLeaf(size_t index,const Index32LeafT & leaf)415 ClosestPointDist<Index32LeafT>::evalLeaf(size_t index, const Index32LeafT& leaf) const
416 {
417     typename Index32LeafT::ValueOnCIter iter;
418     const Vec3s center = mInstancePoints[index];
419     size_t& closestPointIndex = const_cast<size_t&>(mClosestPointIndex);
420 
421     for (iter = leaf.cbeginValueOn(); iter; ++iter) {
422 
423         const Vec3s& point = mSurfacePointList[iter.getValue()];
424         float tmpDist = (point - center).lengthSqr();
425 
426         if (tmpDist < mInstanceDistances[index]) {
427             mInstanceDistances[index] = tmpDist;
428             closestPointIndex = iter.getValue();
429         }
430     }
431 }
432 
433 
434 template<typename Index32LeafT>
435 void
evalNode(size_t pointIndex,size_t nodeIndex)436 ClosestPointDist<Index32LeafT>::evalNode(size_t pointIndex, size_t nodeIndex) const
437 {
438     if (nodeIndex >= mLeafRanges.size()) return;
439 
440     const Vec3R& pos = mInstancePoints[pointIndex];
441     float minDist = mInstanceDistances[pointIndex];
442     size_t minDistIdx = 0;
443     Vec3R center;
444     bool updatedDist = false;
445 
446     for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
447         i < mLeafRanges[nodeIndex].second; ++i, ++n)
448     {
449         float& distToLeaf = const_cast<float&>(mLeafDistances[n]);
450 
451         center[0] = mLeafBoundingSpheres[i][0];
452         center[1] = mLeafBoundingSpheres[i][1];
453         center[2] = mLeafBoundingSpheres[i][2];
454         const auto radiusSqr = mLeafBoundingSpheres[i][3];
455 
456         distToLeaf = float(std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
457 
458         if (distToLeaf < minDist) {
459             minDist = distToLeaf;
460             minDistIdx = i;
461             updatedDist = true;
462         }
463     }
464 
465     if (!updatedDist) return;
466 
467     evalLeaf(pointIndex, *mLeafNodes[minDistIdx]);
468 
469     for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
470         i < mLeafRanges[nodeIndex].second; ++i, ++n)
471     {
472         if (mLeafDistances[n] < mInstanceDistances[pointIndex] && i != minDistIdx) {
473             evalLeaf(pointIndex, *mLeafNodes[i]);
474         }
475     }
476 }
477 
478 
479 template<typename Index32LeafT>
480 void
operator()481 ClosestPointDist<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
482 {
483     Vec3R center;
484     for (size_t n = range.begin(); n != range.end(); ++n) {
485 
486         const Vec3R& pos = mInstancePoints[n];
487         float minDist = mInstanceDistances[n];
488         size_t minDistIdx = 0;
489 
490         for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
491             float& distToNode = const_cast<float&>(mNodeDistances[i]);
492 
493             center[0] = mNodeBoundingSpheres[i][0];
494             center[1] = mNodeBoundingSpheres[i][1];
495             center[2] = mNodeBoundingSpheres[i][2];
496             const auto radiusSqr = mNodeBoundingSpheres[i][3];
497 
498             distToNode = float(std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
499 
500             if (distToNode < minDist) {
501                 minDist = distToNode;
502                 minDistIdx = i;
503             }
504         }
505 
506         evalNode(n, minDistIdx);
507 
508         for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
509             if (mNodeDistances[i] < mInstanceDistances[n] && i != minDistIdx) {
510                 evalNode(n, i);
511             }
512         }
513 
514         mInstanceDistances[n] = std::sqrt(mInstanceDistances[n]);
515 
516         if (mTransformPoints) mInstancePoints[n] = mSurfacePointList[mClosestPointIndex];
517     }
518 }
519 
520 
521 class UpdatePoints
522 {
523 public:
524     UpdatePoints(
525         const Vec4s& sphere,
526         const std::vector<Vec3R>& points,
527         std::vector<float>& distances,
528         std::vector<unsigned char>& mask,
529         bool overlapping);
530 
radius()531     float radius() const { return mRadius; }
index()532     int index() const { return mIndex; }
533 
534     inline void run(bool threaded = true);
535 
536 
537     UpdatePoints(UpdatePoints&, tbb::split);
538     inline void operator()(const tbb::blocked_range<size_t>& range);
join(const UpdatePoints & rhs)539     void join(const UpdatePoints& rhs)
540     {
541         if (rhs.mRadius > mRadius) {
542             mRadius = rhs.mRadius;
543             mIndex = rhs.mIndex;
544         }
545     }
546 
547 private:
548     const Vec4s& mSphere;
549     const std::vector<Vec3R>& mPoints;
550     std::vector<float>& mDistances;
551     std::vector<unsigned char>& mMask;
552     bool mOverlapping;
553     float mRadius;
554     int mIndex;
555 };
556 
557 inline
UpdatePoints(const Vec4s & sphere,const std::vector<Vec3R> & points,std::vector<float> & distances,std::vector<unsigned char> & mask,bool overlapping)558 UpdatePoints::UpdatePoints(
559     const Vec4s& sphere,
560     const std::vector<Vec3R>& points,
561     std::vector<float>& distances,
562     std::vector<unsigned char>& mask,
563     bool overlapping)
564     : mSphere(sphere)
565     , mPoints(points)
566     , mDistances(distances)
567     , mMask(mask)
568     , mOverlapping(overlapping)
569     , mRadius(0.0)
570     , mIndex(0)
571 {
572 }
573 
574 inline
UpdatePoints(UpdatePoints & rhs,tbb::split)575 UpdatePoints::UpdatePoints(UpdatePoints& rhs, tbb::split)
576     : mSphere(rhs.mSphere)
577     , mPoints(rhs.mPoints)
578     , mDistances(rhs.mDistances)
579     , mMask(rhs.mMask)
580     , mOverlapping(rhs.mOverlapping)
581     , mRadius(rhs.mRadius)
582     , mIndex(rhs.mIndex)
583 {
584 }
585 
586 inline void
run(bool threaded)587 UpdatePoints::run(bool threaded)
588 {
589     if (threaded) {
590         tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPoints.size()), *this);
591     } else {
592         (*this)(tbb::blocked_range<size_t>(0, mPoints.size()));
593     }
594 }
595 
596 inline void
operator()597 UpdatePoints::operator()(const tbb::blocked_range<size_t>& range)
598 {
599     Vec3s pos;
600     for (size_t n = range.begin(); n != range.end(); ++n) {
601         if (mMask[n]) continue;
602 
603         pos.x() = float(mPoints[n].x()) - mSphere[0];
604         pos.y() = float(mPoints[n].y()) - mSphere[1];
605         pos.z() = float(mPoints[n].z()) - mSphere[2];
606 
607         float dist = pos.length();
608 
609         if (dist < mSphere[3]) {
610             mMask[n] = 1;
611             continue;
612         }
613 
614         if (!mOverlapping) {
615             mDistances[n] = std::min(mDistances[n], (dist - mSphere[3]));
616         }
617 
618         if (mDistances[n] > mRadius) {
619             mRadius = mDistances[n];
620             mIndex = int(n);
621         }
622     }
623 }
624 
625 
626 } // namespace v2s_internal
627 
628 /// @endcond
629 
630 ////////////////////////////////////////
631 
632 
633 template<typename GridT, typename InterrupterT>
634 void
fillWithSpheres(const GridT & grid,std::vector<openvdb::Vec4s> & spheres,const Vec2i & sphereCount,bool overlapping,float minRadius,float maxRadius,float isovalue,int instanceCount,InterrupterT * interrupter)635 fillWithSpheres(
636     const GridT& grid,
637     std::vector<openvdb::Vec4s>& spheres,
638     const Vec2i& sphereCount,
639     bool overlapping,
640     float minRadius,
641     float maxRadius,
642     float isovalue,
643     int instanceCount,
644     InterrupterT* interrupter)
645 {
646     spheres.clear();
647 
648     if (grid.empty()) return;
649 
650     const int
651         minSphereCount = sphereCount[0],
652         maxSphereCount = sphereCount[1];
653     if ((minSphereCount > maxSphereCount) || (maxSphereCount < 1)) {
654         OPENVDB_LOG_WARN("fillWithSpheres: minimum sphere count ("
655             << minSphereCount << ") exceeds maximum count (" << maxSphereCount << ")");
656         return;
657     }
658     spheres.reserve(maxSphereCount);
659 
660     auto gridPtr = grid.copy(); // shallow copy
661 
662     if (gridPtr->getGridClass() == GRID_LEVEL_SET) {
663         // Clamp the isovalue to the level set's background value minus epsilon.
664         // (In a valid narrow-band level set, all voxels, including background voxels,
665         // have values less than or equal to the background value, so an isovalue
666         // greater than or equal to the background value would produce a mask with
667         // effectively infinite extent.)
668         isovalue = std::min(isovalue,
669             static_cast<float>(gridPtr->background() - math::Tolerance<float>::value()));
670     } else if (gridPtr->getGridClass() == GRID_FOG_VOLUME) {
671         // Clamp the isovalue of a fog volume between epsilon and one,
672         // again to avoid a mask with infinite extent.  (Recall that
673         // fog volume voxel values vary from zero outside to one inside.)
674         isovalue = math::Clamp(isovalue, math::Tolerance<float>::value(), 1.f);
675     }
676 
677     // ClosestSurfacePoint is inaccurate for small grids.
678     // Resample the input grid if it is too small.
679     auto numVoxels = gridPtr->activeVoxelCount();
680     if (numVoxels < 10000) {
681         const auto scale = 1.0 / math::Cbrt(2.0 * 10000.0 / double(numVoxels));
682         auto scaledXform = gridPtr->transform().copy();
683         scaledXform->preScale(scale);
684 
685         auto newGridPtr = levelSetRebuild(*gridPtr, isovalue,
686             LEVEL_SET_HALF_WIDTH, LEVEL_SET_HALF_WIDTH, scaledXform.get(), interrupter);
687 
688         const auto newNumVoxels = newGridPtr->activeVoxelCount();
689         if (newNumVoxels > numVoxels) {
690             OPENVDB_LOG_DEBUG_RUNTIME("fillWithSpheres: resampled input grid from "
691                 << numVoxels << " voxel" << (numVoxels == 1 ? "" : "s")
692                 << " to " << newNumVoxels << " voxel" << (newNumVoxels == 1 ? "" : "s"));
693             gridPtr = newGridPtr;
694             numVoxels = newNumVoxels;
695         }
696     }
697 
698     const bool addNarrowBandPoints = (numVoxels < 10000);
699     int instances = std::max(instanceCount, maxSphereCount);
700 
701     using TreeT = typename GridT::TreeType;
702     using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
703     using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
704 
705     using RandGen = std::mersenne_twister_engine<uint32_t, 32, 351, 175, 19,
706         0xccab8ee7, 11, 0xffffffff, 7, 0x31b6ab00, 15, 0xffe50000, 17, 1812433253>; // mt11213b
707     RandGen mtRand(/*seed=*/0);
708 
709     const TreeT& tree = gridPtr->tree();
710     math::Transform transform = gridPtr->transform();
711 
712     std::vector<Vec3R> instancePoints;
713     {
714         // Compute a mask of the voxels enclosed by the isosurface.
715         typename Grid<BoolTreeT>::Ptr interiorMaskPtr;
716         if (gridPtr->getGridClass() == GRID_LEVEL_SET) {
717             interiorMaskPtr = sdfInteriorMask(*gridPtr, isovalue);
718         } else {
719             // For non-level-set grids, the interior mask comprises the active voxels.
720             interiorMaskPtr = typename Grid<BoolTreeT>::Ptr(Grid<BoolTreeT>::create(false));
721             interiorMaskPtr->setTransform(transform.copy());
722             interiorMaskPtr->tree().topologyUnion(tree);
723         }
724 
725         if (interrupter && interrupter->wasInterrupted()) return;
726 
727         // If the interior mask is small and eroding it results in an empty grid,
728         // use the uneroded mask instead.  (But if the minimum sphere count is zero,
729         // then eroding away the mask is acceptable.)
730         if (!addNarrowBandPoints || (minSphereCount <= 0)) {
731             tools::erodeActiveValues(interiorMaskPtr->tree(), /*iterations=*/1, tools::NN_FACE, tools::IGNORE_TILES);
732             tools::pruneInactive(interiorMaskPtr->tree());
733         } else {
734             auto& maskTree = interiorMaskPtr->tree();
735             auto copyOfTree = StaticPtrCast<BoolTreeT>(maskTree.copy());
736             tools::erodeActiveValues(maskTree, /*iterations=*/1, tools::NN_FACE, tools::IGNORE_TILES);
737             tools::pruneInactive(maskTree);
738             if (maskTree.empty()) { interiorMaskPtr->setTree(copyOfTree); }
739         }
740 
741         // Scatter candidate sphere centroids (instancePoints)
742         instancePoints.reserve(instances);
743         v2s_internal::PointAccessor ptnAcc(instancePoints);
744 
745         const auto scatterCount = Index64(addNarrowBandPoints ? (instances / 2) : instances);
746 
747         UniformPointScatter<v2s_internal::PointAccessor, RandGen, InterrupterT> scatter(
748             ptnAcc, scatterCount, mtRand, 1.0, interrupter);
749         scatter(*interiorMaskPtr);
750     }
751 
752     if (interrupter && interrupter->wasInterrupted()) return;
753 
754     auto csp = ClosestSurfacePoint<GridT>::create(*gridPtr, isovalue, interrupter);
755     if (!csp) return;
756 
757     // Add extra instance points in the interior narrow band.
758     if (instancePoints.size() < size_t(instances)) {
759         const Int16TreeT& signTree = csp->signTree();
760         for (auto leafIt = signTree.cbeginLeaf(); leafIt; ++leafIt) {
761             for (auto it = leafIt->cbeginValueOn(); it; ++it) {
762                 const int flags = int(it.getValue());
763                 if (!(volume_to_mesh_internal::EDGES & flags)
764                     && (volume_to_mesh_internal::INSIDE & flags))
765                 {
766                     instancePoints.push_back(transform.indexToWorld(it.getCoord()));
767                 }
768                 if (instancePoints.size() == size_t(instances)) break;
769             }
770             if (instancePoints.size() == size_t(instances)) break;
771         }
772     }
773 
774     if (interrupter && interrupter->wasInterrupted()) return;
775 
776     // Assign a radius to each candidate sphere.  The radius is the world-space
777     // distance from the sphere's center to the closest surface point.
778     std::vector<float> instanceRadius;
779     if (!csp->search(instancePoints, instanceRadius)) return;
780 
781     float largestRadius = 0.0;
782     int largestRadiusIdx = 0;
783     for (size_t n = 0, N = instancePoints.size(); n < N; ++n) {
784         if (instanceRadius[n] > largestRadius) {
785             largestRadius = instanceRadius[n];
786             largestRadiusIdx = int(n);
787         }
788     }
789 
790     std::vector<unsigned char> instanceMask(instancePoints.size(), 0);
791 
792     minRadius = float(minRadius * transform.voxelSize()[0]);
793     maxRadius = float(maxRadius * transform.voxelSize()[0]);
794 
795     for (size_t s = 0, S = std::min(size_t(maxSphereCount), instancePoints.size()); s < S; ++s) {
796 
797         if (interrupter && interrupter->wasInterrupted()) return;
798 
799         largestRadius = std::min(maxRadius, largestRadius);
800 
801         if ((int(s) >= minSphereCount) && (largestRadius < minRadius)) break;
802 
803         const Vec4s sphere(
804             float(instancePoints[largestRadiusIdx].x()),
805             float(instancePoints[largestRadiusIdx].y()),
806             float(instancePoints[largestRadiusIdx].z()),
807             largestRadius);
808 
809         spheres.push_back(sphere);
810         instanceMask[largestRadiusIdx] = 1;
811 
812         v2s_internal::UpdatePoints op(
813             sphere, instancePoints, instanceRadius, instanceMask, overlapping);
814         op.run();
815 
816         largestRadius = op.radius();
817         largestRadiusIdx = op.index();
818     }
819 } // fillWithSpheres
820 
821 
822 ////////////////////////////////////////
823 
824 
825 template<typename GridT>
826 template<typename InterrupterT>
827 typename ClosestSurfacePoint<GridT>::Ptr
create(const GridT & grid,float isovalue,InterrupterT * interrupter)828 ClosestSurfacePoint<GridT>::create(const GridT& grid, float isovalue, InterrupterT* interrupter)
829 {
830     auto csp = Ptr{new ClosestSurfacePoint};
831     if (!csp->initialize(grid, isovalue, interrupter)) csp.reset();
832     return csp;
833 }
834 
835 
836 template<typename GridT>
837 template<typename InterrupterT>
838 bool
initialize(const GridT & grid,float isovalue,InterrupterT * interrupter)839 ClosestSurfacePoint<GridT>::initialize(
840     const GridT& grid, float isovalue, InterrupterT* interrupter)
841 {
842     using Index32LeafManagerT = tree::LeafManager<Index32TreeT>;
843     using ValueT = typename GridT::ValueType;
844 
845     const TreeT& tree = grid.tree();
846     const math::Transform& transform = grid.transform();
847 
848     { // Extract surface point cloud
849 
850         BoolTreeT mask(false);
851         volume_to_mesh_internal::identifySurfaceIntersectingVoxels(mask, tree, ValueT(isovalue));
852 
853         mSignTreePt.reset(new Int16TreeT(0));
854         mIdxTreePt.reset(new Index32TreeT(std::numeric_limits<Index32>::max()));
855 
856 
857         volume_to_mesh_internal::computeAuxiliaryData(
858             *mSignTreePt, *mIdxTreePt, mask, tree, ValueT(isovalue));
859 
860         if (interrupter && interrupter->wasInterrupted()) return false;
861 
862         // count unique points
863 
864         using Int16LeafNodeType = typename Int16TreeT::LeafNodeType;
865         using Index32LeafNodeType = typename Index32TreeT::LeafNodeType;
866 
867         std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
868         mSignTreePt->getNodes(signFlagsLeafNodes);
869 
870         const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
871 
872         std::unique_ptr<Index32[]> leafNodeOffsets(new Index32[signFlagsLeafNodes.size()]);
873 
874         tbb::parallel_for(auxiliaryLeafNodeRange,
875             volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
876                 (signFlagsLeafNodes, leafNodeOffsets));
877 
878         {
879             Index32 pointCount = 0;
880             for (size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
881                 const Index32 tmp = leafNodeOffsets[n];
882                 leafNodeOffsets[n] = pointCount;
883                 pointCount += tmp;
884             }
885 
886             mPointListSize = size_t(pointCount);
887             mSurfacePointList.reset(new Vec3s[mPointListSize]);
888         }
889 
890 
891         std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
892         mIdxTreePt->getNodes(pointIndexLeafNodes);
893 
894         tbb::parallel_for(auxiliaryLeafNodeRange, volume_to_mesh_internal::ComputePoints<TreeT>(
895             mSurfacePointList.get(), tree, pointIndexLeafNodes,
896             signFlagsLeafNodes, leafNodeOffsets, transform, ValueT(isovalue)));
897     }
898 
899     if (interrupter && interrupter->wasInterrupted()) return false;
900 
901     Index32LeafManagerT idxLeafs(*mIdxTreePt);
902 
903     using Index32RootNodeT = typename Index32TreeT::RootNodeType;
904     using Index32NodeChainT = typename Index32RootNodeT::NodeChainType;
905     static_assert(Index32NodeChainT::Size > 1,
906         "expected tree depth greater than one");
907     using Index32InternalNodeT = typename Index32NodeChainT::template Get<1>;
908 
909     typename Index32TreeT::NodeCIter nIt = mIdxTreePt->cbeginNode();
910     nIt.setMinDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
911     nIt.setMaxDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
912 
913     std::vector<const Index32InternalNodeT*> internalNodes;
914 
915     const Index32InternalNodeT* node = nullptr;
916     for (; nIt; ++nIt) {
917         nIt.getNode(node);
918         if (node) internalNodes.push_back(node);
919     }
920 
921     std::vector<IndexRange>().swap(mLeafRanges);
922     mLeafRanges.resize(internalNodes.size());
923 
924     std::vector<const Index32LeafT*>().swap(mLeafNodes);
925     mLeafNodes.reserve(idxLeafs.leafCount());
926 
927     typename Index32InternalNodeT::ChildOnCIter leafIt;
928     mMaxNodeLeafs = 0;
929     for (size_t n = 0, N = internalNodes.size(); n < N; ++n) {
930 
931         mLeafRanges[n].first = mLeafNodes.size();
932 
933         size_t leafCount = 0;
934         for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) {
935             mLeafNodes.push_back(&(*leafIt));
936             ++leafCount;
937         }
938 
939         mMaxNodeLeafs = std::max(leafCount, mMaxNodeLeafs);
940 
941         mLeafRanges[n].second = mLeafNodes.size();
942     }
943 
944     std::vector<Vec4R>().swap(mLeafBoundingSpheres);
945     mLeafBoundingSpheres.resize(mLeafNodes.size());
946 
947     v2s_internal::LeafOp<Index32LeafT> leafBS(
948         mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList);
949     leafBS.run();
950 
951 
952     std::vector<Vec4R>().swap(mNodeBoundingSpheres);
953     mNodeBoundingSpheres.resize(internalNodes.size());
954 
955     v2s_internal::NodeOp nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres);
956     nodeBS.run();
957     return true;
958 } // ClosestSurfacePoint::initialize
959 
960 
961 template<typename GridT>
962 bool
search(std::vector<Vec3R> & points,std::vector<float> & distances,bool transformPoints)963 ClosestSurfacePoint<GridT>::search(std::vector<Vec3R>& points,
964     std::vector<float>& distances, bool transformPoints)
965 {
966     distances.clear();
967     distances.resize(points.size(), std::numeric_limits<float>::infinity());
968 
969     v2s_internal::ClosestPointDist<Index32LeafT> cpd(points, distances, mSurfacePointList,
970         mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres,
971         mMaxNodeLeafs, transformPoints);
972 
973     cpd.run();
974 
975     return true;
976 }
977 
978 
979 template<typename GridT>
980 bool
search(const std::vector<Vec3R> & points,std::vector<float> & distances)981 ClosestSurfacePoint<GridT>::search(const std::vector<Vec3R>& points, std::vector<float>& distances)
982 {
983     return search(const_cast<std::vector<Vec3R>& >(points), distances, false);
984 }
985 
986 
987 template<typename GridT>
988 bool
searchAndReplace(std::vector<Vec3R> & points,std::vector<float> & distances)989 ClosestSurfacePoint<GridT>::searchAndReplace(std::vector<Vec3R>& points,
990     std::vector<float>& distances)
991 {
992     return search(points, distances, true);
993 }
994 
995 
996 ////////////////////////////////////////
997 
998 
999 // Explicit Template Instantiation
1000 
1001 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1002 
1003 #ifdef OPENVDB_INSTANTIATE_VOLUMETOSPHERES
1004 #include <openvdb/util/ExplicitInstantiation.h>
1005 #endif
1006 
1007 OPENVDB_INSTANTIATE_CLASS ClosestSurfacePoint<FloatGrid>;
1008 OPENVDB_INSTANTIATE_CLASS ClosestSurfacePoint<DoubleGrid>;
1009 
1010 #define _FUNCTION(TreeT) \
1011     void fillWithSpheres(const Grid<TreeT>&, std::vector<openvdb::Vec4s>&, const Vec2i&, \
1012         bool, float, float, float, int, util::NullInterrupter*)
1013 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1014 #undef _FUNCTION
1015 
1016 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1017 
1018 
1019 } // namespace tools
1020 } // namespace OPENVDB_VERSION_NAME
1021 } // namespace openvdb
1022 
1023 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
1024