From 50b8a8aa94ea05d0eee7caa22b4842f80c4ffffc Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 24 Dec 2024 17:25:58 +0100 Subject: [PATCH] in CalcPocketing : - migliorati percorsi conformal ZigZag/OneWay - migliorie varie. --- CalcPocketing.cpp | 258 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 223 insertions(+), 35 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index cef5396..cbbbf64 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -708,6 +708,32 @@ ResetCurveTempProps( ICurveComposite* pCrvCompo) return true ; } +//---------------------------------------------------------------------------- +static bool +IsCurveCompoHomogeneous( const ICurveComposite* pCrvCompo, bool& bAllClosed, bool& bAllOpen) +{ + // controllo validità della curva + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + bAllClosed = true ; + bAllOpen = true ; + if ( pCrvCompo->GetCurveCount() == 0) + return true ; + + // scorro le curve + for ( int i = 0 ; i < pCrvCompo->GetCurveCount() && ( bAllOpen || bAllClosed) ; ++ i) { + // recupero la sottocurva i-esima + const ICurve* pCrv = pCrvCompo->GetCurve( i) ; + if ( pCrv == nullptr || ! pCrv->IsValid()) + return false ; + int nTmpProp = pCrv->GetTempProp( 0) ; + bAllOpen = bAllOpen && ( nTmpProp == TEMP_PROP_OPEN_EDGE) ; + bAllClosed = bAllClosed && ( nTmpProp == TEMP_PROP_CLOSE_EDGE) ; + } + + return true ; +} + //---------------------------------------------------------------------------- static bool GetSfrCrvCompoLoops( const ISurfFlatRegion* pSfr, ICRVCOMPOPOVECTOR& vCrvCompo) @@ -886,6 +912,9 @@ GetIndOfHypoteticalChunk( const ICRVCOMPOPOVECTOR& vCrv, const ICurveComposite* return false ; } } + + // piccolo Offset di correzione della superfice + pSfrTmp->Offset( 500 * EPS_SMALL, ICurve::OFF_FILLET) ; // classifico le curve con il Chunk nC-esimo CRVCVECTOR ccClass ; if ( pSfrTmp->GetCurveClassification( *pCrvA, EPS_SMALL, ccClass) && @@ -1609,14 +1638,14 @@ ChainCompoCurves( ICRVCOMPOPOVECTOR& vCrvCompo) //---------------------------------------------------------------------------- static bool ChangePtStartForSinglePocketCurve( ICurveComposite* pCrvCompo, const PocketParams& PockParams, - const Point3d& ptRef) + const Point3d& ptRef, bool bInvertOpenCrv) { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; // se la curva è aperta - if ( ! pCrvCompo->IsClosed()) { + if ( ! pCrvCompo->IsClosed() && bInvertOpenCrv) { // se non ho un punto di riferimento, allora non faccio nulla if ( ! ptRef.IsValid()) return true ; @@ -1650,7 +1679,8 @@ ChangePtStartForSinglePocketCurve( ICurveComposite* pCrvCompo, const PocketParam //---------------------------------------------------------------------------- static bool -AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams) +AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, + const PocketParams& PockParams, bool bInvertOpenCrv) { // se non ho curve, allora non faccio nulla @@ -1663,7 +1693,7 @@ AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, if ( IsNull( vCrvCompo[i]) || ! vCrvCompo[i]->IsValid()) return false ; // cambio il punto iniziale della curva - if ( ! ChangePtStartForSinglePocketCurve( vCrvCompo[i], PockParams, PockParams.ptStart)) + if ( ! ChangePtStartForSinglePocketCurve( vCrvCompo[i], PockParams, PockParams.ptStart, bInvertOpenCrv)) return false ; } @@ -1764,7 +1794,7 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara bool bExtAllClose = false ; bool bExtAllOpen = false ; if ( int( vpCrvs.size()) == 1) { - if ( vpCrvs[0]->GetTempProp( 0) == 0) + if ( vpCrvs[0]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) bExtAllClose = true ; else bExtAllOpen = true ; @@ -1918,7 +1948,7 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara // salvo come primo tempParam l'offset massimo della regione ( servirà per la Feed) for ( int i = 0 ; i < int( vCrvCompoRes_tmp.size()) ; ++ i) { vCrvCompoRes_tmp[i]->SetTempParam( dMaxOffs, 0) ; - // se richiesta inversione della curva, allora inverto se chiusa + // se richiesta inversione della curva, allora inverto if ( PockParams.bInvert) vCrvCompoRes_tmp[i]->Invert() ; vCrvCompoRes.emplace_back( Release( vCrvCompoRes_tmp[i])) ; // aggiungo la curva al vettore @@ -1964,8 +1994,8 @@ GetSinglePocketingCurves( ISurfFlatRegion* pSfr, const PocketParams& PockParams, // potrei doverle riconcatenare if ( ! ChainCompoCurves( vCrvSingleCurves)) return false ; - // estendo le curve, definendo ptStart e calcolando le Feeds - if ( ! AdvanceExtendCurves( vCrvSingleCurves, pSfr_clone, PockParams)) + // estendo le curve, definendo ptStart e calcolando le Feeds (non inverto le curve aperte) + if ( ! AdvanceExtendCurves( vCrvSingleCurves, pSfr_clone, PockParams, false)) return false ; // imposto le Feed per tali curve se richiesto for ( int i = 0 ; i < int( vCrvSingleCurves.size()) ; ++ i) { @@ -6555,7 +6585,7 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio if ( ! IsChunkAllHomogeneous( pSfrPock, nC, bIsChunkClosed, bIsChunkAllOpen)) return false ; if ( ! bIsChunkClosed) { - if ( ! AdvanceExtendCurves( vClosedOffs_nC, pSfrOrig, PockParams)) + if ( ! AdvanceExtendCurves( vClosedOffs_nC, pSfrOrig, PockParams, true)) return false ; } @@ -6904,15 +6934,44 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid() || pCrvLink == nullptr || ! pCrvLink->IsValid()) return false ; - // curva precedente e successiva - PtrOwner pCrvBef ; - if ( bFirstOffs0 && pCrvOffs0->IsClosed()) - pCrvBef.Set( pCrvOffs0->GetFirstCurve()->Clone()) ; - else - pCrvBef.Set( pCrvOffs0->GetLastCurve()->Clone()) ; - PtrOwner pCrvAft( pCrvOffs1->GetFirstCurve()->Clone()) ; - if ( IsNull( pCrvBef) || IsNull( pCrvAft) || - ! pCrvBef->IsValid() || ! pCrvAft->IsValid()) + + // curva precedente + PtrOwner pCrvBef( CreateCurveComposite()) ; + if ( IsNull( pCrvBef)) + return false ; + if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { + const ICurve* pCrvFirst = pCrvOffs0->GetFirstCurve() ; + if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) + return false ; + PtrOwner pMyCrv( pCrvFirst->Clone()) ; + if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) + return false ; + pCrvBef->AddCurve( Release( pMyCrv)) ; + } + else { + const ICurve* pCrvLast = pCrvOffs0->GetLastCurve() ; + if ( pCrvLast == nullptr || ! pCrvLast->IsValid()) + return false ; + PtrOwner pMyCrv( pCrvLast->Clone()) ; + if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) + return false ; + pCrvBef->AddCurve( Release( pMyCrv)) ; + } + + // curva successiva + PtrOwner pCrvAft( CreateCurveComposite()) ; + if ( IsNull( pCrvAft)) + return false ; + const ICurve* pCrvFirst = pCrvOffs1->GetFirstCurve() ; + if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) + return false ; + PtrOwner pMyCrv( pCrvFirst->Clone()) ; + if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) + return false ; + pCrvAft->AddCurve( Release( pMyCrv)) ; + + // controllo la validità delle curve precedenti e successive ricavate + if ( IsNull( pCrvBef) || IsNull( pCrvAft) || ! pCrvBef->IsValid() || ! pCrvAft->IsValid()) return false ; // estendo il Link pCrvLink->AddCurve( Release( pCrvBef), false, dTol) ; @@ -6920,11 +6979,17 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve // smusso ModifyCurveToSmoothed( pCrvLink, PockParams, dSmoothPar, dSmoothPar, false) ; // toglo gli estremi - pCrvLink->RemoveFirstOrLastCurve( false) ; - pCrvLink->RemoveFirstOrLastCurve( true) ; + delete( pCrvLink->RemoveFirstOrLastCurve( false)) ; + delete( pCrvLink->RemoveFirstOrLastCurve( true)) ; // modifico Offset0 per raccordarlo al nuovo Link if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { - pCrvOffs0->AddCurve( pCrvLink->GetFirstCurve()->Clone()) ; + const ICurve* pCrvFirst = pCrvLink->GetFirstCurve() ; + if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) + return false ; + PtrOwner pMyCrv( pCrvFirst->Clone()) ; + if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) + return false ; + pCrvOffs0->AddCurve( Release( pMyCrv)) ; pCrvLink->RemoveFirstOrLastCurve( false) ; } else { @@ -6964,8 +7029,8 @@ GetConformalLinkForOpenCrv( const ICurveComposite* pCrvOffs0, const ICurveCompos double dPar0 ; vCrvClassBorder[i]->GetParamAtPoint( ptLinkS, dPar0, dTol) ; double dPar1 ; vCrvClassBorder[i]->GetParamAtPoint( ptLinkE, dPar1, dTol) ; // ricavo le due curve possibili di Link - PtrOwner pCrvLinkA( vCrvClassBorder[i]->CopyParamRange( dPar0, dPar1)) ; - PtrOwner pCrvLinkB( vCrvClassBorder[i]->CopyParamRange( dPar1, dPar0)) ; + PtrOwner pCrvLinkA( ConvertCurveToComposite( vCrvClassBorder[i]->CopyParamRange( dPar0, dPar1))) ; + PtrOwner pCrvLinkB( ConvertCurveToComposite( vCrvClassBorder[i]->CopyParamRange( dPar1, dPar0))) ; // scelgo quella migliore double dLenA = 0. ; if ( ! IsNull( pCrvLinkA) && pCrvLinkA->IsValid()) @@ -7590,7 +7655,8 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const PocketPara if ( vCrvOffs.empty()) return true ; - /* dalla superificie estesa presso i lati aperti, effettuo un Offset interno pari alla somma del + /* + dalla superificie estesa presso i lati aperti, effettuo un Offset interno pari alla somma del raggio utensile e dell'offset radiale. La ricerca delle zone non svuotate avviene all'interno di questa regione */ @@ -7740,7 +7806,7 @@ OrderConformalPaths( ICRVCOMPOPOVECTOR& vCrvPaths, const ISurfFlatRegion* pSfrCh if ( vCrvPaths[i]->GetLastCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) PtrOwner pLastCrv( pCompoPath->RemoveFirstOrLastCurve( true)) ; // creo la regione di svuotatura di tale percorso - vSfrRemoved[i].Set( GetSurfFlatRegionFromFatCurve( CloneCurveComposite( pCompoPath), PockParams.dRad, false, false)) ; + vSfrRemoved[i].Set( GetSurfFlatRegionFromFatCurve( CloneCurveComposite( pCompoPath), PockParams.dRad + 500 * EPS_SMALL, false, false)) ; if ( IsNull( vSfrRemoved[i]) || ! vSfrRemoved[i]->IsValid()) return false ; } @@ -7790,17 +7856,78 @@ OrderConformalPaths( ICRVCOMPOPOVECTOR& vCrvPaths, const ISurfFlatRegion* pSfrCh else { // se lavorazione conformal ZigZag if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { - // se ne ho trovate di più, allora euristicamente prendo la più corta + // se ne ho trovate di più, allora euristicamente prendo la curve che effettua + // meno overlap con la regione da limite double dMinLen = INFINITO ; + double dMinArea = INFINITO ; for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { // privilegio le aperte if ( vCrvPaths[vTempInds[k]]->IsClosed()) continue ; - double dLen ; vCrvPaths[vTempInds[k]]->GetLength( dLen) ; - if ( dLen < dMinLen) { - dMinLen = dLen ; - vInds[i] = vTempInds[k] ; + // se la regione di incidenza è valida + if ( PockParams.SfrLimit.IsValid()) { + dMinLen = 0. ; // non mi interessa in questo caso la lunghezza della curva + PtrOwner pSfrTest( CloneSurfFlatRegion( vSfrRemoved[vTempInds[k]])) ; + if ( IsNull( pSfrTest) || ! pSfrTest->IsValid()) + return false ; + pSfrTest->Intersect( PockParams.SfrLimit) ; + double dArea ; pSfrTest->GetArea( dArea) ; + if ( dArea < dMinArea) { + dMinArea = dArea ; + vInds[i] = vTempInds[k] ; + if ( dArea < EPS_SMALL) + break ; // è ottima... + } } + // se la regione di incidenza non è valida, scelgo erusiticamente la curva più corta + else { + double dLen ; vCrvPaths[vTempInds[k]]->GetLength( dLen) ; + if ( dLen < dMinLen) { + dMinLen = dLen ; + vInds[i] = vTempInds[k] ; + } + } + } + // se ho solo curve adiacenti a regioni di incidenza + if ( dMinArea > EPS_SMALL) { + struct MyCompoClass { + PtrOwner pCrvExtLoop ; + int nIndex ; + int nBorders ; + } ; + // euristicamente scelgo quella il cui bordo esterno contiene più curve di bordo esterno + vector vCrvExtBorder( vTempInds.size() ) ; + for ( int j = 0 ; j < int( vCrvExtBorder.size()) ; ++ j) { + // recupero il bordo esterno (mi auguro sia un solo chunk...) + PtrOwner pCrvExtLoop( ConvertCurveToComposite( vSfrRemoved[vTempInds[j]]->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid() || + ! vCrvExtBorder[j].pCrvExtLoop.Set( pCrvExtLoop)) + return false ; + vCrvExtBorder[j].nIndex = vTempInds[j] ; + vCrvExtBorder[j].nBorders = 0 ; + } + for ( int j = 0 ; j < int( vCrvExtBorder.size()) - 1 ; ++ j) { + for ( int k = j + 1 ; k < int( vCrvExtBorder.size()) ; ++ k) { + IntersCurveCurve ICC( *vCrvExtBorder[j].pCrvExtLoop, *vCrvExtBorder[k].pCrvExtLoop) ; + CRVCVECTOR ccClass ; + if ( ICC.GetCurveClassification( 0, EPS_SMALL, ccClass) && + int( ccClass.size()) == 1) { + // se i-esima interna a j-esima + if ( ccClass[0].nClass == CRVC_IN) + ++ vCrvExtBorder[k].nBorders ; + else if ( ccClass[0].nClass == CRVC_OUT) + ++ vCrvExtBorder[j].nBorders ; + } + } + } + // ordino il vettore delle curve sulla base di quante ne contiene + sort( vCrvExtBorder.begin(), vCrvExtBorder.end(), + [] ( const MyCompoClass& a, const MyCompoClass& b) { + return a.nBorders > b.nBorders ; + }) ; + // recupero l'indice migliore + if ( ! vCrvExtBorder.empty()) + vInds[i] = vCrvExtBorder[0].nIndex ; } // cerco solo tra le chiuse se non ho aperte if ( dMinLen > INFINITO - 1) { @@ -8088,6 +8215,62 @@ CalcConformalGuide( const ICurveComposite* pCrvCloseEdge, const ICurveComposite* } +//---------------------------------------------------------------------------- +static bool +CombineClosedEdgesForConformalOffsets( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParam, + bool& bOk, ICRVCOMPOPOVECTOR& vpCrvs) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + vpCrvs.clear() ; + bOk = false ; + + // se la superficie non ha isole, allora non calcolo nulla + if ( pSfrChunk->GetLoopCount( 0) == 1) + return true ; + + // recupero il bordo esterno e l'eventuale guida associata + ICRVCOMPOPOVECTOR vpCrvHomo ; + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid() || + ! AdjustCloseEsgesForConformalGuide( pCrvExtLoop, PockParam) || + ! IsCompoMadeBy2DifferentHomogeneousParts( pCrvExtLoop, PockParam, bOk, vpCrvHomo)) + return false ; + if ( ! bOk) + return true ; + + // recupero la guida ideale + PtrOwner pCrvGuide( CreateCurveComposite()) ; + if ( IsNull( pCrvGuide) || + ! CalcConformalGuide( vpCrvHomo[0], vpCrvHomo[1], PockParam, pCrvGuide)) + return false ; + if ( ! pCrvGuide->IsValid()) + return true ; + // la guida definisce il tratto chiuso per gli Offsets + vpCrvs.emplace_back( Release( pCrvGuide)) ; + // recupero il bordo esterno della superficie originale + pCrvExtLoop.Set( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) + return false ; + // considero questo bordo come tutto aperto + for ( int i = 0 ; i < pCrvExtLoop->GetCurveCount() ; ++ i) + pCrvExtLoop->SetCurveTempProp( i, 0, TEMP_PROP_OPEN_EDGE) ; + // recupero solo le isole chiuse (di sicuro esistono isole) + for ( int nL = 1 ; nL < pSfrChunk->GetLoopCount( 0) ; ++ nL) { + // recupero la curva dell'isola + PtrOwner pCrvIsl( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, nL))) ; + if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid()) + return false ; + // se curva tutta chiusa, allora la inserisco come isola + bool bAllOpen, bAllClose ; + if ( IsCurveCompoHomogeneous( pCrvIsl, bAllClose, bAllOpen) && bAllClose) + vpCrvs.emplace_back( Release( pCrvIsl)) ; + } + + return true ; +} + //---------------------------------------------------------------------------- static bool GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pSfrClass, const PocketParams& PockParam, @@ -8139,8 +8322,13 @@ GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pS else { if ( ! IsSfrChunkMadeOnlyByClosedIslands( pSfrChunk, PockParam, bOk, vCrvCloseEdges)) return false ; - if ( ! bOk) - return true ; + if ( ! bOk) { + // 3) provo a combinare punto 1) e 2) + if ( ! CombineClosedEdgesForConformalOffsets( pSfrChunk, PockParam, bOk, vCrvCloseEdges)) + return false ; + if ( ! bOk) + return true ; // sarà in SpiralIn/Out... + } } /* Calcolo degli Offsets */ @@ -8148,8 +8336,9 @@ GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pS Voronoi myVRONI ; for ( int i = 0 ; i < int( vCrvCloseEdges.size()) ; ++ i) { vCrvCloseEdges[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; - myVRONI.AddCurve( Release( vCrvCloseEdges[i])) ; + myVRONI.AddCurve( vCrvCloseEdges[i]) ; } + int MAX_ITER = 1000 ; int nIter = 0 ; double dOffs = PockParam.dRad + PockParam.dRadialOffset ; @@ -8280,8 +8469,7 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, if ( PockParams.bAllClosed) return ( AddSpiralOut( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; - // Definisco la superficie di classificazione ( su essa vengono tagliate le curve progressive - // di Offset + // Definisco la superficie di classificazione ( su essa vengono tagliate le curve progressive di Offset) /* NB La superficie di classificazione è ottenuta estendendo di R/4 i lati aperti ( in modo da compensare il fattore di smusso R/8 sulle curve di Offset)