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);
79 template<
typename Gr
idT>
83 using Ptr = std::unique_ptr<ClosestSurfacePoint>;
84 using TreeT =
typename GridT::TreeType;
100 template<
typename InterrupterT = util::NullInterrupter>
101 static inline Ptr create(
const GridT& grid,
float isovalue = 0.0,
102 InterrupterT* interrupter =
nullptr);
107 inline bool search(
const std::vector<Vec3R>&
points, std::vector<float>& distances);
120 using Index32LeafT =
typename Index32TreeT::LeafNodeType;
121 using IndexRange = std::pair<size_t, size_t>;
123 std::vector<Vec4R> mLeafBoundingSpheres, mNodeBoundingSpheres;
124 std::vector<IndexRange> mLeafRanges;
125 std::vector<const Index32LeafT*> mLeafNodes;
127 size_t mPointListSize = 0, mMaxNodeLeafs = 0;
128 typename Index32TreeT::Ptr mIdxTreePt;
129 typename Int16TreeT::Ptr mSignTreePt;
132 template<
typename InterrupterT = util::NullInterrupter>
133 inline bool initialize(
const GridT&,
float isovalue, InterrupterT*);
134 inline bool search(std::vector<Vec3R>&, std::vector<float>&,
bool transformPoints);
145 namespace v2s_internal {
149 PointAccessor(std::vector<Vec3R>&
points)
156 mPoints.push_back(pos);
159 std::vector<Vec3R>& mPoints;
163 template<
typename Index32LeafT>
168 LeafOp(std::vector<Vec4R>& leafBoundingSpheres,
169 const std::vector<const Index32LeafT*>& leafNodes,
173 void run(
bool threaded =
true);
176 void operator()(
const tbb::blocked_range<size_t>&)
const;
179 std::vector<Vec4R>& mLeafBoundingSpheres;
180 const std::vector<const Index32LeafT*>& mLeafNodes;
181 const math::Transform& mTransform;
185 template<
typename Index32LeafT>
186 LeafOp<Index32LeafT>::LeafOp(
187 std::vector<Vec4R>& leafBoundingSpheres,
188 const std::vector<const Index32LeafT*>& leafNodes,
191 : mLeafBoundingSpheres(leafBoundingSpheres)
192 , mLeafNodes(leafNodes)
193 , mTransform(transform)
194 , mSurfacePointList(surfacePointList)
198 template<
typename Index32LeafT>
200 LeafOp<Index32LeafT>::run(
bool threaded)
205 (*this)(tbb::blocked_range<size_t>(0, mLeafNodes.size()));
209 template<
typename Index32LeafT>
211 LeafOp<Index32LeafT>::operator()(
const tbb::blocked_range<size_t>&
range)
const
213 typename Index32LeafT::ValueOnCIter iter;
216 for (
size_t n = range.begin();
n != range.end(); ++
n) {
222 for (iter = mLeafNodes[
n]->cbeginValueOn(); iter; ++iter) {
223 avg += mSurfacePointList[iter.getValue()];
226 if (count > 1) avg *= float(1.0 /
double(count));
229 for (iter = mLeafNodes[
n]->cbeginValueOn(); iter; ++iter) {
230 float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr();
231 if (tmpDist > maxDist) maxDist = tmpDist;
234 Vec4R& sphere = mLeafBoundingSpheres[
n];
238 sphere[3] = maxDist * 2.0;
246 using IndexRange = std::pair<size_t, size_t>;
248 NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
249 const std::vector<IndexRange>& leafRanges,
250 const std::vector<Vec4R>& leafBoundingSpheres);
252 inline void run(
bool threaded =
true);
254 inline void operator()(
const tbb::blocked_range<size_t>&)
const;
257 std::vector<Vec4R>& mNodeBoundingSpheres;
258 const std::vector<IndexRange>& mLeafRanges;
259 const std::vector<Vec4R>& mLeafBoundingSpheres;
263 NodeOp::NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
264 const std::vector<IndexRange>& leafRanges,
265 const std::vector<Vec4R>& leafBoundingSpheres)
266 : mNodeBoundingSpheres(nodeBoundingSpheres)
267 , mLeafRanges(leafRanges)
268 , mLeafBoundingSpheres(leafBoundingSpheres)
273 NodeOp::run(
bool threaded)
278 (*this)(tbb::blocked_range<size_t>(0, mLeafRanges.size()));
283 NodeOp::operator()(
const tbb::blocked_range<size_t>& range)
const
287 for (
size_t n = range.begin();
n != range.end(); ++
n) {
293 int count =
int(mLeafRanges[
n].second) -
int(mLeafRanges[
n].
first);
295 for (
size_t i = mLeafRanges[
n].
first; i < mLeafRanges[
n].second; ++i) {
296 avg[0] += mLeafBoundingSpheres[i][0];
297 avg[1] += mLeafBoundingSpheres[i][1];
298 avg[2] += mLeafBoundingSpheres[i][2];
301 if (count > 1) avg *= float(1.0 /
double(count));
304 double maxDist = 0.0;
306 for (
size_t i = mLeafRanges[
n].
first; i < mLeafRanges[
n].second; ++i) {
307 pos[0] = mLeafBoundingSpheres[i][0];
308 pos[1] = mLeafBoundingSpheres[i][1];
309 pos[2] = mLeafBoundingSpheres[i][2];
310 const auto radiusSqr = mLeafBoundingSpheres[i][3];
312 double tmpDist = (pos - avg).lengthSqr() + radiusSqr;
313 if (tmpDist > maxDist) maxDist = tmpDist;
316 Vec4R& sphere = mNodeBoundingSpheres[
n];
321 sphere[3] = maxDist * 2.0;
329 template<
typename Index32LeafT>
330 class ClosestPointDist
333 using IndexRange = std::pair<size_t, size_t>;
336 std::vector<Vec3R>& instancePoints,
337 std::vector<float>& instanceDistances,
339 const std::vector<const Index32LeafT*>& leafNodes,
340 const std::vector<IndexRange>& leafRanges,
341 const std::vector<Vec4R>& leafBoundingSpheres,
342 const std::vector<Vec4R>& nodeBoundingSpheres,
344 bool transformPoints =
false);
347 void run(
bool threaded =
true);
350 void operator()(
const tbb::blocked_range<size_t>&)
const;
354 void evalLeaf(
size_t index,
const Index32LeafT& leaf)
const;
355 void evalNode(
size_t pointIndex,
size_t nodeIndex)
const;
358 std::vector<Vec3R>& mInstancePoints;
359 std::vector<float>& mInstanceDistances;
363 const std::vector<const Index32LeafT*>& mLeafNodes;
364 const std::vector<IndexRange>& mLeafRanges;
365 const std::vector<Vec4R>& mLeafBoundingSpheres;
366 const std::vector<Vec4R>& mNodeBoundingSpheres;
368 std::vector<float> mLeafDistances, mNodeDistances;
370 const bool mTransformPoints;
371 size_t mClosestPointIndex;
375 template<
typename Index32LeafT>
376 ClosestPointDist<Index32LeafT>::ClosestPointDist(
377 std::vector<Vec3R>& instancePoints,
378 std::vector<float>& instanceDistances,
380 const std::vector<const Index32LeafT*>& leafNodes,
381 const std::vector<IndexRange>& leafRanges,
382 const std::vector<Vec4R>& leafBoundingSpheres,
383 const std::vector<Vec4R>& nodeBoundingSpheres,
385 bool transformPoints)
386 : mInstancePoints(instancePoints)
387 , mInstanceDistances(instanceDistances)
388 , mSurfacePointList(surfacePointList)
389 , mLeafNodes(leafNodes)
390 , mLeafRanges(leafRanges)
391 , mLeafBoundingSpheres(leafBoundingSpheres)
392 , mNodeBoundingSpheres(nodeBoundingSpheres)
393 , mLeafDistances(maxNodeLeafs, 0.0)
394 , mNodeDistances(leafRanges.
size(), 0.0)
395 , mTransformPoints(transformPoints)
396 , mClosestPointIndex(0)
401 template<
typename Index32LeafT>
403 ClosestPointDist<Index32LeafT>::run(
bool threaded)
408 (*this)(tbb::blocked_range<size_t>(0, mInstancePoints.size()));
412 template<
typename Index32LeafT>
414 ClosestPointDist<Index32LeafT>::evalLeaf(
size_t index,
const Index32LeafT& leaf)
const
416 typename Index32LeafT::ValueOnCIter iter;
418 size_t& closestPointIndex =
const_cast<size_t&
>(mClosestPointIndex);
420 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
422 const Vec3s& point = mSurfacePointList[iter.getValue()];
423 float tmpDist = (point -
center).lengthSqr();
425 if (tmpDist < mInstanceDistances[index]) {
426 mInstanceDistances[index] = tmpDist;
427 closestPointIndex = iter.getValue();
433 template<
typename Index32LeafT>
435 ClosestPointDist<Index32LeafT>::evalNode(
size_t pointIndex,
size_t nodeIndex)
const
437 if (nodeIndex >= mLeafRanges.size())
return;
439 const Vec3R& pos = mInstancePoints[pointIndex];
440 float minDist = mInstanceDistances[pointIndex];
441 size_t minDistIdx = 0;
443 bool updatedDist =
false;
445 for (
size_t i = mLeafRanges[nodeIndex].
first,
n = 0;
446 i < mLeafRanges[nodeIndex].second; ++i, ++
n)
448 float& distToLeaf =
const_cast<float&
>(mLeafDistances[
n]);
450 center[0] = mLeafBoundingSpheres[i][0];
451 center[1] = mLeafBoundingSpheres[i][1];
452 center[2] = mLeafBoundingSpheres[i][2];
453 const auto radiusSqr = mLeafBoundingSpheres[i][3];
455 distToLeaf = float(
std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
457 if (distToLeaf < minDist) {
458 minDist = distToLeaf;
464 if (!updatedDist)
return;
466 evalLeaf(pointIndex, *mLeafNodes[minDistIdx]);
468 for (
size_t i = mLeafRanges[nodeIndex].first,
n = 0;
469 i < mLeafRanges[nodeIndex].second; ++i, ++
n)
471 if (mLeafDistances[
n] < mInstanceDistances[pointIndex] && i != minDistIdx) {
472 evalLeaf(pointIndex, *mLeafNodes[i]);
478 template<
typename Index32LeafT>
480 ClosestPointDist<Index32LeafT>::operator()(
const tbb::blocked_range<size_t>& range)
const
483 for (
size_t n = range.begin();
n != range.end(); ++
n) {
485 const Vec3R& pos = mInstancePoints[
n];
486 float minDist = mInstanceDistances[
n];
487 size_t minDistIdx = 0;
489 for (
size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
490 float& distToNode =
const_cast<float&
>(mNodeDistances[i]);
492 center[0] = mNodeBoundingSpheres[i][0];
493 center[1] = mNodeBoundingSpheres[i][1];
494 center[2] = mNodeBoundingSpheres[i][2];
495 const auto radiusSqr = mNodeBoundingSpheres[i][3];
497 distToNode = float(
std::max(0.0, (pos - center).lengthSqr() - radiusSqr));
499 if (distToNode < minDist) {
500 minDist = distToNode;
505 evalNode(
n, minDistIdx);
507 for (
size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
508 if (mNodeDistances[i] < mInstanceDistances[
n] && i != minDistIdx) {
513 mInstanceDistances[
n] =
std::sqrt(mInstanceDistances[
n]);
515 if (mTransformPoints) mInstancePoints[
n] = mSurfacePointList[mClosestPointIndex];
525 const std::vector<Vec3R>&
points,
526 std::vector<float>& distances,
527 std::vector<unsigned char>&
mask,
530 float radius()
const {
return mRadius; }
531 int index()
const {
return mIndex; }
533 inline void run(
bool threaded =
true);
537 inline void operator()(
const tbb::blocked_range<size_t>& range);
538 void join(
const UpdatePoints& rhs)
540 if (rhs.mRadius > mRadius) {
541 mRadius = rhs.mRadius;
547 const Vec4s& mSphere;
548 const std::vector<Vec3R>& mPoints;
549 std::vector<float>& mDistances;
550 std::vector<unsigned char>& mMask;
557 UpdatePoints::UpdatePoints(
559 const std::vector<Vec3R>&
points,
560 std::vector<float>& distances,
561 std::vector<unsigned char>&
mask,
565 , mDistances(distances)
567 , mOverlapping(overlapping)
574 UpdatePoints::UpdatePoints(UpdatePoints& rhs,
tbb::split)
575 : mSphere(rhs.mSphere)
576 , mPoints(rhs.mPoints)
577 , mDistances(rhs.mDistances)
579 , mOverlapping(rhs.mOverlapping)
580 , mRadius(rhs.mRadius)
586 UpdatePoints::run(
bool threaded)
589 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPoints.size()), *
this);
591 (*this)(tbb::blocked_range<size_t>(0, mPoints.size()));
596 UpdatePoints::operator()(
const tbb::blocked_range<size_t>& range)
599 for (
size_t n = range.begin();
n != range.end(); ++
n) {
600 if (mMask[
n])
continue;
602 pos.x() = float(mPoints[n].
x()) - mSphere[0];
603 pos.y() = float(mPoints[n].
y()) - mSphere[1];
604 pos.z() = float(mPoints[n].
z()) - mSphere[2];
608 if (dist < mSphere[3]) {
614 mDistances[
n] =
std::min(mDistances[n], (dist - mSphere[3]));
617 if (mDistances[n] > mRadius) {
618 mRadius = mDistances[
n];
632 template<
typename Gr
idT,
typename InterrupterT>
636 std::vector<openvdb::Vec4s>& spheres,
637 const Vec2i& sphereCount,
643 InterrupterT* interrupter)
647 if (grid.empty())
return;
650 minSphereCount = sphereCount[0],
651 maxSphereCount = sphereCount[1];
652 if ((minSphereCount > maxSphereCount) || (maxSphereCount < 1)) {
654 << minSphereCount <<
") exceeds maximum count (" << maxSphereCount <<
")");
657 spheres.reserve(maxSphereCount);
659 auto gridPtr = grid.copy();
678 auto numVoxels = gridPtr->activeVoxelCount();
679 if (numVoxels < 10000) {
680 const auto scale = 1.0 /
math::Cbrt(2.0 * 10000.0 /
double(numVoxels));
681 auto scaledXform = gridPtr->transform().copy();
682 scaledXform->preScale(
scale);
685 LEVEL_SET_HALF_WIDTH, LEVEL_SET_HALF_WIDTH, scaledXform.get(), interrupter);
687 const auto newNumVoxels = newGridPtr->activeVoxelCount();
688 if (newNumVoxels > numVoxels) {
690 << numVoxels <<
" voxel" << (numVoxels == 1 ?
"" :
"s")
691 <<
" to " << newNumVoxels <<
" voxel" << (newNumVoxels == 1 ?
"" :
"s"));
692 gridPtr = newGridPtr;
693 numVoxels = newNumVoxels;
697 const bool addNarrowBandPoints = (numVoxels < 10000);
698 int instances =
std::max(instanceCount, maxSphereCount);
700 using TreeT =
typename GridT::TreeType;
704 using RandGen = std::mersenne_twister_engine<uint32_t, 32, 351, 175, 19,
705 0xccab8ee7, 11, 0xffffffff, 7, 0x31b6ab00, 15, 0xffe50000, 17, 1812433253>;
708 const TreeT& tree = gridPtr->tree();
711 std::vector<Vec3R> instancePoints;
721 interiorMaskPtr->
tree().topologyUnion(tree);
724 if (interrupter && interrupter->wasInterrupted())
return;
729 if (!addNarrowBandPoints || (minSphereCount <= 0)) {
733 auto& maskTree = interiorMaskPtr->
tree();
734 auto copyOfTree = StaticPtrCast<BoolTreeT>(maskTree.copy());
737 if (maskTree.empty()) { interiorMaskPtr->
setTree(copyOfTree); }
741 instancePoints.reserve(instances);
742 v2s_internal::PointAccessor ptnAcc(instancePoints);
744 const auto scatterCount =
Index64(addNarrowBandPoints ? (instances / 2) : instances);
747 ptnAcc, scatterCount, mtRand, 1.0, interrupter);
748 scatter(*interiorMaskPtr);
751 if (interrupter && interrupter->wasInterrupted())
return;
757 if (instancePoints.size() < size_t(instances)) {
758 const Int16TreeT& signTree = csp->signTree();
759 for (
auto leafIt = signTree.cbeginLeaf(); leafIt; ++leafIt) {
760 for (
auto it = leafIt->cbeginValueOn(); it; ++it) {
761 const int flags =
int(it.getValue());
762 if (!(volume_to_mesh_internal::EDGES & flags)
763 && (volume_to_mesh_internal::INSIDE &
flags))
765 instancePoints.push_back(transform.
indexToWorld(it.getCoord()));
767 if (instancePoints.size() == size_t(instances))
break;
769 if (instancePoints.size() == size_t(instances))
break;
773 if (interrupter && interrupter->wasInterrupted())
return;
777 std::vector<float> instanceRadius;
778 if (!csp->search(instancePoints, instanceRadius))
return;
780 float largestRadius = 0.0;
781 int largestRadiusIdx = 0;
782 for (
size_t n = 0,
N = instancePoints.size(); n <
N; ++
n) {
783 if (instanceRadius[n] > largestRadius) {
784 largestRadius = instanceRadius[
n];
785 largestRadiusIdx =
int(n);
789 std::vector<unsigned char> instanceMask(instancePoints.size(), 0);
791 minRadius = float(minRadius * transform.
voxelSize()[0]);
792 maxRadius = float(maxRadius * transform.
voxelSize()[0]);
794 for (
size_t s = 0,
S =
std::min(
size_t(maxSphereCount), instancePoints.size());
s <
S; ++
s) {
796 if (interrupter && interrupter->wasInterrupted())
return;
798 largestRadius =
std::min(maxRadius, largestRadius);
800 if ((
int(
s) >= minSphereCount) && (largestRadius < minRadius))
break;
803 float(instancePoints[largestRadiusIdx].
x()),
804 float(instancePoints[largestRadiusIdx].
y()),
805 float(instancePoints[largestRadiusIdx].
z()),
808 spheres.push_back(sphere);
809 instanceMask[largestRadiusIdx] = 1;
811 v2s_internal::UpdatePoints op(
812 sphere, instancePoints, instanceRadius, instanceMask, overlapping);
815 largestRadius = op.radius();
816 largestRadiusIdx = op.index();
824 template<
typename Gr
idT>
825 template<
typename InterrupterT>
826 inline typename ClosestSurfacePoint<GridT>::Ptr
830 if (!csp->initialize(grid, isovalue, interrupter)) csp.reset();
835 template<
typename Gr
idT>
836 template<
typename InterrupterT>
839 const GridT& grid,
float isovalue, InterrupterT* interrupter)
842 using ValueT =
typename GridT::ValueType;
844 const TreeT& tree = grid.
tree();
849 BoolTreeT
mask(
false);
850 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(
mask, tree, ValueT(isovalue));
852 mSignTreePt.reset(
new Int16TreeT(0));
856 volume_to_mesh_internal::computeAuxiliaryData(
857 *mSignTreePt, *mIdxTreePt,
mask, tree, ValueT(isovalue));
859 if (interrupter && interrupter->wasInterrupted())
return false;
863 using Int16LeafNodeType =
typename Int16TreeT::LeafNodeType;
864 using Index32LeafNodeType =
typename Index32TreeT::LeafNodeType;
866 std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
867 mSignTreePt->getNodes(signFlagsLeafNodes);
869 const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
871 std::unique_ptr<Index32[]> leafNodeOffsets(
new Index32[signFlagsLeafNodes.size()]);
874 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
875 (signFlagsLeafNodes, leafNodeOffsets));
879 for (
size_t n = 0,
N = signFlagsLeafNodes.size(); n <
N; ++
n) {
880 const Index32 tmp = leafNodeOffsets[
n];
885 mPointListSize = size_t(pointCount);
886 mSurfacePointList.reset(
new Vec3s[mPointListSize]);
890 std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
891 mIdxTreePt->getNodes(pointIndexLeafNodes);
893 tbb::parallel_for(auxiliaryLeafNodeRange, volume_to_mesh_internal::ComputePoints<TreeT>(
894 mSurfacePointList.get(), tree, pointIndexLeafNodes,
895 signFlagsLeafNodes, leafNodeOffsets,
transform, ValueT(isovalue)));
898 if (interrupter && interrupter->wasInterrupted())
return false;
900 Index32LeafManagerT idxLeafs(*mIdxTreePt);
902 using Index32RootNodeT =
typename Index32TreeT::RootNodeType;
903 using Index32NodeChainT =
typename Index32RootNodeT::NodeChainType;
904 static_assert(Index32NodeChainT::Size > 1,
905 "expected tree depth greater than one");
906 using Index32InternalNodeT =
typename Index32NodeChainT::template Get<1>;
908 typename Index32TreeT::NodeCIter nIt = mIdxTreePt->cbeginNode();
909 nIt.setMinDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
910 nIt.setMaxDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
912 std::vector<const Index32InternalNodeT*> internalNodes;
914 const Index32InternalNodeT* node =
nullptr;
917 if (node) internalNodes.push_back(node);
920 std::vector<IndexRange>().
swap(mLeafRanges);
921 mLeafRanges.resize(internalNodes.size());
923 std::vector<const Index32LeafT*>().
swap(mLeafNodes);
924 mLeafNodes.reserve(idxLeafs.leafCount());
926 typename Index32InternalNodeT::ChildOnCIter leafIt;
928 for (
size_t n = 0, N = internalNodes.size(); n <
N; ++
n) {
930 mLeafRanges[
n].first = mLeafNodes.size();
932 size_t leafCount = 0;
933 for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) {
934 mLeafNodes.push_back(&(*leafIt));
938 mMaxNodeLeafs =
std::max(leafCount, mMaxNodeLeafs);
940 mLeafRanges[
n].second = mLeafNodes.size();
943 std::vector<Vec4R>().
swap(mLeafBoundingSpheres);
944 mLeafBoundingSpheres.resize(mLeafNodes.size());
946 v2s_internal::LeafOp<Index32LeafT> leafBS(
947 mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList);
951 std::vector<Vec4R>().
swap(mNodeBoundingSpheres);
952 mNodeBoundingSpheres.resize(internalNodes.size());
954 v2s_internal::NodeOp nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres);
960 template<
typename Gr
idT>
962 ClosestSurfacePoint<GridT>::search(std::vector<Vec3R>&
points,
963 std::vector<float>& distances,
bool transformPoints)
966 distances.resize(points.size(), std::numeric_limits<float>::infinity());
968 v2s_internal::ClosestPointDist<Index32LeafT> cpd(points, distances, mSurfacePointList,
969 mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres,
970 mMaxNodeLeafs, transformPoints);
978 template<
typename Gr
idT>
982 return search(
const_cast<std::vector<Vec3R>&
>(points), distances,
false);
986 template<
typename Gr
idT>
989 std::vector<float>& distances)
991 return search(points, distances,
true);
998 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
GA_API const UT_StringHolder dist
#define OPENVDB_LOG_WARN(mesg)
GLenum GLenum GLenum GLenum GLenum scale
const TreeType & tree() const
Return a const reference to tree associated with this manager.
vfloat4 sqrt(const vfloat4 &a)
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
void swap(T &lhs, T &rhs)
#define OPENVDB_USE_VERSION_NAMESPACE
Tolerance for floating-point comparison.
float Cbrt(float x)
Return the cube root of a floating-point value.
GLuint GLenum GLenum transform
void OIIO_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Extract polygonal surfaces from scalar volumes.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLdouble GLdouble GLdouble z
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
OPENVDB_API void initialize()
Global registration of basic types.
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
Container class that associates a tree with a transform and metadata.
Type Clamp(Type x, Type min, Type max)
Return x clamped to [min, max].
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
#define OPENVDB_LOG_DEBUG_RUNTIME(mesg)
GA_API const UT_StringHolder N
Implementation of morphological dilation and erosion.
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform. ...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
void setTree(TreeBase::Ptr) override
Associate the given tree with this grid, in place of its existing tree.