14 #ifndef OPENVDB_TOOLS_LEVELSETDILATEDMESHIMPL_HAS_BEEN_INCLUDED
15 #define OPENVDB_TOOLS_LEVELSETDILATEDMESHIMPL_HAS_BEEN_INCLUDED
27 #include <tbb/parallel_for.h>
28 #include <tbb/parallel_reduce.h>
31 #include <type_traits>
47 template <
typename Gr
idType,
typename InterruptT = util::NullInterrupter>
51 OpenTriangularPrismVoxelizer<GridType, InterruptT>,
54 using GridPtr =
typename GridType::Ptr;
72 OpenTriangularPrismVoxelizer<GridType, InterruptT>,
87 InterruptT* interrupter =
nullptr)
98 template<
typename ScalarType>
112 setXYRangeData(
const Index& step = 1)
114 const ValueT &x1 = mPts[0].x(), &
x2 = mPts[1].x(), &x3 = mPts[2].x(),
115 &x4 = mPts[3].x(), &x5 = mPts[4].x(), &x6 = mPts[5].x();
117 const ValueT xmin =
math::Min(x1,
x2, x3, x4, x5, x6);
118 const ValueT xmax =
math::Max(x1,
x2, x3, x4, x5, x6);
119 mXYData.reset(xmin, xmax, step);
124 setXYSegmentRangeData<0,1,0>(step);
125 setXYSegmentRangeData<1,2,0>(step);
126 setXYSegmentRangeData<2,0,0>(step);
128 setXYSegmentRangeData<3,4,0>(step);
129 setXYSegmentRangeData<4,5,0>(step);
130 setXYSegmentRangeData<5,3,0>(step);
132 setXYSegmentRangeData<0,3,0>(step);
133 setXYSegmentRangeData<1,4,0>(step);
134 setXYSegmentRangeData<2,5,0>(step);
137 template<Index i, Index j,
int MinMax = 0>
139 setXYSegmentRangeData(
const Index& step = 1)
141 const ValueT &x1 = mPts[i].x(), &
x2 = mPts[
j].x();
150 stepv = ValueT(step);
152 for (ValueT
x = x_start;
x <= x_end;
x += stepv) {
153 if constexpr (MinMax <= 0)
155 if constexpr (MinMax >= 0)
156 mXYData.expandYMax(x, line2D<i,
j>(x));
162 signedDistance(const Vec3T& p)
const
164 return math::Abs(mTriNrml.dot(p - mA)) - mRad;
170 tilePointSignedDistance(
const Vec3T& p)
const
172 const Vec3T pa = p - mA,
187 math::
Abs(mTriNrml.
dot(p - mA));
193 tileCanFit(
const Index& dim)
const
198 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> prismBottomTop =
199 [
this](ValueT& zb, ValueT& zt,
const ValueT&
x,
const ValueT&
y)
201 zb = std::numeric_limits<ValueT>::lowest();
206 setPlaneBottomTop<0>(zb, zt,
x,
y);
207 setPlaneBottomTop<1>(zb, zt,
x,
y);
208 setPlaneBottomTop<2>(zb, zt,
x,
y);
209 setPlaneBottomTop<3>(zb, zt,
x,
y);
210 setPlaneBottomTop<4>(zb, zt,
x,
y);
217 setPlaneBottomTop(ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT&
y)
const
222 const ValueT
z = mPlaneXCoeffs[i]*x + mPlaneYCoeffs[i]*y + mPlaneOffsets[i];
224 if (mFaceNrmls[i].
z() < 0) {
235 template<
typename ScalarType>
237 initialize(
const math::Vec3<ScalarType>& pt1,
const math::Vec3<ScalarType>& pt2,
238 const math::Vec3<ScalarType>& pt3,
const ScalarType&
r)
253 mTriNrml = mBA.cross(mC-mA);
255 mBAXNrml = mTriNrml.cross(mBA);
256 mCBXNrml = mTriNrml.cross(mCB);
257 mACXNrml = mTriNrml.cross(mAC);
263 const ValueT len = mTriNrml.length();
270 const ValueT hwRad = mRad + hw;
275 mA + hwRad * mTriNrml, mB + hwRad * mTriNrml, mC + hwRad * mTriNrml,
276 mA - hwRad * mTriNrml, mB - hwRad * mTriNrml, mC - hwRad * mTriNrml
283 mTriNrml.cross(mA-mB).unitSafe(),
284 mTriNrml.cross(mB-mC).unitSafe(),
285 mTriNrml.cross(mC-mA).unitSafe()
289 static const std::vector<Index> p_ind = {0, 3, 0, 1, 2};
291 mPlaneXCoeffs.assign(5, ValueT(0));
292 mPlaneYCoeffs.assign(5, ValueT(0));
293 mPlaneOffsets.assign(5, ValueT(0));
295 for (
Index i = 0; i < 5; ++i) {
297 const ValueT cx = mFaceNrmls[i].x()/mFaceNrmls[i].z(),
298 cy = mFaceNrmls[i].y()/mFaceNrmls[i].z();
299 const Vec3T p = mPts[p_ind[i]];
300 mPlaneXCoeffs[i] = -cx;
301 mPlaneYCoeffs[i] = -cy;
302 mPlaneOffsets[i] = p.x()*cx + p.y()*cy + p.z();
314 template <Index i, Index j>
316 line2D(
const ValueT& x)
const
318 const ValueT &x1 = mPts[i].x(), &
y1 = mPts[i].y(),
319 &
x2 = mPts[
j].x(), &
y2 = mPts[
j].y();
321 const ValueT m = (
y2-
y1)/(
x2-x1);
323 return y1 + m * (x-x1);
332 Vec3T mBAXNrml, mCBXNrml, mACXNrml;
333 Vec3T mBANorm2, mCBNorm2, mACNorm2;
335 std::vector<Vec3T> mPts = std::vector<Vec3T>(6);
338 std::vector<Vec3T> mFaceNrmls = std::vector<Vec3T>(5);
340 std::vector<ValueT> mPlaneXCoeffs = std::vector<ValueT>(5),
341 mPlaneYCoeffs = std::vector<ValueT>(5),
342 mPlaneOffsets = std::vector<ValueT>(5);
352 template <
typename Gr
idType,
typename InterruptT = util::NullInterrupter>
356 OpenCapsuleWedgeVoxelizer<GridType, InterruptT>,
359 using GridPtr =
typename GridType::Ptr;
378 OpenCapsuleWedgeVoxelizer<GridType, InterruptT>,
392 InterruptT* interrupter =
nullptr)
407 template<
typename ScalarType>
415 if (
initialize(pt1, pt2, radius, nrml1, nrml2))
423 setXYRangeData(
const Index& step = 1)
425 const ValueT stepv = ValueT(step);
428 if (mX1 - mORad > mX2 + mORad) {
435 mXYData.reset(mX1 - mORad, mX1 + mORad, step);
437 for (ValueT x =
tileCeil(mX1 - mORad, step); x <= mX1 + mORad; x += stepv)
438 mXYData.expandYRange(x, circle1Bottom(x), circle1Top(x));
440 intersectWithXYWedgeLines();
446 const ValueT a0 = mX1 - mORad,
453 const ValueT tc0 =
tileCeil(a0, step),
461 for (ValueT x = tc0; x <= a1; x += stepv)
462 mXYData.expandYRange(x, circle1Bottom(x), circle1Top(x));
466 for (ValueT x = tc1; x <=
math::Min(a2, a3); x += stepv)
467 mXYData.expandYRange(x, lineBottom(x), circle1Top(x));
469 for (ValueT x = tc1; x <=
math::Min(a2, a3); x += stepv)
470 mXYData.expandYRange(x, circle1Bottom(x), lineTop(x));
475 for (ValueT x = tc2; x <= a3; x += stepv)
476 mXYData.expandYRange(x, lineBottom(x), lineTop(x));
479 for (ValueT x = tc3; x <= a2; x += stepv)
480 mXYData.expandYRange(x, circle2Bottom(x), circle1Top(x));
482 for (ValueT x = tc3; x <= a2; x += stepv)
483 mXYData.expandYRange(x, circle1Bottom(x), circle2Top(x));
489 for (ValueT x =
math::Max(tc2, tc3); x <= a4; x += stepv)
490 mXYData.expandYRange(x, circle2Bottom(x), lineTop(x));
492 for (ValueT x =
math::Max(tc2, tc3); x <= a4; x += stepv)
493 mXYData.expandYRange(x, lineBottom(x), circle2Top(x));
497 for (ValueT x = tc4; x <= a5; x += stepv)
498 mXYData.expandYRange(x, circle2Bottom(x), circle2Top(x));
500 intersectWithXYStrip();
501 intersectWithXYWedgeLines();
505 intersectWithXYStrip()
511 const Vec3T &pp1 = mPlanePts[0], &pp2 = mPlanePts[1];
512 const ValueT &vx = mV.x(), &vy = mV.y();
515 Vec3T cvec = mORad * Vec3T(-vy, vx, ValueT(0)).unitSafe();
522 const Vec3T cpmin(mPt1 - cvec), cpmax(mPt1 + cvec);
525 const ValueT px = mPt1.x(),
530 intersectWithXYHalfSpace(n.x() < 0 ? n : -
n,
Vec2T(xmin, ValueT(0)));
533 intersectWithXYHalfSpace(n.x() > 0 ? n : -
n,
Vec2T(xmax, ValueT(0)));
535 const ValueT m = mYdiff/mXdiff;
536 const ValueT
y1 = mPt1.y() - m * mPt1.x(),
537 y2 = pp1.y() - m * pp1.x(),
538 y3 = pp2.y() - m * pp2.x();
542 if (!inWedge(vy <= 0 ? cpmin : cpmax))
543 intersectWithXYHalfSpace(n.y() < 0 ? n : -
n,
Vec2T(ValueT(0), ymin));
545 if (!inWedge(vy > 0 ? cpmin : cpmax))
546 intersectWithXYHalfSpace(n.y() > 0 ? n : -
n,
Vec2T(ValueT(0), ymax));
551 intersectWithXYWedgeLines()
553 const Vec3T
v(mORad * mV.unitSafe()),
557 const Vec2T p1_2d(p1.x(), p1.y()), p2_2d(p2.x(), p2.y());
559 Vec2T d(-mPlaneNrmls[0].
x() - mPlaneNrmls[1].
x(),
560 -mPlaneNrmls[0].
y() - mPlaneNrmls[1].
y());
562 Vec2T n0(-mDirVectors[0].
y(), mDirVectors[0].
x()),
563 n1(-mDirVectors[1].
y(), mDirVectors[1].
x());
571 intersectWithXYHalfSpace(n0, n0.dot(p2_2d - p1_2d) < 0 ? p1_2d : p2_2d);
574 intersectWithXYHalfSpace(n1, n1.dot(p2_2d - p1_2d) < 0 ? p1_2d : p2_2d);
578 intersectWithXYHalfSpace(
const Vec2T& n,
const Vec2T& p)
584 const ValueT &px = p.x();
587 for (
Index i = 0; i < m; ++i) {
588 const ValueT x =
mXYData.getX(i);
590 if (x < px)
mXYData.clearYRange(x);
596 const ValueT x =
mXYData.getX(i);
598 if (x > px)
mXYData.clearYRange(x);
606 const bool set_min = n.y() < 0;
609 const ValueT
b = -n.x()/n.y();
610 const ValueT
a = p.y() - b * p.x();
612 ValueT
x, ymin, ymax;
613 for (
Index i = 0; i < m; ++i) {
614 mXYData.XYData(x, ymin, ymax, i);
615 const ValueT yint = a + b *
x;
617 if (ymin <= yint && yint <= ymax) {
618 if (set_min)
mXYData.setYMin(x, yint);
621 if (set_min ? yint > ymax : yint < ymin)
632 signedDistance(
const Vec3T& p)
const
634 const Vec3T
w = p - mPt1;
635 const ValueT
dot = w.dot(mV);
639 return w.length() - mRad;
642 return (p - mPt2).length() - mRad;
644 const ValueT
t = w.dot(mV)/mVLenSqr;
646 return (w - t * mV).length() - mRad;
650 tileCanFit(
const Index& dim)
const
655 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> capsuleBottomTopVertical =
656 [
this](ValueT& zb, ValueT& zt,
const ValueT&
x,
const ValueT&
y)
661 return std::isfinite(zb) && std::isfinite(zt);
664 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)> capsuleBottomTop =
665 [
this](ValueT& zb, ValueT& zt,
const ValueT&
x,
const ValueT&
y)
667 ValueT cylptb, cylptt;
668 if (!infiniteCylinderBottomTop(cylptb, cylptt, x, y))
671 const ValueT dotb = (Vec3T(x, y, cylptb) - mPt1).
dot(mV);
672 const ValueT dott = (Vec3T(x, y, cylptt) - mPt1).
dot(mV);
675 zb = sphere1Bottom(x, y);
676 else if (dotb > mVLenSqr)
677 zb = sphere2Bottom(x, y);
682 zt = sphere1Top(x, y);
683 else if (dott > mVLenSqr)
684 zt = sphere2Top(x, y);
688 if (!std::isfinite(zb) || !std::isfinite(zt))
691 intersectWedge<0,1>(zb, zt,
x,
y);
692 intersectWedge<1,0>(zb, zt,
x,
y);
694 return inWedge(x, y, ValueT(0.5)*(zb+zt));
697 template<Index i, Index j>
699 intersectWedge(ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT& y)
701 const Vec3T& n0 = mPlaneNrmls[i];
706 const ValueT zp = mPlaneXCoeffs[i]*x + mPlaneYCoeffs[i]*y + mPlaneOffsets[i];
708 if (zb <= zp && zp <= zt && inHalfSpace<j>(Vec3T(x, y, zp))) {
717 inWedge(
const ValueT& x,
const ValueT& y,
const ValueT& z)
719 return inWedge(Vec3T(x, y, z));
723 inWedge(
const Vec3T& pt)
725 return inHalfSpace<0>(pt) && inHalfSpace<1>(pt);
730 inHalfSpace(
const Vec3T& pt)
735 static const ValueT VOXFRAC = 0.125;
737 return mPlaneNrmls[i].dot(pt-mPt1) <= VOXFRAC;
742 infiniteCylinderBottomTop(ValueT& cylptb, ValueT& cylptt,
743 const ValueT& x,
const ValueT& y)
const
747 const Vec2T qproj = mPt12d + mV2d*((
q - mPt12d).
dot(mV2d))/mXYNorm2;
749 const ValueT t = mX1 != mX2 ? (qproj[0] - mX1)/mXdiff : (qproj[1] - mY1)/mYdiff;
751 const Vec3T qproj3D = mPt1 + t * mV;
753 const ValueT d2 = (
q - qproj).lengthSqr();
759 const ValueT
h =
math::Sqrt((mORad2 - d2) * mVLenSqr/mXYNorm2);
761 cylptb = qproj3D[2] -
h;
762 cylptt = qproj3D[2] +
h;
768 lineBottom(
const ValueT& x)
const
770 return mY1 + (mYdiff*(x-mX1) - mORad * mXYNorm)/mXdiff;
774 lineTop(
const ValueT& x)
const
776 return mY1 + (mYdiff*(x-mX1) + mORad * mXYNorm)/mXdiff;
780 circle1Bottom(
const ValueT& x)
const
786 circle1Top(
const ValueT& x)
const
792 circle2Bottom(
const ValueT& x)
const
798 circle2Top(
const ValueT& x)
const
804 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const
810 sphere1Top(
const ValueT& x,
const ValueT& y)
const
816 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const
822 sphere2Top(
const ValueT& x,
const ValueT& y)
const
829 template<
typename ScalarType>
831 initialize(
const math::Vec3<ScalarType>& pt1,
const math::Vec3<ScalarType>& pt2,
832 const ScalarType& r,
const math::Vec3<ScalarType>& nrml1,
833 const math::Vec3<ScalarType>& nrml2)
839 if (pt1[0] <= pt2[0]) {
840 mPt1 = Vec3T(pt1)/vx;
841 mPt2 = Vec3T(pt2)/vx;
843 mPt1 = Vec3T(pt2)/vx;
844 mPt2 = Vec3T(pt1)/vx;
851 mORad2 = mORad * mORad;
858 mVLenSqr = mV.lengthSqr();
864 mX1 = mPt1[0]; mY1 = mPt1[1]; mZ1 = mPt1[2];
865 mX2 = mPt2[0]; mY2 = mPt2[1]; mZ2 = mPt2[2];
871 mPt12d =
Vec2T(mX1, mY1);
872 mPt22d =
Vec2T(mX2, mY2);
873 mV2d = mPt22d - mPt12d;
880 const Vec3T n1 = Vec3T(nrml1), n2 = Vec3T(nrml2);
886 mPlaneNrmls[0] = (n1 - n1.projection(mV)).unitSafe();
887 mPlaneNrmls[1] = (n2 - n2.projection(mV)).unitSafe();
890 if (approxAntiParallel(mPlaneNrmls[0], mPlaneNrmls[1]))
893 mDirVectors[0] = mORad * mV.cross(mPlaneNrmls[0]).unitSafe();
894 mDirVectors[1] = mORad * mV.cross(mPlaneNrmls[1]).unitSafe();
896 if (approxParallel(mPlaneNrmls[0], mPlaneNrmls[1])) {
897 mDirVectors[1] = -mDirVectors[0];
899 if (mPlaneNrmls[1].
dot(mDirVectors[0]) > 0)
900 mDirVectors[0] *= ValueT(-1);
901 if (mPlaneNrmls[0].
dot(mDirVectors[1]) > 0)
902 mDirVectors[1] *= ValueT(-1);
905 mPlanePts[0] = mPt1 + mDirVectors[0] + ValueT(0.025) * mPlaneNrmls[0];
906 mPlanePts[1] = mPt1 + mDirVectors[1] + ValueT(0.025) * mPlaneNrmls[1];
910 mPlaneXCoeffs.assign(2, ValueT(0));
911 mPlaneYCoeffs.assign(2, ValueT(0));
912 mPlaneOffsets.assign(2, ValueT(0));
914 for (
Index i = 0; i < 2; ++i) {
916 const ValueT cx = mPlaneNrmls[i].x()/mPlaneNrmls[i].z(),
917 cy = mPlaneNrmls[i].y()/mPlaneNrmls[i].z();
918 const Vec3T p = mPlanePts[i];
919 mPlaneXCoeffs[i] = -cx;
920 mPlaneYCoeffs[i] = -cy;
921 mPlaneOffsets[i] = p.x()*cx + p.y()*cy + p.z();
926 BaseT::bottomTop = mIsVertical ? capsuleBottomTopVertical : capsuleBottomTop;
932 approxAntiParallel(
const Vec3T& n1,
const Vec3T& n2)
934 return approxParallel(n1, -n2);
938 approxParallel(
const Vec3T& n1,
const Vec3T& n2)
940 return n1.unitSafe().eq(n2.unitSafe());
947 Vec3T mPt1, mPt2, mV;
949 Vec2T mPt12d, mPt22d, mV2d;
951 ValueT mORad, mORad2, mRad, mVLenSqr, mXdiff, mYdiff, mZdiff, mXYNorm, mXYNorm2;
953 ValueT mX1, mY1, mZ1, mX2, mY2, mZ2;
957 std::vector<Vec3T> mPlaneNrmls = std::vector<Vec3T>(2),
958 mDirVectors = std::vector<Vec3T>(2),
959 mPlanePts = std::vector<Vec3T>(2);
961 std::vector<ValueT> mPlaneXCoeffs = std::vector<ValueT>(2),
962 mPlaneYCoeffs = std::vector<ValueT>(2),
963 mPlaneOffsets = std::vector<ValueT>(2);
972 template<
typename ValueT>
987 const std::vector<Vec3I>& cells)
988 : mCoords(coords), mCells(cells)
992 mNormals.resize(cells.size());
994 for (
Index i = 0; i < cells.size(); ++i) {
995 const Vec3I& cell = mCells[i];
998 Edge(cell[0], cell[1]),
999 Edge(cell[1], cell[2]),
1000 Edge(cell[2], cell[0])
1003 for (
const Edge& edge : edges) {
1004 mEdgeMap[edge].push_back(i);
1007 if (cell[0] >= n || cell[1] >= n || cell[2] >= n)
1010 const Vec3T &p1 = mCoords[cell[0]],
1011 &p2 = mCoords[cell[1]],
1012 &p3 = mCoords[cell[2]];
1014 mNormals[i] = (p2 - p1).
cross(p3 - p1).unitSafe();
1017 for (
auto& [edge, cells] : mEdgeMap)
1018 sortAdjacentCells(edge, cells);
1031 auto it = mEdgeMap.find(edge);
1032 if (it != mEdgeMap.end()) {
1033 cellIds = it->second;
1043 template <
typename T>
1056 template <
typename T>
1070 template <
typename T>
1071 inline std::vector<Vec3T>
1076 const Vec3I cell = mCells[i];
1078 return {mCoords[cell[0]], mCoords[cell[1]], mCoords[cell[2]]};
1085 template <
typename T>
1100 return mCoords.size();
1109 return mCells.size();
1117 : mV1(std::
min(v1, v2)), mV2(std::
max(v1, v2))
1123 return mV1 < e.mV1 || (mV1 == e.mV1 && mV2 < e.mV2);
1128 centroid(Index cellIdx)
const
1130 const Vec3I cell = mCells[cellIdx];
1131 return (mCoords[cell[0]] + mCoords[cell[1]] + mCoords[cell[2]]) / 3.0;
1135 onSameHalfPlane(
const Vec3T &n,
const Vec3T& p0,
const Vec3T &p1,
const Vec3T &p2)
1141 sortAdjacentCells(
const Edge& edge, std::vector<Index>& cells)
1143 if (cells.size() <= 2)
return;
1145 const Vec3I &base_cell = mCells[cells[0]];
1148 const Index p1Ind = base_cell[0] + base_cell[1] + base_cell[2] -
offset;
1150 const Vec3T &p1 = mCoords[p1Ind],
1151 &n1 = mNormals[cells[0]];
1153 const Vec3T p0 = mCoords[edge.mV1];
1155 Vec3T bi_nrml = n1.cross(p0 - mCoords[edge.mV2]);
1156 if (bi_nrml.dot(p1 - p0) > 0)
1157 bi_nrml *= ValueT(-1);
1159 auto windingamount = [&](
Index cellIdx)
1161 if (cellIdx == 0)
return 0.0f;
1163 const Vec3I &cell = mCells[cellIdx];
1164 const Index p2Ind = cell[0] + cell[1] + cell[2] -
offset;
1166 const Vec3T &p2 = mCoords[p2Ind],
1167 &n2 = mNormals[cellIdx];
1169 const ValueT cos_theta =
math::Abs(n1.dot(n2));
1175 ? ValueT(1) + ValueT(sgn2) * cos_theta
1176 : ValueT(3) - ValueT(sgn2) * cos_theta
1178 : (onSameHalfPlane(bi_nrml, p0, p1, p2) ? ValueT(0) : ValueT(2));
1182 return windingamount(t1) < windingamount(t2);
1188 const std::vector<Vec3T>& mCoords;
1189 const std::vector<Vec3I>& mCells;
1191 std::vector<Vec3T> mNormals;
1193 std::map<Edge, std::vector<Index>> mEdgeMap;
1205 typename InterruptT = util::NullInterrupter,
bool PtPartition =
true>
1208 using GridPtr =
typename GridType::Ptr;
1209 using TreeT =
typename GridType::TreeType;
1210 using LeafT =
typename TreeT::LeafNodeType;
1237 , mVox(voxelSize), mHw(halfWidth), mRad(radius)
1238 , mInterrupter(interrupter)
1242 if constexpr (PtPartition)
1243 initializePartitioner();
1245 mPVoxelizer = std::make_shared<PrismVoxelizer>(mGrid,
false);
1246 mWVoxelizer = std::make_shared<WedgeVoxelizer>(mGrid,
false);
1250 : mMesh(other.mMesh), mVox(other.mVox), mHw(other.mHw)
1251 , mRad(other.mRad), mInterrupter(other.mInterrupter)
1252 , mPtPartitioner(other.mPtPartitioner)
1256 mPVoxelizer = std::make_shared<PrismVoxelizer>(mGrid,
false);
1257 mWVoxelizer = std::make_shared<WedgeVoxelizer>(mGrid,
false);
1262 if (!checkInterrupter())
1265 if constexpr (PtPartition) {
1266 for (
size_t i = rng.begin(); i < rng.end(); ++i)
1267 for (
auto it = mPtPartitioner->indices(i); it; ++it)
1268 voxelizeTriangle(*it);
1270 for (
size_t i = rng.begin(); i < rng.end(); ++i)
1271 voxelizeTriangle(i);
1281 other.mGrid =
nullptr;
1293 affinelyIndependent(
const Vec3T& p1,
const Vec3T& p2,
const Vec3T& p3)
const
1295 const Vec3T n = (p2-p1).
cross(p3-p1);
1302 voxelizeTriangle(
const size_t& i)
1304 const Vec3I &cell = mMesh->getCell(i);
1305 const std::vector<Vec3T> pts = mMesh->getPrimitive(i);
1308 if (!affinelyIndependent(pts[0], pts[1], pts[2])) {
1309 voxelizeCapsule(pts[0], pts[1], pts[2]);
1314 (*mPVoxelizer)(pts[0], pts[1], pts[2], mRad);
1316 std::vector<Index> cellIds;
1321 const bool success = mMesh->getAdjacentCells(cell[
j], cell[(j+1) % 3], cellIds);
1322 if (success && cellIds[0] == i) {
1323 if (findWedgeNormals(
Index(i), j, cellIds, n1, n2))
1324 (*mWVoxelizer)(pts[
j], pts[(j+1) % 3], mRad, n1, n2);
1330 voxelizeCapsule(
const Vec3T& p1,
const Vec3T& p2,
const Vec3T& p3)
1332 lvlset::CapsuleVoxelizer<GridType, InterruptT> voxelizer(mGrid,
false);
1334 ScalarType d1 = (p2-p1).lengthSqr(),
1335 d2 = (p3-p2).lengthSqr(),
1336 d3 = (p1-p3).lengthSqr();
1338 ScalarType maxd =
math::Max(d1, d2, d3);
1341 voxelizer(p1, p2, mRad);
1342 else if (maxd == d2)
1343 voxelizer(p2, p3, mRad);
1345 voxelizer(p3, p1, mRad);
1349 findWedgeNormals(
const Index& cellIdx,
const Index& vIdx,
1350 const std::vector<Index>& cellIds, Vec3T& n1, Vec3T& n2)
const
1352 if (cellIds.size() == 1)
1353 return findWedgeNormals1(cellIdx, vIdx, n1, n2);
1354 else if (cellIds.size() == 2)
1355 return findWedgeNormals2(cellIdx, vIdx, cellIds[1], n1, n2);
1356 else if (cellIds.size() > 2)
1357 return findWedgeNormals3(cellIdx, vIdx, cellIds, n1, n2);
1363 findWedgeNormals1(
const Index& cellIdx,
const Index& vIdx,
1364 Vec3T& n1, Vec3T& n2)
const
1366 const Vec3I &cell = mMesh->getCell(cellIdx);
1367 const Vec3T &p1 = mMesh->getCoord(cell[vIdx]),
1368 &p2 = mMesh->getCoord(cell[(vIdx+1) % 3]),
1369 &p3 = mMesh->getCoord(cell[(vIdx+2) % 3]);
1371 const Vec3T &n = mMesh->getNormal(cellIdx);
1373 n1 = n.
cross(p2-p1).unitSafe();
1374 if (n1.dot(p3-p1) < 0) n1 *= -1.0
f;
1382 findWedgeNormals2(
const Index& cellIdx,
const Index& vIdx,
1383 const Index& cellIdx2, Vec3T& n1, Vec3T& n2)
const
1385 const Vec3I &cell = mMesh->getCell(cellIdx),
1386 &cell2 = mMesh->getCell(cellIdx2);
1388 const Index cIdx2 = cell2[0] + cell2[1] + cell2[2] - cell[vIdx] - cell[(vIdx+1) % 3];
1390 const Vec3T &p1 = mMesh->getCoord(cell[vIdx]),
1391 &p2 = mMesh->getCoord(cell[(vIdx+1) % 3]),
1392 &p3 = mMesh->getCoord(cell[(vIdx+2) % 3]),
1393 &p4 = mMesh->getCoord(cIdx2);
1395 const Vec3T &nrml1 = mMesh->getNormal(cellIdx),
1396 &nrml2 = mMesh->getNormal(cellIdx2);
1398 n1 = nrml1.cross(p2-p1).unitSafe(),
1399 n2 = nrml2.cross(p2-p1).unitSafe();
1401 if (n1.dot(p3-p1) < 0) n1 *= -1.0
f;
1402 if (n2.dot(p4-p1) < 0) n2 *= -1.0
f;
1408 findWedgeNormals3(
const Index& cellIdx,
const Index& vIdx,
1409 const std::vector<Index>& cellIds, Vec3T& n1, Vec3T& n2)
const
1411 const Vec3I &cell = mMesh->getCell(cellIdx);
1413 const Index64 n = cellIds.size();
1414 const Index offset = cell[vIdx] + cell[(vIdx+1) % 3];
1417 const Vec3I &cell0 = mMesh->getCell(cellIds[i]),
1418 &cell1 = mMesh->getCell(cellIds[(i+1) % n]),
1419 &cell2 = mMesh->getCell(cellIds[(i+2) % n]);
1421 const Index cIdx0 = cell0[0] + cell0[1] + cell0[2] -
offset,
1422 cIdx1 = cell1[0] + cell1[1] + cell1[2] -
offset,
1423 cIdx2 = cell2[0] + cell2[1] + cell2[2] -
offset;
1425 const Vec3T &p0 = mMesh->getCoord(cIdx0),
1426 &p1 = mMesh->getCoord(cIdx1),
1427 &p2 = mMesh->getCoord(cIdx2);
1429 Vec3T nrml0 = mMesh->getNormal(cellIds[i]),
1430 nrml1 = mMesh->getNormal(cellIds[(i+1) % n]);
1432 if (nrml0.dot(p1-p0) > 0) nrml0 *= ScalarType(-1);
1433 if (nrml1.dot(p0-p1) > 0) nrml1 *= ScalarType(-1);
1435 if (nrml0.dot(p2-p0) > 0 || nrml1.dot(p2-p1) > 0)
1439 if (cell0[0] == cell[vIdx])
1440 vIdxi = cell0[1] == cell[(vIdx+1) % 3] ? 0 : 2;
1441 else if (cell0[1] == cell[vIdx])
1442 vIdxi = cell0[2] == cell[(vIdx+1) % 3] ? 1 : 0;
1444 vIdxi = cell0[0] == cell[(vIdx+1) % 3] ? 2 : 1;
1446 return findWedgeNormals2(cellIds[i], vIdxi, cellIds[(i+1) % n], n1, n2);
1453 computeCentroids(std::vector<Vec3T>& centroids)
1455 centroids.resize(mMesh->cellCount());
1458 [&](
const tbb::blocked_range<size_t>& r) {
1459 for (
size_t i = r.begin(); i != r.end(); ++i) {
1460 const std::vector<Vec3T> prim = mMesh->getPrimitive(i);
1461 centroids[i] = (prim[0] + prim[1] + prim[2]) / ScalarType(3);
1469 mGrid = createLevelSet<GridType>(mVox, mHw);
1473 initializePartitioner()
1475 std::vector<Vec3T> centroids;
1476 computeCentroids(centroids);
1478 lvlset::PointArray<Vec3T>
points(centroids);
1480 mPtPartitioner = std::make_shared<PartitionerT>();
1481 mPtPartitioner->construct(
points, mGrid->transform());
1488 openvdb::thread::cancelGroupExecution();
1496 std::shared_ptr<const MeshConnectivity> mMesh;
1498 const float mVox, mHw;
1500 const ScalarType mRad;
1502 InterruptT* mInterrupter;
1506 std::shared_ptr<PartitionerT> mPtPartitioner;
1508 std::shared_ptr<PrismVoxelizer> mPVoxelizer;
1509 std::shared_ptr<WedgeVoxelizer> mWVoxelizer;
1518 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1519 typename GridType::Ptr
1526 using GridPtr =
typename GridType::Ptr;
1532 "createLevelSetDilatedMesh must return a scalar grid");
1534 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1535 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
1537 Voxelizer
op(vertices, triangles, radius, voxelSize, halfWidth, interrupter);
1539 const tbb::blocked_range<size_t> triangleRange(0, op.bucketSize());
1540 tbb::parallel_reduce(triangleRange, op);
1542 GridPtr grid = op.getGrid();
1548 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1549 typename GridType::Ptr
1559 "createLevelSetDilatedMesh must return a scalar grid");
1561 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1562 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
1564 const Index64 n = quads.size();
1565 std::vector<Vec3I> triangles(2*n);
1568 [&](
const tbb::blocked_range<size_t>& r) {
1569 for (
Index64 i = r.begin(); i != r.end(); ++i) {
1570 const Vec4I&
q = quads[i];
1571 triangles[i] =
Vec3I(q.
x(), q.
y(), q.
z());
1572 triangles[i +
n] =
Vec3I(q.
x(), q.
z(), q.
w());
1576 return createLevelSetDilatedMesh<GridType, ScalarType, InterruptT>(
1580 template <
typename Gr
idType,
typename ScalarType,
typename InterruptT>
1581 typename GridType::Ptr
1583 const std::vector<Vec3I>& triangles,
const std::vector<Vec4I>&
quads,
1591 "createLevelSetDilatedMesh must return a scalar grid");
1593 if (voxelSize <= 0)
OPENVDB_THROW(ValueError,
"voxel size must be positive");
1594 if (halfWidth <= 0)
OPENVDB_THROW(ValueError,
"half-width must be positive");
1597 return createLevelSetDilatedMesh<GridType, ScalarType, InterruptT>(
1598 vertices, triangles, radius, voxelSize, halfWidth, interrupter);
1600 const Index64 tn = triangles.size(), qn = quads.size();
1602 std::vector<Vec3I> tris(tn + 2*qn);
1605 [&](
const tbb::blocked_range<size_t>& r) {
1606 for (
Index64 i = r.begin(); i != r.end(); ++i) {
1607 tris[i] = triangles[i];
1612 [&](
const tbb::blocked_range<size_t>& r) {
1613 for (
Index64 i = r.begin(); i != r.end(); ++i) {
1614 const Vec4I&
q = quads[i];
1615 tris[i + tn] =
Vec3I(q.
x(), q.
y(), q.
z());
1616 tris[i + qn2] =
Vec3I(q.
x(), q.
z(), q.
w());
1620 return createLevelSetDilatedMesh<GridType, ScalarType, InterruptT>(
1628 #endif // OPENVDB_TOOLS_LEVELSETDILATEDMESHIMPL_HAS_BEEN_INCLUDED
GU_API exint quads(GU_Detail *gdp, UT_Array< GA_OffsetArray > &rings, UT_Array< GA_OffsetArray > &originalRings, GA_PrimitiveGroup *patchgroup, GA_PrimitiveGroup *loopgroup, bool smooth, fpreal smoothstrength, bool edgeloop, fpreal edgeloopPercentage)
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
GLdouble GLdouble GLdouble z
GLboolean GLboolean GLboolean GLboolean a
#define OPENVDB_USE_VERSION_NAMESPACE
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
PUGI__FN void sort(I begin, I end, const Pred &pred)
GLfloat GLfloat GLfloat v2
GLdouble GLdouble GLdouble q
Generate a narrow-band level set of a capsule, tapered capsule, and tube complex. ...
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.
bool operator<(const GU_TetrahedronFacet &a, const GU_TetrahedronFacet &b)
Vec3< T > cross(const Vec3< T > &v) const
Return the cross product of "this" vector and v;.
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
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...
GLboolean GLboolean GLboolean b
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
math::Vec3< Index32 > Vec3I
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
GLubyte GLubyte GLubyte GLubyte w
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.
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
#define OPENVDB_THROW(exception, message)
Type Clamp01(Type x)
Return x clamped to [0, 1].