From 0bf76e8efba9bd54036f6a32b20b6d657ccdcfdd Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 1 Sep 2026 12:08:04 +0200 Subject: [PATCH] EgtMachKernel : - in Finiture di lama Along5A migliorata la collisione tra lama e sezione e aggiunto ricalcolo SideStep. --- SawFinishing.cpp | 850 ++++++++++++++++++++++++++++++++++++++--------- SawFinishing.h | 38 ++- 2 files changed, 714 insertions(+), 174 deletions(-) diff --git a/SawFinishing.cpp b/SawFinishing.cpp index b3f5a1c..d5362e3 100644 --- a/SawFinishing.cpp +++ b/SawFinishing.cpp @@ -39,10 +39,13 @@ #include "/EgtDev/Include/EgtPointerOwner.h" #define DEBUG_SAW_FIN 0 -#if DEBUG_SAW_FIN +#define BISECTION_ALONG5AX 0 +#if DEBUG_SAW_FIN || BISECTION_ALONG5AX #include "EgtDev/Include/EGkGeoPoint3d.h" #include "EgtDev/Include/EGkGeoVector3d.h" #include "EgtDev/Include/EGkGeoFrame3d.h" + #include "/EgtDev/Include/EGkGeoObjSave.h" + std::vector VT ; std::vector VC ; #endif // per far dimenticare macro di WinUser.h #undef GetClassName @@ -84,7 +87,7 @@ enum nCrvClass { CCL_FLAT = 2, CCL_FALL = 3, CCL_RISE = 4 -}; +} ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_SAWFINISHING), SawFinishing) ; @@ -2641,6 +2644,8 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const } // elimino eventuali sottosquadra e oriento ogni curva secondo X descrescente + // NB. -->! nonostante la finitura 5Ax non necessita della rimozione dei sottosquadra, qui vengono lo stesso effettuati in + // quanto non vi è ancora una sgrossatura per la loro rimozione !<-- ICRVCOMPOPOVECTOR vpNucCrvs ; vpNucCrvs.reserve( vpSects.size()) ; for ( const auto& pSect : vpSects) { PtrOwner pCrvCompo( CreateCurveComposite()) ; @@ -2745,12 +2750,19 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const else return m_Params.m_nHeadSide ; } ; + // ----------------------------------------------------------------------------------------------- + + // estensione dei tratti di classificazione + enum nCrvClass5Ax { + CCL_VERT_RISE = 5, + CCL_VERT_FALL = 6 + } ; // per ogni sezione semplice for ( int i = 0 ; i < ssize( vSections) ; ++ i) { // riferimenti - SectionInfo& CurrSection = vSections[i] ; + SectionInfo5Ax& CurrSection = vSections[i] ; SUBSECTIONVECTOR& vCurrSubSections = CurrSection.vSubSections ; // spezzo eventuali archi sopra e sotto @@ -2776,11 +2788,21 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const PtrOwner pCompoSubSect( ConvertCurveToComposite( CurrSection.pSection->CopyParamRange( double( i - 1), double( i)))) ; if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, GetHeadSide( vnClass[0]))) return false ; + vCurrSubSections.back().vnClass.emplace_back( vnClass[0]) ; + if ( vnClass[0] == CCL_VERT) { + Point3d ptS ; vCurrSubSections.back().pSubSection->GetStartPoint( ptS) ; + Point3d ptE ; vCurrSubSections.back().pSubSection->GetEndPoint( ptE) ; + if ( ptS.y < ptE.y) + vCurrSubSections.back().vnClass.back() = CCL_VERT_RISE ; + else + vCurrSubSections.back().vnClass.back() = CCL_VERT_FALL ; + } + bCanSwapHead = ( vnClass[0] != CCL_RISE && vnClass[0] != CCL_FALL) ; } // classificazione corrente const int& nCurrClass = vnClass[i] ; // classificazione precedente - const int& nPrevClass = vnClass[i - 1] ; + const int& nPrevClass = vnClass[i-1] ; // parametri per copia sotto-tratto corrente double dUS = double( i) ; double dUE = double( i + 1) ; @@ -2793,10 +2815,43 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const case CCL_SMALL : case CCL_VERT : { - // a prescindere dai valori precedenti si aggiunge semplicemente il tratto di sezione - if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub))) - return false ; - bCanSwapHead = ( bCanSwapHead && ( nPrevClass != CCL_RISE && nPrevClass != CCL_FALL)) ; + // determino la vera classificazione corrente + int nMyClass = nCurrClass ; + if ( nCurrClass == CCL_VERT) { + Point3d ptS ; pCompoSub->GetStartPoint( ptS) ; + Point3d ptE ; pCompoSub->GetEndPoint( ptE) ; + if ( ptS.y < ptE.y) + nMyClass = CCL_VERT_RISE ; + else + nMyClass = CCL_VERT_FALL ; + } + + // se posso invertire la testa + if ( bCanSwapHead || ( nMyClass == CCL_FLAT || nMyClass == CCL_SMALL)) { + // a prescindere dai valori precedenti si aggiunge semplicemente il tratto di sezione + if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub))) + return false ; + bCanSwapHead = ( bCanSwapHead && ( nPrevClass != CCL_RISE && nPrevClass != CCL_FALL)) ; + } + // se non posso invertire la testa, controllo se posso collegare il tratto corrente all SubSection corrente + else { + int nOtherClass = ( nMyClass == CCL_VERT_FALL ? CCL_VERT_RISE : CCL_VERT_FALL) ; + if ( find( vCurrSubSections.back().vnClass.begin(), vCurrSubSections.back().vnClass.end(), nOtherClass) != vCurrSubSections.back().vnClass.end()) { + // nuova sezione + PtrOwner pCompoSubSect( ::Release( pCompoSub)) ; + if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, m_Params.m_nHeadSide)) + return false ; + bCanSwapHead = true ; + } + else { + // aggiungo alla sezione precedente + if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub))) + return false ; + bCanSwapHead = ( bCanSwapHead && ( nPrevClass != CCL_RISE && nPrevClass != CCL_FALL)) ; + } + } + + vCurrSubSections.back().vnClass.emplace_back( nMyClass) ; break ; } // --- classificazione corrente Fall (la testa deve essere a destra) @@ -2837,6 +2892,7 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_RIGHT)) return false ; } + vCurrSubSections.back().vnClass.emplace_back( CCL_FALL) ; break ; } // --- classificazione corrente Rise (la testa deve essere a sinistra) @@ -2877,6 +2933,7 @@ SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub))) return false ; } + vCurrSubSections.back().vnClass.emplace_back( CCL_RISE) ; break ; } } @@ -3466,41 +3523,47 @@ SawFinishing::CalcCAvSect5Ax( const ICurveComposite* pSubSect, const ICRVCOMPOPO bOtherCollision = false ; bAwayFromPoint = false ; - // definisco il numero di punti di campionamento progressivi - const int MAX_NUM = 3 ; + // definisco le costanti di collisione e i parametri di ricerca + const int MAX_NUM = 3 ; // -->! dispari, in modo da controllare sempre il centro della sezione della lama !<-- const double LINE_LEN = 1e4 ; - const double TOL = 50. * EPS_SMALL ; - double dSqMaxElev = EPS_ZERO ; + const double COLLISION_TOL = 10. * EPS_SMALL ; + const double AWAY_TOL = 2. ; + + // NB -->! ptP è sulla metà della sezione della lama PtrOwner pLineInters( CreateCurveLine()) ; - if ( IsNull( pLineInters) || ! pLineInters->Set( ptP, ptP + vtCorr * LINE_LEN)) + if ( IsNull( pLineInters) || ! pLineInters->Set( ptP + vtCorr * COLLISION_TOL, ptP + vtCorr * LINE_LEN)) return false ; - DistPointCurve distPtCrv( ptP + vtTool * m_TParams.m_dThick / 2., *pSubSect) ; + DistPointCurve distPtCrv( ptP, *pSubSect) ; Point3d ptMidSaw ; int nFlag ; - if ( ! distPtCrv.GetMinDistPoint( 0., ptMidSaw, nFlag)) - return false ; - double dLenAtMiSaw ; - if ( ! pSubSect->GetLengthAtPoint( ptMidSaw, dLenAtMiSaw, TOL)) - return false ; - double dLenSec ; - if ( ! pSubSect->GetLength( dLenSec)) + double dLenAtMidSaw ; double dLenSec ; + if ( ! distPtCrv.GetMinDistPoint( 0., ptMidSaw, nFlag) || + ! pSubSect->GetLengthAtPoint( ptMidSaw, dLenAtMidSaw, COLLISION_TOL) || + ! pSubSect->GetLength( dLenSec)) return false ; + + // porto la linea all'estremo della sezione della lama, in direzione opposta a vtTool + pLineInters->Translate( - ( m_TParams.m_dThick / 2.) * vtTool) ; + // per ogni punto di campionamento + double dSqMaxElev = EPS_ZERO ; for ( int i = 0 ; i < MAX_NUM ; ++ i) { + // traslo la retta di intersezione if ( i > 0) pLineInters->Translate( ( m_TParams.m_dThick) / ( MAX_NUM - 1) * vtTool) ; + // calcolo l'intersezione tra la retta e la sezione Point3d ptLineS ; pLineInters->GetStartPoint( ptLineS) ; IntersCurveCurve ICC( *pLineInters, *pSubSect) ; for ( int j = ICC.GetIntersCount() - 1 ; j >= 0 ; -- j) { IntCrvCrvInfo aInfo ; if ( ICC.GetIntCrvCrvInfo( j, aInfo)) { - Point3d ptColl = aInfo.bOverlap ? aInfo.IciA[1].ptI : aInfo.IciA[0].ptI ; + Point3d ptColl = ( aInfo.bOverlap ? aInfo.IciA[1].ptI : aInfo.IciA[0].ptI) ; double dLenAtColl ; - if ( ! pSubSect->GetLengthAtPoint( ptColl, dLenAtColl, TOL)) + if ( ! pSubSect->GetLengthAtPoint( ptColl, dLenAtColl, AWAY_TOL)) return false ; - if ( dLenAtColl < max( 0., dLenAtMiSaw - m_TParams.m_dThick / 2. - TOL) || - min( dLenSec, dLenAtMiSaw + m_TParams.m_dThick / 2. + TOL) < dLenAtColl) { + if ( dLenAtColl < max( 0., dLenAtMidSaw - m_TParams.m_dThick / 2. - AWAY_TOL) || + min( dLenSec, dLenAtMidSaw + m_TParams.m_dThick / 2. + AWAY_TOL) < dLenAtColl) { bAwayFromPoint = true ; return true ; } @@ -3529,7 +3592,449 @@ SawFinishing::CalcCAvSect5Ax( const ICurveComposite* pSubSect, const ICRVCOMPOPO //---------------------------------------------------------------------------- bool -SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend, +SawFinishing::CalcStepsFor5AxSections( SECTIONVECTOR& vSections) const +{ + // Struttura per pramatrizzazione di una curva in base ai suoi angoli interni ed esterni + enum AngleType5Ax { INTERNAL = -1, EXTERNAL = 1 } ; + vector> vAngleParams ; // + + // Funzioni per calcolo di Bisezione ============================================================================= + // --- + auto CalcSideStep = [&] ( const ICurve* pCurve, int& nStep, double& dStep) { + + dStep = max( m_Params.m_dSideStep, 10. * EPS_SMALL) ; + double dLen ; + if ( ! pCurve->GetLength( dLen)) + return false ; + if ( dLen < 10. * EPS_SMALL) + return true ; + nStep = static_cast( ceil( dLen / dStep)) ; + dStep = dLen / nStep ; + return true ; + + } ; + + // --- + auto CalcPointAndDirections = [&]( const ICurveComposite* pCompo, double dUCurr, ICurve::Side nSide, Point3d& ptCurr, Vector3d& vtTan, Vector3d& vtOut) { + + // Recupero il punto e la direzione tangente normalizzata + if ( ! pCompo->GetPointD1D2( dUCurr, nSide, ptCurr, &vtTan) || ! vtTan.Normalize()) + return false ; + + // Calcolo la direzione perpendicolare di uscita + vtOut = GetRotate( vtTan, Z_AX, - ANG_RIGHT) ; + return true ; + } ; + + // --- + auto CheckCollision = [&]( const ICurveComposite* pCompo, const ICurveComposite* pCompoCollision, const Point3d& ptP, const Vector3d& vtTan, + const Vector3d& vtOut, bool& bCollision) { + + // Posiziono correttamente la lama (punti di campionamento) e vedo quando spostarmi lungo vtOut + const double ELEV_TOL = 10. * EPS_SMALL ; + const int POINT_NBR = 5 ; // (potrebbe essere maggiore, basta che sia dispari per passare nel centro lama) + double dElev = 0. ; + const Point3d ptLineS = ptP - vtTan * ( m_TParams.m_dThick / 2.) + ELEV_TOL * vtOut ; + const Point3d ptLineE = ptP - vtTan * ( m_TParams.m_dThick / 2.) + 1e4 * vtOut ; + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine) || ! pLine->Set( ptLineS, ptLineE)) + return false ; + + #if BISECTION_ALONG5AX + VT.clear() ; VC.clear() ; + VT.emplace_back( pCompo->Clone()) ; VC.emplace_back( BLUE) ; + #endif + + // Calcolo di quanto traslare la lama lungo vtOut per evitare collisioni con il tratto corrente + Point3d ptInters ; + for ( int i = 0 ; i < POINT_NBR ; ++ i) { + if ( i > 0) + pLine->Translate( ( m_TParams.m_dThick / ( POINT_NBR - 1) * vtTan)) ; + IntersCurveCurve ICC( *pLine, *pCompo) ; + + #if BISECTION_ALONG5AX + VT.emplace_back( pLine->Clone()) ; VC.emplace_back( AQUA) ; + #endif + + if ( ICC.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + ptInters = ( aInfo.bOverlap ? aInfo.IciA[1].ptI : aInfo.IciA[0].ptI) ; + dElev = Dist( ptLineS, ptInters) ; + } + } + } + + #if BISECTION_ALONG5AX + if ( pCompoCollision != nullptr && pCompoCollision->IsValid()) { + VT.emplace_back( pCompoCollision->Clone()) ; VC.emplace_back( WHITE) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\Collision.nge") ; + #endif + + // Traslo la linea + if ( ! pLine->Set( ptLineS + dElev * vtOut, ptLineS + 1e4 * vtOut)) + return false ; + + // Verifico la collisione con l'altra porzione di curva + bCollision = false ; + if ( pCompoCollision != nullptr && pCompoCollision->IsValid()) { + // costrusco la vera geometria della lama + PtrOwner pCompoSaw( CreateCurveComposite()) ; + if ( IsNull( pCompoSaw) || ! pCompoSaw->AddPoint( ptLineS) || + ! pCompoSaw->AddLine( ptLineS + m_TParams.m_dDiam * vtOut) || + ! pCompoSaw->AddLine( ptLineS + m_TParams.m_dDiam * vtOut + vtTan * m_TParams.m_dThick) || + ! pCompoSaw->AddLine( ptLineS + vtTan * m_TParams.m_dThick) || + ! pCompoSaw->Close()) + return false ; + IntersCurveCurve ICC( *pCompoSaw, *pCompoCollision) ; + if ( ICC.GetCrossIntersCount() > 0) { + bCollision = true ; + return true ; + } + } + + return true ; + } ; + + // --- + auto AdjustCompoByCollision = [&]( ICurveComposite* pCompo, const ICurveComposite* pCompoCollision, bool bStart) { + + // Calcolo il punto corrente su cui posizionare il centro della lama + Point3d ptCurr ; Vector3d vtTan, vtOut ; + if ( bStart) { + if ( ! CalcPointAndDirections( pCompo, 0., ICurve::FROM_PLUS, ptCurr, vtTan, vtOut)) + return false ; + } + else { + if ( ! CalcPointAndDirections( pCompo, double( pCompo->GetCurveCount()), ICurve::FROM_MINUS, ptCurr, vtTan, vtOut)) + return false ; + } + + // Verifico che in tale punto la collisione esista, altrimenti non faccio nulla + bool bCollision = false ; + if ( ! CheckCollision( pCompo, pCompoCollision, ptCurr, vtTan, vtOut, bCollision)) + return false ; + if ( ! bCollision) + return true ; + + // Scorro la curva per trovare un punto senza collisione (riferimento sempre per il centro lama) + double dLen ; pCompo->GetLength( dLen) ; + const double SAMPLE_LEN = m_TParams.m_dThick / 2. ; + double dCurrLen = ( bStart ? min( SAMPLE_LEN, dLen) : max( 0., dLen - SAMPLE_LEN)) ; + Point3d ptA = ptCurr ; // -->! punto con collisione !<-- + Point3d ptB = ptCurr ; // -->! punto senza collisione !<-- + bool bCollisionFound = false ; + while ( ( bStart ? dCurrLen < dLen - EPS_SMALL : dCurrLen > 0.)) { + + // Recupero il Punto e le direzioni correnti + double dUCurr ; + if ( ! pCompo->GetParamAtLength( dCurrLen, dUCurr) || + ! CalcPointAndDirections( pCompo, dUCurr, bStart ? ICurve::FROM_PLUS : ICurve::FROM_MINUS, ptCurr, vtTan, vtOut)) + return false ; + + // Verifico la collisione + if ( ! CheckCollision( pCompo, pCompoCollision, ptCurr, vtTan, vtOut, bCollision)) + return false ; + if ( ! bCollision) { + ptB = ptCurr ; + bCollisionFound = true ; + break ; + } + + dCurrLen += ( bStart ? SAMPLE_LEN : - SAMPLE_LEN) ; + ptA = ptCurr ; + } + if ( ! bCollisionFound) { + // I due estremi per la bisezione non sono stati trovati, pCompo viene scartata + pCompo->Clear() ; + return true ; + } + if ( AreSamePointEpsilon( ptA, ptB, 10. * EPS_SMALL)) + return true ; // tratto troppo piccolo per trovare una collisione, non modifico nulla + + // Applico il metodo di bisezione per calcolare il punto ideale per posizionare l'utensile + const int MAX_ITER = 10 ; + int nIter = 0 ; + bool bCollisionA = true ; + double dLenA = 0., dLenB = 0. ; + while ( nIter < MAX_ITER && ! AreSamePointEpsilon( ptA, ptB, 10. * EPS_SMALL)) { + + // Ricavo le rispettive lunghezze + if ( ! pCompo->GetLengthAtPoint( ptA, dLenA) || ! pCompo->GetLengthAtPoint( ptB, dLenB)) + return false ; + + // Recupero i parametri a metà lunghezza + double dUCurr ; + if ( ! pCompo->GetParamAtLength( 0.5 * ( dLenA + dLenB), dUCurr) || + ! pCompo->GetPointD1D2( dUCurr, bStart ? ICurve::FROM_PLUS : ICurve::FROM_MINUS, ptCurr) || + ! CalcPointAndDirections( pCompo, dUCurr, bStart ? ICurve::FROM_PLUS : ICurve::FROM_MINUS, ptCurr, vtTan, vtOut)) + return false ; + + // Verifico la collisione in tale punto + if ( ! CheckCollision( pCompo, pCompoCollision, ptCurr, vtTan, vtOut, bCollision)) + return false ; + + if ( bCollision == bCollisionA) + ptA = ptCurr ; + else + ptB = ptCurr ; + + ++ nIter ; + } + + #if BISECTION_ALONG5AX + VT.clear(); VC.clear() ; + VT.emplace_back( pCompo->Clone()) ; VC.emplace_back( BLUE) ; + VT.emplace_back( pCompoCollision->Clone()) ; VC.emplace_back( WHITE) ; + double _dL = dLenB ; + double _dU ; pCompo->GetParamAtLength( _dL, _dU) ; + Point3d _ptA ; Vector3d _vtA, _vtB ; + CalcPointAndDirections( pCompo, _dU, bStart ? ICurve::FROM_PLUS : ICurve::FROM_MINUS, _ptA, _vtA, _vtB) ; + PtrOwner _pCompoSaw( CreateCurveComposite()) ; + _pCompoSaw->AddPoint( _ptA + _vtA * m_TParams.m_dThick / 2) ; + _pCompoSaw->AddLine( _ptA + _vtA * m_TParams.m_dThick / 2 + _vtB * m_TParams.m_dDiam) ; + _pCompoSaw->AddLine( _ptA - _vtA * m_TParams.m_dThick / 2 + _vtB * m_TParams.m_dDiam) ; + _pCompoSaw->AddLine( _ptA - _vtA * m_TParams.m_dThick / 2) ; + _pCompoSaw->Close() ; + VT.emplace_back( _pCompoSaw->Clone()) ; VC.emplace_back( RED) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Result.nge") ; + #endif + + // Trim della curva nel punto ricavato (ultimo punto senza collissione) + double dLenTrim = dLenB ; + if ( bStart) + return ( pCompo->TrimStartAtLen( dLenTrim)) ; + else + return ( pCompo->TrimEndAtLen( dLenTrim)) ; + } ; + + // --- + typedef vector> SectionSplitParVector ; + auto SplitSectionInterval = [&] ( INTVECTOR vSectionInterval, double dUS, double dUE, SectionSplitParVector& vRes) { + + vRes.clear() ; + + // Se inizio maggiore di fine, l'intervallo non è valido + if ( dUS > dUE - EPS_SMALL) + return ; + + // Scorro gli intervalli + for ( int i = 0 ; i < ssize( vSectionInterval) - 1 ; ++ i) { + double dIntS = double( vSectionInterval[i]) ; + double dIntE = double( vSectionInterval[i+1]) ; + + // Se l'intero intervallo del vettore è prima del nostro inizio, passo oltre + if ( dIntE <= dUS + EPS_SMALL) + continue ; + // Se l'intero intervallo del vettore è dopo la fine, posso fermarmi + if ( dIntS >= dUE - EPS_SMALL) { + break ; + } + + // Calcolo l'intersezione + double dCurrUS = max( dUS, dIntS) ; + double dCurrUE = min( dUE, dIntE) ; + // Se porzione valida, la aggiungo al risultato + if ( dCurrUS < dCurrUE) + vRes.emplace_back( make_tuple( i, dCurrUS, dCurrUE )) ; + } + + } ; + // ======================================================================================================= + + const double SAW_EXTERNAL_ANGLE_LEN_TOL = 0.5 ; + + // Scorro le sezioni (sono nel piano XY) + for ( SectionInfo5Ax& Section : vSections) { + + // Se la sezione non è valida, errore + if ( Section.pSection == nullptr || ! Section.pSection->IsValid()) + continue ; + + // Il percorso che la lama deve seguire è definito dalle SubSections + PtrOwner pMySection( CreateCurveComposite()) ; + if ( IsNull( pMySection)) + return false ; + for ( const SubSectionInfo5Ax& SubSection : Section.vSubSections) { + if ( SubSection.pSubSection != nullptr && SubSection.pSubSection->IsValid()) { + if ( ! pMySection->AddCurve( SubSection.pSubSection->Clone())) + return false ; + } + } + + // Numero di curve contenute in ogni SubSection della sezione corrente + INTVECTOR vnCrv( Section.vSubSections.size() + 1, 0) ; + for ( int i = 0 ; i < ssize( Section.vSubSections) ; ++ i) { + if ( Section.vSubSections[i].pSubSection == nullptr || ! Section.vSubSections[i].pSubSection->IsValid()) + continue ; + int nToTCrv = Section.vSubSections[i].pSubSection->GetCurveCount() ; + vnCrv[i + 1] = vnCrv[i] + nToTCrv ; + } + + // Scorro le curve della sezione corrente (valuto sempre l'estremo iniziale della singola curva) + vAngleParams.emplace_back( make_pair( 0., EXTERNAL)) ; // vertice iniziale associato ad angolo esterno + int nCrvCnt = pMySection->GetCurveCount() ; + + #if BISECTION_ALONG5AX + VT.emplace_back( pMySection->Clone()) ; + VC.emplace_back( RED) ; + SaveGeoObj( VT, VC, "C:\\Temp\\section.nge") ; + #endif + + for ( int nCrv = 1 ; nCrv < nCrvCnt ; ++ nCrv) { + + // Recupero le due direzione di tangenza (precedente e successiva) + Point3d ptJoin ; + Vector3d vtTanPrev, vtTanNext ; + if ( ! pMySection->GetPointD1D2( double( nCrv), ICurve::FROM_MINUS, ptJoin, &vtTanPrev) || ! vtTanPrev.Normalize() || + ! pMySection->GetPointD1D2( double( nCrv), ICurve::FROM_PLUS, ptJoin, &vtTanNext) || ! vtTanNext.Normalize()) + continue ; + + // Se le direzioni sono tra loro parallele, allora è un tratto C' Locale, non faccio nulla + if ( AreSameVectorApprox( vtTanPrev, vtTanNext)) + continue ; + + // Verifico se angolo interno o esterno (Segno del determinante) + double dDet = ( vtTanPrev.x * vtTanNext.y) - ( vtTanPrev.y * vtTanNext.x) ; + bool bAngInt = ( dDet < EPS_ZERO) ; + + // Memorizzo i risultati + vAngleParams.emplace_back( make_pair( double( nCrv), bAngInt ? INTERNAL : EXTERNAL)) ; + } + vAngleParams.emplace_back( make_pair( nCrvCnt, EXTERNAL)) ; // vertice finale associato ad angolo esterno + + // Scorro le parametrizzazioni a coppie, in modo da isolare la parte di curva tra due spigoli + for ( int i = 0 ; i < ssize( vAngleParams) - 1 ; ++ i) { + const double& dUS = vAngleParams[i].first ; + const double& dUE = vAngleParams[i+1].first ; + + // Verifico quale SubSection Comprende la curva C' corrente + SectionSplitParVector vSplit ; SplitSectionInterval( vnCrv, dUS, dUE, vSplit) ; + + // Recupero il tratto di curva corrente + PtrOwner pCompo( ConvertCurveToComposite( pMySection->CopyParamRange( dUS, dUE))) ; + if ( IsNull( pCompo) || ! pCompo->IsValid()) + return false ; + + // --- Inizio + // Se angolo esterno all'inizio + if ( vAngleParams[i].second == EXTERNAL) + pCompo->ExtendStartByLen( max( SAW_EXTERNAL_ANGLE_LEN_TOL, m_TParams.m_dThick / 2. - m_Params.m_dSideStep)) ; + // Se angolo interno all'inizio + else { + // Mediante la bisezione verifico se esiste collisione + PtrOwner pCompoColl( ConvertCurveToComposite( pMySection->CopyParamRange( 0., dUS))) ; + if ( ! AdjustCompoByCollision( pCompo, pCompoColl, true)) + return false ; + if ( ! pCompo->IsValid()) + continue ; + } + + // --- Fine + // Se angolo esterno alla fine + if ( vAngleParams[i+1].second == EXTERNAL) { + double dLen ; pCompo->GetLength( dLen) ; + pCompo->TrimEndAtLen( max( 0., dLen - m_TParams.m_dThick / 2. + SAW_EXTERNAL_ANGLE_LEN_TOL)) ; + } + // Se angolo interno alla fine + else { + // Mediante la bisezione verifico se esiste la collisione + PtrOwner pCompoColl( ConvertCurveToComposite( pMySection->CopyParamRange( dUE, double( nCrvCnt)))) ; + if ( ! AdjustCompoByCollision( pCompo, pCompoColl, false)) + return false ; + if ( ! pCompo->IsValid()) + continue ; + } + + // Memorizzo il risultato ottenuto + if ( vSplit.empty()) + continue ; + else if ( ssize( vSplit) == 1) { + // Con le modifiche apportate alla curva, calcolo gli Step + int nStep ; double dStep ; + CalcSideStep( pCompo, nStep, dStep) ; + int nSection = get<0>( vSplit[0]) ; + Section.vSubSections[nSection].CompoMidSawParams.resize( Section.vSubSections[nSection].CompoMidSawParams.size() + 1) ; + Section.vSubSections[nSection].CompoMidSawParams.back().pCompo.Set( ::Release( pCompo)) ; + Section.vSubSections[nSection].CompoMidSawParams.back().nStep = nStep ; + Section.vSubSections[nSection].CompoMidSawParams.back().dStep = dStep ; + } + else { + for ( int j = 0 ; j < ssize( vSplit) ; ++ j) { + int nSection = get<0>( vSplit[j]) ; + // Recupero il punto finale della sezione corrente + Point3d ptEndSection ; Section.vSubSections[nSection].pSubSection->GetEndPoint( ptEndSection) ; + if ( pCompo->IsPointOn( ptEndSection)) { + double dUTrim ; pCompo->GetParamAtPoint( ptEndSection, dUTrim) ; + PtrOwner pMyCompo( ConvertCurveToComposite( pCompo->CopyParamRange( 0, dUTrim))) ; + if ( ! IsNull( pMyCompo) && pMyCompo->IsValid()) { + int nStep ; double dStep ; + CalcSideStep( pMyCompo, nStep, dStep) ; + Section.vSubSections[nSection].CompoMidSawParams.resize( Section.vSubSections[nSection].CompoMidSawParams.size() + 1) ; + Section.vSubSections[nSection].CompoMidSawParams.back().pCompo.Set( ::Release( pMyCompo)) ; + Section.vSubSections[nSection].CompoMidSawParams.back().nStep = nStep ; + Section.vSubSections[nSection].CompoMidSawParams.back().dStep = dStep ; + pCompo->TrimStartAtParam( dUTrim) ; + } + } + } + if ( pCompo->IsValid()) { + int nLastSection = get<0>( vSplit.back()) ; + if ( Section.vSubSections[nLastSection].CompoMidSawParams.empty()) + Section.vSubSections[nLastSection].CompoMidSawParams.resize( Section.vSubSections[nLastSection].CompoMidSawParams.size() + 1) ; + if ( IsNull( Section.vSubSections[nLastSection].CompoMidSawParams.back().pCompo) || + ! Section.vSubSections[nLastSection].CompoMidSawParams.back().pCompo->IsValid()) { + if ( ! Section.vSubSections[nLastSection].CompoMidSawParams.back().pCompo.Set( CreateCurveComposite())) + return false ; + } + if ( ! Section.vSubSections[nLastSection].CompoMidSawParams.back().pCompo->AddCurve( ::Release( pCompo))) + return false ; + int nStep ; double dStep ; + CalcSideStep( Section.vSubSections[nLastSection].CompoMidSawParams.back().pCompo, nStep, dStep) ; + Section.vSubSections[nLastSection].CompoMidSawParams.back().nStep = nStep ; + Section.vSubSections[nLastSection].CompoMidSawParams.back().dStep = dStep ; + } + + } + } + + #if BISECTION_ALONG5AX + VT.clear() ; VC.clear() ; + VT.emplace_back( pMySection->Clone()) ; VC.emplace_back( BLUE) ; + for ( int i = 0 ; i < ssize( Section.vSubSections) ; ++ i) { + for ( int j = 0 ; j < ssize( Section.vSubSections[i].CompoMidSawParams) ; ++ j) { + VT.emplace_back( Section.vSubSections[i].CompoMidSawParams[j].pCompo->Clone()) ; VC.emplace_back( AQUA) ; + Point3d ptA ; Vector3d vtA, vtB ; + CalcPointAndDirections( Section.vSubSections[i].CompoMidSawParams[j].pCompo, 0, ICurve::FROM_PLUS, ptA, vtA, vtB) ; + PtrOwner pCompoSaw( CreateCurveComposite()) ; + pCompoSaw->AddPoint( ptA + vtA * m_TParams.m_dThick / 2) ; + pCompoSaw->AddLine( ptA + vtA * m_TParams.m_dThick / 2 + vtB * m_TParams.m_dDiam) ; + pCompoSaw->AddLine( ptA - vtA * m_TParams.m_dThick / 2 + vtB * m_TParams.m_dDiam) ; + pCompoSaw->AddLine( ptA - vtA * m_TParams.m_dThick / 2) ; + pCompoSaw->Close() ; + VT.emplace_back( pCompoSaw->Clone()) ; VC.emplace_back( RED) ; + CalcPointAndDirections( Section.vSubSections[i].CompoMidSawParams[j].pCompo, Section.vSubSections[i].CompoMidSawParams[j].pCompo->GetCurveCount(), ICurve::FROM_PLUS, ptA, vtA, vtB) ; + pCompoSaw->Clear() ; + pCompoSaw->AddPoint( ptA + vtA * m_TParams.m_dThick / 2) ; + pCompoSaw->AddLine( ptA + vtA * m_TParams.m_dThick / 2 + vtB * m_TParams.m_dDiam) ; + pCompoSaw->AddLine( ptA - vtA * m_TParams.m_dThick / 2 + vtB * m_TParams.m_dDiam) ; + pCompoSaw->AddLine( ptA - vtA * m_TParams.m_dThick / 2) ; + pCompoSaw->Close() ; + VT.emplace_back( pCompoSaw->Clone()) ; VC.emplace_back( RED) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\Result.nge") ; + #endif + + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SawFinishing::CalcAlong5ACuts( SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, const BBox3d& b3Raw, const ISurfTriMesh* pStmRaw) { @@ -3543,6 +4048,7 @@ SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& fr double dRawMaxZ = b3Raw.GetMax().z ; // aggiungo due tratti verticali agli estremi delle sezioni per il calcolo delle collisioni + // !<-- Queste sezioni servono solo per il calcolo delle collisioni -->! ICRVCOMPOPOVECTOR vBoundedSections( vSections.size()) ; for ( int nSect = 0 ; nSect < ssize( vSections) ; ++ nSect) { if ( vSections[nSect].pSection != nullptr && vSections[nSect].pSection->IsValid() && @@ -3554,12 +4060,11 @@ SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& fr } } - // scorro le sezioni - double dLastElev = 0. ; + // per ogni sezione effettuo il trim (se richiesto) for ( int nSect = 0 ; nSect < ssize( vSections) ; ++ nSect) { // recupero la sezione - const SectionInfo& Section = vSections[nSect] ; + SectionInfo5Ax& Section = vSections[nSect] ; if ( Section.pSection == nullptr || ! Section.pSection->IsValid()) continue ; @@ -3604,164 +4109,185 @@ SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& fr } } } + } - // scorro le SubSection ottenute - bool bLastToolInv = false ; - bool bFirst = true ; + // modifico le curve della sezione corrente in modo da pulire più materiale possibile in presenza di spigoli interni e di non + // eccedere con le passate in presenza di spigoli esterni + if ( ! CalcStepsFor5AxSections( vSections)) + return false ; + + // scorro le sezioni da lavorare + double dLastElev = 0. ; + for ( int nSect = 0 ; nSect < ssize( vSections) ; ++ nSect) { + + // verifico che la Section corrente sia valida, altrimento passo alla successiva + const SectionInfo5Ax& Section = vSections[nSect] ; + if ( Section.pSection == nullptr || ! Section.pSection) + continue ; + + // scorro le SubSections + bool bLastToolInv = false, bFirst = true ; Point3d ptStartPrev ; - Vector3d vtCorrPrev = V_NULL, - vtToolPrev = V_NULL ; + Vector3d vtCorrPrev = V_NULL, vtToolPrev = V_NULL ; for ( int nSubSect = 0 ; nSubSect < ssize( Section.vSubSections) ; ++ nSubSect) { - // recupero la SubSection corrente, se non valida, passo alla successiva - const SubSectionInfo& SubSection = Section.vSubSections[nSubSect] ; - PtrOwner pSubSect( CloneCurveComposite( SubSection.pSubSection)) ; - if ( pSubSect == nullptr || ! pSubSect->IsValid()) + // verifico che la SubSection corrente sia valida, altrimenti passo alla successiva + const SubSectionInfo5Ax& SubSection = Section.vSubSections[nSubSect] ; + if ( SubSection.pSubSection == nullptr || ! SubSection.pSubSection->IsValid()) continue ; - // calcolo della lunghezza dello step e del numero di step complessivi - double dStep = max( m_Params.m_dSideStep, 10. * EPS_SMALL) ; - double dLen ; - if ( ! pSubSect->GetLength( dLen)) - return false ; - if ( dLen < 10. * EPS_SMALL) - return true ; - int nStep = static_cast( ceil( dLen / dStep)) ; - dStep = dLen / nStep ; + // per ogni sezione recupero le curve di centro lama + + for ( int nMidSawCrv = 0 ; nMidSawCrv < ssize( SubSection.CompoMidSawParams) ; ++ nMidSawCrv) { - // Ciclo sulle passate - for ( int i = 0 ; i <= nStep ; ++ i) { - // coordinate nel punto, del versore correzione e del versore utensile - double dLcurr = i * dStep ; - double dU ; pSubSect->GetParamAtLength( dLcurr, dU) ; - Point3d ptP ; - Vector3d vtTan, vtPerp ; - if ( ! pSubSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP, &vtTan) || ! vtTan.Normalize()) - return false ; - Vector3d vtCorr = GetToGlob( vtTan, frSect) ; - vtCorr.Rotate( vtGdDir, m_Params.m_bInvert ? - ANG_RIGHT : ANG_RIGHT) ; - // se tangente circa orizzontale, correggo la direzione per evitare inversioni di vtTool - if ( abs( vtTan.y) < 5 * EPS_SMALL) { - if ( ( SubSection.nHeadSide == SAWFIN_HS_LEFT)) { - vtTan.y = abs( vtTan.y) ; // y > 0. - vtTan.x = - abs( vtTan.x) ; // x < 0. - } - else if ( SubSection.nHeadSide == SAWFIN_HS_RIGHT) { - vtTan.y = - abs( vtTan.y) ; // y < 0. - vtTan.x = abs( vtTan.x) ; // x > 0. - } - } - Vector3d vtTool = GetToGlob( vtTan, frSect) ; - - // determino l'orientamento della testa - // NB. vtTool deve sempre avere la componente Z come positiva (quindi vtCorr.y >= 0) - bool bCurrToolInv = ( SubSection.nHeadSide == SAWFIN_HS_RIGHT) ; - if ( vtTool.z < - 5. * EPS_SMALL) - vtTool.Invert() ; - - // punto di passata è sulla metà della sezione lama - ptP += - 0.5 * m_TParams.m_dThick * GetToLoc( vtTool, frSect) ; - - // verifico posizionando la lama nel punto corrente se devo spostarmi per evitare collisione con la sezione - double dSectElev = 0. ; - bool bOtherColl = false, bAwayFromPoint = false ; - if ( ! CalcCAvSect5Ax( pSubSect, vBoundedSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dSectElev, - bOtherColl, bAwayFromPoint)) { - m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; - return false ; - } - // se collisione con altra sezione o collisione distante dal punto corrente, passo allo step successivo (non inserisco la passata corrente) - if ( bOtherColl || bAwayFromPoint) + // verifico che la Curva di Centro Lama sia valida, altrimenti passo alla successiva + const SubSectionStep5Ax& MidSawPath = SubSection.CompoMidSawParams[nMidSawCrv] ; + if ( MidSawPath.pCompo == nullptr || ! MidSawPath.pCompo->IsValid()) continue ; + const ICurveComposite* pCompoPath = MidSawPath.pCompo ; + const int& nStep = MidSawPath.nStep ; + const double& dStep = MidSawPath.dStep ; - // verifico se inversione della testa - bool bSpecialAppr = ( m_Params.m_nLeadLinkType != SAWFIN_LL_CENT && ! bFirst && ( bCurrToolInv != bLastToolInv)) ; + // Ciclo sulle passate + bool bFirstMidSawCrv = true ; + for ( int i = 0 ; i <= nStep ; ++ i) { - // definisco gli estremi del tratto rettilineo in globale - Point3d ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dSectElev ; - if ( m_Params.m_bInvert) - ptPCAvSect.Translate( - vtGdDir * Dist( ptGdStart, ptGdEnd)) ; - Point3d ptStart = ptPCAvSect ; - Point3d ptEnd = ptPCAvSect + vtGdDir * ( Dist( ptGdStart, ptGdEnd)) ; - - // verifico eventuale estensione degli estremi sul grezzo - if ( bExtend) { - if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw)) + // coordinate nel punto, del versore correzione e del versore utensile + double dLcurr = i * dStep ; + double dU ; pCompoPath->GetParamAtLength( dLcurr, dU) ; + Point3d ptP ; + Vector3d vtTan, vtPerp ; + if ( ! pCompoPath->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP, &vtTan) || ! vtTan.Normalize()) return false ; - } + Vector3d vtCorr = GetToGlob( vtTan, frSect) ; + vtCorr.Rotate( vtGdDir, m_Params.m_bInvert ? - ANG_RIGHT : ANG_RIGHT) ; + // se tangente circa orizzontale, correggo la direzione per evitare inversioni di vtTool + if ( abs( vtTan.y) < 5 * EPS_SMALL) { + if ( ( SubSection.nHeadSide == SAWFIN_HS_LEFT)) { + vtTan.y = abs( vtTan.y) ; // y > 0. + vtTan.x = - abs( vtTan.x) ; // x < 0. + } + else if ( SubSection.nHeadSide == SAWFIN_HS_RIGHT) { + vtTan.y = - abs( vtTan.y) ; // y < 0. + vtTan.x = abs( vtTan.x) ; // x > 0. + } + } + Vector3d vtTool = GetToGlob( vtTan, frSect) ; - // determino l'elevazione del taglio ( per confrontarla con la MaxDepth consentita) - Vector3d vtThick = vtTool * m_TParams.m_dThick ; - double dElev, dElev2 ; - if ( ! GetElevation( m_nPhase, ptStart, ptEnd, Z_AX, dElev) || - ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, Z_AX, dElev2)) { - m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; - return false ; - } - dElev = max( dElev, dElev2) ; - if ( dElev < EPS_SMALL) - dElev = max( { dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z, 0.}) ; - // la confronto con il massimo affondamento e con la massima lavorazione della lama. Se sotto alla massima Depth allora riporto - // l'utensile in verticale e ricalcolo il punto più adatto in z per il tratto lineare - double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ; - if ( dElev > dMaxDepth) { - // modifica versore correzione e direzione utensile - vtTool.z = 0. ; - if ( ! vtTool.Normalize()) - return false ; - vtCorr = Z_AX ; - double dElevTmp = 0. ; - if ( ! CalcCAvSect5Ax( pSubSect, vBoundedSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dElevTmp, + // determino l'orientamento della testa + // NB. -->! vtTool deve sempre avere la componente Z come positiva (quindi vtCorr.y >= 0) !<-- + bool bCurrToolInv = ( SubSection.nHeadSide == SAWFIN_HS_RIGHT) ; + if ( vtTool.z < - 5. * EPS_SMALL) + vtTool.Invert() ; + + // verifico posizionando la lama nel punto corrente se devo spostarmi per evitare collisione con la sezione + double dSectElev = 0. ; + bool bOtherColl = false, bAwayFromPoint = false ; + if ( ! CalcCAvSect5Ax( pCompoPath, vBoundedSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dSectElev, bOtherColl, bAwayFromPoint)) { m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; return false ; } + // se collisione con altra sezione o collisione distante dal punto corrente, passo allo step successivo (non inserisco la passata corrente) if ( bOtherColl || bAwayFromPoint) continue ; - ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dElevTmp ; - double dElev3 ; - if ( ! GetElevation( m_nPhase, ptPCAvSect, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtCorr, dElev3)) { - m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; - return false ; - } - Point3d ptPTopRaw = ptPCAvSect + ( dElev3 - m_TParams.m_dDiam / 2.) * vtCorr ; - ptStart.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ; - ptEnd.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ; - dElev = dMaxDepth ; - } - else { - double dElev4, dElev5 ; - if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev4) || - ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev5)) { - m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; - return false ; - } - dElev = max( dElev4, dElev5) ; - } - // Imposto dati comune - SetToolDir( vtTool) ; - SetCorrAuxDir( vtCorr) ; - // se utensile non piatto - if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10. * EPS_SMALL)) { - if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { - if ( ! CalcAlong5AOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtToolPrev, vtCorr, vtCorrPrev, dElev, bExtend, false, - bFirst, bSpecialAppr)) + // punto di passata è sulla metà della sezione lama + ptP += - 0.5 * m_TParams.m_dThick * GetToLoc( vtTool, frSect) ; + + // verifico se inversione della testa + bool bSpecialAppr = ( m_Params.m_nLeadLinkType != SAWFIN_LL_CENT && ! bFirst && ( bCurrToolInv != bLastToolInv)) ; + + // definisco gli estremi del tratto rettilineo in globale + Point3d ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dSectElev ; + if ( m_Params.m_bInvert) + ptPCAvSect.Translate( - vtGdDir * Dist( ptGdStart, ptGdEnd)) ; + Point3d ptStart = ptPCAvSect ; + Point3d ptEnd = ptPCAvSect + vtGdDir * ( Dist( ptGdStart, ptGdEnd)) ; + + // verifico eventuale estensione degli estremi sul grezzo + if ( bExtend) { + if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw)) return false ; } + + // determino l'elevazione del taglio ( per confrontarla con la MaxDepth consentita) + Vector3d vtThick = vtTool * m_TParams.m_dThick ; + double dElev, dElev2 ; + if ( ! GetElevation( m_nPhase, ptStart, ptEnd, Z_AX, dElev) || + ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, Z_AX, dElev2)) { + m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; + return false ; + } + dElev = max( dElev, dElev2) ; + if ( dElev < EPS_SMALL) + dElev = max( { dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z, 0.}) ; + + // la confronto con il massimo affondamento e con la massima lavorazione della lama. Se sotto alla massima Depth allora riporto + // l'utensile in verticale e ricalcolo il punto più adatto in z per il tratto lineare + double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ; + if ( dElev > dMaxDepth) { + // modifica versore correzione e direzione utensile + vtTool.z = 0. ; + if ( ! vtTool.Normalize()) + return false ; + vtCorr = Z_AX ; + double dElevTmp = 0. ; + ptP += + 0.5 * m_TParams.m_dThick * GetToLoc( vtTool, frSect) ; + if ( ! CalcCAvSect5Ax( pCompoPath, vBoundedSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dElevTmp, + bOtherColl, bAwayFromPoint)) { + m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; + return false ; + } + if ( bOtherColl || bAwayFromPoint) + continue ; + ptP += - 0.5 * m_TParams.m_dThick * GetToLoc( vtTool, frSect) ; + ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dElevTmp ; + double dElev3 ; + if ( ! GetElevation( m_nPhase, ptPCAvSect, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtCorr, dElev3)) { + m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; + return false ; + } + Point3d ptPTopRaw = ptPCAvSect + ( dElev3 - m_TParams.m_dDiam / 2.) * vtCorr ; + ptStart.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ; + ptEnd.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ; + dElev = dMaxDepth ; + } else { - if ( ! CalcAlong5AZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtToolPrev, vtCorr, vtCorrPrev, dElev, dLastElev, bExtend, false, - bFirst, bSpecialAppr, 2. * ( dStep - 10. * EPS_SMALL))) + double dElev4, dElev5 ; + if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev4) || + ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev5)) { + m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ; return false ; + } + dElev = max( dElev4, dElev5) ; } - // salvo dati correnti - dLastElev = dElev ; - ptStartPrev = ptStart ; + + // Imposto dati comune + SetToolDir( vtTool) ; + SetCorrAuxDir( vtCorr) ; + // se utensile non piatto + if ( bFirst || bFirstMidSawCrv || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10. * EPS_SMALL)) { + if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { + if ( ! CalcAlong5AOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtToolPrev, vtCorr, vtCorrPrev, dElev, bExtend, false, + bFirst, bSpecialAppr)) + return false ; + } + else { + if ( ! CalcAlong5AZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtToolPrev, vtCorr, vtCorrPrev, dElev, dLastElev, bExtend, false, + bFirst, bSpecialAppr, 2. * ( dStep - 10. * EPS_SMALL))) + return false ; + } + // salvo dati correnti + dLastElev = dElev ; + ptStartPrev = ptStart ; + } + bFirst = false ; + bFirstMidSawCrv = false ; + vtCorrPrev = vtCorr ; + vtToolPrev = vtTool ; + bLastToolInv = bCurrToolInv ; } - bFirst = false ; - vtCorrPrev = vtCorr ; - vtToolPrev = vtTool ; - bLastToolInv = bCurrToolInv ; } } // se ZigZag e non centrato aggiungo risalita diff --git a/SawFinishing.h b/SawFinishing.h index 63d0a1b..13ed678 100644 --- a/SawFinishing.h +++ b/SawFinishing.h @@ -26,21 +26,34 @@ class ISurfFlatRegion ; class ISurfTriMesh ; class Polygon3d ; -// Definizione strutture per Section/SubSection ------------------------------ -struct SubSectionInfo { - PtrOwner pSubSection ; - int nHeadSide ; - SubSectionInfo() +// Definizione strutture per Section/SubSection/SubSectionStep per Along5Ax ------------------------------ +// -------------------------- +struct SubSectionStep5Ax { + PtrOwner pCompo ; // Curva ideale per centro lama + int nStep ; // Numero di Step per lavorare pCompo + double dStep ; // Lunghezza degli Step per lavorare pCompo + SubSectionStep5Ax() + : pCompo( nullptr), nStep( 0), dStep( 0.) {} ; +} ; +typedef std::vector SUBSECTIONSTEPVECTOR ; +// -------------------------- +struct SubSectionInfo5Ax { + PtrOwner pSubSection ; // Porzione della sezione da lavorare senza cambiare Side della testa + int nHeadSide ; // Side della testa per la lavorazione + SUBSECTIONSTEPVECTOR CompoMidSawParams ; // Curve modificate di pSubSection per posizionamento centro lama ideale + INTVECTOR vnClass ; // Insieme dei tratti di classificazione + SubSectionInfo5Ax() : pSubSection( nullptr), nHeadSide( -1) {} ; } ; -typedef std::vector SUBSECTIONVECTOR ; -struct SectionInfo { - PtrOwner pSection ; - SUBSECTIONVECTOR vSubSections ; - SectionInfo() +// -------------------------- +typedef std::vector SUBSECTIONVECTOR ; +struct SectionInfo5Ax { + PtrOwner pSection ; // Curva di Sezione + SUBSECTIONVECTOR vSubSections ; // Partizione di pSection in SubSection (parti che mantengono il Side della testa costante) + SectionInfo5Ax() : pSection( nullptr), vSubSections( SUBSECTIONVECTOR{}) {} ; } ; -typedef std::vector SECTIONVECTOR ; +typedef std::vector SECTIONVECTOR ; //---------------------------------------------------------------------------- class SawFinishing : public Machining @@ -119,13 +132,14 @@ class SawFinishing : public Machining bool CalcCAvSect5Ax( const ICurveComposite* pSubSect, const std::vector>& vBoundedSections, const Vector3d& vtTool, const Vector3d& vtCorr, const Point3d& ptP, double& dElev, bool& bOtherCollision, bool& bAwayFromPoint) const ; + bool CalcStepsFor5AxSections( SECTIONVECTOR& vSections) const ; bool CalcAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect, bool bExtend, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, double dRaxMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw) ; bool CalcAlongStdCuts( ICurve* pSect, double dUmin, double dUmax, bool bSkipVertMin, bool bSkipVertMax, bool bSkipVertIni, bool bSkipVertFin, bool bInvert, const Frame3d& frSect, bool bExtend, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw) ; - bool CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend, + bool CalcAlong5ACuts( SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, const BBox3d& b3Raw, const ISurfTriMesh* pStmRaw) ; bool CalcAlong5AOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir, const Vector3d& vtTool,