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;
73 CapsuleVoxelizer<GridType, InterruptT>,
87 InterruptT* interrupter =
nullptr)
97 template<
typename ScalarType>
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),
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)
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
362 circle1Top(
const ValueT& x)
const
368 circle2Bottom(
const ValueT& x)
const
374 circle2Top(
const ValueT& x)
const
380 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const
386 sphere1Top(
const ValueT& x,
const ValueT& y)
const
392 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const
398 sphere2Top(
const ValueT& x,
const ValueT& y)
const
405 template<
typename ScalarType>
408 const math::Vec3<ScalarType>& pt2,
const ScalarType&
r)
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;
495 TaperedCapsuleVoxelizer<GridType, InterruptT>,
509 InterruptT* interrupter =
nullptr)
520 template<
typename ScalarType>
523 const ScalarType& radius1,
const ScalarType& radius2)
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.");
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)
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),
628 for (; x <=
x2; x += step, y += delta)
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 = {
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.0
f) {
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
857 circle1Top(
const ValueT& x)
const
863 circle2Bottom(
const ValueT& x)
const
869 circle2Top(
const ValueT& x)
const
875 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const
881 sphere1Top(
const ValueT& x,
const ValueT& y)
const
887 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const
893 sphere2Top(
const ValueT& x,
const ValueT& y)
const
900 template<
typename ScalarType>
902 initialize(
const math::Vec3<ScalarType>& pt1,
const math::Vec3<ScalarType>& pt2,
903 const ScalarType& r1,
const ScalarType& r2)
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));
937 const math::Vec3<ScalarType> pt_0 = r2 <= r1 ? pt1 : pt2;
938 const ScalarType r_0 = r2 <= r1 ? r1 : r2;
940 const math::Vec3<ScalarType> pt_mid = t*pt1 + (ScalarType(1)-
t)*pt2;
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;
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;
1025 typename InterruptT = util::NullInterrupter,
bool PerSegmentRadii =
true>
1028 using GridPtr =
typename GridType::Ptr;
1029 using TreeT =
typename GridType::TreeType;
1030 using LeafT =
typename TreeT::LeafNodeType;
1051 : mVox(voxelSize), mHw(halfWidth), mRad(radius)
1052 , mCoords(vertices), mCells(segments), mRadii(getEmptyVector())
1053 , mInterrupter(interrupter)
1056 initializePartitioner();
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)
1171 CapsuleVoxelizer<GridType, InterruptT> voxelizer(mGrid,
false);
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)
1185 TaperedCapsuleVoxelizer<GridType, InterruptT> tc_voxelizer(mGrid,
false);
1187 CapsuleVoxelizer<GridType, InterruptT> c_voxelizer(mGrid,
false);
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());
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);
1244 lvlset::PointArray<Vec3T>
points(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)
1299 using GridPtr =
typename GridType::Ptr;
1305 "createLevelSetTubeComplex must return a scalar grid");
1307 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1308 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
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)
1331 using GridPtr =
typename GridType::Ptr;
1338 "createLevelSetTubeComplex must return a scalar grid");
1340 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1341 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
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)
1404 using GridPtr =
typename GridType::Ptr;
1410 "createLevelSetCapsule must return a scalar grid");
1412 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1413 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
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)
1443 using GridPtr =
typename GridType::Ptr;
1450 "createLevelSetTaperedCapsule must return a scalar grid");
1452 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1453 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
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
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
GLdouble GLdouble GLint GLint const GLdouble * points
Type Pow2(Type x)
Return x2.
GridType
List of types that are currently supported by NanoVDB.
GLsizei const GLfloat * value
vfloat4 sqrt(const vfloat4 &a)
GLdouble GLdouble GLdouble z
#define OPENVDB_USE_VERSION_NAMESPACE
float Cos(const float &x)
Return cos x.
GLdouble GLdouble GLdouble q
Spatially partitions points using a parallel radix-based sorting algorithm.
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.
Coord Abs(const Coord &xyz)
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
OIIO_UTIL_API void parallel_for(int32_t begin, int32_t end, function_view< void(int32_t)> task, paropt opt=0)
float Sqrt(float x)
Return the square root of a floating-point value.
Defined various multi-threaded utility functions for trees.
math::Vec2< Index32 > Vec2I
GLfloat GLfloat GLfloat alpha
Tag dispatch class that distinguishes constructors that steal.
OPENVDB_API void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
GLfloat GLfloat GLfloat GLfloat h
int Sign(const Type &x)
Return the sign of the given value as an integer (either -1, 0 or 1).
IMATH_NAMESPACE::V2f IMATH_NAMESPACE::Box2i std::string this attribute is obsolete as of OpenEXR v3 float
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
int Floor(float x)
Return the floor of x.
GLubyte GLubyte GLubyte GLubyte w
float Sin(const float &x)
Return sin x.
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
GLdouble GLdouble GLdouble y2
bool wasInterrupted(T *i, int percent=-1)
Base class used to generate the narrow-band level set of a convex region.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
#define OPENVDB_THROW(exception, message)