51 OpenTriangularPrismVoxelizer<GridType, InterruptT>,
54 using GridPtr =
typename GridType::Ptr;
87 InterruptT* interrupter =
nullptr)
98 template<
typename ScalarType>
103 static_assert(std::is_floating_point<ScalarType>::value);
105 if (initialize(pt1, pt2, pt3, radius))
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();
145 if (tileCeil(x1, step) == tileCeil(x2, step))
148 const ValueT x_start = tileCeil(
math::Min(x1, x2), step),
150 stepv = ValueT(step);
152 for (ValueT x = x_start; x <= x_end; x += stepv) {
153 if constexpr (MinMax <= 0)
154 mXYData.expandYMin(x, line2D<i,j>(x));
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,
177 math::Sign(mBAXNrml.dot(pa)) +
178 math::Sign(mCBXNrml.dot(pb)) +
179 math::Sign(mACXNrml.dot(pc)) < 2
181 math::Sqrt(math::Min(
182 (mBA * math::Clamp01(mBANorm2.dot(pa)) - pa).lengthSqr(),
183 (mCB * math::Clamp01(mCBNorm2.dot(pb)) - pb).lengthSqr(),
184 (mAC * math::Clamp01(mACNorm2.dot(pc)) - pc).lengthSqr()
187 math::Abs(mTriNrml.dot(p - mA));
193 tileCanFit(
const Index& dim)
const
195 return mRad >= BaseT::halfWidth() + ValueT(0.5) * (ValueT(dim)-ValueT(1));
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();
202 zt = std::numeric_limits<ValueT>::max();
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
219 if (math::isApproxZero(mFaceNrmls[i].z()))
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)
240 const ValueT vx = BaseT::voxelSize(),
241 hw = BaseT::halfWidth();
253 mTriNrml = mBA.cross(mC-mA);
255 mBAXNrml = mTriNrml.cross(mBA);
256 mCBXNrml = mTriNrml.cross(mCB);
257 mACXNrml = mTriNrml.cross(mAC);
259 mBANorm2 = math::isApproxZero(mBA.lengthSqr()) ? mBA : mBA/mBA.lengthSqr();
260 mCBNorm2 = math::isApproxZero(mCB.lengthSqr()) ? mCB : mCB/mCB.lengthSqr();
261 mACNorm2 = math::isApproxZero(mAC.lengthSqr()) ? mAC : mAC/mAC.lengthSqr();
263 const ValueT len = mTriNrml.length();
264 if (math::isApproxZero(len)) {
270 const ValueT hwRad = mRad + hw;
271 if (math::isApproxZero(hwRad) || hwRad < 0)
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) {
296 if (!math::isApproxZero(mFaceNrmls[i].z())) {
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();
307 BaseT::bottomTop = prismBottomTop;
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);
356 OpenCapsuleWedgeVoxelizer<GridType, InterruptT>,
359 using GridPtr =
typename GridType::Ptr;
392 InterruptT* interrupter =
nullptr)
393 : BaseT(grid,
threaded, interrupter)
407 template<
typename ScalarType>
413 static_assert(std::is_floating_point<ScalarType>::value);
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),
454 tc1 = tileCeil(a1, step),
455 tc2 = tileCeil(a2, step),
456 tc3 = tileCeil(a3, step),
457 tc4 = tileCeil(a4, step);
459 mXYData.reset(a0, a5, 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));
487 if (!math::isApproxZero(mXdiff)) {
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();
514 Vec2T n = Vec2T(-vy, vx).unitSafe();
515 Vec3T cvec = mORad * Vec3T(-vy, vx, ValueT(0)).unitSafe();
517 if (math::isApproxZero(vy))
518 cvec.y() = math::Abs(cvec.y());
522 const Vec3T cpmin(mPt1 - cvec), cpmax(mPt1 + cvec);
524 if (math::isApproxZero(mXdiff)) {
525 const ValueT px = mPt1.x(),
526 xmin = math::Min(px, pp1.x(), pp2.x()),
527 xmax = math::Max(px, pp1.x(), pp2.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();
539 const ValueT ymin = math::Min(y1, y2, y3),
540 ymax = math::Max(y1, y2, y3);
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());
570 if (!math::isApproxZero(n0.lengthSqr()))
571 intersectWithXYHalfSpace(n0, n0.dot(p2_2d - p1_2d) < 0 ? p1_2d : p2_2d);
573 if (!math::isApproxZero(n1.lengthSqr()))
574 intersectWithXYHalfSpace(n1, n1.dot(p2_2d - p1_2d) < 0 ? p1_2d : p2_2d);
578 intersectWithXYHalfSpace(
const Vec2T& n,
const Vec2T& p)
580 if (mXYData.size() == 0)
583 if (math::isApproxZero(n.y())) {
584 const ValueT &px = p.x();
586 const Index m = mXYData.size();
587 for (Index i = 0; i < m; ++i) {
588 const ValueT x = mXYData.getX(i);
590 if (x < px) mXYData.clearYRange(x);
594 Index i = mXYData.size()-1;
596 const ValueT x = mXYData.getX(i);
598 if (x > px) mXYData.clearYRange(x);
606 const bool set_min = n.y() < 0;
607 const Index m = mXYData.size();
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);
619 else mXYData.setYMax(x, yint);
621 if (set_min ? yint > ymax : yint < ymin)
622 mXYData.clearYRange(x);
632 signedDistance(
const Vec3T& p)
const
634 const Vec3T w = p - mPt1;
635 const ValueT dot = w.dot(mV);
638 if (dot <= math::Tolerance<ValueT>::value())
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
652 return mRad >= BaseT::halfWidth() + ValueT(0.5) * (ValueT(dim)-ValueT(1));
655 std::function<
bool(ValueT&, ValueT&,
const ValueT&,
const ValueT&)> capsuleBottomTopVertical =
656 [
this](ValueT& zb, ValueT& zt,
const ValueT& x,
const ValueT& y)
658 zb = BaseT::sphereBottom(mX1, mY1, math::Min(mZ1, mZ2), mORad, x, y);
659 zt = BaseT::sphereTop(mX2, mY2, math::Max(mZ1, mZ2), mORad, x, 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];
703 if (math::isApproxZero(n0.z()))
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
782 return BaseT::circleBottom(mX1, mY1, mORad, x);
786 circle1Top(
const ValueT& x)
const
788 return BaseT::circleTop(mX1, mY1, mORad, x);
792 circle2Bottom(
const ValueT& x)
const
794 return BaseT::circleBottom(mX2, mY2, mORad, x);
798 circle2Top(
const ValueT& x)
const
800 return BaseT::circleTop(mX2, mY2, mORad, x);
804 sphere1Bottom(
const ValueT& x,
const ValueT& y)
const
806 return BaseT::sphereBottom(mX1, mY1, mZ1, mORad, x, y);
810 sphere1Top(
const ValueT& x,
const ValueT& y)
const
812 return BaseT::sphereTop(mX1, mY1, mZ1, mORad, x, y);
816 sphere2Bottom(
const ValueT& x,
const ValueT& y)
const
818 return BaseT::sphereBottom(mX2, mY2, mZ2, mORad, x, y);
822 sphere2Top(
const ValueT& x,
const ValueT& y)
const
824 return BaseT::sphereTop(mX2, mY2, mZ2, mORad, x, y);
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)
835 const ValueT vx = BaseT::voxelSize(),
836 hw = BaseT::halfWidth();
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;
854 if (math::isApproxZero(mORad) || mORad < 0)
858 mVLenSqr = mV.lengthSqr();
861 if (math::isApproxZero(mVLenSqr))
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;
875 mXYNorm2 = math::Pow2(mXdiff) + math::Pow2(mYdiff);
876 mXYNorm = math::Sqrt(mXYNorm2);
877 mIsVertical = math::isApproxZero(mXYNorm);
880 const Vec3T n1 = Vec3T(nrml1), n2 = Vec3T(nrml2);
883 if (math::isApproxZero(n1.lengthSqr()) || math::isApproxZero(n2.lengthSqr()))
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) {
915 if (!math::isApproxZero(mPlaneNrmls[i].z())) {
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);
1208 using GridPtr =
typename GridType::Ptr;
1209 using TreeT =
typename GridType::TreeType;
1210 using LeafT =
typename TreeT::LeafNodeType;
1221 static_assert(std::is_floating_point<ScalarType>::value);
1235 ScalarType radius,
float voxelSize,
float halfWidth, InterruptT* interrupter)
1236 : mMesh(
std::make_shared<const MeshConnectivity>(MeshConnectivity(vertices, triangles)))
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;
1320 for (
Index j = 0; j < 3; ++j) {
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);
1374 if (n1.dot(p3-p1) < 0) n1 *= -1.0f;
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.0f;
1402 if (n2.dot(p4-p1) < 0) n2 *= -1.0f;
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];
1416 for (Index64 i = 0; i < n; ++i) {
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());
1457 tbb::parallel_for(tbb::blocked_range<size_t>(0, centroids.size()),
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());
1487 if (util::wasInterrupted(mInterrupter)) {
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;