14 #ifndef OPENVDB_TOOLS_LEVELSETTUBESIMPL_HAS_BEEN_INCLUDED 15 #define OPENVDB_TOOLS_LEVELSETTUBESIMPL_HAS_BEEN_INCLUDED 27 #include <tbb/parallel_sort.h> 28 #include <tbb/parallel_for.h> 29 #include <tbb/parallel_reduce.h> 33 #include <type_traits> 47 template <
typename Gr
idType,
typename InterruptT = util::NullInterrupter>
51 CapsuleVoxelizer<GridType, InterruptT>,
54 using GridPtr =
typename GridType::Ptr;
63 using BaseT::tileCeil;
73 CapsuleVoxelizer<GridType, InterruptT>,
87 InterruptT* interrupter =
nullptr)
97 template<
typename ScalarType>
102 static_assert(std::is_floating_point<ScalarType>::value);
171 setXYRangeData(
const Index& step = 1)
173 const ValueT stepv = ValueT(step);
176 if (mX1 - mORad > mX2 + mORad) {
183 mXYData.reset(mX1 - mORad, mX1 + mORad, step);
185 for (ValueT x = tileCeil(mX1 - mORad, step); x <= mX1 + mORad; x += stepv)
186 mXYData.expandYRange(x, circle1Bottom(x), circle1Top(x));
192 const ValueT a0 = mX1 - mORad,
199 const ValueT tc0 = tileCeil(a0, step),
200 tc1 = tileCeil(a1, step),
201 tc2 = tileCeil(a2, step),
202 tc3 = tileCeil(a3, step),
203 tc4 = tileCeil(a4, step);
205 mXYData.reset(a0, a5, step);
207 for (ValueT x = tc0; x <= a1; x += stepv)
208 mXYData.expandYRange(x, circle1Bottom(x), circle1Top(x));
212 for (ValueT x = tc1; x <=
math::Min(a2, a3); x += stepv)
213 mXYData.expandYRange(x, lineBottom(x), circle1Top(x));
215 for (ValueT x = tc1; x <=
math::Min(a2, a3); x += stepv)
216 mXYData.expandYRange(x, circle1Bottom(x), lineTop(x));
221 for (ValueT x = tc2; x <= a3; x += stepv)
222 mXYData.expandYRange(x, lineBottom(x), lineTop(x));
225 for (ValueT x = tc3; x <= a2; x += stepv)
226 mXYData.expandYRange(x, circle2Bottom(x), circle1Top(x));
228 for (ValueT x = tc3; x <= a2; x += stepv)
229 mXYData.expandYRange(x, circle1Bottom(x), circle2Top(x));
235 for (ValueT x =
math::Max(tc2, tc3); x <= a4; x += stepv)
236 mXYData.expandYRange(x, circle2Bottom(x), lineTop(x));
238 for (ValueT x =
math::Max(tc2, tc3); x <= a4; x += stepv)
239 mXYData.expandYRange(x, lineBottom(x), circle2Top(x));
243 for (ValueT x = tc4; x <= a5; x += stepv)
244 mXYData.expandYRange(x, circle2Bottom(x), circle2Top(x));
251 signedDistance(
const Vec3T& p)
const 253 const Vec3T w = p - mPt1;
254 const ValueT dot = w.dot(mV);
258 return w.length() - mRad;
261 return (p - mPt2).length() - mRad;
263 const ValueT t = w.dot(mV)/mVLenSqr;
265 return (w - t * mV).length() - mRad;
269 tileCanFit(
const Index& dim)
const 271 return mRad >= BaseT::halfWidth() + ValueT(0.70711) * (ValueT(dim)-ValueT(1));
277 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> capsuleBottomTopVertical =
278 [
this](ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT& y)
280 zb = BaseT::sphereBottom(mX1, mY1,
math::Min(mZ1, mZ2), mORad, x, y);
281 zt = BaseT::sphereTop(mX2, mY2,
math::Max(mZ1, mZ2), mORad, x, y);
283 return std::isfinite(zb) && std::isfinite(zt);
290 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> capsuleBottomTop =
291 [
this](ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT& y)
293 ValueT cylptb, cylptt;
294 if (!infiniteCylinderBottomTop(cylptb, cylptt, x, y))
297 const ValueT dotb = (Vec3T(x, y, cylptb) - mPt1).dot(mV);
298 const ValueT dott = (Vec3T(x, y, cylptt) - mPt1).dot(mV);
301 zb = sphere1Bottom(x, y);
302 else if (dotb > mVLenSqr)
303 zb = sphere2Bottom(x, y);
308 zt = sphere1Top(x, y);
309 else if (dott > mVLenSqr)
310 zt = sphere2Top(x, y);
314 return std::isfinite(zb) && std::isfinite(zt);
319 infiniteCylinderBottomTop(ValueT& cylptb, ValueT& cylptt,
const ValueT& x,
const ValueT& y)
const 323 const Vec2T qproj = mPt12d + mV2d*((q - mPt12d).dot(mV2d))/mXYNorm2;
325 const ValueT t = mX1 != mX2 ? (qproj[0] - mX1)/mXdiff : (qproj[1] - mY1)/mYdiff;
327 const Vec3T qproj3D = mPt1 + t * mV;
329 const ValueT d2 = (q - qproj).lengthSqr();
335 const ValueT h =
math::Sqrt((mORad2 - d2) * mVLenSqr/mXYNorm2);
337 cylptb = qproj3D[2] - h;
338 cylptt = qproj3D[2] + h;
344 lineBottom(
const ValueT& x)
const 346 return mY1 + (mYdiff*(x-mX1) - mORad * mXYNorm)/mXdiff;
350 lineTop(
const ValueT& x)
const 352 return mY1 + (mYdiff*(x-mX1) + mORad * mXYNorm)/mXdiff;
356 circle1Bottom(
const ValueT& x)
const 358 return BaseT::circleBottom(mX1, mY1, mORad, x);
362 circle1Top(
const ValueT& x)
const 364 return BaseT::circleTop(mX1, mY1, mORad, x);
368 circle2Bottom(
const ValueT& x)
const 370 return BaseT::circleBottom(mX2, mY2, mORad, x);
374 circle2Top(
const ValueT& x)
const 376 return BaseT::circleTop(mX2, mY2, mORad, x);
380 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const 382 return BaseT::sphereBottom(mX1, mY1, mZ1, mORad, x, y);
386 sphere1Top(
const ValueT& x,
const ValueT& y)
const 388 return BaseT::sphereTop(mX1, mY1, mZ1, mORad, x, y);
392 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const 394 return BaseT::sphereBottom(mX2, mY2, mZ2, mORad, x, y);
398 sphere2Top(
const ValueT& x,
const ValueT& y)
const 400 return BaseT::sphereTop(mX2, mY2, mZ2, mORad, x, y);
405 template<
typename ScalarType>
410 const ValueT vx = BaseT::voxelSize(),
411 hw = BaseT::halfWidth();
413 if (pt1[0] <= pt2[0]) {
414 mPt1 = Vec3T(pt1)/vx;
415 mPt2 = Vec3T(pt2)/vx;
417 mPt1 = Vec3T(pt2)/vx;
418 mPt2 = Vec3T(pt1)/vx;
425 mORad2 = mORad * mORad;
428 mVLenSqr = mV.lengthSqr();
430 mX1 = mPt1[0]; mY1 = mPt1[1]; mZ1 = mPt1[2];
431 mX2 = mPt2[0]; mY2 = mPt2[1]; mZ2 = mPt2[2];
437 mPt12d = Vec2T(mX1, mY1);
438 mPt22d = Vec2T(mX2, mY2);
439 mV2d = mPt22d - mPt12d;
445 BaseT::bottomTop = mIsVertical ? capsuleBottomTopVertical : capsuleBottomTop;
452 Vec3T mPt1, mPt2, mV;
454 Vec2T mPt12d, mPt22d, mV2d;
456 ValueT mORad, mORad2, mRad, mVLenSqr, mXdiff, mYdiff, mZdiff, mXYNorm, mXYNorm2;
458 ValueT mX1, mY1, mZ1, mX2, mY2, mZ2;
469 template <
typename Gr
idType,
typename InterruptT = util::NullInterrupter>
473 TaperedCapsuleVoxelizer<GridType, InterruptT>,
476 using GridPtr =
typename GridType::Ptr;
484 using BaseT::mXYData;
485 using BaseT::tileCeil;
495 TaperedCapsuleVoxelizer<GridType, InterruptT>,
509 InterruptT* interrupter =
nullptr)
520 template<
typename ScalarType>
523 const ScalarType& radius1,
const ScalarType& radius2)
525 static_assert(std::is_floating_point<ScalarType>::value);
530 if ((pt1 - pt2).lengthSqr() <=
math::Pow2(radius1 - radius2)) {
532 "The tapered capsule is degenerate, in this case it is a ball. Consider using the CapsuleVoxelizer class instead.");
536 if (
math::Abs(radius1 - radius2) < 0.001f*BaseT::voxelSize()) {
538 "The tapered capsule is degenerate, in this case it is a capsule. Consider using the CapsuleVoxelizer class instead.");
548 setXYRangeData(
const Index& step = 1)
550 const ValueT stepv = ValueT(step);
553 if (mXYNorm2 <= mRdiff2) {
554 if (mX1 - mORad1 <= mX2 - mORad2) {
555 mXYData.reset(mX1 - mORad1, mX1 + mORad1, step);
556 for (ValueT x = tileCeil(mX1 - mORad1, step); x <= mX1 + mORad1; x += stepv)
557 mXYData.expandYRange(x, circle1Bottom(x), circle1Top(x));
559 mXYData.reset(mX2 - mORad2, mX2 + mORad2, step);
560 for (ValueT x = tileCeil(mX2 - mORad2, step); x <= mX2 + mORad2; x += stepv)
561 mXYData.expandYRange(x, circle2Bottom(x), circle2Top(x));
572 Vec2T p1t, p2t, p1b, p2b;
573 const bool success = pullyPoints(p1t, p2t, p1b, p2b);
576 setLineXYData(p1t, p2t, stepv);
577 setLineXYData(p1b, p2b, stepv);
579 setCircleXYData(p1t, p1b, stepv,
true);
580 setCircleXYData(p2t, p2b, stepv,
false);
588 pullyPoints(Vec2T& p1t, Vec2T& p2t, Vec2T& p1b, Vec2T& p2b)
const 590 const ValueT diff = mXYNorm2 - mRdiff2;
594 const ValueT alpha = std::atan2(mYdiff, mXdiff),
600 p1t.x() = mX1 + mORad1*cos1; p1t.y() = mY1 + mORad1*sin1;
601 p2t.x() = mX2 + mORad2*cos1; p2t.y() = mY2 + mORad2*sin1;
602 p2b.x() = mX2 + mORad2*cos2; p2b.y() = mY2 - mORad2*sin2;
603 p1b.x() = mX1 + mORad1*cos2; p1b.y() = mY1 - mORad1*sin2;
609 setLineXYData(
const Vec2T& q1,
const Vec2T& q2,
const ValueT& step)
612 ValueT x = tileCeil(q1.x(), step);
614 mXYData.expandYRange(x, q1.y());
615 mXYData.expandYRange(x, q2.y());
618 const bool q1_left = q1.x() < q2.x();
619 const ValueT &x1 = q1_left ? q1.x() : q2.x(),
620 &y1 = q1_left ? q1.y() : q2.y(),
621 &x2 = q1_left ? q2.x() : q1.x(),
622 &y2 = q1_left ? q2.y() : q1.y();
624 ValueT m = (y2 - y1)/(x2 - x1),
625 x = tileCeil(x1, step),
628 for (; x <= x2; x += step, y += delta)
629 mXYData.expandYRange(x, y);
634 setCircleXYData(
const Vec2T& q1,
const Vec2T& q2,
635 const ValueT& step,
const bool is_pt1)
637 const Vec3T &p1 = is_pt1 ? mPt1 : mPt2;
638 const ValueT &r1 = is_pt1 ? mORad1 : mORad2;
640 const std::vector<ValueT> xs = {
641 tileCeil(p1.x() - r1, step),
642 tileCeil(
math::Min(q1.x(), q2.x()), step),
643 tileCeil(
math::Max(q1.x(), q2.x()), step),
644 tileCeil(p1.x() + r1, step)
647 for (
int i = 0; i < int(xs.size()-1); ++i) {
648 setCircleHiXYData(xs[i], xs[i+1], step, is_pt1);
649 setCircleLoXYData(xs[i], xs[i+1], step, is_pt1);
654 setCircleHiXYData(
const ValueT& x1,
const ValueT& x2,
655 const ValueT& step,
const bool& is_pt1)
657 const ValueT x_test =
static_cast<ValueT
>(
math::Floor(ValueT(0.5)*(x1+x2)));
661 if (
math::Abs(x2-x1) < 5 || mXYData.getYMax(x_test) <= circle1Top(x_test)) {
662 for (ValueT x = x1; x < x2; x += step)
663 mXYData.expandYMax(x, circle1Top(x));
666 if (
math::Abs(x2-x1) < 5 || mXYData.getYMax(x_test) <= circle2Top(x_test)) {
667 for (ValueT x = x1; x < x2; x += step)
668 mXYData.expandYMax(x, circle2Top(x));
674 setCircleLoXYData(
const ValueT& x1,
const ValueT& x2,
675 const ValueT& step,
const bool& is_pt1)
677 const ValueT x_test =
static_cast<ValueT
>(
math::Floor(ValueT(0.5)*(x1+x2)));
681 if (
math::Abs(x2-x1) < 5 || mXYData.getYMin(x_test) >= circle1Bottom(x_test)) {
682 for (ValueT x = x1; x < x2; x += step)
683 mXYData.expandYMin(x, circle1Bottom(x));
686 if (
math::Abs(x2-x1) < 5 || mXYData.getYMin(x_test) >= circle2Bottom(x_test)) {
687 for (ValueT x = x1; x < x2; x += step)
688 mXYData.expandYMin(x, circle2Bottom(x));
696 signedDistance(
const Vec3T& p)
const 698 const Vec3T w = p - mPt1;
699 const ValueT y = w.dot(mV),
701 x2 = (w*mVLenSqr - mV*y).lengthSqr(),
707 return math::Sqrt(x2 + z2)*mInvVLenSqr - mRad2;
710 return math::Sqrt(x2 + y2)*mInvVLenSqr - mRad1;
712 return (
math::Sqrt(x2*mA2*mInvVLenSqr) + y*mRdiff)*mInvVLenSqr - mRad1;
716 tileCanFit(
const Index& dim)
const 719 return mRad1 >= BaseT::halfWidth() + ValueT(0.70711) * (ValueT(dim)-ValueT(1));
722 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> taperedCapsuleBottomTop =
723 [
this](ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT& y)
727 const bool in_ball1 = (q - mPt12d).lengthSqr() <= mORad1Sqr,
728 in_ball2 = (q - mPt22d).lengthSqr() <= mORad2Sqr;
731 zt = sphere1Top(x, y);
737 const ValueT zt2 = sphere2Top(x, y),
738 zb2 = 2.0f*mZ2 - zt2;
743 zt = sphere2Top(x, y);
749 if (in_ball1 || in_ball2) {
750 const double ht = mConeD.dot(
Vec3d(x,y,zt) - mConeV);
752 if (mH1 > ht || ht > mH2) {
753 const double hb = mConeD.dot(
Vec3d(x,y,zb) - mConeV);
755 if (mH1 > hb || hb > mH2)
760 ValueT conezb = 0.0f, conezt = 0.0f;
762 openConeFrustumBottomTop(conezb, conezt, cint_cnt, x, y);
764 if (in_ball1 && in_ball2) {
768 }
else if (cint_cnt == 1) {
777 if (cint_cnt == 2 || (!in_ball1 && !in_ball2)) {
778 zb = conezb; zt = conezt;
779 return cint_cnt == 2;
799 openConeFrustumBottomTop(ValueT& conezb, ValueT& conezt,
int& cint_cnt,
800 const ValueT& x,
const ValueT& y)
const 803 const Vec3d p(
double(x),
double(y), mRayZ);
804 const Vec3d diff = p - mConeV;
806 const double ddotdiff = mConeD.
dot(diff);
808 const double c1 = mGamma * diff.z() - mConeD.z() * ddotdiff;
809 const double c0 = ddotdiff * ddotdiff - mGamma * diff.lengthSqr();
812 const double delta = c1*c1 - c0*mC2;
815 const double t1 = mC2Inv*(-c1 + sqrt);
816 if (validFrustumRange(t1, ddotdiff)) {
818 conezb = ValueT(mRayZ - t1);
820 const double t2 = mC2Inv*(-c1 - sqrt);
821 if (validFrustumRange(t2, ddotdiff)) {
823 if (cint_cnt == 2 && t1 > t2)
824 conezt = ValueT(mRayZ - t2);
827 conezb = ValueT(mRayZ - t2);
831 }
else if (c1 != 0.0f) {
832 const double t = -c0/(2.0f*c1);
833 if (validFrustumRange(t, ddotdiff)) {
835 conezb = ValueT(mRayZ - t);
843 validFrustumRange(
const double& t,
const double& ddotdiff)
const 845 const double h = ddotdiff - t * mConeD.z();
847 return mH1 <= h && h <= mH2;
851 circle1Bottom(
const ValueT& x)
const 853 return BaseT::circleBottom(mX1, mY1, mORad1, x);
857 circle1Top(
const ValueT& x)
const 859 return BaseT::circleTop(mX1, mY1, mORad1, x);
863 circle2Bottom(
const ValueT& x)
const 865 return BaseT::circleBottom(mX2, mY2, mORad2, x);
869 circle2Top(
const ValueT& x)
const 871 return BaseT::circleTop(mX2, mY2, mORad2, x);
875 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const 877 return BaseT::sphereBottom(mX1, mY1, mZ1, mORad1, x, y);
881 sphere1Top(
const ValueT& x,
const ValueT& y)
const 883 return BaseT::sphereTop(mX1, mY1, mZ1, mORad1, x, y);
887 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const 889 return BaseT::sphereBottom(mX2, mY2, mZ2, mORad2, x, y);
893 sphere2Top(
const ValueT& x,
const ValueT& y)
const 895 return BaseT::sphereTop(mX2, mY2, mZ2, mORad2, x, y);
900 template<
typename ScalarType>
903 const ScalarType& r1,
const ScalarType& r2)
905 const ValueT vx = BaseT::voxelSize(),
906 hw = BaseT::halfWidth();
910 mPt1 = Vec3T(pt1)/vx;
911 mPt2 = Vec3T(pt2)/vx;
912 mRad1 = ValueT(r1)/vx;
913 mRad2 = ValueT(r2)/vx;
915 mPt1 = Vec3T(pt2)/vx;
916 mPt2 = Vec3T(pt1)/vx;
917 mRad1 = ValueT(r2)/vx;
918 mRad2 = ValueT(r1)/vx;
924 mORad1Sqr = mORad1 * mORad1;
925 mORad2Sqr = mORad2 * mORad2;
928 if (mORad1 <= ScalarType(0))
934 if (mORad2 < ScalarType(0)){
935 const ScalarType t = (r2 <= r1 ? r2/(r2 - r1) : r1/(r1 - r2));
938 const ScalarType r_0 = r2 <= r1 ? r1 : r2;
941 const ScalarType r_mid = ScalarType(0);
947 mVLenSqr = mV.lengthSqr();
948 mInvVLenSqr = mVLenSqr != ValueT(0) ? ValueT(1)/mVLenSqr : ValueT(1);
950 mX1 = mPt1[0]; mY1 = mPt1[1]; mZ1 = mPt1[2];
951 mX2 = mPt2[0]; mY2 = mPt2[1]; mZ2 = mPt2[2];
957 mPt12d = Vec2T(mX1, mY1);
958 mPt22d = Vec2T(mX2, mY2);
959 mV2d = mPt22d - mPt12d;
963 mIXYNorm2 = mXYNorm2 != ValueT(0) ? ValueT(1)/mXYNorm2 : ValueT(1);
966 mRdiff = mRad1 - mRad2;
967 mRdiff2 = mRdiff * mRdiff;
968 mA2 = mVLenSqr - mRdiff2;
975 const double P = mV.length(),
978 mGamma = 1.0 - mRdiff2/(P*P);
979 mH1 = mORad2*(csc-sin);
980 mH2 = mORad1*(csc-sin);
982 mConeD = -((
Vec3d)mV).unitSafe();
983 mConeV = (
Vec3d)mPt1 - (
double)mORad1 * csc * mConeD;
985 mRayZ =
math::Max(mZ1 + mORad1, mZ2 + mORad2) + 2.0;
987 mC2Inv = mC2 != 0.0 ? 1.0/mC2 : 1.0;
989 BaseT::bottomTop = taperedCapsuleBottomTop;
998 Vec3T mPt1, mPt2, mV;
1000 Vec2T mPt12d, mPt22d, mV2d;
1002 ValueT mORad1, mORad2, mORad1Sqr, mORad2Sqr, mRad1, mRad2, mVLenSqr, mInvVLenSqr,
1003 mXdiff, mYdiff, mZdiff, mXYNorm, mXYNorm2, mIXYNorm2, mRdiff, mRdiff2, mA2;
1005 ValueT mX1, mY1, mZ1, mX2, mY2, mZ2;
1010 Vec3d mConeV, mConeD;
1012 double mRayZ, mGamma, mC2, mC2Inv, mH1, mH2;
1024 template <
typename GridType,
typename ScalarType = float,
1028 using GridPtr =
typename GridType::Ptr;
1029 using TreeT =
typename GridType::TreeType;
1030 using LeafT =
typename TreeT::LeafNodeType;
1036 static_assert(std::is_floating_point<ScalarType>::value);
1050 ScalarType radius,
float voxelSize,
float halfWidth, InterruptT* interrupter)
1051 : mVox(voxelSize), mHw(halfWidth), mRad(radius)
1052 , mCoords(vertices), mCells(segments), mRadii(getEmptyVector())
1053 , mInterrupter(interrupter)
1056 initializePartitioner();
1073 const std::vector<ScalarType>& radii,
float voxelSize,
float halfWidth,
1074 InterruptT* interrupter)
1075 : mVox(voxelSize), mHw(halfWidth), mRad(0.0)
1076 , mCoords(vertices), mCells(segments), mRadii(radii)
1077 , mInterrupter(interrupter)
1079 if constexpr (PerSegmentRadii) {
1080 if (mCells.size() != mRadii.size())
1082 "TubeComplexVoxelizer needs the same number of segments and radii");
1084 if (mCoords.size() != mRadii.size())
1086 "TubeComplexVoxelizer needs the same number of coordinates and radii");
1090 initializePartitioner();
1094 : mVox(other.mVox), mHw(other.mHw), mRad(other.mRad)
1095 , mCoords(other.mCoords), mCells(other.mCells), mRadii(other.mRadii)
1096 , mPtPartitioner(other.mPtPartitioner), mInterrupter(other.mInterrupter)
1101 template<
bool PSR = PerSegmentRadii>
1102 inline typename std::enable_if_t<PSR, void>
1105 if (!checkInterrupter())
1108 if (mRadii.size() == 0)
1109 constantRadiusVoxelize(rng);
1111 perSegmentRadiusVoxelize(rng);
1114 template<
bool PSR = PerSegmentRadii>
1115 inline typename std::enable_if_t<!PSR, void>
1118 if (!checkInterrupter())
1121 if (mRadii.size() == 0)
1122 constantRadiusVoxelize(rng);
1124 perVertexRadiusVoxelize(rng);
1133 other.mGrid =
nullptr;
1155 constantRadiusVoxelize(
const tbb::blocked_range<size_t>& rng)
1159 for (
size_t i = rng.begin(); i < rng.end(); ++i) {
1160 for (
auto it = mPtPartitioner->indices(i); it; ++it) {
1161 const Index k = *it;
1162 const Vec2I& cell = mCells[k];
1163 voxelizer(mCoords[cell[0]], mCoords[cell[1]], mRad);
1169 perSegmentRadiusVoxelize(
const tbb::blocked_range<size_t>& rng)
1173 for (
size_t i = rng.begin(); i < rng.end(); ++i) {
1174 for (
auto it = mPtPartitioner->indices(i); it; ++it) {
1175 const Index k = *it;
1176 const Vec2I& cell = mCells[k];
1177 voxelizer(mCoords[cell[0]], mCoords[cell[1]], mRadii[k]);
1183 perVertexRadiusVoxelize(
const tbb::blocked_range<size_t>& rng)
1189 for (
size_t i = rng.begin(); i < rng.end(); ++i) {
1190 for (
auto it = mPtPartitioner->indices(i); it; ++it) {
1191 const Index k = *it;
1192 const Vec2I& cell = mCells[k];
1193 const Index32 &i = cell.
x(), &j = cell.
y();
1195 const Vec3T &pt1 = mCoords[i], &pt2 = mCoords[j];
1196 const ScalarType &r1 = mRadii[i], &r2 = mRadii[j];
1198 if ((pt1 - pt2).lengthSqr() <=
math::Pow2(r1-r2)) {
1200 c_voxelizer(pt1, pt1, r1);
1202 c_voxelizer(pt2, pt2, r2);
1203 }
else if (
math::Abs(r1-r2) < 0.001*mVox) {
1204 c_voxelizer(pt1, pt2, r1);
1206 tc_voxelizer(pt1, pt2, r1, r2);
1213 computeCentroids(std::vector<Vec3T>& centroids)
1217 centroids.resize(mCells.size());
1219 tbb::parallel_for(tbb::blocked_range<size_t>(0, centroids.size()),
1220 [&](
const tbb::blocked_range<size_t>& r) {
1221 for (
size_t i = r.begin(); i != r.end(); ++i) {
1222 const Vec2I &cell = mCells[i];
1224 if (cell[0] >= n || cell[1] >= n)
1227 centroids[i] = ScalarType(0.5) * (mCoords[cell[0]] + mCoords[cell[1]]);
1235 mGrid = createLevelSet<GridType>(mVox, mHw);
1239 initializePartitioner()
1241 std::vector<Vec3T> centroids;
1242 computeCentroids(centroids);
1246 mPtPartitioner = std::make_shared<PartitionerT>();
1247 mPtPartitioner->construct(points, mGrid->transform());
1254 openvdb::thread::cancelGroupExecution();
1260 static const std::vector<ScalarType>&
1262 static const std::vector<ScalarType>
empty;
1268 const float mVox, mHw;
1270 const ScalarType mRad;
1272 const std::vector<Vec3T>& mCoords;
1273 const std::vector<Vec2I>& mCells;
1274 const std::vector<ScalarType>& mRadii;
1276 std::shared_ptr<PartitionerT> mPtPartitioner;
1278 InterruptT* mInterrupter;
1291 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1292 typename GridType::Ptr
1294 const std::vector<Vec2I>& segments, ScalarType radius,
1295 float voxelSize,
float halfWidth, InterruptT* interrupter)
1297 static_assert(std::is_floating_point<ScalarType>::value);
1299 using GridPtr =
typename GridType::Ptr;
1300 using ValueT =
typename GridType::ValueType;
1304 static_assert(std::is_floating_point<ValueT>::value,
1305 "createLevelSetTubeComplex must return a scalar grid");
1310 ComplexVoxelizer
op(vertices, segments, radius, voxelSize, halfWidth, interrupter);
1312 const tbb::blocked_range<size_t> segmentRange(0, op.bucketSize());
1313 tbb::parallel_reduce(segmentRange, op);
1315 GridPtr tubegrid = op.getGrid();
1323 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1324 typename GridType::Ptr
1326 const std::vector<Vec2I>& segments,
const std::vector<ScalarType>& radii,
1327 float voxelSize,
float halfWidth,
TubeRadiiPolicy radii_policy, InterruptT* interrupter)
1329 static_assert(std::is_floating_point<ScalarType>::value);
1331 using GridPtr =
typename GridType::Ptr;
1332 using ValueT =
typename GridType::ValueType;
1337 static_assert(std::is_floating_point<ValueT>::value,
1338 "createLevelSetTubeComplex must return a scalar grid");
1344 if (vertices.size() != radii.size() && segments.size() != radii.size())
1346 "createLevelSetTubeComplex requires equal number of vertices and radii, or segments and radii, with automatic radii policy.");
1355 switch(resolved_radii_policy) {
1357 if (vertices.size() != radii.size())
1359 "createLevelSetTubeComplex requires equal number of vertices and radii with per-vertex radii policy.");
1361 TaperedCapsuleComplexVoxelizer
op(vertices, segments, radii,
1362 voxelSize, halfWidth, interrupter);
1364 const tbb::blocked_range<size_t> segmentRange(0, op.bucketSize());
1365 tbb::parallel_reduce(segmentRange, op);
1367 tubegrid = op.getGrid();
1371 if (segments.size() != radii.size())
1373 "createLevelSetTubeComplex requires equal number of segments and radii with per-segment radii policy.");
1375 CapsuleComplexVoxelizer
op(vertices, segments, radii,
1376 voxelSize, halfWidth, interrupter);
1378 const tbb::blocked_range<size_t> segmentRange(0, op.bucketSize());
1379 tbb::parallel_reduce(segmentRange, op);
1381 tubegrid = op.getGrid();
1396 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1397 typename GridType::Ptr
1399 ScalarType radius,
float voxelSize,
float halfWidth,
1400 InterruptT* interrupter,
bool threaded)
1402 static_assert(std::is_floating_point<ScalarType>::value);
1404 using GridPtr =
typename GridType::Ptr;
1405 using ValueT =
typename GridType::ValueType;
1409 static_assert(std::is_floating_point<ValueT>::value,
1410 "createLevelSetCapsule must return a scalar grid");
1415 GridPtr grid = createLevelSet<GridType>(voxelSize, halfWidth);
1417 CapsuleVoxelizer voxelizer(grid, threaded, interrupter);
1418 voxelizer(pt1, pt2, radius);
1423 template <
typename Gr
idType,
typename ScalarType>
1424 typename GridType::Ptr
1426 ScalarType radius,
float voxelSize,
float halfWidth,
bool threaded)
1428 return createLevelSetCapsule<GridType, ScalarType, util::NullInterrupter>(
1429 pt1, pt2, radius, voxelSize, halfWidth,
nullptr,
threaded);
1435 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1436 typename GridType::Ptr
1438 ScalarType radius1, ScalarType radius2,
1439 float voxelSize,
float halfWidth, InterruptT* interrupter,
bool threaded)
1441 static_assert(std::is_floating_point<ScalarType>::value);
1443 using GridPtr =
typename GridType::Ptr;
1444 using ValueT =
typename GridType::ValueType;
1449 static_assert(std::is_floating_point<ValueT>::value,
1450 "createLevelSetTaperedCapsule must return a scalar grid");
1455 GridPtr grid = createLevelSet<GridType>(voxelSize, halfWidth);
1457 if ((pt1 - pt2).lengthSqr() <=
math::Pow2(radius1 - radius2)) {
1459 CapsuleVoxelizer voxelizer(grid, threaded, interrupter);
1460 if (radius1 >= radius2)
1461 voxelizer(pt1, pt1, radius1);
1463 voxelizer(pt2, pt2, radius2);
1465 }
else if (
math::Abs(radius1 - radius2) < 0.001*voxelSize) {
1467 CapsuleVoxelizer voxelizer(grid, threaded, interrupter);
1468 voxelizer(pt1, pt2, radius1);
1472 TaperedCapsuleVoxelizer voxelizer(grid, threaded, interrupter);
1473 voxelizer(pt1, pt2, radius1, radius2);
1479 template <
typename Gr
idType,
typename ScalarType>
1480 typename GridType::Ptr
1482 ScalarType radius1, ScalarType radius2,
float voxelSize,
float halfWidth,
bool threaded)
1484 return createLevelSetTaperedCapsule<GridType, ScalarType, util::NullInterrupter>(
1485 pt1, pt2, radius1, radius2, voxelSize, halfWidth,
nullptr,
threaded);
1492 #endif // OPENVDB_TOOLS_LEVELSETTUBESIMPL_HAS_BEEN_INCLUDED
Definition: NodeManager.h:37
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
uint64_t Index64
Definition: Types.h:53
int Floor(float x)
Return the floor of x.
Definition: Math.h:848
Coord Abs(const Coord &xyz)
Definition: Coord.h:518
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
OPENVDB_IMPORT void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:761
float Cos(const float &x)
Return cos x.
Definition: Math.h:725
Index32 Index
Definition: Types.h:54
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
Definition: Math.h:349
openvdb::GridBase::Ptr GridPtr
Definition: Utils.h:44
Spatially partitions points using a parallel radix-based sorting algorithm.
Defined various multi-threaded utility functions for trees.
Base class used to generate the narrow-band level set of a convex region.
Definition: Exceptions.h:65
void foreachTopDown(const NodeOp &op, bool threaded=true, size_t leafGrainSize=1, size_t nonLeafGrainSize=1)
Threaded method that applies a user-supplied functor to all the nodes in the tree.
Definition: NodeManager.h:977
Base class for interrupters.
Definition: NullInterrupter.h:25
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:758
uint32_t Index32
Definition: Types.h:52
Definition: Exceptions.h:63
Type Pow2(Type x)
Return x2.
Definition: Math.h:548
Tolerance for floating-point comparison.
Definition: Math.h:148
float Sin(const float &x)
Return sin x.
Definition: Math.h:716
bool empty(const char *str)
tests if a c-string str is empty, that is its first value is '\0'
Definition: Util.h:144
Definition: Exceptions.h:13
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
Vec3< double > Vec3d
Definition: Vec3.h:665
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:220
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
Definition: Math.h:656
T & y()
Definition: Vec2.h:72
int Sign(const Type &x)
Return the sign of the given value as an integer (either -1, 0 or 1).
Definition: Math.h:736
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition: Math.h:595
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
void split(ContainerT &out, const std::string &in, const char delim)
Definition: Name.h:43
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec2.h:71
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:192
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218