From 2b4090619bd13636d11a1684cd19a5b8a1ca4539 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 6 Aug 2024 15:11:11 +0200 Subject: [PATCH] EgtGeomKernel : - In CalcPocketing miglorate le Feed, le regioni non svuotate e le lavorazioni ConformalZigZag. --- CalcPocketing.cpp | 2170 +++++++++++++++------------------------------ 1 file changed, 712 insertions(+), 1458 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index c36d618..6a4b1d3 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -50,7 +50,7 @@ struct PocketParams { double dSideStep_prec = -1. ; // step della lavorazione precedente double dRadialOffset = 0. ; // offset radiale double dRadialOffset_prec = -1. ; // offset radiale precedente - double dOpenEdgeRad = 0. ; // massimo raggio per estensione lati aperti + double dMaxOpenEdgeRad = 0. ; // massimo raggio per estensione lati aperti double dOpenMinSafe = 5. ; // estensione minima di sicurezza double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag @@ -72,6 +72,7 @@ struct PocketParams { double dOffsExtra = 2. ; // Offset aggiuntivo per percosi a ZigZag/OneWay se richieste le curve di bordo Frame3d frLocXY ; // frame per conti nel piano XY int nOffsType = ICurve::OFF_FILLET ; // tipologia di Offset per estensione degli aperti + double dOpenEdgeRad = 0. ; // raggio effettivo di estensione degli aperti } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket @@ -166,7 +167,7 @@ GetFeedForParam( double dPar, const PocketParams& PockParams, double& dFeed) GetSideStep() Diam */ - if ( dPar > PockParams.dRad * 2 || dPar < 0 ) // dominio... + if ( dPar > PockParams.dRad * 2 || dPar < 0 ) // dominio... return false ; if ( PockParams.dRad * 2 - PockParams.dSideStep < 50 * EPS_SMALL) { // se la funzione è costante... @@ -376,14 +377,14 @@ CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nSt //---------------------------------------------------------------------------- static bool AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig, - const PocketParams& PockParams, bool bAllowOverWrite) + const PocketParams& PockParams) { // se non rischiesto il calcolo della Feed, lascio quella standard - if ( ! PockParams.bCalcFeed && bAllowOverWrite) + if ( ! PockParams.bCalcFeed) return AssignMaxFeed( pCrv, PockParams) ; // controllo se qualche curva passa sopra ad un lato aperto... - if ( pCrvOF_orig != nullptr ) { + if ( pCrvOF_orig != nullptr) { for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { const ICurve* pCrv_u = pCrv->GetCurve( u) ; if ( pCrv_u == nullptr) @@ -391,9 +392,7 @@ AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig int nStat = -1 ; if ( CheckSimpleOverlap( pCrv_u, pCrvOF_orig, nStat, 1500 * EPS_SMALL) && nStat == 1) { double dFeed = GetMinFeed( PockParams) ; - double dPar = PockParams.dRad ; - if ( ! GetFeedForParam( dPar, PockParams, dFeed)) - return false ; + GetFeedForParam( PockParams.dOpenEdgeRad, PockParams, dFeed) ; pCrv->SetCurveTempParam( u, dFeed, 0) ; } } @@ -501,9 +500,9 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, //---------------------------------------------------------------------------- static bool -AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs, bool bIsLink, - const ICRVCOMPOPOVECTOR& vLinks_done, const ICurveComposite* pCrv_orig, - const PocketParams& PockParams, double dToll) +AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, bool bIsLink, + bool bFirstOffs, const ICurveComposite* pCrv_orig, const PocketParams& PockParams, + double dToll) { // controllo la validità della curva if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) @@ -512,52 +511,48 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs // controllo se il Flag per assegnare la Feed è attivo if ( ! PockParams.bCalcFeed) return AssignMaxFeed( pCrv, PockParams) ; - + + // Se link di conformal ZigZag + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG && bIsLink) + return AssignMaxFeed( pCrv, PockParams) ; + // imposto di Default la Feed minima per ogni sottocurva AssignMinFeed( pCrv, PockParams) ; // se non ho una superificie svuotata, allora esco ( con Feed Minima) - if ( pSrfRemoved_offs == nullptr || ! pSrfRemoved_offs->IsValid() || pSrfRemoved_offs->GetChunkCount() == 0) { + if ( pSrfRemoved == nullptr || ! pSrfRemoved->IsValid() || pSrfRemoved->GetChunkCount() == 0) { // controllo eventuali sovrapposizioni con lati aperti - AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams, true) ; - return true ; + return AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; } + // parametro di Offset per regione svuotata ( restringo la superficie in maniera appropriata) + double dOffs = 0. ; + if ( bIsLink) + dOffs = - PockParams.dRad ; + else if ( PockParams.dRad < PockParams.dSideStep) + dOffs = PockParams.dSideStep - PockParams.dRad ; + // clono la superificie ( valida) - PtrOwner pSrf_Removed_offs_clone( pSrfRemoved_offs->Clone()) ; - if ( IsNull( pSrf_Removed_offs_clone) || ! pSrf_Removed_offs_clone->IsValid() || - pSrf_Removed_offs_clone->GetChunkCount() == 0) + PtrOwner pSrfRemovedOffs( pSrfRemoved->CreateOffsetSurf( dOffs, ICurve::OFF_FILLET)) ; + if ( IsNull( pSrfRemovedOffs) || ! pSrfRemovedOffs->IsValid() || pSrfRemovedOffs->GetChunkCount() == 0) return true ; // esco ( sempre con Feed Minima) - // restringo la superificie in maniera appropriata - if ( bIsLink) { // se curva di Link - if ( ! pSrf_Removed_offs_clone->Offset( - PockParams.dRad, ICurve::OFF_CHAMFER) || - ! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0) - return true ; // esco ( sempre con Feed Minima) - } - else if ( PockParams.dRad < PockParams.dSideStep) { // se curva di Offset e raggio utensile < Side step - if ( ! pSrf_Removed_offs_clone->Offset( PockParams.dSideStep - PockParams.dRad, ICurve::OFF_CHAMFER) || - ! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0) - return true ; // esco ( sempre con Feed Minima) - } - // classifico le parti interne alla superificie creata solo dagli Offset CRVCVECTOR ccClass ; - if ( ! pSrf_Removed_offs_clone->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) + if ( ! pSrfRemovedOffs->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) return true ; // esco ( sempre con Feed Minima) // creo la nuova curva con le Feed regolate PtrOwner pCrv_new( CreateCurveComposite()) ; if ( IsNull( pCrv_new)) return false ; - for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { // recupero il tratto di curva ricavato dalla classificazione - double dCurrFeed = GetMinFeed( PockParams) ; PtrOwner pCrv_sez( ConvertCurveToComposite( pCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; if ( IsNull( pCrv_sez)) continue ; // curva troppo piccola, passo alla successiva // controllo se interno o fuori alla regione ( regolando quindi la Feed) + double dCurrFeed = GetMinFeed( PockParams) ; if ( ccClass[i].nClass == CRVC_IN) // se interna alla regione rimossa... dCurrFeed = GetMaxFeed( PockParams) ; // assegno tale Feed ad ogni sottocurva ricavata dal tratto di classificazione @@ -571,37 +566,6 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs pCrv->Clear() ; pCrv->AddCurve( Release( pCrv_new)) ; - // controllo eventuali sovrapposizioni tra la curva attuale e i Link in precedenza percorsi - for ( int l = 0 ; l < int( vLinks_done.size()) ; ++ l) { - // classificazione - IntersCurveCurve intCC( *pCrv, *vLinks_done[l]) ; - for ( int i = 0 ; i < intCC.GetIntersCount() ; ++ i) { // per ogni tratto ricavato - IntCrvCrvInfo aInfo ; - if ( ! intCC.GetIntCrvCrvInfo( i, aInfo) || ! aInfo.bOverlap || - AreSamePointApprox( aInfo.IciA[0].ptI, aInfo.IciA[1].ptI)) - continue ; // passo al successivo se non c'è overlap o se i punti coicidono - // tratto precedente - PtrOwner pCrv_before( pCrv->Clone()) ; - if ( ! pCrv_before->TrimEndAtParam( aInfo.IciA[0].dU)) - pCrv_before->Clear() ; // se troppo piccolo, elimino - // tratto successivo - PtrOwner pCrv_after( pCrv->Clone()) ; - if ( ! pCrv_after->TrimStartAtParam( aInfo.IciA[1].dU)) - pCrv_after->Clear() ; // se troppo piccolo, elimino - // tratto di overlap - PtrOwner pCrv_overlap( ConvertCurveToComposite( pCrv->CopyParamRange( aInfo.IciA[0].dU, aInfo.IciA[1].dU))) ; - if ( ! IsNull( pCrv_overlap) && pCrv_overlap->IsValid()) { - for ( int u = 0 ; u < pCrv_overlap->GetCurveCount() ; ++ u) - pCrv_overlap->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ; - // sostituisco unendo i 3 tratti - pCrv->Clear() ; - pCrv->AddCurve( Release( pCrv_before)) ; - pCrv->AddCurve( Release( pCrv_overlap)) ; - pCrv->AddCurve( Release( pCrv_after)) ; - } - } - } - if ( ! bIsLink) { // ---------------- NEL CASO DI OFFSET ---------------- // creo un intervallo con tutte le Feed Minime Intervals IntMinFeed ; @@ -611,7 +575,6 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs IntMinFeed.Add( u, u + 1) ; } double dParS = EPS_SMALL ; double dParE = EPS_SMALL ; - // a questo intervallo tolgo tutti i sottotratti di lunghezza inferiore alla tolleranza richiesta Intervals IntMinFeed_noSmall ; bool bFound = IntMinFeed.GetFirst( dParS, dParE) ; @@ -622,55 +585,54 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs IntMinFeed_noSmall.Add( dParS, dParE) ; bFound = IntMinFeed.GetNext( dParS, dParE) ; } - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - if ( IntMinFeed_noSmall.IsInside( u + 0.5)) - pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; - else + if ( ! IntMinFeed_noSmall.IsInside( u + 0.5)) pCrv->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ; } } else { // ---------------- NEL CASO DI LINK ---------------- // le curve con lunghezza < dToll vanno modificate - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + for ( int j = 0 ; j < pCrv->GetCurveCount() ; ++ j) { double dLen = EPS_SMALL ; - pCrv->GetCurve( u)->GetLength( dLen) ; + pCrv->GetCurve( j)->GetLength( dLen) ; if ( dLen < dToll + 5 * EPS_SMALL) { - PtrOwner pCrvCompo( pCrv->Clone()) ; - if ( ! pCrvCompo->TrimStartAtParam( u)) - pCrvCompo->Clear() ; - if ( ! pCrvCompo->TrimEndAtLen( dLen + PockParams.dRad * 2)) - pCrvCompo->Clear() ; - if ( pCrvCompo->IsValid()) { - bool bFound = false ; - for ( int uu = 1 ; uu < pCrvCompo->GetCurveCount() ; ++ uu) { - double dLenH = EPS_SMALL ; pCrvCompo->GetCurve( uu)->GetLength( dLenH) ; - if ( dLenH < dToll + 5 * EPS_SMALL) - continue ; - // cerco tra le curve successive vicine se ne trovo una con Feed Minima - double dParam ; pCrvCompo->GetCurveTempParam( uu, dParam, 0) ; - if ( abs( dParam - GetMinFeed( PockParams)) < 5 * EPS_SMALL) { - pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; - bFound = true ; - break ; - } - } - if ( ! bFound && u != 0) { - // arrivato qui, so che successivamente non ho curve con Feed Minima vicine - double dParam ; pCrv->GetCurveTempParam( u - 1, dParam, 0) ; - if ( abs( dParam - GetMaxFeed( PockParams)) < 5 * EPS_SMALL) - // se anche la precedente ha Feed Massima -> la curva u-esima è piccola ed Isolata - pCrv->SetCurveTempParam( u, dParam, 0) ; + // se curva piccola, ricavo il tratto successivo lungo quanto il diametro + double dLenStart ; + pCrv->GetLengthAtParam( j, dLenStart) ; + double dLenEnd = dLenStart + dLen + 2 * PockParams.dRad ; + double dUE = pCrv->GetCurveCount() ; + pCrv->GetParamAtLength( dLenEnd, dUE) ; + bool bFound = false ; + for ( int k = j + 1 ; k < int( ceil( dUE)) ; ++ k) { + double dLenH = EPS_SMALL ; + pCrv->GetCurve( k)->GetLength( dLenH) ; + if ( dLenH < dToll + 5 * EPS_SMALL) + continue ; + // cerco tra le curve successive vicine se ne trovo una con Feed Minima + double dParam ; + pCrv->GetCurveTempParam( k, dParam, 0) ; + if ( abs( dParam - GetMinFeed( PockParams)) < 5 * EPS_SMALL) { + pCrv->SetCurveTempParam( k, dParam, 0) ; + bFound = true ; + break ; } } + if ( ! bFound && j != 0) { + // arrivato qui, so che successivamente non ho curve con Feed Minima vicine + double dParam ; pCrv->GetCurveTempParam( j - 1, dParam, 0) ; + if ( abs( dParam - GetMaxFeed( PockParams)) < 5 * EPS_SMALL) + // se anche la precedente ha Feed Massima -> la curva u-esima è piccola ed Isolata + pCrv->SetCurveTempParam( j, dParam, 0) ; + } else - pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; + pCrv->SetCurveTempParam( j, GetMinFeed( PockParams), 0) ; } } } - // controllo eventuali sovrapposizioni con lati aperti - AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams, true) ; + if ( bFirstOffs) + AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + return true ; } @@ -725,68 +687,6 @@ AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveC return true ; } -//---------------------------------------------------------------------------- -static bool -AssignFeedConformalZigZag( ICurveComposite* pCompoPath, const ICurveComposite* pCrvLoop, - const PocketParams& PockParams, ISurfFlatRegion* pSfrToRemove) -{ - // controllo dei parametri - if ( pCompoPath == nullptr || ! pCompoPath->IsValid()) - return false ; - - // controllo se il Flag per assegnare la Feed è attivo - if ( ! PockParams.bCalcFeed) - AssignMaxFeed( pCompoPath, PockParams) ; - else - AssignMinFeed( pCompoPath, PockParams) ; - - // creo la superficie di classificazione ( creata mediante raggio utensile e SideStep) - // creo la curva da restituire con le Feed Assegnate - PtrOwner pSfrRemoved( CreateSurfFlatRegion()) ; - PtrOwner pCompoPathWithFeed( CreateCurveComposite()) ; - if ( IsNull( pSfrRemoved) || IsNull( pCompoPathWithFeed)) - return false ; - ICRVCOMPOPOVECTOR vCrvEmpty ; - - // scorro tutte le curve del percorso - for ( int i = 0 ; i < pCompoPath->GetCurveCount() ; ++ i) { - // recupero la singola curva come composita - PtrOwner pSingleCompo( ConvertCurveToComposite( pCompoPath->GetCurve( i)->Clone())) ; - if ( IsNull( pSingleCompo) || ! pSingleCompo->IsValid()) - return false ; - - // calcolo la Feed per tale curva - AssignFeedSpiral( pSingleCompo, pSfrRemoved, false, vCrvEmpty, pCrvLoop, PockParams, 2 * PockParams.dRad / 3) ; - - // aggiorno la regione svuotata dal Tool - PtrOwner pSfrSingleCompo( GetSurfFlatRegionFromFatCurve( pSingleCompo->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( ! IsNull( pSfrSingleCompo) || ! pSfrSingleCompo->IsValid()) { - if ( ! pSfrRemoved->IsValid()) - pSfrRemoved->CopyFrom( pSfrSingleCompo) ; - else - pSfrRemoved->Add( *pSfrSingleCompo) ; - } - - if ( ! pCompoPathWithFeed->AddCurve( Release( pSingleCompo))) - return false ; - } - - // definisco la regione da svuotare - PtrOwner pMyLoop( CloneCurveComposite( pCrvLoop)) ; - pSfrToRemove->Clear() ; - - if ( ! pSfrToRemove->AddExtLoop( Release( pMyLoop)) || - ! pSfrToRemove->Offset( - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET) || - ! pSfrToRemove->Subtract( *pSfrRemoved)) - pSfrToRemove->Clear() ; // alla peggio non rimuovo le Uncleared Regions... - - // restituisco la curva se valida - if ( pCompoPathWithFeed->IsValid()) - pCompoPath->CopyFrom( pCompoPathWithFeed) ; - - return true ; -} - //---------------------------------------------------------------------------- static bool ResetCurveTempProps( ICurveComposite* pCrvCompo) @@ -1335,28 +1235,44 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const PocketParams& PockPara Point3d pt1 ; pCrv->GetEndPoint( pt1) ; Point3d pt4 ; pCrv->GetStartPoint( pt4) ; - // creo la regione dalle curve + // verifico se una delle due curve esiste + bool bExistExt = ( ! IsNull( pOffsExt) && pOffsExt->IsValid()) ; + bool bExistInt = ( ! IsNull( pOffsInt) && pOffsInt->IsValid()) ; + PtrOwner pCrvExtLoopSurfInc( CreateCurveComposite()) ; - if ( IsNull( pCrvExtLoopSurfInc) || - ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsExt)) || - ! pCrvExtLoopSurfInc->AddLine( pt1)) + if ( IsNull( pCrvExtLoopSurfInc)) return false ; - Point3d pt5 ; pCrvExtLoopSurfInc->GetStartPoint( pt5) ; - if ( ! IsNull( pOffsInt) && pOffsInt->IsValid()) { + if ( bExistExt && bExistInt) { Point3d pt2 ; pOffsInt->GetEndPoint( pt2) ; Point3d pt3 ; pOffsInt->GetStartPoint( pt3) ; - if ( ! pCrvExtLoopSurfInc->AddLine( pt2) || + Point3d pt5 ; pOffsExt->GetStartPoint( pt5) ; + if ( ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsExt)) || + ! pCrvExtLoopSurfInc->AddLine( pt1) || + ! pCrvExtLoopSurfInc->AddLine( pt2) || ! pOffsInt->Invert() || ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsInt)) || ! pCrvExtLoopSurfInc->AddLine( pt4) || ! pCrvExtLoopSurfInc->AddLine( pt5)) return false ; } - else { - if ( ! pCrvExtLoopSurfInc->AddLine( pt4) || + else if ( bExistExt) { + Point3d pt5 ; pOffsExt->GetStartPoint( pt5) ; + if ( ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsExt)) || + ! pCrvExtLoopSurfInc->AddLine( pt1) || + ! pCrvExtLoopSurfInc->AddLine( pt4) || ! pCrvExtLoopSurfInc->AddLine( pt5)) return false ; } + else if ( bExistInt) { + Point3d pt5 ; pOffsInt->GetStartPoint( pt5) ; + if ( ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsInt)) || + ! pCrvExtLoopSurfInc->AddLine( pt1) || + ! pCrvExtLoopSurfInc->AddLine( pt4) || + ! pCrvExtLoopSurfInc->AddLine( pt5)) + return false ; + } + else + return false ; // per sicurezza... pCrvExtLoopSurfInc->Close() ; @@ -1364,7 +1280,15 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const PocketParams& PockPara if ( ! pSfrInc->AddExtLoop( Release( pCrvExtLoopSurfInc))) return false ; - return ( pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0) ; + // guarda Z_AX come normale + if ( pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0) { + Vector3d vtN = pSfrInc->GetNormVersor() ; + if ( AreOppositeVectorApprox( vtN, Z_AX)) + pSfrInc->Invert() ; + return true ; + } + + return false ; } //---------------------------------------------------------------------------- @@ -1629,7 +1553,7 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI //---------------------------------------------------------------------------- static bool -AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvIsl, const PocketParams& PockParams) +AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvIsl, PocketParams& PockParams) { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) @@ -1645,8 +1569,8 @@ AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvI if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_ZIGZAG) dOutEdge = max( dOutEdge, dDiam - dStep) ; double dRad = dOutEdge + dOffR ; - if ( abs( PockParams.dOpenEdgeRad) > 0 && PockParams.dOpenEdgeRad < dRad) - dRad = PockParams.dOpenEdgeRad ; + if ( abs( PockParams.dMaxOpenEdgeRad) > 0 && PockParams.dMaxOpenEdgeRad < dRad) + dRad = PockParams.dMaxOpenEdgeRad ; // se lavorazione ZigZag/OneWay con richiesta di curve di Bordo, gli aperti vanno leggermente allargati if ( PockParams.bAllowZigZagOneWayBorders && ( PockParams.nType == POCKET_ZIGZAG || PockParams.nType == POCKET_ONEWAY)) @@ -1655,6 +1579,8 @@ AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvI if ( PockParams.nType == POCKET_ZIGZAG && PockParams.bSmooth) dRad += max( PockParams.dSideStep / 2, PockParams.dRad / 8) ; + // salvo il raggio trovato + PockParams.dOpenEdgeRad = dRad ; // ricavo i tratti omogenei ICRVCOMPOPOVECTOR vpCrvs ; @@ -1664,7 +1590,7 @@ AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvI // Offset esterno per CurveJ double dDiamJ = 1.05 * ( dDiam) + 2 * dOffR ; - if ( abs( PockParams.dOpenEdgeRad) > 0) + if ( abs( PockParams.dMaxOpenEdgeRad) > 0) dDiamJ = 100 * EPS_SMALL ; // NB. 1.05 serve per eccedere leggermente, in modo che il contro-offset della prima curva di svuotatura presenti // dei piccoli archi tra i chiusi e gli aperti ( in modo da svuotare bene lungo il chiuso) @@ -1797,9 +1723,14 @@ AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, return true ; // controllo validità delle curve - for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) + for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) { if ( IsNull( vCrvCompo[i]) || ! vCrvCompo[i]->IsValid()) return false ; + } + + // se superficie tutta chiusa, allora non estendo nulla + if ( PockParams.bAllClosed) + return true ; /* L'estensione della curva permettendo un'entrata da fuori è valida se il @@ -4162,7 +4093,6 @@ ModifyCurveToSmoothed( ICurveComposite* pCrv, const PocketParams& PockParams, do dUS_ref = dLeftLen * dULast2 ; } - // prendo i punti sulle due curve rispetto a tali parametri Point3d ptS, ptE ; if ( ! vCrvStepsToFill[i]->GetPointD1D2( dUE_ref, ICurve::FROM_PLUS, ptS) || @@ -4257,6 +4187,8 @@ ModifyCurveToSmoothed( ICurveComposite* pCrv, const PocketParams& PockParams, do // aggiungo la curva 'tagliata per il raccordo' } + // imposto la proprietà di raccord + vCrvArcs[i]->SetTempProp( TEMP_PROP_SMOOTH, 1) ; if ( ! pCrvCO_temp->AddCurve( vCrvArcs[i]->Clone())) // aggiungo l'arco di raccordo return false ; ptArcHelp = ptArcE ; @@ -4309,9 +4241,16 @@ ModifyCurveToSmoothed( ICurveComposite* pCrv, const PocketParams& PockParams, do } // restituisco + int nProp0 = pCrv->GetTempProp( 0) ; + int nProp1 = pCrv->GetTempProp( 1) ; + double dParam0 = pCrv->GetTempParam( 0) ; + double dParam1 = pCrv->GetTempParam( 1) ; pCrv->Clear() ; pCrv->AddCurve( Release( pCrvCO_temp)) ; - + pCrv->SetTempProp( nProp0, 0) ; + pCrv->SetTempProp( nProp1, 1) ; + pCrv->SetTempParam( dParam0, 0) ; + pCrv->SetTempParam( dParam1, 1) ; return true ; } @@ -4599,9 +4538,9 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const //---------------------------------------------------------------------------- static bool -CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOMPOPOVECTOR& vOffsCL, - const ICRVCOMPOPOVECTOR& vFirstOffset, const PocketParams& PockParams, ICurveComposite* pCrvLink, - double dLenPercS, double dLenPercE, int nMaxIter) +CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOMPOPOVECTOR& vFirstOffset, + const PocketParams& PockParams, double dLenPercS, double dLenPercE, + ICurveComposite* pCrvLink) { // controllo i parametri if ( pCrvS == nullptr || pCrvE == nullptr ) @@ -4640,16 +4579,20 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : PockParams.dRad) ; dLenE = 0 ; - // calcolo i possibili BiArchi tra le due curve - int nIter = 0 ; - + /* + calcolo il biArco tra il punto iniziale e finale dei due offset consecutivi + se richiesto lo smusso -> accorcio entrambi i tratti di Offset e, riuscendo, si sotituisce + il biArco calcolato prima con quest'ultimo + */ + int nMaxIter = 2 ; if ( ! PockParams.bSmooth) nMaxIter = 1 ; // taglio la curva al massimo nMaxIter-volte e mi fermo al taglio più opportuno + int nIter = 0 ; while ( nIter < nMaxIter) { - // calcolo il BiArco + // calcolo il biArco PtrOwner ptBiArc( CreateBasicCurveComposite()) ; if ( ! CalcBoundedSmoothedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, PockParams, ptBiArc) || ptBiArc->GetCurveCount() == 0) @@ -4661,21 +4604,6 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM if ( dLenPercE == 0 && dLenPercS == 0 ) break ; - // se il BiArco creato interseca le altre curve di Offset allora mi fermo... - bool bInterr = false ; - for ( int i = 0 ; i < int( vOffsCL.size()) && ! bInterr ; ++ i) { - if ( vOffsCL[i]->IsPointOn( ptSE) || vOffsCL[i]->IsPointOn( ptES)) - continue ; - - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *ptBiArc, *vOffsCL[i]) ; - intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; - if ( ccClass.size() > 1) // se intersezione - bInterr = true ; - } - if ( bInterr) - break ; // così come ultimo arco ho quello precedente (valido) - // se ho trovato un BiArco valido, allora accorcio le due curve di Offset dLenS -= dLStepS ; dLenE += dLStepE ; @@ -4687,8 +4615,8 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM pCrvE->GetPointD1D2( dUES, ICurve::FROM_PLUS, ptES) ; // ricalcolo il vettore tangente iniziale e finale - PtrOwner pCrvS_clone( pCrvS->Clone()) ; // curva di Offset iniziale accorciata - PtrOwner pCrvE_clone( pCrvE->Clone()) ; // curva di Offset finale accorciata + PtrOwner pCrvS_clone( CloneCurveComposite( pCrvS)) ; + PtrOwner pCrvE_clone( CloneCurveComposite( pCrvE)) ; pCrvS_clone->ChangeStartPoint( dUSE) ; pCrvE_clone->ChangeStartPoint( dUES) ; pCrvS_clone->GetStartDir( vS) ; @@ -4698,18 +4626,17 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM } pCrvLink->AddCurve( Release( ptCrvFinal)) ; // ultimo arco valido trovato - return true ; } //---------------------------------------------------------- static bool -GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICURVEPOVECTOR& vLinks, - const ICurveComposite* pCrv_orig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) +GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, + const ICurveComposite* pCrv_orig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) { // controllo dei parametri - if ( vFirstOffs.empty() || int( vCrvs.size()) < int( vFirstOffs.size())) + if ( vFirstOffs.empty() || int( vOffs.size()) < int( vFirstOffs.size())) return false ; pSrfToCut->Clear() ; @@ -4730,75 +4657,75 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU } // ---- le seguenti regioni sono distinte per calcolar emeglio la Feed ---- - // 2) Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links - PtrOwner pSrfTool_Offs( CreateSurfFlatRegion()) ; - PtrOwner pSrfTool_Links( CreateSurfFlatRegion()) ; - PtrOwner pSrfTool( CreateSurfFlatRegion()) ; - if ( IsNull( pSrfTool_Offs) || IsNull( pSrfTool_Links) || IsNull( pSrfTool)) + // Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links + PtrOwner pSfrTool( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrTool)) return false ; // creo un vettore che conterrà solamente i Link percorsi fino ad Ora - ICRVCOMPOPOVECTOR vLinks_done ; - - for ( int i = ( PockParams.nType == POCKET_SPIRALIN ? 0 : int( vCrvs.size()) - 1) ; - ( PockParams.nType == POCKET_SPIRALIN ? i < int( vCrvs.size()) : i >= 0 ) ; - ( PockParams.nType == POCKET_SPIRALIN ? ++ i : -- i)) { - - // ================= LINK ================================ - // ( Il primo link è nullo, inatti non vi è nessun raccordo per raggiungere il primo Offset) - if ( i <= int( vLinks.size()) && ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { - // Feed - PtrOwner pCompoLink_i( CreateCurveComposite()) ; - if ( IsNull( pCompoLink_i)) - return false ; - pCompoLink_i->AddCurve( vLinks[i]->Clone()) ; - if ( ! AssignFeedSpiral( pCompoLink_i, pSrfTool_Offs, true, vLinks_done, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) - return false ; - - // per Link ... - PtrOwner pCrvLink_i( vLinks[i]->Clone()) ; - if ( IsNull( pCrvLink_i)) - return false ; - PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( Release( pCrvLink_i), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( ! IsNull( pSrfToolRegLinki)) { - if ( ! pSrfTool_Links->IsValid() || pSrfTool_Links->GetChunkCount() == 0) - pSrfTool_Links.Set( pSrfToolRegLinki) ; - else - pSrfTool_Links->Add( *pSrfToolRegLinki) ; - } - - // risetto il Link come curva composita ... - vLinks[i].Set( pCompoLink_i->Clone()) ; - - // inserisco il Link nel vettore dei Link percorsi - vLinks_done.emplace_back( Release( pCompoLink_i)) ; - } + bool bFollowOrder = ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_CONFORMAL_ZIGZAG) ; + for ( int i = ( bFollowOrder ? 0 : int( vOffs.size()) - 1) ; + ( bFollowOrder ? i < int( vOffs.size()) : i >= 0 ) ; + ( bFollowOrder ? ++ i : -- i)) { // ================== OFFSET ============================= + // recupero le proprietà temporanee + int nProp0 = vOffs[i]->GetTempProp( 0) ; + int nProp1 = vOffs[i]->GetTempProp( 1) ; + // Feed - if ( ! AssignFeedSpiral( vCrvs[i], pSrfTool_Offs, false, vLinks_done, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) - return false ; + bool bFirstOffs = false ; + Point3d ptStart ; vOffs[i]->GetStartPoint( ptStart) ; + for ( int j = 0 ; j < int( vFirstOffs.size()) && ! bFirstOffs ; ++ j) + bFirstOffs = vFirstOffs[j]->IsPointOn( ptStart, 100 * EPS_SMALL) ; + // calcolo gli intervalli di Feed per la curva di Offset + if ( ! AssignFeedSpiral( vOffs[i], pSfrTool, false, bFirstOffs, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) + return false ; + // aggiorno la superificie svuotata + PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( vOffs[i]->Clone() , PockParams.dRad + 5 * EPS_SMALL, false, false)) ; + if ( ! IsNull( pSrfToolRegOffi)) { + if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) + pSfrTool.Set( pSrfToolRegOffi) ; + else + pSfrTool->Add( *pSrfToolRegOffi) ; + } + vOffs[i]->SetTempProp( nProp0, 0) ; + vOffs[i]->SetTempProp( nProp1, 1) ; - // aggiorno la superificie svuotata - PtrOwner pCrvOffs_i( vCrvs[i]->Clone()) ; - if ( IsNull( pCrvOffs_i)) - return false ; - PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( Release( pCrvOffs_i) , PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( ! IsNull( pSrfToolRegOffi)) { - if ( ! pSrfTool_Offs->IsValid() || pSrfTool_Offs->GetChunkCount() == 0) - pSrfTool_Offs.Set( pSrfToolRegOffi) ; - else - pSrfTool_Offs->Add( *pSrfToolRegOffi) ; + // ================= LINK ================================ + int nLink_Ind = ( bFollowOrder ? i + 1 : i) ; + // ( Il primo link è nullo, inatti non vi è nessun raccordo per raggiungere il primo Offset) + if ( nLink_Ind < int( vLinks.size()) && ! IsNull( vLinks[nLink_Ind]) && + vLinks[nLink_Ind]->IsValid()) { + + // recupero le proprietà temporanee + int nProp0 = vLinks[nLink_Ind]->GetTempProp( 0) ; + int nProp1 = vLinks[nLink_Ind]->GetTempProp( 1) ; + // Feed + PtrOwner pCrvLink( ConvertCurveToComposite( vLinks[nLink_Ind]->Clone())) ; + // calcolo gli intervalli di Feed per la curva di Link + if ( IsNull( pCrvLink) || ! pCrvLink->IsValid() || + ! AssignFeedSpiral( pCrvLink, pSfrTool, true, false, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) + return false ; + // aggiorno la regione svuotata + PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( pCrvLink->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; + if ( ! IsNull( pSrfToolRegLinki)) { + if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) + pSfrTool.Set( pSrfToolRegLinki) ; + else + pSfrTool->Add( *pSrfToolRegLinki) ; + } + // risetto il Link come curva composita ... + pCrvLink->SetTempProp( nProp0, 0) ; + pCrvLink->SetTempProp( nProp1, 1) ; + vLinks[nLink_Ind].Set( pCrvLink) ; } - } - // 3) Calcolo la superificie svuotata - pSrfTool.Set( pSrfTool_Offs) ; - pSrfTool->Add( *pSrfTool_Links) ; + } // 4) Creo la regione contenente tutte le parti non svuotate pSrfToCut->CopyFrom( pSrfExtern) ; - if ( ! pSrfToCut->Subtract( *pSrfTool)) + if ( ! pSrfToCut->Subtract( *pSfrTool)) return false ; return true ; @@ -4806,1085 +4733,318 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU //---------------------------------------------------------------------------- static bool -RemoveFirstLoopFromSfr( ISurfFlatRegion* pSrfOrig) +RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, + ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { - // controllo dei parametri - if ( pSrfOrig == nullptr) + // se non ho nessuna superficie valida da svuotare, allora esco + if ( pSfrUncleared == nullptr) + return false ; + if ( ! pSfrUncleared->IsValid() || pSfrUncleared->GetChunkCount() == 0) return true ; - // superficie da restituire - PtrOwner pSrfRes( CreateBasicSurfFlatRegion()) ; - if ( IsNull( pSrfRes)) - return false ; - // scorro tutti i chunk tranne il primo ( escludo quindi il primo chunk) - for ( int c = 1 ; c < pSrfOrig->GetChunkCount() ; ++ c) { - PtrOwner pSrfHelp( CreateBasicSurfFlatRegion()) ; - if ( IsNull( pSrfHelp)) - return false ; - pSrfHelp->AddExtLoop( pSrfOrig->GetLoop( c, 0)) ; - if ( c == 1) - pSrfRes.Set( pSrfHelp) ; - else - pSrfRes->Add( *pSrfHelp) ; - } - // restituisco - pSrfOrig->Clear() ; - pSrfOrig->CopyFrom( pSrfRes) ; - return true ; -} + // scorro tutti i Chunk della regione + ICRVCOMPOPOVECTOR vCrvCurl ; + for ( int nC = 0 ; nC < pSfrUncleared->GetChunkCount() ; ++ nC) { -//---------------------------------------------------------------------------- -static bool -RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECTOR& vOffsFirstCurve, - const PocketParams& PockParams, int& nOptFlag, Point3d& ptCentroid, ICurveComposite* pCrvPath) -{ + // recupero il centroide del Chunk da rimuovere + Point3d ptCentroid ; pSfrUncleared->GetChunkCentroid( nC, ptCentroid) ; - // nOptFlag : 0 -> non faccio nulla | 1 -> svuoto con un centroide | 2 -> svuoto con un percorso - - // variabili iniziali - nOptFlag = 2 ; - bool bForceCentroid = false ; - if ( pChunkToCut == nullptr) - return false ; - - // curva che l'utensile dovrà seguire per svuotare la regione e curva di ingombro del tool - PtrOwner pCrvStepByStepPath( CreateBasicCurveComposite()) ; - if ( IsNull( pCrvStepByStepPath)) - return false ; - - // copie del chunk che devo svuotare - PtrOwner pSrfChunkToCutClone( pChunkToCut->Clone()) ; - double dArea = INFINITO ; - ICRVCOMPOPOVECTOR vCrvCoMedAxi ; // vettore dei medial Axis - PNTVECTOR vPtCentroid ; // vettore di centroidi - int nIter = 0 ; // numero di iterazioni - - while ( pSrfChunkToCutClone->IsValid() && pSrfChunkToCutClone->GetChunkCount() != 0 && - pSrfChunkToCutClone->GetArea( dArea) && dArea > 10 * EPS_SMALL) { - // finchè restano parti non svuotate la cui area totale è suffcientemente grande... - - if ( nIter > 25) // troppi tentativi... - break ; - - nIter++ ; - PtrOwner pSrfBiggerChunk( pSrfChunkToCutClone->CloneChunk( 0)) ; - if ( IsNull( pSrfBiggerChunk)) - return false ; - if ( ! pSrfBiggerChunk->IsValid()) - break ; - - double dAreaExt ; - // se l'area del chunk è piccola... rimuovo il chunk dalla superficie da svuotare - if ( pSrfBiggerChunk->GetArea( dAreaExt) && dAreaExt < 10 * EPS_SMALL) { - if ( ! RemoveFirstLoopFromSfr( pSrfChunkToCutClone)) - return false ; - if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) - break ; - continue ; - } - - // prendo il centroide del chunk - Point3d ptC ; - if ( ! pSrfBiggerChunk->GetCentroid( ptC)) - break ; - - // creo la superficie che racchiude il mio tool - PtrOwner pCrvToolShape( CreateBasicCurveArc()) ; - if ( IsNull( pCrvToolShape)) - return false ; - pCrvToolShape->SetXY( ptC, PockParams.dRad + 5 * EPS_SMALL) ; - PtrOwner pSrfTool( CreateBasicSurfFlatRegion()) ; - if ( IsNull( pSrfTool) || ! pSrfTool->AddExtLoop( Release( pCrvToolShape)) || - ! pSrfTool->IsValid()) - break ; - - PtrOwner pSrfTest( CloneBasicSurfFlatRegion( pSrfBiggerChunk)) ; - if ( IsNull( pSrfTest)) - return false ; - - pSrfTest->Subtract( *pSrfTool) ; - if ( IsNull( pSrfTest) || ! pSrfTest->IsValid() || ! pSrfTest->GetArea( dArea) || dArea < 10 * EPS_SMALL || - bForceCentroid) { - // se prima iterazione -> ritorno il centroide con punto - if ( nIter == 1) { - nOptFlag = 1 ; - ptCentroid = ptC ; - return true ; + /* + Tra tutte le curve di Offset escludo le curve che : + - Sono di primo Offset + - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) + ... e cerco la più vicina tra le rimanenti + */ + int nInd = -1 ; + double dRefDist = INFINITO - 1 ; + Point3d ptCloser ; // serve nel caso non bastasse la curva a ricciolo per svuotare il chunk nC-esimo + int nFlag ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + // se la curva è di primo Offset, allora la salto + Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; + bool bSkip = false ; + for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) { + if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) + bSkip = ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) ; + else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) + bSkip = vOffs[i]->GetTempProp( 0) == 0 ; } - // se non sono alla prima iterazione -> memorizzo il centroide nel vettore - else { - // controllo di non aver trovato un centroide già inserito ( per simmetria del chunk) - for ( int cen = 0 ; cen < int( vPtCentroid.size()) ; ++ cen) { - if ( AreSamePointApprox( vPtCentroid[cen], ptC)) { - pSrfChunkToCutClone->Clear() ; - break ; - } + if ( bSkip) + continue ; + // se la curva contiene il centroide, allora la salto + int nSide ; + DistPointCurve DistPtCrv( ptCentroid, *vOffs[i]) ; + if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { + if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { + if ( nSide == ( ! PockParams.bInvert ? MDS_LEFT : MDS_RIGHT)) + continue ; } - vPtCentroid.push_back( ptC) ; - pSrfChunkToCutClone->Subtract( *pSrfTool) ; - if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) + else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { + if ( nSide != vOffs[i]->GetTempProp( 1)) + continue ; + } + } + // controllo se la distanza è ammissibile + double dCurrDist = INFINITO ; + if ( DistPtCrv.GetSqDist( dCurrDist) && dCurrDist < dRefDist) { + dRefDist = dCurrDist ; + nInd = i ; + DistPtCrv.GetMinDistPoint( EPS_SMALL, ptCloser, nFlag) ; + } + } + // se non ho trovato alcun indice, salto il Chunk nC-esimo + if ( nInd == -1) + continue ; + + // cerco sulla curva di Offset nInd-esima la sottocurva dove cade il punto a minima distanza + double dURef = 0 ; + if ( ! vOffs[nInd]->GetParamAtPoint( ptCloser, dURef)) + continue ; + int nCrv = int( floor( dURef)) ; + const ICurve* pCrv = vOffs[nInd]->GetCurve( nCrv) ; + if ( pCrv == nullptr || ! pCrv->IsValid()) + continue ; + + // determino se la curva è di raccordo o meno + bool bIsSmoothCrv = ( PockParams.bSmooth && pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; + + // clono la curva di Offset corrente ( in questo modo non modifico l'originale) + PtrOwner pMyOffs( CloneCurveComposite( vOffs[nInd])) ; + if ( IsNull( pMyOffs) || ! pMyOffs->IsValid()) + return false ; + + // versore uscente ed entrante dall'Offset attuale per creazione della curva a ricciolo + Vector3d vt1, vt2, vtMain ; + // punto di uscita e di ingresso dall'Offset attuale per creazione della curva a ricciolo + Point3d pt1, pt2, ptMain ; + // paramtro di uscita e di ingresso dall'Offset attuale per creazione della curva a ricciolo + double dURef1, dURef2 ; + // inizializzo la curva a ricciolo + PtrOwner pCrvCurl( CreateCurveComposite()) ; + if ( IsNull( pCrvCurl)) + return false ; + + // se è di raccordo, "ricostruisco lo spigolo vivo della curva originale di Offset" + if ( bIsSmoothCrv) { + // cerco la prima curva in precedenza e in successione non di raccordo + vt1 = V_INVALID ; + for ( int i = nCrv - 1 ; i >= 0 ; -- i) { + const ICurve* pCrvPrec = pMyOffs->GetCurve( i) ; + if ( pCrvPrec == nullptr || ! pCrvPrec->IsValid()) break ; + if ( pCrvPrec->GetTempProp( 1) != TEMP_PROP_SMOOTH) { + // definisco il versore uscente + pCrvPrec->GetEndDir( vt1) ; + // definisco il punto di uscita + pCrvPrec->GetEndPoint( pt1) ; + // definisco il parametro di uscita + dURef1 = i + 1 ; + break ; + } + } + if ( ! vt1.IsValid()) continue ; - } - } - bForceCentroid = false ; - - // 1) ricavo il bordo della regione - PtrOwner pCrvBorder( pSrfBiggerChunk->GetLoop( 0, 0)) ; - if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) - return false ; - - // 2) ricavo il medial Axis del bordo - PolyLine PlMedAx ; - if ( ! CurveSimpleMedialAxis( pCrvBorder, PlMedAx)) { - bForceCentroid = true ; - -- nIter ; - continue ; - } - - PtrOwner pCrvMedAx( CreateBasicCurveComposite()) ; - if ( IsNull( pCrvMedAx)) - return false ; - if ( ! pCrvMedAx->FromPolyLine( PlMedAx)) { - // se questo medial Axis è troppo piccolo e la polyLine non è convertitibile in curva composita ... - bForceCentroid = true ; // 2a) forzo ad andare nel centroide - -- nIter ; // 2b) scalo una iterzione - continue ; - } - - // abbellisco la curva - pCrvMedAx->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; - PolyArc PlMedAxArc ; - pCrvMedAx->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, 20.0, PlMedAxArc) ; - pCrvMedAx->Clear() ; - if( ! pCrvMedAx->FromPolyArc( PlMedAxArc)) { - bForceCentroid = true ; - -- nIter ; - continue ; - } - // smusso la curva - ModifyCurveToSmoothed( pCrvMedAx, PockParams, 0.025, 0.025, true) ; - // se curva valida la inserisco nel vettore, altrimenti forzo il centroide - if ( pCrvMedAx->IsValid()) - vCrvCoMedAxi.emplace_back( pCrvMedAx->Clone()) ; - else { - bForceCentroid = true ; - -- nIter ; - continue ; - } - - // 3) guardo quale regione svuoto con questa curva - PtrOwner pSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrvMedAx), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( IsNull( pSrfRemoved) || ! pSrfRemoved->IsValid()) - break ; - - // 4) aggiorno la regione togliendo la parte percorsa dal tool - if ( ! pSrfChunkToCutClone->Subtract( *pSrfRemoved)) - break ; - if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) - break ; - - } - - // se entrambi i vettori sono vuoti l'area originaria era più piccola di 10 * EPS_SMALL -> non faccio nulla - if ( vCrvCoMedAxi.empty() && vPtCentroid.empty()) { - nOptFlag = 0 ; - return true ; - } - - // ora collego la varie curve medial Axis trovate tra loro (ottenendo quindi una curva che svuota tutta la regione) - // curva che collega primo e ultimo medial Axis - PtrOwner pCrvCoBackLink( CreateBasicCurveComposite()) ; - if ( IsNull( pCrvCoBackLink)) - return false ; - Point3d ptSOriginal, ptEOriginal ; - Vector3d vtSOriginal, vtEOriginal ; - - // parametri iniziali del primo e ultimo medial Axis trovato - if ( ! vCrvCoMedAxi[0]->GetStartPoint( ptSOriginal) || - ! vCrvCoMedAxi.back()->GetEndPoint( ptEOriginal) || - ! vCrvCoMedAxi[0]->GetStartDir( vtSOriginal) || - ! vCrvCoMedAxi.back()->GetEndDir( vtEOriginal)) - return false ; - - pCrvPath->AddCurve( vCrvCoMedAxi[0]->Clone()) ; // inserisco il primo medial Axis nel percorso finale - - for ( int i = 1 ; i < int( vCrvCoMedAxi.size()) ; ++ i) { // scorro i restanti - Point3d ptS, ptE ; Vector3d vtS, vtE ; - // parametri iniziali del medialAxis i-esimo e (i-1)esimo - if ( ! vCrvCoMedAxi[i]->GetStartPoint( ptE) || - ! vCrvCoMedAxi[i-1]->GetEndPoint( ptS) || - ! vCrvCoMedAxi[i]->GetStartDir( vtE) || - ! vCrvCoMedAxi[i-1]->GetEndDir( vtS)) - return false ; - - PtrOwner pCrvLink( CreateBasicCurveComposite()) ; - if ( IsNull( pCrvLink)) - return false ; - - if ( ! CalcBoundedSmoothedLink( ptS, vtS, ptE, vtE, 0.5, vOffsFirstCurve, PockParams, pCrvLink)) - if ( ! CalcBoundedLink( ptS, ptE, vOffsFirstCurve, pCrvLink)) - return false ; - - if ( ! pCrvPath->AddCurve( pCrvLink->Clone()) || ! pCrvPath->AddCurve( vCrvCoMedAxi[i]->Clone())) - return false ; - } - - if ( ! AreSamePointEpsilon( ptEOriginal, ptSOriginal, EPS_SMALL) && - ! CalcBoundedSmoothedLink( ptEOriginal, vtEOriginal, ptSOriginal, vtSOriginal, 0.5, vOffsFirstCurve, - PockParams, pCrvCoBackLink) && - ! CalcBoundedLink( ptEOriginal, ptSOriginal, vOffsFirstCurve, pCrvCoBackLink)) - return false ; - - // se ho trovato dei centroidi li unisco nei punti più vicini a questo percorso - for ( int i = 0 ; i < int( vPtCentroid.size()) ; ++ i) { - - // 1) cerco il punto sulla curva più vicino al centroide i - Point3d ptClosestOnPath ; int nFlag ; - if ( ! DistPointCurve( vPtCentroid[i], *pCrvPath).GetMinDistPoint( EPS_SMALL, ptClosestOnPath, nFlag)) - return false ; - // 2) spezzo la curva al paramtro del punto più vicino - double dU ; - if ( ! pCrvPath->GetParamAtPoint( ptClosestOnPath, dU)) - return false ; - - PtrOwner pCrvA( GetBasicCurveComposite( pCrvPath->CopyParamRange( 0, dU))) ; - if ( IsNull( pCrvA)) - return false ; - PtrOwner pCrvB( GetBasicCurveComposite( pCrvPath->CopyParamRange( dU, pCrvPath->GetCurveCount()))) ; - if ( IsNull( pCrvB)) - return false ; - - // 3) prendo il vettore tangente al percorso nel punto trovato nel pCrvPath - Vector3d vtTanCpt ; Point3d ptH ; - if ( ! pCrvPath->GetPointTang( dU, ICurve::FROM_MINUS, ptH, vtTanCpt)) - return false ; - - // 4) collego i due punti (centroide e punto più vicino alla curva) - PtrOwner pCrvPath1( CreateBasicCurveComposite()) ; - if ( IsNull( pCrvPath1)) - return false ; - - if ( ! CalcBoundedSmoothedLink( ptClosestOnPath, vtTanCpt, vPtCentroid[i], vtTanCpt, 0, - vOffsFirstCurve, PockParams, pCrvPath1) && - ! CalcBoundedLink( ptClosestOnPath, vPtCentroid[i], vOffsFirstCurve, pCrvPath1)) - return false ; - - pCrvPath->Clear() ; - pCrvPath->AddCurve( Release( pCrvA)) ; - if ( ! pCrvPath->AddCurve( Release( pCrvPath1))) - return false ; - pCrvPath->AddCurve( Release( pCrvB)) ; - } - - // la curva resitituita è una curva aperta che ha come primo punto il punto iniziale del primo medialAxis - // la curva restituita collega tutti i medial Axis tra di loro - // la curva restitutita collega tutti i centroidi con delle circonferenze - // la curva restituita ha come punto finale l'ultimo punto dell'ultimo medial Axis - - return true ; -} - -//--------------------------------------------------------------------------- -static bool -CutOffsetToClosestPoint( ICRVCOMPOPOVECTOR& vCurves, const Point3d& ptFocus, - ICurveComposite* pCrv1, ICurveComposite* pCrv2, int& nIndex) -{ - // controllo di avere almeno un offset... - if ( vCurves.empty()) - return false ; - - // variabili iniziali - Point3d ptCl_H ; - double dDistance = INFINITO ; - int nFlag ; - pCrv1->Clear() ; - pCrv2->Clear() ; - nIndex = -1 ; - Point3d ptCL ; - - // scorro tutti gli offset ad eccezione del primo ( a meno di averne uno solo ) - for ( int j = ( int( vCurves.size()) == 1 ? 0 : 1) ; j < int( vCurves.size()) ; ++ j) { - - // non ho offset nulli, però controllo... - if ( IsNull( vCurves[j])) - continue ; - - // prendo il punto più vicino - if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag)) - continue ; - - // cerco il punto in assoluto più vicino - if ( dDistance > Dist( ptCl_H, ptFocus)) { - dDistance = Dist( ptCl_H, ptFocus) ; - ptCL = ptCl_H ; - nIndex = j ; - } - } - - // se non ho trovato nulla, esco - if ( nIndex < 0) - return false ; - - // ricavo le due curve ( l'Offset viene spezzato in due sottocurve mediante il punto trovato) - double dUTan ; - vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ; - pCrv1->AddCurve( vCurves[nIndex]->Clone()) ; - if ( ! pCrv1->TrimEndAtParam( dUTan)) - pCrv1->Clear() ; - pCrv2->AddCurve( vCurves[nIndex]->Clone()) ; - if ( ! pCrv2->TrimStartAtParam( dUTan)) - pCrv2->Clear() ; - - return true ; -} - -//--------------------------------------------------------------------------- -static bool -CutLinkToClosestPoint( ICURVEPOVECTOR& vCurves, ICRVCOMPOPOVECTOR& vOffs, const Point3d& ptFocus, - ICurveComposite* pCrv1, ICurveComposite* pCrv2, bool& bFound, int& nIndex) -{ - - // variabili iniziali - double dDistance = INFINITO ; - Point3d ptCl_H ; - int nFlag ; - pCrv1->Clear() ; - pCrv2->Clear() ; - Point3d ptCL ; - nIndex = - 1 ; - bFound = false ; - - // scorro tutti i link cercando il più vicino - for ( int j = 0 ; j < int( vCurves.size()) ; ++ j) { - - // escludo i links nulli ... - if ( IsNull( vCurves[j])) - continue ; - - // distanza minima tra link e curva - if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag)) - continue ; - - // cerco la distanza minimia assoluta ( non deve essere sopra un Offset ) - if ( dDistance > Dist( ptCl_H, ptFocus) && - ! ( vOffs[j-1]->IsPointOn( ptCl_H) || vOffs[j]->IsPointOn( ptCl_H))) { - dDistance = Dist( ptCl_H, ptFocus) ; - nIndex = j ; - bFound = true ; - } - } - - // se non ho trovato nulla, esco - if ( nIndex < 0) - return false ; - - // ricavo le due curve ( il link viene spezzato in due sottocurve mediante il punto trovato ) - double dUTan ; - vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ; - pCrv1->AddCurve( vCurves[nIndex]->Clone()) ; - if ( ! pCrv1->TrimEndAtParam( dUTan)) - pCrv1->Clear( ) ; - pCrv2->AddCurve( vCurves[nIndex]->Clone()) ; - if ( ! pCrv2->TrimStartAtParam( dUTan)) - pCrv2->Clear() ; - - return true ; -} - -//------------------------------------------------------------------------------ -static bool -CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) -{ - - // controllo parametri ingresso - if ( vOffs.empty()) - return true ; - - // vettore di curve ausiliario - ICRVCOMPOPOVECTOR vOffOrig( vOffs.size()) ; - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) - vOffOrig[i].Set( vOffs[i]->Clone()) ; - - // punto iniziale corrente - Point3d ptStart ; - if ( ! pCurve->GetStartPoint( ptStart)) - return false ; - - // curve d'appoggio - PtrOwner pCompo( pCurve->Clone()) ; - PtrOwner pCompoHelp( pCurve->Clone()) ; - PtrOwner pOffCheck( CreateCurveComposite()) ; - if ( IsNull( pCompoHelp) || IsNull( pCompo) || IsNull( pOffCheck)) - return false ; - - int nTypeOfCut = -1 ; - - // scorro tutte le curve - for ( int i = 0; i < int( vOffOrig.size()) ; ++ i) { - - // controllo se la curva è quella attuale - if ( vOffOrig[i]->IsPointOn( ptStart)) - pOffCheck.Set( vOffOrig[i]->Clone()) ; - // classificazione - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCompo, *vOffOrig[i]) ; - intCC.GetCurveClassification( 0, 10 * EPS_SMALL, ccClass) ; - if ( ! pCompoHelp->Clear()) - return false ; - // se In/Out - if ( ccClass.size() > 1) { - if ( ccClass[0].nClass == CRVC_IN) - nTypeOfCut = CRVC_OUT ; - else - nTypeOfCut = CRVC_IN ; - // scorro le classificazioni ottenute - for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { - if ( ccClass[j].nClass == nTypeOfCut) { - Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; - double dOffS ; vOffOrig[i]->GetParamAtPoint( ptS, dOffS) ; - Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; - double dOffE ; vOffOrig[i]->GetParamAtPoint( ptE, dOffE) ; - // recupero i due possibili percorsi e uso il più corto - PtrOwner pCrvA( vOffOrig[i]->CopyParamRange( dOffS, dOffE)) ; - PtrOwner pCrvB( vOffOrig[i]->CopyParamRange( dOffE, dOffS)) ; - - if ( IsNull( pCrvA) || IsNull( pCrvB)) - return false ; - - double dLenA ; pCrvA->GetLength( dLenA) ; - double dLenB ; pCrvB->GetLength( dLenB) ; - - if ( dLenA < dLenB) { - - CRVCVECTOR ccClassA ; - IntersCurveCurve intCCA( *pCrvA, *pOffCheck) ; - intCCA.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassA) ; - - if ( ccClassA.size() > 0 && i == vOffOrig.size() - 1 && ccClassA[0].nClass == CRVC_ON_M) { - if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) - return false ; - continue ; - } - - if ( ! pCompoHelp->AddCurve( Release( pCrvA))) - return false ; - } - else { - pCrvB->Invert() ; - - CRVCVECTOR ccClassB ; - IntersCurveCurve intCCB( *pCrvB, *pOffCheck) ; - intCCB.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassB) ; - - if ( ccClassB.size() > 0 && i == vOffOrig.size() - 1 && ccClassB[0].nClass == CRVC_ON_M) { - if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) - return false ; - continue ; - } - - if ( ! pCompoHelp->AddCurve( Release( pCrvB))) - return false ; - } - } - else { - if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) - return false ; + vt2 = V_INVALID ; + for ( int i = nCrv + 1 ; i < pMyOffs->GetCurveCount() ; ++ i) { + const ICurve* pCrvSucc = pMyOffs->GetCurve( i) ; + if ( pCrvSucc == nullptr || ! pCrvSucc->IsValid()) + break ; + if ( pCrvSucc->GetTempProp( 1) != TEMP_PROP_SMOOTH) { + // definisco il versore entrante + pCrvSucc->GetStartDir( vt2) ; + // definisco il punto di entrata + pCrvSucc->GetStartPoint( pt2) ; + // definisco il parametro di entrata + dURef2 = i ; + break ; } } - - pCompo->Clear() ; - pCompo->AddCurve( pCompoHelp->Clone()) ; - } - } - // restituisco la nuova curva - pCurve->Clear() ; - pCurve->AddCurve( Release( pCompo)) ; - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, - const PocketParams& PockParams, Point3d& ptC, - bool bCir, ICRVCOMPOPOVECTOR& VFirstOff, ICurveComposite* pCrvNewCurve) -{ - // creazione dei due possibili percorsi per raggiungere il centroide - PtrOwner pPath1( CreateCurveComposite()) ; - PtrOwner pPath2( CreateCurveComposite()) ; - if ( IsNull( pPath1) || IsNull( pPath2)) - return false ; - pCrvNewCurve->Clear() ; - Point3d ptS, ptE = ptC ; - Vector3d vtTanS, vtTanE ; - - // creo una circonferenza - if ( bCir) { - // prendo il punto iniziale - if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { - if ( ! pCrvH2->GetStartPoint( ptS)) - return false ; - } - else { - if ( ! pCrvH1->GetEndPoint( ptS)) - return false ; - } - - // creo la circonferenza - if ( ! CalcBoundedSmoothedLink( ptS, vtTanS, ptE, vtTanE, 0, VFirstOff, PockParams, pPath1)) - return false ; - Vector3d vtS_cir ; pPath1->GetStartDir( vtS_cir) ; - Vector3d vtS_CrvH1 ; pCrvH1->GetEndDir( vtS_CrvH1) ; - if ( ! AreSameVectorApprox( vtS_cir, vtS_CrvH1)) - pPath1->Invert() ; - - // assegno la Feed - AssignMinFeed( pPath1, PockParams) ; - - // controllo che la circonferenza sia ammissibile ( solo che non esca dalle prime curve di Offset) - Point3d ptCrvS ; pPath1->GetStartPoint( ptCrvS) ; - if ( ! CutCurveByOffsets( pPath1, VFirstOff)) // taglio la curva sugli Offsets - return false ; - - double dUCrvS ; - ModifyCurveToSmoothed( pPath1, PockParams, 0.075, 0.075, true) ; - if ( pPath1->IsClosed()) { - pPath1->GetParamAtPoint( ptCrvS, dUCrvS) ; - pPath1->ChangeStartPoint( dUCrvS) ; - } - - // creo la nuova curva con la circonferenza - if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) - if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio - return false ; - if ( ! pCrvNewCurve->AddCurve( pPath1->Clone())) // aggiungo la circonferenza - return false ; - if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) - if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine - return false ; - } - // creo un BiArco - else { - - // prendo il vettore tangente e il punto iniziale - if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { - if ( ! pCrvH2->GetStartDir( vtTanS) || - ! pCrvH2->GetStartPoint( ptS)) - return false ; - } - else { - if ( ! pCrvH1->GetEndDir( vtTanS) || - ! pCrvH1->GetEndPoint( ptS)) - return false ; - } - - // creo i due Biarchi - if ( ! CalcBoundedSmoothedLink( ptS, vtTanS, ptE, vtTanS, 0.5, VFirstOff, PockParams, pPath1) || - ! CalcBoundedSmoothedLink( ptE, vtTanS, ptS, vtTanS, 0.5, VFirstOff, PockParams, pPath2)) - return false ; - - // assegno la Feed a queste due nuove curve - AssignMinFeed( pPath1, PockParams) ; - AssignMinFeed( pPath2, PockParams) ; - - // creo la nuova curva con il doppio Biarco - if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) - if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio - return false ; - if ( ! pCrvNewCurve->AddCurve( pPath1->Clone()) || ! pCrvNewCurve->AddCurve( pPath2->Clone())) // aggiungo i due BiArchi - return false ; - if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) - if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine - return false ; - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICurveComposite* pPath1, - const PocketParams& PockParams, ICurveComposite* pPath2, ICRVCOMPOPOVECTOR& vOffsCL) -{ - // controllo parametri - if ( pCrv == nullptr) - return false ; - - // check AutoIntersezioni... - SelfIntersCurve SICrv( *pCrv) ; - if ( SICrv.GetCrossOrOverlapIntersCount() > 0) { // se ci sono autointersezioni - - Vector3d vTanE ; Point3d ptHS ; - pCrvPath->GetEndDir( vTanE) ; - pCrvPath->GetEndPoint( ptHS) ; - - bool bFound = false ; - int nIter = - 45 ; // angolo incrementale nel caso di autointersezioni - - while ( ! bFound && nIter < 45) { - vTanE.Rotate( Z_AX, 90 - nIter) ; // vettore perpendicolare - PtrOwner pLine( CreateCurveLine()) ; - pLine->SetPVL( ptHS, vTanE, ( 2 * PockParams.dRad) / 3 - 5 * EPS_SMALL) ; // segmento uscente - - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pLine, *pCrv) ; - intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; - if ( int( ccClass.size()) > 1) // se intersezione con parte precedente inverto la direzione - pLine->SetPVL( ptHS, - vTanE, ( 2 * PockParams.dRad) / 3 - 5 * EPS_SMALL) ; - - if ( IsNull( pLine) || ! pLine->IsValid()) - break ; - - // punto finale segmento uscente - Point3d ptEndLine ; - pLine->GetEndPoint( ptEndLine) ; - Point3d ptNear ; - double dUS, dUE ; - pPath2->GetDomain( dUS, dUE) ; - PtrOwner pCrvHelper(( pPath2->CopyParamRange( dUS, dUE - 0.5))) ; - pCrvHelper->GetEndPoint( ptNear) ; - PtrOwner pLine1( GetLinePointTgCurve( ptEndLine, *pPath2, ptNear)) ; // segmento tangente - - if ( IsNull( pLine1) || ! pLine1->IsValid()) - break ; - - // creo la nuova curva formata da BiArco 1 - Path - Segmento uscente - Segmento tangente - parte restante di Biarco 2 - Point3d ptELine1 ; - pLine1->GetEndPoint( ptELine1) ; - pPath2->GetParamAtPoint( ptELine1, dUS) ; - PtrOwner pNewPath2( GetCurveComposite( pPath2->CopyParamRange( dUS, dUE))) ; - - // creo la curva formata dai due segmenti ma smussati tra loro... - PtrOwner pCrvTwoSeg( CreateCurveComposite()) ; - if ( ! pCrvTwoSeg->AddCurve( pCrvPath->Clone()) || - ! pCrvTwoSeg->AddCurve( pLine->Clone()) || - ! pCrvTwoSeg->AddCurve( pLine1->Clone())) - return false ; - - ModifyCurveToSmoothed( pCrvTwoSeg, PockParams, 0.2, 0.2, true) ; - - PtrOwner ptNewCrv( CreateCurveComposite()) ; - if ( ptNewCrv->AddCurve( pPath1->Clone()) && - ptNewCrv->AddCurve( pCrvTwoSeg->Clone()) && - ptNewCrv->AddCurve( pNewPath2->Clone())) { - - SelfIntersCurve SICrvLoop( *ptNewCrv) ; - - if ( SICrvLoop.GetCrossOrOverlapIntersCount() == 0) { - pCrv->Clear() ; - pCrv->AddCurve( Release( ptNewCrv)) ; - bFound = true ; - } - else { // se trovo autointersezioni, ripeto cambiando l'angolo del segmento uscente - ++nIter ; + if ( ! vt2.IsValid()) + continue ; + // trovo il punto di intersezione tra le due direzioni tangenti applicate + const double EXTENSION_LEN = 1000. ; + // segmento iniziale ------- + PtrOwner pLineS( CreateCurveLine()) ; + if ( IsNull( pLineS) || ! pLineS->Set( pt1, pt1 + vt1 * EXTENSION_LEN)) + continue ; + // segmento finale -------- + PtrOwner pLineE( CreateCurveLine()) ; + if ( IsNull( pLineE) || ! pLineE->Set( pt2, pt2 - vt2 * EXTENSION_LEN)) + continue ; + // intersezione + IntersCurveCurve ILL( *pLineS, *pLineE) ; + if ( ILL.GetCrossIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + if ( ILL.GetIntCrvCrvInfo( 0, aInfo)) { + if ( ! pCrvCurl->AddPoint( pt1) || + ! pCrvCurl->AddLine( aInfo.IciA[0].ptI)) + continue ; + ptMain = aInfo.IciA[0].ptI ; } } else - break ; + continue ; } - } - - // smusso questa curva sulle varie curve di offsets - Point3d ptCheck1, ptCheck2 ; - PtrOwner pCrvH( pCrv->Clone()) ; // copia della curva - - if ( ! CutCurveByOffsets( pCrv, vOffsCL)) { // taglio la curva sugli Offsets - pCrv->Clear() ; - pCrv->AddCurve( Release( pCrvH)) ; - } - else { // controllo che i punti iniziali coincidano - pCrv->GetStartPoint( ptCheck1) ; - pCrvH->GetStartPoint( ptCheck2) ; - if ( ! AreSamePointApprox( ptCheck1, ptCheck2)) { // se i punti iniziali della curva prima e dopo lo smusso non coincidono ... - pCrv->Clear() ; - pCrv->AddCurve( Release( pCrvH)) ; + // se invece non è di raccordo, allora ho già lo spigolo vivo + else { + // definisco il versore entrante ed uscente + // definisco il punto di entrata e di uscita ( sono coincidenti) + // definisco il parametro di entrata e di uscita ( sono coincidenti) + dURef1 = dURef ; + dURef2 = dURef ; + if ( ! vOffs[nInd]->GetPointD1D2( dURef1, ICurve::FROM_MINUS, ptMain, &vt1) || + ! vOffs[nInd]->GetPointD1D2( dURef2, ICurve::FROM_PLUS, ptMain, &vt2)) + continue ; + vt1.Normalize() ; vt2.Normalize() ; } - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, ICurveComposite* pCrvPath, - ICRVCOMPOPOVECTOR& VFirstOff, ICRVCOMPOPOVECTOR& VoffsCl, const PocketParams& PockParams, - ICurveComposite* pCrvNewCurve) -{ - // inizializzo i due possibili percorsi - PtrOwner pPath1( CreateCurveComposite()) ; - PtrOwner pPath2( CreateCurveComposite()) ; - if ( IsNull( pPath1) || IsNull( pPath2) || pCrvPath == nullptr) - return false ; - pCrvNewCurve->Clear() ; - Point3d ptS, ptE, ptH ; - Vector3d vtTanS, vtTanE, vtH ; - if ( ! pCrvPath->GetStartPoint( ptE) || - ! pCrvPath->GetStartDir( vtTanE) || - ! pCrvPath->GetEndPoint( ptH) || - ! pCrvPath->GetEndDir( vtH)) - return false ; - - if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { - if ( ! pCrvH2->GetStartPoint( ptS) || - ! pCrvH2->GetStartDir( vtTanS)) - return false ; - } - else { - if ( ! pCrvH1->GetEndPoint( ptS) || - ! pCrvH1->GetEndDir( vtTanS)) - return false ; - } - - // creo i due Biarchi - if ( ! CalcBoundedSmoothedLink( ptS, vtTanS, ptE, vtTanE, 0.5, VFirstOff, PockParams, pPath1)) - if ( ! CalcBoundedLink( ptS, ptE, VFirstOff, pPath1)) - return false ; - if ( ! CalcBoundedSmoothedLink( ptH, vtH, ptS, vtTanS, 0.5, VFirstOff, PockParams, pPath2)) - if ( ! CalcBoundedLink( ptH, ptS, VFirstOff, pPath2)) - return false ; - - // creo la curva formata da BiArco1 - Path - BiArco 2 - PtrOwner pCrvToAdd( CreateCurveComposite()) ; - if ( IsNull( pCrvToAdd) || - ! pCrvToAdd->AddCurve( pPath1->Clone()) || - ! pCrvToAdd->AddCurve( pCrvPath->Clone()) || - ! pCrvToAdd->AddCurve( pPath2->Clone())) - return false ; - - // cerco di togliere le auto intersezioni tra i biarchi e le curve di Medial Axis - if ( ! ManageSmoothAndAutoInters( pCrvToAdd, pCrvPath, pPath1, PockParams, pPath2, VoffsCl)) - return false ; - - // imposto la Feed - AssignMinFeed( pCrvToAdd, PockParams) ; - - // curva finale - if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) - if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio - return false ; - - if ( ! pCrvNewCurve->AddCurve( pCrvToAdd->Clone())) { // aggiungo BiArco - Path - BiArco - // nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ... - Vector3d vtHS, vtHE ; - Point3d ptHS, ptHE ; - pCrvNewCurve->GetEndPoint( ptHS) ; - pCrvNewCurve->GetEndDir( vtHS) ; - pCrvToAdd->GetStartPoint( ptHE) ; - pCrvToAdd->GetStartDir( vtHE) ; - PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; - if ( ! CalcBoundedSmoothedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, PockParams, pCrvBiArcHelper)) - if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper)) - return false ; - - // assegno la Feed - AssignMinFeed( pCrvBiArcHelper, PockParams) ; - - if ( ! pCrvNewCurve->AddCurve( Release( pCrvBiArcHelper)) || - ! pCrvNewCurve->AddCurve( pCrvToAdd->Clone())) - return false ; - } - if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) { - if ( ! pCrvNewCurve->AddCurve( pCrvH2->Clone())) { // aggiungo fine - // nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ... - int nTry = 1 ; int nMaxTry = 10 ; bool bFound = false ; - while ( nTry < nMaxTry && ! bFound) { - Vector3d vtHS, vtHE ; - Point3d ptHS, ptHE ; - pCrvNewCurve->GetEndPoint( ptHS) ; - pCrvNewCurve->GetEndDir( vtHS) ; - pCrvH2->GetStartPoint( ptHE) ; - pCrvH2->GetStartDir( vtHE) ; - PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; - if ( ! CalcBoundedSmoothedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, PockParams, pCrvBiArcHelper)) - if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper) ) - return false ; - - // assegno la Feed - AssignMinFeed( pCrvBiArcHelper, PockParams) ; - - if ( ! pCrvNewCurve->AddCurve( pCrvBiArcHelper->Clone()) || - ! pCrvNewCurve->AddCurve( pCrvH2->Clone())) { - ++nTry ; - } - else { - bFound = true ; - } - } - if ( ! bFound) - return false ; + // se i due vettori sono tra loro paralleli... + bool bSameDir = AreSameVectorEpsilon( vt1, vt2, 2 * EPS_SMALL) ; + if ( bSameDir) { + vt1 = ( ptCentroid + ( PockParams.dSideStep / 4 * vt1)) - ptCloser ; + vt2 = ( ptCentroid - ( PockParams.dSideStep / 4 * vt2)) - ptCloser ; + vt2.Invert() ; } - } - return true ; -} - -//--------------------------------------------------------------------------- -static bool -GetCurveWeightInfo( const ICurveComposite* pCrvCompo, double dMaxLen, double& dToTRot, int& nSmallArcs, int& nSmallLines) -{ - - dToTRot = 0 ; nSmallArcs = 0 ; nSmallLines = 0 ; - if ( pCrvCompo == nullptr) - return true ; - - int nLines = 0 ; - PtrOwner pCrvLineOld( CreateCurveLine()) ; - if ( IsNull( pCrvLineOld)) - return false ; - - // scorro tutte le curve della composita - const ICurve* pMyCrv = pCrvCompo->GetFirstCurve() ; - while ( pMyCrv != nullptr) { - if ( pMyCrv->GetType() == CRV_ARC) { // nel caso di archi ... - nLines = 0 ; - PtrOwner pCrvArc( GetCurveArc( pMyCrv->Clone())) ; - double dAngCenter = abs( pCrvArc->GetAngCenter()) ; - dToTRot += abs( dAngCenter) ; - double dLen = 0 ; - if ( pCrvArc->GetLength( dLen) && dLen < dMaxLen) - ++ nSmallArcs ; - } - else if ( pMyCrv->GetType() == CRV_LINE) { // nel caso di linee ... - ++ nLines ; - if ( nLines == 1) - pCrvLineOld.Set( GetCurveLine( pMyCrv->Clone())) ; - else { - PtrOwner pNewMyCrv( GetCurveLine( pMyCrv->Clone())) ; - Vector3d vtNew, vtOld ; - pCrvLineOld->GetEndDir( vtOld) ; - pNewMyCrv->GetStartDir( vtNew) ; - double dAngCorner ; vtOld.GetAngle( vtNew, dAngCorner) ; - dToTRot += abs( dAngCorner) ; - pCrvLineOld.Set( pNewMyCrv) ; - nLines = 0 ; - } - - double dLen = 0 ; - if ( pMyCrv->GetLength( dLen) && dLen < dMaxLen) - ++ nSmallLines ; - } - pMyCrv = pCrvCompo->GetNextCurve() ; - } - - return true ; -} - -//--------------------------------------------------------------------------- -static bool -ChoosePath( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nP, double dPerP, double dMaxLen, int& nC) -{ - - // controllo dei parametri - if ( pCrv1 == nullptr || pCrv2 == nullptr || - ! ( nP == 0 || nP == 1) || dPerP > 1 || dPerP < 0 || dMaxLen < EPS_SMALL) - return false ; - - // # di archi piccoli tra le due curve - int dSmallArcs1 = 0 ; int dSmallArcs2 = 0 ; - // # di segmenti piccoli tra le due curve - int dSmallLines1 = 0 ; int dSmallLines2 = 0 ; - - // ------------- lunghezze -------------- - double dLen1 = 0 ; double dLen2 = 0 ; - pCrv1->GetLength( dLen1) ; - pCrv2->GetLength( dLen2) ; - - double CL1, CL2 ; // rapporto tra lunghezza corrente e massima - - if ( dLen1 < EPS_SMALL && dLen2 < EPS_SMALL) { - CL1 = 0 ; - CL2 = 0 ; - } - else { - CL1 = dLen1 / max( dLen1, dLen2) ; - CL2 = dLen2 / max( dLen1, dLen2) ; - } - - // ------------- rotazioni -------------- - double dRot1 = 0 ; double dRot2 = 0 ; - if ( ! GetCurveWeightInfo( pCrv1, dMaxLen, dRot1, dSmallArcs1, dSmallLines1) || - ! GetCurveWeightInfo( pCrv2, dMaxLen, dRot2, dSmallArcs2, dSmallLines2)) - return false ; - - double CR1, CR2 ; // rapporto tra la somma de rotazione degli angoli correnti e quella massima - - if ( dRot1 == 0 && dRot2 == 0) { - CR1 = 0 ; - CR2 = 0 ; - } - else { - CR1 = dRot1 / max( dRot1, dRot2) ; - CR2 = dRot2 / max( dRot1, dRot2) ; - } - - // funzione peso ( bilancio tra lunghezze e rotazioni complessive pesate) - double Fp1 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL1 + dSmallLines1) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR1 + dSmallArcs1) ; - double Fp2 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL2 + dSmallLines2) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR2 + dSmallArcs2) ; - - // scelta della prima o della seconda curva - nC = ( Fp1 > Fp2 ? 1 : 0) ; - return true ; -} - -//---------------------------------------------------------------------------- -static bool -RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsClosedCurves, - ICRVCOMPOPOVECTOR& vOffsFirstCurve, ICURVEPOVECTOR& vLinks, const PocketParams& PockParams) -{ - - // controllo parametri - if ( pSrfToCut == nullptr || vOffs.empty()) - return true ; - - // ciclo tutti i chunk della regione da tagliare - for ( int i = 0 ; i < pSrfToCut->GetChunkCount() ; ++ i) { - - // regione i-esima da rimuovere ( chunk i-esimo ) - PtrOwner pSrfChunkToCut( pSrfToCut->CloneChunk( i)) ; - if ( IsNull( pSrfChunkToCut)) - return false ; - - // Curva nel caso la regione si svuoti con MedialAxis - PtrOwner pCrvPath( CreateCurveComposite()) ; - if ( IsNull( pCrvPath)) - return false ; - - // nel caso la regione si svuoti con un centroide -> ptGoTo è il centroide - // nel caso la regione si svuoti con un medial Axis -> ptGoTo è il punto iniziale - // -> ptGoTo è il punto finale - Point3d ptGoTo, ptGoToI ; - // flag : 0 -> non faccio nulla | 1 -> svuoto con centroide | 2 -> svuoto con un percorso - int nOptFlag = 0 ; - - // ricavo il flag - // ptGoTo è il centroide, pCrvPath è la curva da seguire per svuotare la regione ( nel caso non bastasse il centroide) - if ( ! RemoveExtraPartByMedialAxis( pSrfChunkToCut, vOffsFirstCurve, PockParams, nOptFlag, ptGoTo, pCrvPath) || - nOptFlag == 0) + // calcolo la direzione tra pt1 e ptCentroid + Vector3d vtDir = ( ptCentroid - ptMain) ; vtDir.Normalize() ; + vtDir.Rotate( Z_AX, ANG_RIGHT) ; + double dAngMain ; bool bDet ; + vt1.GetRotation( vt2, Z_AX, dAngMain, bDet) ; + if ( dAngMain > - EPS_ZERO) + vtDir.Invert() ; + // calcolo i due Biarchi di raccordo + PtrOwner pCrvBiArc1( CreateCurveComposite()) ; + PtrOwner pCrvBiArc2( CreateCurveComposite()) ; + if ( IsNull( pCrvBiArc1) || IsNull( pCrvBiArc2) || + ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vtDir, 0.5, vOffsFirstCurve, PockParams, pCrvBiArc1) || + ! CalcBoundedSmoothedLink( ptCentroid, vtDir, ptMain, vt2, 0.5, vOffsFirstCurve, PockParams, pCrvBiArc2)) continue ; - if ( nOptFlag == 2 ) // se ho una curva di Medial Axis, ricavo il punto iniziale e finale - if ( ! pCrvPath->GetStartPoint( ptGoTo) || - ! pCrvPath->GetEndPoint( ptGoToI)) - continue ; - - // una volta trovata la curva di medial Axis ( se la regione non si svuota semplicemente passando per il - // centroide, controllo in quale direzione è più conveniente percorrerla ... ( I = Inverso) - PtrOwner pCrvH1( CreateCurveComposite()) ; - PtrOwner pCrvH2( CreateCurveComposite()) ; - PtrOwner pCrvH1I( CreateCurveComposite()) ; - PtrOwner pCrvH2I( CreateCurveComposite()) ; - if ( IsNull( pCrvH1) || IsNull( pCrvH2) || IsNull( pCrvH2) || IsNull( pCrvH2I)) - return false ; - int nIndexO = 0 ; - int nIndexOI = 0 ; - - // cerco il punto pià vicino a ptGoTo sugli tra i vari Offset ( escludendo il primo ) - // NB. PtGoTo è il centroide o il punto iniziale del percorso di medial Axis non invertito - if ( ! CutOffsetToClosestPoint( vOffs, ptGoTo, pCrvH1, pCrvH2, nIndexO)) + // aggiorno la curva a ricciolo + if ( ! pCrvCurl->AddCurve( Release( pCrvBiArc1)) || + ! pCrvCurl->AddCurve( Release( pCrvBiArc2)) || + ! pCrvCurl->IsValid()) continue ; - if ( nOptFlag == 2) // se ho un percorso di Medial Axis, lo cerco anche per PtGoToI - if ( ! CutOffsetToClosestPoint( vOffs, ptGoToI, pCrvH1I, pCrvH2I, nIndexOI)) - continue ; - // A) SE IL PUNTO PIU' VICINO E' SU UN ESTREMO DELL'OFFSET... -> Cerco un punto sui collegamenti - // ( controllo solo i punti trovati sugli offset mediante Medial Axis non invertiti) - if ( IsNull( pCrvH1) || IsNull( pCrvH2) || pCrvH1->GetCurveCount() == 0 || pCrvH2->GetCurveCount() == 0) { - bool bFound, bFoundI ; int nIndexL, nIndexLI ; - if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoTo, pCrvH1, pCrvH2, bFound, nIndexL)) - continue ; - if ( nOptFlag == 2) { // nel caso curva di Medial Axis, controllo anche nel caso invertito - if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoToI, pCrvH1I, pCrvH2I, bFoundI, nIndexLI)) - continue ; - } + // controllo se devo raccordarmi con Offset + if ( bIsSmoothCrv) + pCrvCurl->AddLine( pt2) ; - // link finale scelto... - PtrOwner ptCrvNewLink( CreateCurveComposite()) ; - if ( IsNull( ptCrvNewLink)) + // controllo se tale curva effettivamente rimuove il Chunk nC-esimo + PtrOwner pSfrFatCurl( GetSurfFlatRegionFromFatCurve( pCrvCurl->Clone(), PockParams.dRad, false, false)) ; + if ( IsNull( pSfrFatCurl) || ! pSfrFatCurl->IsValid()) + continue ; + PtrOwner pSfrChunk( pSfrUncleared->CloneChunk( nC)) ; + if ( IsNull( pSfrFatCurl) || ! pSfrFatCurl->IsValid()) + return false ; + pSfrChunk->Subtract( *pSfrFatCurl) ; + + // se la curva a ricciolo non svuota il Chunk nC-esimo -> percorro il bordo di tale Chunk + if ( pSfrChunk->IsValid() || pSfrChunk->GetChunkCount() > 0) { + // so che il punto più vicino alla curva è ptCloser + // ricavo dunque il punto più vicino sul bordo del Chunk nC-esimo + PtrOwner pCompoChunkBorder( ConvertCurveToComposite( pSfrUncleared->GetLoop( nC, 0))) ; + if ( IsNull( pCompoChunkBorder) || ! pCompoChunkBorder->IsValid()) return false ; - - if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) - if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, PockParams, ptGoTo, bFound, vOffsFirstCurve, ptCrvNewLink)) + if ( PockParams.bInvert) + pCompoChunkBorder->Invert() ; + DistPointCurve distPtChunkBorder( ptCloser, *pCompoChunkBorder) ; + Point3d ptCloserOnChunk ; + if ( ! distPtChunkBorder.GetMinDistPoint( EPS_SMALL, ptCloserOnChunk, nFlag)) + continue ; + // cambio il punto di inizio della curva su tale punto + double dUS = 0. ; + pCompoChunkBorder->GetParamAtPoint( ptCloserOnChunk, dUS) ; + pCompoChunkBorder->ChangeStartPoint( dUS) ; + /* + Creo due curve composite rappresentanti un piccolo tratto tangente sulla curva di + Offset attuale; questi servono per la partenza e l'arrivo dei biArchi + */ + PtrOwner pCompoHelpS( CreateCurveComposite()) ; + if ( IsNull( pCompoHelpS) || ! pCompoHelpS->AddPoint( pt1 - vt1 / 4) || + ! vt1.Normalize() || ! pCompoHelpS->AddLine( pt1)) + continue ; + PtrOwner pCompoHelpE( CreateCurveComposite()) ; + if ( IsNull( pCompoHelpE) || ! pCompoHelpE->AddPoint( pt2) || + ! vt2.Normalize() || ! pCompoHelpE->AddLine( pt2 + vt2 / 4)) + continue ; + /* + creo il Biarco iniziale + ( nel caso non si riuscisse diventa un segmento lineare) + */ + PtrOwner pCrvBiArc1( CreateCurveComposite()) ; + if ( IsNull( pCrvBiArc1)) + return false ; + if ( ! CutCurveToConnect( pCompoHelpS, pCompoChunkBorder, vOffsFirstCurve, PockParams, + 0, 10 * EPS_SMALL, pCrvBiArc1)) { + if ( ! CalcBoundedLink( ptCloser, ptCloserOnChunk, vOffsFirstCurve, pCrvBiArc1)) continue ; - } - else if ( nOptFlag == 2) { // se svuoto con curva di medial Axis... - - bool bSucc = true ; bool bSuccI = true ; - - // ricavo il nuovo Offset con la curva di medial Axis aggiunta - if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, - PockParams, ptCrvNewLink)) - bSucc = false ; - - PtrOwner pCrvPathI( pCrvPath->Clone()) ; - pCrvPathI->Invert() ; - PtrOwner ptCrvNewLinkI( CreateCurveComposite()) ; - if ( IsNull( ptCrvNewLinkI)) - return false ; - - // ricavo il nuovo Offset con la curva di medial Axis Invertita aggiunta - if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, - PockParams, ptCrvNewLinkI)) - bSuccI = false ; - - // scelgo il miglior percorso ottenuto ( sempre verificando che siano validi...) - int nC = 0 ; - if ( bSucc && bSuccI) { // se entrambi i percorsi sono validi allora li confronto - if ( ChoosePath( ptCrvNewLink, ptCrvNewLinkI, 0, 0.25, 5 * 1000 * EPS_SMALL, nC) && nC == 1) { - ptCrvNewLink.Set( ptCrvNewLinkI) ; - nIndexL = nIndexLI ; - } - } - else if ( ! bSucc) { // altrimenti tengo l'unico valido - ptCrvNewLink.Set( ptCrvNewLinkI) ; - nIndexL = nIndexLI ; - } } - vLinks[nIndexL].Set( ptCrvNewLink) ; // setto il nuovo Link + // aggiorno i nuovi punti e i nuovi parametri + double dMyU ; + Point3d ptMyPoint ; + if ( ! pCrvBiArc1->GetEndPoint( ptMyPoint) || + ! pCompoChunkBorder->GetParamAtPoint( ptMyPoint, dMyU)) + continue ; + // accorgio il bordo dell'Offset in raccordo al BiArco iniziale + if ( dMyU > EPS_SMALL) + pCompoChunkBorder->TrimStartAtParam( dMyU) ; + /* + creo il Biarco finale + ( nel caso non si riuscisse diventa un segmento lineare) + */ + // creo il Biarco iniziale ( nel caso non si riuscisse diventa un segmento lineare) + PtrOwner pCrvBiArc2( CreateCurveComposite()) ; + if ( IsNull( pCrvBiArc2)) + return false ; + if ( ! CutCurveToConnect( pCompoChunkBorder, pCompoHelpE, vOffsFirstCurve, PockParams, + 0., 0., pCrvBiArc2)) { + if ( ! CalcBoundedLink( ptCloserOnChunk, ptCloser, vOffsFirstCurve, pCrvBiArc2)) + continue ; + } + // aggiorno i nuovi punti e i nuovi parametri + if ( ! pCrvBiArc2->GetStartPoint( ptMyPoint) || + ! pCompoChunkBorder->GetParamAtPoint( ptMyPoint, dMyU)) + continue ; + // la curva a ricciolo ora diventa l'unione di pCrvBiArc1 - pCompoChunkBorder - pCrvBiArc2 + pCrvCurl->Clear() ; + // smusso la curva di bordo del Chunk ( è aperta) + double dSmoothPar = PockParams.dRad / 8. ; + ModifyCurveToSmoothed( pCompoChunkBorder, PockParams, dSmoothPar, dSmoothPar, false) ; + if ( ! pCrvCurl->AddCurve( Release( pCrvBiArc1)) || + ! pCrvCurl->AddCurve( Release( pCompoChunkBorder)) || + ! pCrvCurl->AddCurve( Release( pCrvBiArc2))) + continue ; } - else { // B) SE NON SONO AD UN ESTREMO DELLA CURVA DI OFFSET - - // nuovo Offset da restituire - PtrOwner ptCrvNewOffs( CreateCurveComposite()) ; - if ( IsNull( ptCrvNewOffs)) - return false ; - if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) - if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, PockParams, ptGoTo, true, vOffsFirstCurve, ptCrvNewOffs)) - continue ; - } - else if ( nOptFlag == 2) { // nel caso aggiungo un medial Axis non agli estremi di un Offset + // attribuisco alla curva a ricciolo la Feed minima + AssignMinFeed( pCrvCurl, PockParams) ; - bool bSucc = true ; bool bSuccI = true ; - - // come prima controllo il percorso normal ed invertito - if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, - PockParams, ptCrvNewOffs)) - bSucc = false ; - - PtrOwner pCrvPathI( pCrvPath->Clone()) ; - pCrvPathI->Invert() ; - PtrOwner ptCrvNewOffsI( CreateCurveComposite()) ; - if ( IsNull( ptCrvNewOffsI)) - return false ; - - if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, - PockParams, ptCrvNewOffsI)) - bSuccI = false ; - - int nC = 0 ; // se entrambi i percorsi sono validi allora li confronto - if ( bSucc && bSuccI) { - if ( ChoosePath( ptCrvNewOffs, ptCrvNewOffsI, 0, 0.5, 5 * 1000 * EPS_SMALL, nC) && nC == 1) { - ptCrvNewOffs.Set( ptCrvNewOffsI) ; - nIndexO = nIndexOI ; - } - } - else if ( ! bSucc) { // altrimenti tengo l'unico valido - ptCrvNewOffs.Set( ptCrvNewOffsI) ; - nIndexO = nIndexOI ; - } - } - vOffs[nIndexO].Set( ptCrvNewOffs) ; // setto il nuovo Offset + // aggiorno il nuovo Offset aggiungendo la curva a ricciolo + PtrOwner pCrvTest( CreateCurveComposite()) ; + if ( IsNull( pCrvTest)) + return false ; + // aggiungo tratto iniziale di Offset + pCrvTest->AddCurve( ConvertCurveToBasicComposite( pMyOffs->CopyParamRange( 0, dURef1))) ; + // aggiungo la curva a ricciolo + if ( ! pCrvTest->AddCurve( Release( pCrvCurl))) + continue ; + // aggiungo il tratto finale di Offset + pCrvTest->AddCurve( ConvertCurveToBasicComposite( pMyOffs->CopyParamRange( dURef2, pMyOffs->GetCurveCount()))) ; + // nel caso di direzioni parallele manca uno smusso + if ( bSameDir) { + double dSmoothPar = PockParams.dRad / 8. ; + ModifyCurveToSmoothed( pCrvTest, PockParams, dSmoothPar, dSmoothPar, false) ; + } + // provo a controllare che i punti inzili e finali coincidano, in caso aggiorno il nuovo Offset + Point3d ptStart_Old ; vOffs[nInd]->GetStartPoint( ptStart_Old) ; + Point3d ptEnd_Old ; vOffs[nInd]->GetEndPoint( ptEnd_Old) ; + Point3d ptStart_New ; pCrvTest->GetStartPoint( ptStart_New) ; + Point3d ptEnd_New ; pCrvTest->GetEndPoint( ptEnd_New) ; + if ( AreSamePointApprox( ptStart_Old, ptStart_New) && AreSamePointApprox( ptEnd_Old, ptEnd_New)) { + pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 0), 0) ; + pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 1), 1) ; + vOffs[nInd].Set( pCrvTest) ; } } @@ -5894,7 +5054,7 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP //---------------------------------------------------------------------------- static bool CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, const PocketParams& PockParams, - const ICRVCOMPOPOVECTOR& vOffsClosedCurves, const ICRVCOMPOPOVECTOR& vOffsFirstCurve) + const ICRVCOMPOPOVECTOR& vOffsFirstCurve) { // controllo dei parametri if ( vOffs.empty() || vOffsFirstCurve.empty()) @@ -5975,8 +5135,9 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con if ( IsNull( pCrvLink)) return false ; // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset - if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsClosedCurves, vOffsFirstCurve, PockParams, pCrvLink, - i == 0 ? 0 : 0.01, 0.01, 2) || ! pCrvLink->IsValid()) { + if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, + ( i == 0 ? 0. : 10 * EPS_SMALL), 10 * EPS_SMALL, pCrvLink) || + ! pCrvLink->IsValid()) { // se non sono riuscito, cerco una strada più semplice // ripristino le curve pCrvLink->Clear() ; @@ -6005,7 +5166,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // imposto il punto iniziale della curva successiva ( i+1 esima) vOffs[i+1]->ChangeStartPoint( dUNewE) ; - PtrOwner pCrvNewOffs( vOffs[i]->Clone()) ; + PtrOwner pCrvNewOffs( CloneCurveComposite( vOffs[i])) ; if ( dUNewS > EPS_SMALL) { pCrvNewOffs.Set( ConvertCurveToComposite( vOffs[i]->CopyParamRange( 0, dUNewS))) ; // sostituisco la curva i esima con quella tagliata @@ -6226,14 +5387,26 @@ IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const Po //---------------------------------------------------------------------------- static bool CalcCrvGuideConformalZigZag( const ISurfFlatRegion* pSfrChunk, PocketParams& PockParams, ICurveComposite* pCompoGuide, - ICurveComposite* pCompoClass) + ICurveComposite* pCompoClass, ICurveComposite* pCompoClass_UR) { + /* + NB. La curva di classificazione pCompoClass è una curva chiusa che deriva dall'estensione + presso i lati aperti con un tool di ragggio a max( dRad / 8, PockParams.dSideStep / 2). + NB. La curva di classificazione pCompoClass_UR è la curva mediante la quale i Biarchi di + raccordo ( curve a racciolo non devono uscire) ; in questo caso l'estensione della + curva è paragonabile a quella di un tool con raggio + max( dRad / 8, PockParams.dSideStep / 2) + PockParams.Rad + in questo modo il controOffset della regione definisce correttamente la curva per la classificazione + */ + + // controllo dei parametri - if ( pCompoGuide == nullptr || pCompoClass == nullptr || + if ( pCompoGuide == nullptr || pCompoClass == nullptr || pCompoClass_UR == nullptr || pSfrChunk == nullptr || ! pSfrChunk->IsValid()) return false ; pCompoGuide->Clear() ; pCompoClass->Clear() ; + pCompoClass_UR->Clear() ; // la superficie deve avere un Chunk e non avere isole if ( pSfrChunk->GetChunkCount() > 1 || pSfrChunk->GetLoopCount( 0) > 1) @@ -6342,12 +5515,95 @@ CalcCrvGuideConformalZigZag( const ISurfFlatRegion* pSfrChunk, PocketParams& Poc pCompoClass->CopyFrom( pCompoPerimeter) ; ResetCurveTempProps( pCompoClass) ; + // creo la curva di classificazione per le regioni non svuotate + dRad = PockParams.dRad ; + PockParams.dRad = max( dRad / 8, PockParams.dSideStep / 2) + dRad ; + PtrOwner pCompoClassUnclearedRegion( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCompoClassUnclearedRegion) || ! pCompoClassUnclearedRegion->IsValid() || + ! AdjustContourWithOpenEdges( pCompoClassUnclearedRegion, vCrvEmpty, PockParams)) + return false ; + PockParams.dRad = dRad ; + if ( pCompoClassUnclearedRegion->IsValid()) { + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCompoClassUnclearedRegion, - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) + return false ; + PtrOwner pMyCrv( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; + if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) + return false ; + pCompoClass_UR->CopyFrom( pMyCrv) ; + } + return true ; } //---------------------------------------------------------------------------- static bool -AddAddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, +AdapthLinkToOffsBySmooth( ICurveComposite* pCrvLink, ICurveComposite* pCrvOffsPrec, + ICurveComposite* pCrvOffsSucc, const PocketParams& PockParams) +{ + // controllo dei parametri + if ( pCrvLink == nullptr || pCrvOffsPrec == nullptr || pCrvOffsSucc == nullptr || + ! pCrvLink->IsValid() || ! pCrvOffsPrec->IsValid() || ! pCrvOffsSucc->IsValid()) + return false ; + + // clono la curva di Link ( in modo da non rovinare l'originale) + PtrOwner pCrvMyLink( CloneCurveComposite( pCrvLink)) ; + if ( IsNull( pCrvMyLink) || ! pCrvMyLink->IsValid()) + return false ; + + // aggiungo la curva finale dell'Offset precedente e la curva iniziale dell'Offset successivo + // al tratto di Link + PtrOwner pCrvPrec( pCrvOffsPrec->GetLastCurve()->Clone()) ; + PtrOwner pCrvSucc( pCrvOffsSucc->GetFirstCurve()->Clone()) ; + if ( IsNull( pCrvPrec) || IsNull( pCrvSucc) || + ! pCrvPrec->IsValid() || ! pCrvSucc->IsValid()) + return false ; + // assegno proprietà di invalidità delle curve + pCrvPrec->SetTempProp( TEMP_PROP_INVALID, 1) ; + pCrvSucc->SetTempProp( TEMP_PROP_INVALID, 1) ; + // aggiungo + if ( ! pCrvMyLink->AddCurve( Release( pCrvPrec), false) || + ! pCrvMyLink->AddCurve( Release( pCrvSucc), true)) + return false ; + + // estendo la curva, in modo da non perdere i tratti estremi + const double EXT_LEN = 1000. ; + if ( ! pCrvMyLink->AddLineTg( EXT_LEN, false) || + ! pCrvMyLink->AddLineTg( EXT_LEN, true)) + return false ; + + // smusso il Link + double dSmoothParam = PockParams.dRad / 8. ; + ModifyCurveToSmoothed( pCrvMyLink, PockParams, dSmoothParam, dSmoothParam, false) ; + + // rimuovo la prima e l'ultima curva ( e quella invalida) + delete( pCrvMyLink->RemoveFirstOrLastCurve( false)) ; // tratto lineare + delete( pCrvMyLink->RemoveFirstOrLastCurve( true)) ; // tratto lineare + const ICurve* pCrvFirst = pCrvMyLink->GetFirstCurve() ; + if ( pCrvFirst != nullptr && pCrvFirst->GetTempProp( 1) == TEMP_PROP_INVALID) // sottocurva di Offs + delete( pCrvMyLink->RemoveFirstOrLastCurve( false)) ; + const ICurve* pCrvLast = pCrvMyLink->GetLastCurve() ; + if ( pCrvLast != nullptr && pCrvLast->GetTempProp( 1) == TEMP_PROP_INVALID) // sottocurva di Offs + delete( pCrvMyLink->RemoveFirstOrLastCurve( true)) ; + + // recupero punto iniziale e finale del Link + Point3d ptS ; pCrvMyLink->GetStartPoint( ptS) ; + Point3d ptE ; pCrvMyLink->GetEndPoint( ptE) ; + // recupero i paramtri sulle curve di Offset + double dUTrim ; + if ( ! pCrvOffsPrec->GetParamAtPoint( ptS, dUTrim, 500 * EPS_SMALL) || + ! pCrvOffsPrec->TrimEndAtParam( dUTrim)) + return false ; + if ( ! pCrvOffsSucc->GetParamAtPoint( ptE, dUTrim, 500 * EPS_SMALL) || + ! pCrvOffsSucc->TrimStartAtParam( dUTrim)) + return false ; + pCrvLink->CopyFrom( pCrvMyLink) ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { /* @@ -6377,17 +5633,19 @@ AddAddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, // ricavo la guida ideale e la curva su cui tagliare gli Offset a partire dal Chunk nC-esimo PtrOwner pCrvGuideExt( CreateCurveComposite()) ; PtrOwner pCrvClass( CreateCurveComposite()) ; + PtrOwner pCrvClassUR( CreateCurveComposite()) ; if ( IsNull( pCrvGuideExt) || IsNull( pCrvClass) || - ! CalcCrvGuideConformalZigZag( pSfr, PockParams, pCrvGuideExt, pCrvClass)) + ! CalcCrvGuideConformalZigZag( pSfr, PockParams, pCrvGuideExt, pCrvClass, pCrvClassUR)) return false ; // se non è stata trovata una guida ideale, allora passo al Chunk successivo if ( ! pCrvGuideExt->IsValid() || pCrvGuideExt->GetCurveCount() == 0 || - ! pCrvClass->IsValid() || pCrvClass->GetCurveCount() == 0) { + ! pCrvClass->IsValid() || pCrvClass->GetCurveCount() == 0 || + ! pCrvClassUR->IsValid() || pCrvClassUR->GetCurveCount() == 0) { return true ; } // memorizzo le curve di Offset tagliate a seconda dalla geometria del perimetro - ICRVCOMPOPOVECTOR vCompoInternalOffs ; + ICRVCOMPOPOVECTOR vOffs ; const int MAX_ITER = 100 ; double dOffs = PockParams.dRad + PockParams.dRadialOffset ; for ( int i = 0 ; i < MAX_ITER ; ++ i) { @@ -6440,133 +5698,109 @@ AddAddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, if ( ! IsNull( pCrvOffs_Int) && pCrvOffs_Int->IsValid()) { // salvo come prima proprietà temporanea, il numero di Offset progressivo pCrvOffs_Int->SetTempProp( i, 0) ; + // salvo come seconda proprietà temporanea il lato esterno + pCrvOffs_Int->SetTempProp( ( ! IsEven( i) && ! PockParams.bInvert) || + ( IsEven( i) && PockParams.bInvert) ? + MDS_LEFT : MDS_RIGHT, 1) ; // salvo la curva - vCompoInternalOffs.emplace_back( ConvertCurveToComposite( Release( pCrvOffs_Int))) ; + vOffs.emplace_back( ConvertCurveToComposite( Release( pCrvOffs_Int))) ; } } } dOffs += PockParams.dSideStep ; } // se non ho ottenuto Offset, passo al Chunk successivo - if ( vCompoInternalOffs.empty()) + if ( vOffs.empty()) return true ; - /* - Creo la curva di Svuotatura come unione di due curve : - - La curva che non deve essere smussata ( curve di primo Offset e raccordi) - - La Curva che necessita di smusso ( le altre) - NB. Nel caso non sia richiesto lo smusso, allora la seconda curva non viene smussata, ma la - logica rimane la stessa. - */ + // inverto il vettore degli Offset, in modo da partire dal più esterno fino ad arrivare al + // più interno + reverse( vOffs.begin(), vOffs.end()) ; - PtrOwner pCompoNoSmooth( CreateCurveComposite()) ; - PtrOwner pCompoSmooth( CreateCurveComposite()) ; - if ( IsNull( pCompoNoSmooth) || IsNull( pCompoSmooth)) - return false ; - - // scorro i tratti di Offset interni e aggiungo i raccordi sul bordo esterno - // raccordo il tratto di Offset interno corrente al successivo - const double TOL_JOINT = 25. * EPS_SMALL ; + // calcolo la lunghezza del semiperimetro della curva di classificazione + // ( serve per decidere il tratto di curva di raccordo) double dHalfLenPerimeter ; pCrvClass->GetLength( dHalfLenPerimeter) ; dHalfLenPerimeter /= 2. ; - for ( int i = 0 ; i < int( vCompoInternalOffs.size()) - 1 ; ++ i) { + + // creo il vettore dei Link e definisco la tolleranza di Join tra Offset e Link + ICURVEPOVECTOR vLinks( int( vOffs.size())) ; + Point3d ptSplit ; // punto dal quale smussare tutti i percorsi + for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { // recupero il parametro iniziale del raccordo sulla curva di perimetro - Point3d ptS ; vCompoInternalOffs[i]->GetEndPoint( ptS) ; + Point3d ptS ; vOffs[i]->GetEndPoint( ptS) ; double dUS ; pCrvClass->GetParamAtPoint( ptS, dUS) ; + if ( vOffs[i]->GetTempProp( 0) == 0) + ptSplit = ptS ; // recupero il parametro finale del raccordo sulla curva di perimetro - Point3d ptE ; vCompoInternalOffs[i+1]->GetStartPoint( ptE) ; + Point3d ptE ; vOffs[i+1]->GetStartPoint( ptE) ; double dUE ; pCrvClass->GetParamAtPoint( ptE, dUE) ; - // aggiungo il tratto di Offset interno corrente alla curva di svuotatura - if ( vCompoInternalOffs[i]->GetTempProp() == 0) { - // se deriva dal primo Offset - if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT)) - return false ; - } - else { - // se deriva da Offset successivi - if ( ! pCompoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT)) - return false ; - } // recupero il tratto di curva di interesse - PtrOwner pCrvJoint( pCrvClass->CopyParamRange( dUS, dUE)) ; + PtrOwner pCrvJoint( ConvertCurveToComposite( pCrvClass->CopyParamRange( dUS, dUE))) ; if ( ! IsNull( pCrvJoint) && pCrvJoint->IsValid()) { double dLen ; pCrvJoint->GetLength( dLen) ; if ( dLen > dHalfLenPerimeter) { - pCrvJoint.Set( pCrvClass->CopyParamRange( dUE, dUS)) ; + pCrvJoint.Set( ConvertCurveToComposite( pCrvClass->CopyParamRange( dUE, dUS))) ; pCrvJoint->Invert() ; } - // aggiungo il tratto di percorso - if ( vCompoInternalOffs[i+1]->GetTempProp() == 0) { - // se l'offset successivo deriva ancora dal primo - if ( ! pCompoNoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT)) - return false ; - } - else { - // se l'Offset successivo non deriva dal primo Offset - if ( ! pCompoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT)) + // solo se non siamo in presenza di curve di primo Offset, aggiungo al Link l'ultima + // curva dell'Offset precedente e la prima curva dell'Offset successivo + if ( vOffs[i]->GetTempProp( 0) > 0 || vOffs[i+1]->GetTempProp( 0) > 0) { + if ( ! AdapthLinkToOffsBySmooth( pCrvJoint, vOffs[i], vOffs[i+1], PockParams)) return false ; } + vLinks[i+1].Set( Release( pCrvJoint)) ; } } - // aggiungo l'ultimo tratto di Offset - if ( vCompoInternalOffs.back()->GetTempProp() == 0) { - if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs.back()), true, TOL_JOINT)) - return false ; - } - else { - if ( ! pCompoSmooth->AddCurve( vCompoInternalOffs.back()->Clone(), true, TOL_JOINT)) - return false ; - } - // porto l'ultima curva del percorso NoSmooth nel percorso Smooth per avere un raccordo anche - // sul tratto di giunzione tra esse - if ( pCompoSmooth->IsValid() && pCompoNoSmooth->IsValid()) { - PtrOwner pCrv( pCompoNoSmooth->GetLastCurve()->Clone()) ; - if ( IsNull( pCrv) || ! pCrv->IsValid() || - ! pCompoSmooth->AddCurve( Release( pCrv), false, TOL_JOINT)) - return false ; - delete( pCompoNoSmooth->RemoveFirstOrLastCurve( true)) ; + + // smusso tutte le curve di Offset ( tranne quelle generate alla prima iterazione) + double dSmoothParam = PockParams.dRad / 8. ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + if ( vOffs[i]->GetTempProp( 0) > 0) + ModifyCurveToSmoothed( vOffs[i], PockParams, dSmoothParam, dSmoothParam, false) ; + } + + // determino la regione piana dove sono contenute le zone non svuotate ( se esistono) + PtrOwner pSfrFirstOffs( CloneSurfFlatRegion( pSfrChunk)) ; + if ( IsNull( pSfrFirstOffs) || ! pSfrFirstOffs->IsValid() || + ! pSfrFirstOffs->Offset( - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) + return false ; + ICRVCOMPOPOVECTOR vCrvFirstOffs ; + for ( int nC_ = 0 ; nC_ < pSfrFirstOffs->GetChunkCount() ; ++ nC_) + vCrvFirstOffs.emplace_back( ConvertCurveToComposite( pSfrFirstOffs->GetLoop( nC_, 0))) ; + // inizializzo la regione contenente le parti non svuotate + PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrUncleared)) + return false ; + // calcolo la Feed e la regione contenente le parti non svuotate + if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vOffs, vLinks, pCrvClass, PockParams, pSfrUncleared)) { + // Modifico i percorsi + vCrvFirstOffs.clear() ; + vCrvFirstOffs.emplace_back( Release( pCrvClassUR)) ; + if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vCrvFirstOffs, PockParams)) + return false ; } - // smusso dove necessario - ModifyCurveToSmoothed( pCompoSmooth, PockParams, PockParams.dRad / 8, PockParams.dRad / 8, false) ; // creo il percorso di svuotatura PtrOwner pCompoTempPath( CreateCurveComposite()) ; if ( IsNull( pCompoTempPath)) return false ; - if ( pCompoNoSmooth->IsValid() && pCompoNoSmooth->GetCurveCount() > 0) { - if ( ! pCompoTempPath.Set( pCompoNoSmooth)) - return false ; - } - if ( pCompoSmooth->IsValid()) { - if ( ! pCompoTempPath->AddCurve( Release( pCompoSmooth), true, TOL_JOINT)) - return false ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + if ( ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { + if ( ! pCompoTempPath->AddCurve( Release( vLinks[i]))) + return false ; + } + if ( ! IsNull( vOffs[i]) && vOffs[i]->IsValid()) { + if ( ! pCompoTempPath->AddCurve( Release( vOffs[i]))) + return false ; + } } + // se la curva finale di Pocketing è valida, allora la resituisco if ( pCompoTempPath->IsValid()) { - // inverto l'ordine delle curve di Offset ( in modo da partire sempre ad eseguire il percorso - // più lontano dal dai lati chiusi) - pCompoTempPath->Invert() ; - // controllo eventuali parti non svuotate... - // calcolo la Feed del percorso trovato - PtrOwner pSfrToRemove( CreateSurfFlatRegion()) ; - ICRVCOMPOPOVECTOR vOffs ; vOffs.emplace_back( CloneCurveComposite( pCompoTempPath)) ; - ICRVCOMPOPOVECTOR vOffsClosedCrv ; - OffsetCurve OffsCrv ; - if ( ! OffsCrv.Make( pCrvClass, - PockParams.dRad - PockParams.dRadialOffset + 15 * EPS_SMALL, ICurve::OFF_FILLET)) - return false ; - PtrOwner pCrvFirstOffs( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; - if ( IsNull( pCrvFirstOffs) || ! pCrvFirstOffs->IsValid()) - return false ; - vOffsClosedCrv.emplace_back( Release( pCrvFirstOffs)) ; - ICURVEPOVECTOR vCompoEmpty ; - if ( IsNull( pSfrToRemove) || - ! AssignFeedConformalZigZag( pCompoTempPath, pCrvClass, PockParams, pSfrToRemove) || - ! RemoveExtraParts( pSfrToRemove, vOffs, vOffsClosedCrv, vOffsClosedCrv, vCompoEmpty, PockParams)) - return false ; - if ( ! vOffs.empty() && ! IsNull( vOffs[0]) && vOffs[0]->IsValid()) - pCompoTempPath.Set( vOffs[0]) ; + // semplifico le curve mediante uniformità delle Feeds + SimplifyCurveByFeeds( pCompoTempPath, PockParams, 10 * EPS_SMALL) ; // aggiugno il tratto iniziale e finale per entrate da fuori Vector3d vtStart ; pCompoTempPath->GetStartDir( vtStart) ; vtStart.Invert() ; @@ -6802,16 +6036,20 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int vOffs[0]->ChangeStartPoint( dNewUS) ; vOffs[0]->SetTempParam( 0., 0) ; // prima iterazione - // riordino le curve cambiando e creo i collegamenti + // riordino le curve e creo i collegamenti + /* + Se richiesto parametro di smusso, tutti gli Offset ( ad eccezione di quelli generati alla + prima iterazione vengono tagliati, quindi diventano aperti + */ ICURVEPOVECTOR vLinks( vOffs.size()) ; - if ( ! CreateSpiralPocketingPath( vOffs, vLinks, PockParams, vOffsClosedCurves, vOffsFirstCurve)) + if ( ! CreateSpiralPocketingPath( vOffs, vLinks, PockParams, vOffsFirstCurve)) return false ; - // controllo eventuali parti non svuotate... - PtrOwner pSrfToCut( CreateSurfFlatRegion()) ; - if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, vCrvOrigChunkLoops[0], PockParams, pSrfToCut)) { + // controllo eventuali parti non svuotate ( e setto la Feed degli Offset e dei Link)... + PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; + if ( GetUnclearedRegionAndSetFeed( vOffsFirstCurve, vOffs, vLinks, vCrvOrigChunkLoops[0], PockParams, pSfrUncleared)) { // Modifico i percorsi - if ( ! RemoveExtraParts( pSrfToCut, vOffs, vOffsClosedCurves, vOffsFirstCurve, vLinks, PockParams)) + if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) return false ; } @@ -7495,12 +6733,23 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio pSfrLimit->Offset( PockParams.dRad + PockParams.dRadialOffset - 50 * EPS_SMALL, ICurve::OFF_FILLET) ; } + // le curve che ricavo devono essere sempre conenute nella regione che sto svuotando + /* + Se siamo in presenza di isole chiuse molto vicine a lati chiusi non posso estendere il bordo + dell'isola chiusa a piacere, devo limitarlo alla regione di svuotatura + */ + PtrOwner pSfrBucket( CloneSurfFlatRegion( pSfrPock)) ; + if ( IsNull( pSfrBucket) || ! pSfrBucket->IsValid() || + ! pSfrBucket->Offset( - PockParams.dRad - PockParams.dRadialOffset + 50 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + // vettore delle curve chiuse Offsettate ICRVCOMPOPOVECTOR vClosedOffs ; - // scorro i Chunk e i Loop della regione + // scorro i Chunk e i Loop della regione ( se OneWay potrei avere più Chunks) for ( int nC = 0 ; nC < pSfrPock->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfrPock->GetLoopCount( nC) ; ++ nL) { + ICRVCOMPOPOVECTOR vClosedOffs_nC ; // loop come curva composita PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrPock->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) @@ -7542,13 +6791,13 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio // recupero il tratto di curva PtrOwner pCrv( pOffLongestCrv->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; if ( ! IsNull( pCrv) && pCrv->IsValid()) - vClosedOffs.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; + vClosedOffs_nC.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; } } } } else - vClosedOffs.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; + vClosedOffs_nC.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; // passo alla successiva pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; @@ -7556,47 +6805,52 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio } } } + + // se non ho ricavato curve dal Chunk nC-esimo, passo al successivo + if ( vClosedOffs_nC.empty()) + continue ; + + // limito le curve ad essere contenute nella pSfrBucket + ICRVCOMPOPOVECTOR vClosedOffs1 ; + // scorro le curve di Offset chiuse ricavate + for ( int i = 0 ; i < int( vClosedOffs_nC.size()) ; ++ i) { + CRVCVECTOR ccClass ; + if ( pSfrBucket->GetCurveClassification( *vClosedOffs_nC[i], EPS_SMALL, ccClass)) { + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + if ( ccClass[j].nClass == CRVC_IN) { + // recupero il tratto di curva + PtrOwner pCrv( vClosedOffs_nC[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; + if ( ! IsNull( pCrv) && pCrv->IsValid()) + vClosedOffs1.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; + } + } + } + } + if ( vClosedOffs1.empty()) + continue ; + swap( vClosedOffs_nC, vClosedOffs1) ; + + // concateno eventuali percorsi + if ( ! ChainCompoCurves( vClosedOffs_nC)) + return false ; + // determino ora il punto di inizio, il tratto per il LeadIn + bool bIsChunkClosed = false ; + if ( ! IsChunkAllClosed( pSfrPock, nC, bIsChunkClosed)) + return false ; + if ( ! bIsChunkClosed) { + if ( ! AdvanceExtendCurves( vClosedOffs_nC, pSfrOrig, PockParams)) + return false ; + } + + // aggiungo le curve ottenute al vettore + for ( int i = 0 ; i < int( vClosedOffs_nC.size()) ; ++ i) + vClosedOffs.emplace_back( Release( vClosedOffs_nC[i])) ; } } // se non ho percorsi ho finito if ( vClosedOffs.empty()) return true ; - // le curve che ricavo devono essere sempre conenute nella regione che sto svuotando - /* - Se siamo in presenza di isole chiuse molto vicine a lati chiusi non posso estendere il bordo - dell'isola chiusa a piacere, devo limitarlo alla regione di svuotatura - */ - PtrOwner pSfrBucket( CloneSurfFlatRegion( pSfrPock)) ; - if ( IsNull( pSfrBucket) || ! pSfrBucket->IsValid() || - ! pSfrBucket->Offset( - PockParams.dRad - PockParams.dRadialOffset + 50 * EPS_SMALL, ICurve::OFF_FILLET)) - return false ; - ICRVCOMPOPOVECTOR vClosedOffs1 ; - // scorro le curve di Offset chiuse ricavate - for ( int i = 0 ; i < int( vClosedOffs.size()) ; ++ i) { - CRVCVECTOR ccClass ; - if ( pSfrBucket->GetCurveClassification( *vClosedOffs[i], EPS_SMALL, ccClass)) { - for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { - if ( ccClass[j].nClass == CRVC_IN) { - // recupero il tratto di curva - PtrOwner pCrv( vClosedOffs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; - if ( ! IsNull( pCrv) && pCrv->IsValid()) - vClosedOffs1.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; - } - } - } - } - if ( vClosedOffs1.empty()) - return true ; - swap( vClosedOffs, vClosedOffs1) ; - - // concateno eventuali percorsi - if ( ! ChainCompoCurves( vClosedOffs)) - return false ; - // determino ora il punto di inizio, il tratto per il LeadIn - if ( ! AdvanceExtendCurves( vClosedOffs, pSfrOrig, PockParams)) - return false ; - // Calcolo ora le Feed e restituisco le curve ottenute for ( int i = 0 ; i < int( vClosedOffs.size()) ; ++ i) { // se ZigZag -> ho percorso i tratti a ZigZag, quindi posso andare a Feed massima @@ -7939,7 +7193,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double return false ; break ; case POCKET_CONFORMAL_ZIGZAG : - if ( ! AddAddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes)) + if ( ! AddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes)) return false ; break ; }