diff --git a/VolZmap.h b/VolZmap.h index 30a27e0..3a36b3f 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -398,8 +398,6 @@ class VolZmap : public IVolZmap, public IGeoObjRW const Frame3d& frTruncPyramFrame, double dSegMin, double dSegMax, double dHeight, Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const ; bool TestIntersPlaneZmapBBox( const Plane3d& plPlane) const ; - // aggiornamento intersezioni - bool UpdateMaxMin( Point3d& ptBez, Vector3d& vtN, PNTVEC3DVECTOR& vInters) const ; // Voxel: esistenza e passaggio da N a ijk per i voxel bool IsValidVoxel( int nN) const ; bool IsValidVoxel( int nI, int nJ, int nK) const ; diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index 742461c..1c7a9ce 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -25,6 +25,7 @@ #include "/EgtDev/Include/EGkSurfBezier.h" #include "/EgtDev/Include/ENkPolynomialRoots.h" #include "/EgtDev/Include/EGkGeoObjSave.h" // debug +#include "SurfBezier.h" #include #include @@ -1132,8 +1133,8 @@ GetAlongAcrossRotation( const Vector3d& vtDir1, const Vector3d& vtDir2, const Ve } //---------------------------------------------------------------------------- -bool -VolZmap::UpdateMaxMin( Point3d& ptBez, Vector3d& vtN, PNTVEC3DVECTOR& vInters) const +static bool +UpdateMaxMin( Point3d& ptBez, Vector3d& vtN, PNTVEC3DVECTOR& vInters) { if ( ! AreSameVectorExact( vtN, V_NULL)) vInters.emplace_back( PNTVEC3D( ptBez, vtN)) ; @@ -1310,7 +1311,7 @@ VolZmap::GenTool_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& return true ; } -#if true +#if false //debug #define TEST static vector vGeo ; @@ -1318,6 +1319,226 @@ VolZmap::GenTool_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& //debug #endif +static void +SortGroupInters( PNTVEC3DVECTOR& vInters, INTINTVECTOR& vStartEnds, const Vector3d& vMainAx) { + if( AreSameVectorExact(vMainAx, Z_AX)) + sort( vInters.begin(), vInters.end(), [](PNTVEC3D& a, PNTVEC3D& b) { return a.first.z < b.first.z ; }) ; + else if( AreSameVectorExact(vMainAx, Y_AX)) + sort( vInters.begin(), vInters.end(), [](PNTVEC3D& a, PNTVEC3D& b) { return a.first.y < b.first.y ; }) ; + else if( AreSameVectorExact(vMainAx, X_AX)) + sort( vInters.begin(), vInters.end(), [](PNTVEC3D& a, PNTVEC3D& b) { return a.first.x < b.first.x ; }) ; + // devo controllare che le intersezioni estreme abbiano direzione opposta + // in caso contrario potrei avere ad uno dei due estremi due punti quasi coincidenti e stare prendendo per più esterno quello con la normale sbagliata + bool bExtremesAreOpposite = ( vInters.front().second * vMainAx) * (vInters.back().second * vMainAx) < 0 ; + if ( ! bExtremesAreOpposite) { + // se ad uno dei due estremi trovo due punti quasi coincidenti scambio le normali dei due punti di intersezione + bool bAtStart = false ; + bool bAtEnd = false ; + if( AreSameVectorExact(vMainAx, Z_AX)) { + bAtStart = (vInters[0].first.z - vInters[1].first.z) < EPS_SMALL ; + bAtEnd = (vInters.back().first.z - vInters.end()[-2].first.z) < EPS_SMALL ; + } + else if ( AreSameVectorExact(vMainAx, Y_AX) ) { + bAtStart = (vInters[0].first.y - vInters[1].first.y) < EPS_SMALL ; + bAtEnd = (vInters.back().first.y - vInters.end()[-2].first.y) < EPS_SMALL ; + } + else if ( AreSameVectorExact(vMainAx, X_AX) ) { + bAtStart = (vInters[0].first.x - vInters[1].first.x) < EPS_SMALL ; + bAtEnd = (vInters.back().first.x - vInters.end()[-2].first.x) < EPS_SMALL ; + } + if( bAtStart) + swap( vInters[0].second, vInters[1].second) ; + else if( bAtEnd) + swap( vInters.back().second, vInters.end()[-2].second) ; + } + + INTINT pStartEnd ; + bool bDirStart = vInters.front().second * vMainAx > 0 ; + bool bFirstEndFound = false ; + pStartEnd.first = 0 ; + for ( int w = 1 ; w < int( vInters.size()) ; ++w) { + bool bDir = vInters[w].second * vMainAx > 0 ; + // se è l'ultimo punto esco + if ( w == int( vInters.size() - 1) && bDirStart != bDir) { + pStartEnd.second = w ; + vStartEnds.push_back(pStartEnd) ; + break ; + } + // sennò scorro finché non trovo l'uscita più lontana ( prima di un altro ingresso o eventualmente l'ultima inters) + else if( bDirStart != bDir) + bFirstEndFound = true ; + // se trovo di nuovo un'intersezione orientata come la prima dello spillone allora ho un nuovo start e posso chiudere l'intervallo precedente + else if( bFirstEndFound && bDirStart == bDir) { + pStartEnd.second = w - 1 ; + bFirstEndFound = false ; + vStartEnds.push_back(pStartEnd) ; + pStartEnd.first = w ; + pStartEnd.second = -1 ; + } + } +} + +struct SurfBezForInters { + SurfBezier sBez ; + BBox3d bbSurf ; + Vector3d a3, a2, a1, a0, b3, b2, b1, b0 ; +}; + +static bool +IntersLineBezierSurfSet( const Point3d& ptLineStart, const Vector3d& vtLineDir, const vector& vSurfBez, PNTVEC3DVECTOR& vInters, INTVECTOR& vSurfInters) { + Point3d r = ptLineStart ; + Vector3d q = vtLineDir ; + + bool bNeedToRotX = AreSameVectorApprox( q, X_AX) ; + bool bNeedToRotY = AreSameVectorApprox( q, Y_AX) ; + bool bNeedToRot = bNeedToRotX || bNeedToRotY ; + Frame3d frRot ; + if( bNeedToRotX) + frRot.Set( ORIG, X_AX) ; + if( bNeedToRotY) + frRot.Set( ORIG, Y_AX) ; + if ( bNeedToRot ) { + r.ToLoc( frRot) ; + q.ToLoc( frRot) ; + } + // interseco con le bezier + for( int s = 0 ; s < int( vSurfBez.size()) ; ++s) { + const SurfBezForInters& srf = vSurfBez[s] ; + BBox3d bbox = srf.bbSurf ; + if( bNeedToRot) + bbox.ToLoc( frRot) ; + // verifico che lo spillone faccia interferenza con il box della superficie + if ( bbox.SqDistFromPointXY( r) < EPS_ZERO) { + //const Vector3d& a3 = srf.a3 ; + //const Vector3d& a2 = srf.a2 ; + //const Vector3d& a1 = srf.a1 ; + //const Vector3d& a0 = srf.a0 ; + //const Vector3d& b3 = srf.b3 ; + //const Vector3d& b2 = srf.b2 ; + //const Vector3d& b1 = srf.b1 ; + //const Vector3d& b0 = srf.b0 ; + + // se la linea è parallela all'asse X o Y allora ruoto tutto di 45 gradi rispetto a Z + Vector3d a3, a2, a1, a0, b3, b2, b1, b0 ; + if ( ! bNeedToRot) { + a3 = srf.a3 ; + a2 = srf.a2 ; + a1 = srf.a1 ; + a0 = srf.a0 ; + b3 = srf.b3 ; + b2 = srf.b2 ; + b1 = srf.b1 ; + b0 = srf.b0 ; + } + else { + SurfBezier sBezRot = srf.sBez ; + sBezRot.ToLoc( frRot) ; + PNTVECTOR vPntCtrl = sBezRot.GetAllControlPoints() ; + + Vector3d A = vPntCtrl[4] - vPntCtrl[0] ; + Vector3d B = vPntCtrl[5] - vPntCtrl[1] ; + Vector3d C = vPntCtrl[6] - vPntCtrl[2] ; + Vector3d D = vPntCtrl[7] - vPntCtrl[3] ; + Vector3d E = vPntCtrl[0] - ORIG ; + Vector3d F = vPntCtrl[1] - ORIG ; + Vector3d G = vPntCtrl[2] - ORIG ; + Vector3d H = vPntCtrl[3] - ORIG ; + + a3 = -A + 3*B - 3*C + D ; + a2 = 3*A - 6*B + 3*C ; + a1 = -3*A +3*B ; + a0 = A ; + + b3 = -E + 3*F - 3*G + H ; + b2 = 3*E - 6*F + 3*G ; + b1 = -3*E + 3*F ; + b0 = E ; + } + + DBLVECTOR vdCoeff, vdRoots ; + // coefficienti dal grado più basso al grado più alto + vdCoeff = { // c0 + q.x*q.z*a0.y*b0.z - q.x*q.y*a0.z*b0.z // 3 + - r.z*q.x*q.z*a0.y + r.z*q.x*q.y*a0.z + // 3 + q.y*q.z*a0.z*b0.z - q.z*q.z*a0.y*b0.x // 4 + - r.x*q.y*q.z*a0.z + r.x*q.z*q.z*a0.y + // 4 + q.z*q.z*a0.x*b0.y - q.y*q.z*a0.x*b0.z - q.x*q.z*a0.z*b0.y + q.x*q.y*a0.z*b0.z // 5 + - r.y*q.z*q.z*a0.x + r.z*q.y*q.z*a0.x + r.y*q.x*q.z*a0.z - r.z*q.x*q.y*a0.z, // 5 + + // c1 + q.x*q.z*(a1.y*b0.z + a0.y*b1.z) - q.x*q.y*(a1.z*b0.z + a0.z*b1.z) // 3 + - r.z*q.x*q.z*a1.y + r.z*q.x*q.y*a1.z + // 3 + q.y*q.z*(a1.z*b0.x + a0.z*b1.x) - q.z*q.z*(a1.y*b0.x + a0.y*b1.x) // 4 + - r.x*q.y*q.z*a1.z + r.x*q.z*q.z*a1.y + // 4 + q.z*q.z*(a1.x*b0.y + a0.x*b1.y) - q.y*q.z*(a1.x*b0.z + a0.x*b1.z) // 5 + - q.x*q.z*(a1.z*b0.y + a0.z*b1.y) + q.x*q.y*(a1.z*b0.z + a0.z*b1.z) // 5 + - r.y*q.z*q.z*a1.x + r.z*q.y*q.z*a1.x + r.y*q.x*q.z*a1.z - r.z*q.x*q.y*a1.z, // 5 + + // c2 + q.x*q.z*(a2.y*b0.z + a1.y*b1.z + a0.y*b2.z) - q.x*q.y*(a2.z*b0.z + a1.z*b1.z + a0.z*b2.z) // 3 + - r.z*q.x*q.z*a2.y + r.z*q.x*q.y*a2.z + // 3 + q.y*q.z*(a2.z*b0.x + a1.z*b1.x + a0.z*b2.x) - q.z*q.z*(a2.y*b0.x + a1.y*b1.x + a0.y*b2.x) // 4 + - r.x*q.y*q.z*a2.z + r.x*q.z*q.z*a2.y + // 4 + q.z*q.z*(a2.x*b0.y + a1.x*b1.y + a0.x*b2.y) - q.y*q.z*(a2.x*b0.z + a1.x*b1.z + a0.x*b2.z) // 5 + - q.x*q.z*(a2.z*b0.y + a1.z*b1.y + a0.z*b2.y) - q.x*q.y*(a2.z*b0.z + a1.z*b1.z + a0.z*b2.z)// 5 + - r.y*q.z*q.z*a2.x + r.z*q.y*q.z*a2.x + r.y*q.x*q.z*a2.z - r.z*q.x*q.y*a2.z, // 5 + + // c3 + q.x*q.z*(a3.y*b0.z + a2.y*b1.z + a1.y*b2.z + a0.y*b3.z) - q.x*q.y*(a3.z*b0.z + a2.z*b1.z + a1.z*b2.z + a0.z*b3.z) // 3 + - r.z*q.x*q.z*a3.y + r.z*q.x*q.y*a3.z + // 3 + q.y*q.z*(a3.z*b0.x + a2.z*b1.x + a1.z*b2.x + a0.z*b3.x) - q.z*q.z*(a3.y*b0.x + a2.y*b1.x + a1.y*b2.x + a0.y*b3.x) // 4 + - r.x*q.y*q.z*a3.z + r.x*q.z*q.z*a3.y + // 4 + q.z*q.z*(a3.x*b0.y + a2.x*b1.y + a1.x*b2.y + a0.x*b3.y) - q.y*q.z*(a3.x*b0.z + a2.x*b1.z + a1.x*b2.z + a0.x*b3.z) // 5 + - q.x*q.z*(a3.z*b0.y + a2.z*b1.y + a1.z*b2.y + a0.z*b3.y) - q.x*q.y*(a3.z*b0.z + a2.z*b1.z + a1.z*b2.z + a0.z*b3.z)// 5 + - r.y*q.z*q.z*a3.x + r.z*q.y*q.z*a3.x + r.y*q.x*q.z*a3.z - r.z*q.x*q.y*a3.z, // 5 + + // c4 + q.x*q.z*(a3.y*b1.z + a2.y*b2.z + a1.y*b3.z) - q.x*q.y*(a3.z*b1.z + a2.z*b2.z + a1.z*b3.z) + // 3 + q.y*q.z*(a3.z*b1.x + a2.z*b2.x + a1.z*b3.x) - q.z*q.z*(a3.y*b1.x + a2.y*b2.x + a1.y*b3.x) + // 4 + q.z*q.z*(a3.x*b1.y + a2.x*b2.y + a1.x*b3.y) - q.y*q.z*(a3.x*b1.z + a2.x*b2.z + a1.x*b3.z) // 5 + - q.x*q.z*(a3.z*b1.y + a2.z*b2.y + a1.z*b3.y) + q.x*q.y*(a3.z*b1.z + a2.z*b2.z + a1.z*b3.z), // 5 + + // c5 + q.x*q.z*(a3.y*b2.z + a2.y*b3.z) - q.x*q.y*(a3.z*b2.z + a2.z*b3.z) + // 3 + q.y*q.z*(a3.z*b2.x + a2.z*b3.x) - q.z*q.z*(a3.y*b2.x + a2.y*b3.x) + // 4 + q.z*q.z*(a3.x*b2.y + a2.x*b3.y) - q.y*q.z*(a3.x*b2.z + a2.x*b3.z) // 5 + - q.x*q.z*(a3.z*b2.y + a2.z*b3.y) + q.x*q.y*(a3.z*b2.z + a2.z*b3.z), // 5 + + // c6 + q.x*q.z*a3.y*b3.z - q.x*q.y*a3.z*b3.z + // 3 + q.y*q.z*a3.z*b3.z - q.z*q.z*a3.y*b3.x + // 4 + q.z*q.z*a3.x*b3.y - q.y*q.z*a3.x*b3.z - q.x*q.z*a3.z*b3.y + q.x*q.y*a3.z*b3.z} ; // 5 + int nRoots = PolynomialRoots( 6, vdCoeff, vdRoots) ; + for( int w = 0 ; w < nRoots ; ++w) { + double dU = 0, dV = 0 ; + if ( vdRoots[w] > 0 - EPS_ZERO && vdRoots[w] < 1 + EPS_ZERO) { + dU = vdRoots[w] ; + // verifico che non sia una soluzione con molteplicità > 1 + bool bAlreadyFound = false ; + for ( int k = w - 1 ; k >= 0 && ! bAlreadyFound ; --k) + bAlreadyFound = abs( dU - vdRoots[k]) < EPS_PARAM ; + if( ! bAlreadyFound) { + Vector3d vAlpha = a3 * pow(dU, 3) + a2 * pow( dU, 2) + a1 * dU + a0 ; + Vector3d vBeta = b3 * pow(dU, 3) + b2 * pow( dU, 2) + b1 * dU + b0 ; + dV = - ( vBeta.x - r.x) / vAlpha.x ; + if ( dV > - EPS_ZERO && dV < 1 + EPS_ZERO) { + Point3d ptBez ; + Vector3d vtN ; + srf.sBez.GetPointNrmD1D2(dU, dV, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptBez, vtN) ; + vtN *= -1 ; + UpdateMaxMin( ptBez, vtN, vInters) ; + + //debug + vSurfInters.push_back( s) ; + } + } + } + } + } + } + return true ; +} + //---------------------------------------------------------------------------- bool VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& ptE, const VCT3DVECTOR& vtLs, const VCT3DVECTOR& vtLe, @@ -1348,18 +1569,8 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt else if( n5AxisType == VolZmap::Move5Axis::ACROSS) nTotSurf = 2 * nStepCnt + nSub * 4 * nStepCnt + nSub * 2 + 16 ; // come caso ALONG - VCT3DVECTOR a3( nTotSurf) ; - VCT3DVECTOR a2( nTotSurf) ; - VCT3DVECTOR a1( nTotSurf) ; - VCT3DVECTOR a0( nTotSurf) ; - VCT3DVECTOR b3( nTotSurf) ; - VCT3DVECTOR b2( nTotSurf) ; - VCT3DVECTOR b1( nTotSurf) ; - VCT3DVECTOR b0( nTotSurf) ; - int nSurfInd = 0 ; - ISURFBEZPOVECTOR vSurfBez( nTotSurf * nStepCnt) ; - BOXVECTOR vSurfBox( nTotSurf * nStepCnt) ; + vector vSurfBez( nTotSurf) ; double dSide = 0 ; // punti per le bilineari, sulle posizioni del tool alle estremità del movimento PNTVECTOR vPntTipStartExF ; @@ -1901,17 +2112,16 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt // inizializzo le superfici bilineari e i parametri per le intersezioni for( int z = 0 ; z < int( vvPtCtrl.size()) ; ++z) { - vSurfBez[nSurfInd].Set( CreateSurfBezier()) ; - vSurfBez[nSurfInd]->Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; - vSurfBez[nSurfInd]->SetControlPoint( 0, vvPtCtrl[z][0]) ; - vSurfBez[nSurfInd]->SetControlPoint( 1, vvPtCtrl[z][1]) ; - vSurfBez[nSurfInd]->SetControlPoint( 2, vvPtCtrl[z][2]) ; - vSurfBez[nSurfInd]->SetControlPoint( 3, vvPtCtrl[z][3]) ; - vSurfBez[nSurfInd]->SetControlPoint( 4, vvPtCtrl[z][4]) ; - vSurfBez[nSurfInd]->SetControlPoint( 5, vvPtCtrl[z][5]) ; - vSurfBez[nSurfInd]->SetControlPoint( 6, vvPtCtrl[z][6]) ; - vSurfBez[nSurfInd]->SetControlPoint( 7, vvPtCtrl[z][7]) ; - vSurfBox[nSurfInd].Add( vvPtCtrl[z]) ; + vSurfBez[nSurfInd].sBez.Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 0, vvPtCtrl[z][0]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 1, vvPtCtrl[z][1]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 2, vvPtCtrl[z][2]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 3, vvPtCtrl[z][3]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 4, vvPtCtrl[z][4]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 5, vvPtCtrl[z][5]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 6, vvPtCtrl[z][6]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 7, vvPtCtrl[z][7]) ; + vSurfBez[nSurfInd].bbSurf.Add( vvPtCtrl[z]) ; Vector3d A = vvPtCtrl[z][4] - vvPtCtrl[z][0] ; Vector3d B = vvPtCtrl[z][5] - vvPtCtrl[z][1] ; @@ -1919,22 +2129,22 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt Vector3d D = vvPtCtrl[z][7] - vvPtCtrl[z][3] ; Vector3d E = vvPtCtrl[z][0] - ORIG ; Vector3d F = vvPtCtrl[z][1] - ORIG ; - Vector3d G = vvPtCtrl[z][2] - ORIG; + Vector3d G = vvPtCtrl[z][2] - ORIG ; Vector3d H = vvPtCtrl[z][3] - ORIG ; - a3[nSurfInd] = -A + 3*B - 3*C + D ; - a2[nSurfInd] = 3*A - 6*B + 3*C ; - a1[nSurfInd] = -3*A +3*B ; - a0[nSurfInd] = A ; + vSurfBez[nSurfInd].a3 = -A + 3*B - 3*C + D ; + vSurfBez[nSurfInd].a2 = 3*A - 6*B + 3*C ; + vSurfBez[nSurfInd].a1 = -3*A +3*B ; + vSurfBez[nSurfInd].a0 = A ; - b3[nSurfInd] = -E + 3*F - 3*G + H ; - b2[nSurfInd] = 3*E - 6*F + 3*G ; - b1[nSurfInd] = -3*E + 3*F ; - b0[nSurfInd] = E ; + vSurfBez[nSurfInd].b3 = -E + 3*F - 3*G + H ; + vSurfBez[nSurfInd].b2 = 3*E - 6*F + 3*G ; + vSurfBez[nSurfInd].b1 = -3*E + 3*F ; + vSurfBez[nSurfInd].b0 = E ; #ifdef TEST if ( nGrid == 0) - vGeo.push_back( vSurfBez[nSurfInd]->Clone()) ; + vGeo.push_back( vSurfBez[nSurfInd].sBez.Clone()) ; #endif ++ nSurfInd ; } @@ -1950,34 +2160,30 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt //debug #endif - - //BBox3d bbStartCyl = GetCylMoveBBox( ptS[0], ptS[0], vtLs[0], dMaxRad, dHeight) ; - //BBox3d bbEndCyl = GetCylMoveBBox( ptE.back(), ptE.back(), vtLe.back(), dMaxRad, dHeight) ; - - //// se sono nel caso di un cono calcolo già i parametri utili - //Point3d ptVS, ptVE ; - //double dTan = 0, dMinH, dMaxH ; - //Point3d ptP1T = ptS[0] - vtLs[0] * dHeight ; - //Point3d ptP2T = ptE.back() - vtLe.back() * dHeight ; - //if ( dMinRad < EPS_SMALL) { - // ptVS = ptP1T ; - // ptVE = ptP2T ; - // dMinH = 0 ; - // dMaxH = dHeight ; - // dTan = dMaxRad / dHeight ; - //} - //else { - // dTan = (dMaxRad - dMinRad) / dHeight ; - // dMaxH = dMaxRad * dTan ; - // dMinH = dMaxH - dHeight ; - // ptVS = ptS[0] - vtLs[0] * dMaxH ; - // ptVE = ptE.back() - vtLe.back() * dMaxH ; - //} - // scorro tutti gli spilloni interessati int nAllStepsSurfs = nTotSurf * nStepCnt ; + int j = 0 ; + int nLastForwardJ = -1 ; + struct IntervalsToSubtract { + int i = 0 ; + int j = 0 ; + bool bUseOnlyExtremes = false ; + PNTVEC3DVECTOR vInters ; + INTINTVECTOR vStartEnds ; + IntervalsToSubtract( int nI, int nJ, PNTVEC3DVECTOR& vPntInt, INTINTVECTOR& vSE, bool bUseExtremes) : i( nI), j( nJ), bUseOnlyExtremes( bUseExtremes), vInters( vPntInt), vStartEnds( vSE) {} + } ; + bool bUseOnlyExtremes = false ; + bool bFirstAmbiguousCaseType = false ; + bool bForward = true ; + bool bAllSameType = false ; + vector vIntervalsToSubtr ; for ( int i = nStartI ; i <= nEndI ; ++ i) { - for ( int j = nStartJ ; j <= nEndJ ; ++ j) { + nLastForwardJ = -1 ; + j = nStartJ ; + bAllSameType = false ; + bForward = true ; + bFirstAmbiguousCaseType = false ; + while ( j <= nEndJ && j > nLastForwardJ) { double dX = ( i + 0.5) * m_dStep ; double dY = ( j + 0.5) * m_dStep ; Point3d r( dX, dY, 0) ; @@ -1986,70 +2192,70 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt //debug INTVECTOR vSurfInters ; - // interseco con le bilineari - for( int s = 0 ; s < int( vSurfBez.size()) ; ++s) { - // verifico che lo spillone faccia interferenza con il box della superficie - if ( vSurfBox[s].SqDistFromPointXY( r) < EPS_ZERO) { - DBLVECTOR vdCoeff, vdRoots ; - // coefficienti dal grado più basso al grado più alto - vdCoeff = { - a0[s].y * b0[s].x + r.x * a0[s].y + a0[s].x * b0[s].y - r.y * a0[s].x, - - a1[s].y * b0[s].x - a0[s].y * b1[s].x + r.x * a1[s].y + a1[s].x * b0[s].y + a0[s].x * b1[s].y - r.y * a1[s].x, - - a2[s].y * b0[s].x - a1[s].y * b1[s].x - a0[s].y * b2[s].x + r.x * a2[s].y + a2[s].x * b0[s].y + a1[s].x * b1[s].y + a0[s].x * b2[s].y - r.y * a2[s].x, - - a3[s].y * b0[s].x - a2[s].y * b1[s].x - a1[s].y * b2[s].x - a0[s].y * b3[s].x + r.x * a3[s].y + a3[s].x * b0[s].y + a2[s].x * b1[s].y + a1[s].x * b2[s].y + a0[s].x * b3[s].y - r.y * a3[s].x, - - a3[s].y * b1[s].x - a2[s].y * b2[s].x - a1[s].y * b3[s].x + a3[s].x * b1[s].y + a2[s].x * b2[s].y + a1[s].x * b3[s].y, - - a3[s].y * b2[s].x - a2[s].y * b3[s].x + a3[s].x * b2[s].y + a2[s].x * b3[s].y, - - a3[s].y * b3[s].x + a3[s].x * b3[s].y} ; - int nRoots = PolynomialRoots( 6, vdCoeff, vdRoots) ; - for( int w = 0 ; w < nRoots ; ++w) { - double dU = 0, dV = 0 ; - if ( vdRoots[w] > 0 - EPS_ZERO && vdRoots[w] < 1 + EPS_ZERO) { - dU = vdRoots[w] ; - Vector3d vAlpha = a3[s] * pow(dU, 3) + a2[s] * pow( dU, 2) + a1[s] * dU + a0[s] ; - Vector3d vBeta = b3[s] * pow(dU, 3) + b2[s] * pow( dU, 2) + b1[s] * dU + b0[s] ; - dV = - ( vBeta.x - r.x) / vAlpha.x ; - if ( dV > - EPS_ZERO && dV < 1 + EPS_ZERO) { - Point3d ptBez ; - Vector3d vtN ; - vSurfBez[s]->GetPointNrmD1D2(dU, dV, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptBez, vtN) ; - vtN *= -1 ; - UpdateMaxMin( ptBez, vtN, vInters) ; - - //debug - vSurfInters.push_back( s) ; - } - } - } - } - } - + //debug + IntersLineBezierSurfSet( r, q, vSurfBez, vInters, vSurfInters) ; if ( vInters.size() > 2) { - sort( vInters.begin(), vInters.end(), [](PNTVEC3D& a, PNTVEC3D& b) { return a.first.z < b.first.z ; }) ; - INTINT pStartEnd ; - bool bDirStart = vInters.front().second * Z_AX > 0 ; - bool bFirstEndFound = false ; - pStartEnd.first = 0 ; - for ( int w = 1 ; w < int( vInters.size()) ; ++w) { - bool bDir = vInters[w].second * Z_AX > 0 ; - // se è l'ultimo punto esco - if ( w == int( vInters.size() - 1) && bDirStart != bDir) { - pStartEnd.second = w ; - vStartEnds.push_back(pStartEnd) ; - break ; - } - // sennò scorro finché non trovo l'uscita più lontana ( prima di un altro ingresso o eventualmente l'ultima inters) - else if( bDirStart != bDir) - bFirstEndFound = true ; - // se trovo di nuovo un'intersezione orientata come la prima dello spillone allora ho un nuovo start e posso chiudere l'intervallo precedente - else if( bFirstEndFound && bDirStart == bDir) { - pStartEnd.second = w - 1 ; - bFirstEndFound = false ; - vStartEnds.push_back(pStartEnd) ; - pStartEnd.first = w ; - pStartEnd.second = -1 ; - } + SortGroupInters( vInters, vStartEnds, Z_AX) ; + if ( bForward && vStartEnds.size() > 1) { + // se ho più di un intervallo da togliere allora devo capire se sono dentro il volume spazzato dal tool o no + nLastForwardJ = j ; + j = nEndJ + 1 ; + bForward = false ; + } + if ( ! bForward && vStartEnds.size() > 1) { + // salvo la prima intersezione dubbia e comincio a scorrere al contrario per trovare l'ultima e capire se è dello stesso tipo della prima + + if( ! bAllSameType) { + bUseOnlyExtremes = false ; + // calcolo le intersezioni anche sugli altri due spilloni passanti per un punto a metà tra due dei vari intervalli + // ho almeno due intervalli; prendo un punto a metà tra la fine del primo e l'inzio del secondo + Point3d ptLineStart = (vInters[vStartEnds[0].second].first + vInters[vStartEnds[1].first].first ) / 2 ; + Vector3d vtLineStart = X_AX ; + PNTVEC3DVECTOR vIntersX ; + INTVECTOR vSurfX ; + INTINTVECTOR vStartEndsX ; + bool bXInclude = false ; + IntersLineBezierSurfSet( ptLineStart, vtLineStart, vSurfBez, vIntersX, vSurfX) ; + if( vIntersX.size() > 0) { + SortGroupInters( vIntersX, vStartEndsX, X_AX) ; + // se ho più di una intersezione e il punto di studio è compreso tra questi punti allora le info lungo questa direzione mi dicono che sono interno al volume spazzato + bXInclude = vIntersX[vStartEndsX.front().first].first.x < ptLineStart.x && vIntersX[vStartEndsX.back().second].first.x > ptLineStart.x ; + } + + vtLineStart = Y_AX ; + PNTVEC3DVECTOR vIntersY ; + INTVECTOR vSurfY ; + INTINTVECTOR vStartEndsY ; + bool bYInclude = false ; + IntersLineBezierSurfSet( ptLineStart, vtLineStart, vSurfBez, vIntersY, vSurfY) ; + if ( vIntersY.size() > 1) { + SortGroupInters( vIntersY, vStartEndsY, Y_AX) ; + // se ho più di una intersezione e il punto di studio è compreso tra questi punti allora le info lungo questa direzione mi dicono che sono interno al volume spazzato + bYInclude = vIntersY[vStartEndsY.front().first].first.y < ptLineStart.y && vIntersY[vStartEndsY.back().second].first.y > ptLineStart.y ; + } + + // se anche gli spilloni nelle altre due direzioni fanno intersezione sia a destra che a sinistra rispetto al punto a metà tra gli intervalli, allora sono all'interno del volume + if( bXInclude && bYInclude) + bUseOnlyExtremes = true ; + } + + int nJToSave = j ; + if( j == nEndJ + 1) { + nJToSave = nLastForwardJ ; + bFirstAmbiguousCaseType = bUseOnlyExtremes ; + } + else { + // se ho trovato un caso ambiguo ( scorrendo al contrario) che è uguale al primo che ho trovato scorrendo dritto allora posso considerare tutti gli spilloni restanti di + // questo tipo e calcolare solo le intersezioni + if ( bUseOnlyExtremes == bFirstAmbiguousCaseType) + bAllSameType = true ; + } + vIntervalsToSubtr.emplace_back( i, nJToSave, vInters, vStartEnds, bUseOnlyExtremes) ; + } + else { + for( auto p : vStartEnds) + SubtractIntervals(nGrid, i, j, vInters[p.first].first.z, vInters[p.second].first.z, vInters[p.first].second, vInters[p.second].second, nToolNum) ; } - for( auto p : vStartEnds ) - SubtractIntervals(nGrid, i, j, vInters[p.first].first.z, vInters[p.second].first.z, vInters[p.first].second, vInters[p.second].second, nToolNum) ; } else if ( vInters.size() == 2){ vStartEnds.push_back(INTINT(0, 1)) ; @@ -2057,6 +2263,24 @@ VolZmap::Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& pt } else if ( vInters.size() == 1) return false ; + + if ( bForward) + ++j ; + else + --j ; + } + } + + for ( IntervalsToSubtract& intToSub : vIntervalsToSubtr) { + if ( intToSub.bUseOnlyExtremes) + SubtractIntervals( nGrid, intToSub.i, intToSub.j, intToSub.vInters.front().first.z, intToSub.vInters.back().first.z, intToSub.vInters.front().second, intToSub.vInters.back().second, nToolNum) ; + else { + // scorro le intersezione su questo spillone togliendo gli intervalli usando vStartEnds + for ( int z = 0 ; z < int( intToSub.vStartEnds.size()) ; ++z) { + int nStart = intToSub.vStartEnds[z].first ; + int nEnd = intToSub.vStartEnds[z].second ; + SubtractIntervals( nGrid, intToSub.i, intToSub.j, intToSub.vInters[nStart].first.z, intToSub.vInters[nEnd].first.z, intToSub.vInters[nStart].second, intToSub.vInters[nEnd].second, nToolNum) ; + } } }