8 #ifndef OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
9 #define OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
19 #include <tbb/blocked_range.h>
20 #include <tbb/parallel_for.h>
21 #include <tbb/parallel_reduce.h>
59 template<
typename Gr
idT,
typename InterrupterT = util::NullInterrupter>
63 std::vector<openvdb::Vec4s>& spheres,
65 bool overlapping =
false,
66 float minRadius = 1.0,
69 int instanceCount = 10000,
70 InterrupterT* interrupter =
nullptr);
74 template<
typename Gr
idT,
typename InterrupterT = util::NullInterrupter>
79 std::vector<openvdb::Vec4s>& spheres,
81 bool overlapping =
false,
82 float minRadius = 1.0,
85 int instanceCount = 10000,
86 InterrupterT* interrupter =
nullptr);
95 template<
typename Gr
idT>
99 using Ptr = std::unique_ptr<ClosestSurfacePoint>;
100 using TreeT =
typename GridT::TreeType;
101 using BoolTreeT =
typename TreeT::template ValueConverter<bool>::Type;
102 using Index32TreeT =
typename TreeT::template ValueConverter<Index32>::Type;
103 using Int16TreeT =
typename TreeT::template ValueConverter<Int16>::Type;
116 template<
typename InterrupterT = util::NullInterrupter>
117 static inline Ptr create(
const GridT& grid,
float isovalue = 0.0,
118 InterrupterT* interrupter =
nullptr);
123 inline bool search(
const std::vector<Vec3R>& points, std::vector<float>& distances);
128 inline bool searchAndReplace(std::vector<Vec3R>& points, std::vector<float>& distances);
136 using Index32LeafT =
typename Index32TreeT::LeafNodeType;
137 using IndexRange = std::pair<size_t, size_t>;
139 std::vector<Vec4R> mLeafBoundingSpheres, mNodeBoundingSpheres;
140 std::vector<IndexRange> mLeafRanges;
141 std::vector<const Index32LeafT*> mLeafNodes;
143 size_t mPointListSize = 0, mMaxNodeLeafs = 0;
144 typename Index32TreeT::Ptr mIdxTreePt;
145 typename Int16TreeT::Ptr mSignTreePt;
148 template<
typename InterrupterT = util::NullInterrupter>
149 inline bool initialize(
const GridT&,
float isovalue, InterrupterT*);
150 inline bool search(std::vector<Vec3R>&, std::vector<float>&,
bool transformPoints);
159 namespace v2s_internal {
170 mPoints.push_back(pos);
173 std::vector<Vec3R>& mPoints;
177 template<
typename Index32LeafT>
182 LeafOp(std::vector<Vec4R>& leafBoundingSpheres,
183 const std::vector<const Index32LeafT*>& leafNodes,
187 void run(
bool threaded =
true);
190 void operator()(
const tbb::blocked_range<size_t>&)
const;
193 std::vector<Vec4R>& mLeafBoundingSpheres;
194 const std::vector<const Index32LeafT*>& mLeafNodes;
199 template<
typename Index32LeafT>
201 std::vector<Vec4R>& leafBoundingSpheres,
202 const std::vector<const Index32LeafT*>& leafNodes,
205 : mLeafBoundingSpheres(leafBoundingSpheres)
206 , mLeafNodes(leafNodes)
207 , mTransform(transform)
208 , mSurfacePointList(surfacePointList)
212 template<
typename Index32LeafT>
217 tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafNodes.size()), *
this);
219 (*this)(tbb::blocked_range<size_t>(0, mLeafNodes.size()));
223 template<
typename Index32LeafT>
227 typename Index32LeafT::ValueOnCIter iter;
230 for (
size_t n = range.begin(); n != range.end(); ++n) {
236 for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
237 avg += mSurfacePointList[iter.getValue()];
240 if (count > 1) avg *= float(1.0 /
double(count));
243 for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
244 float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr();
245 if (tmpDist > maxDist) maxDist = tmpDist;
248 Vec4R& sphere = mLeafBoundingSpheres[n];
252 sphere[3] = maxDist * 2.0;
262 NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
263 const std::vector<IndexRange>& leafRanges,
264 const std::vector<Vec4R>& leafBoundingSpheres);
266 inline void run(
bool threaded =
true);
268 inline void operator()(
const tbb::blocked_range<size_t>&)
const;
271 std::vector<Vec4R>& mNodeBoundingSpheres;
272 const std::vector<IndexRange>& mLeafRanges;
273 const std::vector<Vec4R>& mLeafBoundingSpheres;
278 const std::vector<IndexRange>& leafRanges,
279 const std::vector<Vec4R>& leafBoundingSpheres)
280 : mNodeBoundingSpheres(nodeBoundingSpheres)
281 , mLeafRanges(leafRanges)
282 , mLeafBoundingSpheres(leafBoundingSpheres)
290 tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafRanges.size()), *
this);
292 (*this)(tbb::blocked_range<size_t>(0, mLeafRanges.size()));
301 for (
size_t n = range.begin(); n != range.end(); ++n) {
307 int count = int(mLeafRanges[n].second) - int(mLeafRanges[n].first);
309 for (
size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
310 avg[0] += mLeafBoundingSpheres[i][0];
311 avg[1] += mLeafBoundingSpheres[i][1];
312 avg[2] += mLeafBoundingSpheres[i][2];
315 if (count > 1) avg *= float(1.0 /
double(count));
318 double maxDist = 0.0;
320 for (
size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
321 pos[0] = mLeafBoundingSpheres[i][0];
322 pos[1] = mLeafBoundingSpheres[i][1];
323 pos[2] = mLeafBoundingSpheres[i][2];
324 const auto radiusSqr = mLeafBoundingSpheres[i][3];
326 double tmpDist = (pos - avg).lengthSqr() + radiusSqr;
327 if (tmpDist > maxDist) maxDist = tmpDist;
330 Vec4R& sphere = mNodeBoundingSpheres[n];
335 sphere[3] = maxDist * 2.0;
343 template<
typename Index32LeafT>
350 std::vector<Vec3R>& instancePoints,
351 std::vector<float>& instanceDistances,
353 const std::vector<const Index32LeafT*>& leafNodes,
354 const std::vector<IndexRange>& leafRanges,
355 const std::vector<Vec4R>& leafBoundingSpheres,
356 const std::vector<Vec4R>& nodeBoundingSpheres,
358 bool transformPoints =
false);
361 void run(
bool threaded =
true);
364 void operator()(
const tbb::blocked_range<size_t>&)
const;
368 void evalLeaf(
size_t index,
const Index32LeafT& leaf)
const;
369 void evalNode(
size_t pointIndex,
size_t nodeIndex)
const;
372 std::vector<Vec3R>& mInstancePoints;
373 std::vector<float>& mInstanceDistances;
377 const std::vector<const Index32LeafT*>& mLeafNodes;
378 const std::vector<IndexRange>& mLeafRanges;
379 const std::vector<Vec4R>& mLeafBoundingSpheres;
380 const std::vector<Vec4R>& mNodeBoundingSpheres;
382 std::vector<float> mLeafDistances, mNodeDistances;
384 const bool mTransformPoints;
385 size_t mClosestPointIndex;
389 template<
typename Index32LeafT>
391 std::vector<Vec3R>& instancePoints,
392 std::vector<float>& instanceDistances,
394 const std::vector<const Index32LeafT*>& leafNodes,
395 const std::vector<IndexRange>& leafRanges,
396 const std::vector<Vec4R>& leafBoundingSpheres,
397 const std::vector<Vec4R>& nodeBoundingSpheres,
399 bool transformPoints)
400 : mInstancePoints(instancePoints)
401 , mInstanceDistances(instanceDistances)
402 , mSurfacePointList(surfacePointList)
403 , mLeafNodes(leafNodes)
404 , mLeafRanges(leafRanges)
405 , mLeafBoundingSpheres(leafBoundingSpheres)
406 , mNodeBoundingSpheres(nodeBoundingSpheres)
407 , mLeafDistances(maxNodeLeafs, 0.0)
408 , mNodeDistances(leafRanges.size(), 0.0)
409 , mTransformPoints(transformPoints)
410 , mClosestPointIndex(0)
415 template<
typename Index32LeafT>
420 tbb::parallel_for(tbb::blocked_range<size_t>(0, mInstancePoints.size()), *
this);
422 (*this)(tbb::blocked_range<size_t>(0, mInstancePoints.size()));
426 template<
typename Index32LeafT>
430 typename Index32LeafT::ValueOnCIter iter;
431 const Vec3s center = mInstancePoints[index];
432 size_t& closestPointIndex =
const_cast<size_t&
>(mClosestPointIndex);
434 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
436 const Vec3s& point = mSurfacePointList[iter.getValue()];
437 float tmpDist = (point - center).lengthSqr();
439 if (tmpDist < mInstanceDistances[index]) {
440 mInstanceDistances[index] = tmpDist;
441 closestPointIndex = iter.getValue();
447 template<
typename Index32LeafT>
449 ClosestPointDist<Index32LeafT>::evalNode(
size_t pointIndex,
size_t nodeIndex)
const
451 if (nodeIndex >= mLeafRanges.size())
return;
453 const Vec3R& pos = mInstancePoints[pointIndex];
454 float minDist = mInstanceDistances[pointIndex];
455 size_t minDistIdx = 0;
457 bool updatedDist =
false;
459 for (
size_t i = mLeafRanges[nodeIndex].first, n = 0;
460 i < mLeafRanges[nodeIndex].second; ++i, ++n)
462 float& distToLeaf =
const_cast<float&
>(mLeafDistances[n]);
464 center[0] = mLeafBoundingSpheres[i][0];
465 center[1] = mLeafBoundingSpheres[i][1];
466 center[2] = mLeafBoundingSpheres[i][2];
467 const auto radiusSqr = mLeafBoundingSpheres[i][3];
469 distToLeaf = float(
std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
471 if (distToLeaf < minDist) {
472 minDist = distToLeaf;
478 if (!updatedDist)
return;
480 evalLeaf(pointIndex, *mLeafNodes[minDistIdx]);
482 for (
size_t i = mLeafRanges[nodeIndex].first, n = 0;
483 i < mLeafRanges[nodeIndex].second; ++i, ++n)
485 if (mLeafDistances[n] < mInstanceDistances[pointIndex] && i != minDistIdx) {
486 evalLeaf(pointIndex, *mLeafNodes[i]);
492 template<
typename Index32LeafT>
497 for (
size_t n = range.begin(); n != range.end(); ++n) {
499 const Vec3R& pos = mInstancePoints[n];
500 float minDist = mInstanceDistances[n];
501 size_t minDistIdx = 0;
503 for (
size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
504 float& distToNode =
const_cast<float&
>(mNodeDistances[i]);
506 center[0] = mNodeBoundingSpheres[i][0];
507 center[1] = mNodeBoundingSpheres[i][1];
508 center[2] = mNodeBoundingSpheres[i][2];
509 const auto radiusSqr = mNodeBoundingSpheres[i][3];
511 distToNode = float(
std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
513 if (distToNode < minDist) {
514 minDist = distToNode;
519 evalNode(n, minDistIdx);
521 for (
size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
522 if (mNodeDistances[i] < mInstanceDistances[n] && i != minDistIdx) {
527 mInstanceDistances[n] = std::sqrt(mInstanceDistances[n]);
529 if (mTransformPoints) mInstancePoints[n] = mSurfacePointList[mClosestPointIndex];
539 const std::vector<Vec3R>& points,
540 std::vector<float>& distances,
541 std::vector<unsigned char>& mask,
545 int index()
const {
return mIndex; }
547 inline void run(
bool threaded =
true);
551 inline void operator()(
const tbb::blocked_range<size_t>& range);
554 if (rhs.mRadius > mRadius) {
555 mRadius = rhs.mRadius;
561 const Vec4s& mSphere;
562 const std::vector<Vec3R>& mPoints;
563 std::vector<float>& mDistances;
564 std::vector<unsigned char>& mMask;
573 const std::vector<Vec3R>& points,
574 std::vector<float>& distances,
575 std::vector<unsigned char>& mask,
579 , mDistances(distances)
581 , mOverlapping(overlapping)
589 : mSphere(rhs.mSphere)
590 , mPoints(rhs.mPoints)
591 , mDistances(rhs.mDistances)
593 , mOverlapping(rhs.mOverlapping)
594 , mRadius(rhs.mRadius)
603 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPoints.size()), *
this);
605 (*this)(tbb::blocked_range<size_t>(0, mPoints.size()));
613 for (
size_t n = range.begin(); n != range.end(); ++n) {
614 if (mMask[n])
continue;
616 pos.
x() = float(mPoints[n].x()) - mSphere[0];
617 pos.y() = float(mPoints[n].y()) - mSphere[1];
618 pos.z() = float(mPoints[n].z()) - mSphere[2];
620 float dist = pos.length();
622 if (dist < mSphere[3]) {
628 mDistances[n] =
std::min(mDistances[n], (dist - mSphere[3]));
631 if (mDistances[n] > mRadius) {
632 mRadius = mDistances[n];
645 template<
typename Gr
idT,
typename InterrupterT>
649 std::vector<openvdb::Vec4s>& spheres,
656 InterrupterT* interrupter)
659 minRadius, maxRadius, isovalue, instanceCount, interrupter);
663 template<
typename Gr
idT,
typename InterrupterT>
667 std::vector<openvdb::Vec4s>& spheres,
668 const Vec2i& sphereCount,
674 InterrupterT* interrupter)
678 if (grid.empty())
return;
681 minSphereCount = sphereCount[0],
682 maxSphereCount = sphereCount[1];
683 if ((minSphereCount > maxSphereCount) || (maxSphereCount < 1)) {
685 << minSphereCount <<
") exceeds maximum count (" << maxSphereCount <<
")");
688 spheres.reserve(maxSphereCount);
690 auto gridPtr = grid.copy();
709 auto numVoxels = gridPtr->activeVoxelCount();
710 if (numVoxels < 10000) {
711 const auto scale = 1.0 /
math::Cbrt(2.0 * 10000.0 /
double(numVoxels));
712 auto scaledXform = gridPtr->transform().copy();
713 scaledXform->preScale(
scale);
718 const auto newNumVoxels = newGridPtr->activeVoxelCount();
719 if (newNumVoxels > numVoxels) {
721 << numVoxels <<
" voxel" << (numVoxels == 1 ?
"" :
"s")
722 <<
" to " << newNumVoxels <<
" voxel" << (newNumVoxels == 1 ?
"" :
"s"));
723 gridPtr = newGridPtr;
724 numVoxels = newNumVoxels;
728 const bool addNarrowBandPoints = (numVoxels < 10000);
729 int instances =
std::max(instanceCount, maxSphereCount);
731 using TreeT =
typename GridT::TreeType;
732 using BoolTreeT =
typename TreeT::template ValueConverter<bool>::Type;
733 using Int16TreeT =
typename TreeT::template ValueConverter<Int16>::Type;
735 using RandGen = std::mersenne_twister_engine<uint32_t, 32, 351, 175, 19,
736 0xccab8ee7, 11, 0xffffffff, 7, 0x31b6ab00, 15, 0xffe50000, 17, 1812433253>;
739 const TreeT& tree = gridPtr->tree();
742 std::vector<Vec3R> instancePoints;
751 interiorMaskPtr->setTransform(transform.
copy());
752 interiorMaskPtr->
tree().topologyUnion(tree);
755 if (interrupter && interrupter->wasInterrupted())
return;
760 if (!addNarrowBandPoints || (minSphereCount <= 0)) {
763 auto& maskTree = interiorMaskPtr->
tree();
764 auto copyOfTree = StaticPtrCast<BoolTreeT>(maskTree.copy());
766 if (maskTree.empty()) { interiorMaskPtr->
setTree(copyOfTree); }
770 instancePoints.reserve(instances);
773 const auto scatterCount =
Index64(addNarrowBandPoints ? (instances / 2) : instances);
776 ptnAcc, scatterCount, mtRand, 1.0, interrupter);
777 scatter(*interiorMaskPtr);
780 if (interrupter && interrupter->wasInterrupted())
return;
786 if (instancePoints.size() <
size_t(instances)) {
787 const Int16TreeT& signTree = csp->signTree();
788 for (
auto leafIt = signTree.cbeginLeaf(); leafIt; ++leafIt) {
789 for (
auto it = leafIt->cbeginValueOn(); it; ++it) {
790 const int flags = int(it.getValue());
794 instancePoints.push_back(transform.
indexToWorld(it.getCoord()));
796 if (instancePoints.size() ==
size_t(instances))
break;
798 if (instancePoints.size() ==
size_t(instances))
break;
802 if (interrupter && interrupter->wasInterrupted())
return;
806 std::vector<float> instanceRadius;
807 if (!csp->search(instancePoints, instanceRadius))
return;
809 float largestRadius = 0.0;
810 int largestRadiusIdx = 0;
811 for (
size_t n = 0, N = instancePoints.size(); n < N; ++n) {
812 if (instanceRadius[n] > largestRadius) {
813 largestRadius = instanceRadius[n];
814 largestRadiusIdx = int(n);
818 std::vector<unsigned char> instanceMask(instancePoints.size(), 0);
820 minRadius = float(minRadius * transform.
voxelSize()[0]);
821 maxRadius = float(maxRadius * transform.
voxelSize()[0]);
823 for (
size_t s = 0, S =
std::min(
size_t(maxSphereCount), instancePoints.size()); s < S; ++s) {
825 if (interrupter && interrupter->wasInterrupted())
return;
827 largestRadius =
std::min(maxRadius, largestRadius);
829 if ((
int(s) >= minSphereCount) && (largestRadius < minRadius))
break;
832 float(instancePoints[largestRadiusIdx].x()),
833 float(instancePoints[largestRadiusIdx].y()),
834 float(instancePoints[largestRadiusIdx].z()),
837 spheres.push_back(sphere);
838 instanceMask[largestRadiusIdx] = 1;
841 sphere, instancePoints, instanceRadius, instanceMask, overlapping);
844 largestRadius = op.
radius();
845 largestRadiusIdx = op.
index();
853 template<
typename Gr
idT>
854 template<
typename InterrupterT>
859 if (!csp->initialize(grid, isovalue, interrupter)) csp.reset();
864 template<
typename Gr
idT>
865 template<
typename InterrupterT>
868 const GridT& grid,
float isovalue, InterrupterT* interrupter)
871 using ValueT =
typename GridT::ValueType;
873 const TreeT& tree = grid.
tree();
878 BoolTreeT mask(
false);
881 mSignTreePt.reset(
new Int16TreeT(0));
886 *mSignTreePt, *mIdxTreePt, mask, tree, ValueT(isovalue));
888 if (interrupter && interrupter->wasInterrupted())
return false;
892 using Int16LeafNodeType =
typename Int16TreeT::LeafNodeType;
893 using Index32LeafNodeType =
typename Index32TreeT::LeafNodeType;
895 std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
896 mSignTreePt->getNodes(signFlagsLeafNodes);
898 const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
900 std::unique_ptr<Index32[]> leafNodeOffsets(
new Index32[signFlagsLeafNodes.size()]);
902 tbb::parallel_for(auxiliaryLeafNodeRange,
904 (signFlagsLeafNodes, leafNodeOffsets));
908 for (
size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
909 const Index32 tmp = leafNodeOffsets[n];
915 mSurfacePointList.reset(
new Vec3s[mPointListSize]);
919 std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
920 mIdxTreePt->getNodes(pointIndexLeafNodes);
922 tbb::parallel_for(auxiliaryLeafNodeRange, volume_to_mesh_internal::ComputePoints<TreeT>(
923 mSurfacePointList.get(), tree, pointIndexLeafNodes,
924 signFlagsLeafNodes, leafNodeOffsets, transform, ValueT(isovalue)));
927 if (interrupter && interrupter->wasInterrupted())
return false;
929 Index32LeafManagerT idxLeafs(*mIdxTreePt);
931 using Index32RootNodeT =
typename Index32TreeT::RootNodeType;
932 using Index32NodeChainT =
typename Index32RootNodeT::NodeChainType;
933 static_assert(Index32NodeChainT::Size > 1,
934 "expected tree depth greater than one");
935 using Index32InternalNodeT =
typename Index32NodeChainT::template Get<1>;
937 typename Index32TreeT::NodeCIter nIt = mIdxTreePt->cbeginNode();
938 nIt.setMinDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
939 nIt.setMaxDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
941 std::vector<const Index32InternalNodeT*> internalNodes;
943 const Index32InternalNodeT* node =
nullptr;
946 if (node) internalNodes.push_back(node);
949 std::vector<IndexRange>().swap(mLeafRanges);
950 mLeafRanges.resize(internalNodes.size());
952 std::vector<const Index32LeafT*>().swap(mLeafNodes);
953 mLeafNodes.reserve(idxLeafs.leafCount());
955 typename Index32InternalNodeT::ChildOnCIter leafIt;
957 for (
size_t n = 0, N = internalNodes.size(); n < N; ++n) {
959 mLeafRanges[n].first = mLeafNodes.size();
961 size_t leafCount = 0;
962 for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) {
963 mLeafNodes.push_back(&(*leafIt));
967 mMaxNodeLeafs =
std::max(leafCount, mMaxNodeLeafs);
969 mLeafRanges[n].second = mLeafNodes.size();
972 std::vector<Vec4R>().swap(mLeafBoundingSpheres);
973 mLeafBoundingSpheres.resize(mLeafNodes.size());
975 v2s_internal::LeafOp<Index32LeafT> leafBS(
976 mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList);
980 std::vector<Vec4R>().swap(mNodeBoundingSpheres);
981 mNodeBoundingSpheres.resize(internalNodes.size());
983 v2s_internal::NodeOp nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres);
989 template<
typename Gr
idT>
992 std::vector<float>& distances,
bool transformPoints)
995 distances.resize(points.size(), std::numeric_limits<float>::infinity());
997 v2s_internal::ClosestPointDist<Index32LeafT> cpd(points, distances, mSurfacePointList,
998 mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres,
999 mMaxNodeLeafs, transformPoints);
1007 template<
typename Gr
idT>
1011 return search(
const_cast<std::vector<Vec3R>&
>(points), distances,
false);
1015 template<
typename Gr
idT>
1018 std::vector<float>& distances)
1020 return search(points, distances,
true);
1027 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED