diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 3800841..5883f73 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -60,12 +60,15 @@ struct PocketParams { Point3d ptStart = P_INVALID ; // punto d'inizio Point3d ptEnd = P_INVALID ; // punto di fine SurfFlatRegion SfrLimit ; // superficie limite per estensione lati aperti - bool bCalcFeed = false ; // flag per calcolo della Feed + bool bCalcFeed = true ; // flag per calcolo della Feed double dFeed = 1000 ; // feed di riferimento per frazione double dToolFeed = 1000 ; // feed del tool } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket +static int TMP_PROP_SINGLE_CURVE = 3 ; // percorso singola curva aperta ( seguendo i chiusi) +static int TMP_PROP_CRV_OPEN_SIDE = 2 ; // segmento per entrata da fuori +static int TMP_PROP_OPT_TRAPEZOID = 4 ; // caso ottimizzato Trapezio //--------------------------------------------------------------------------- @@ -93,15 +96,47 @@ GetFeed( const PocketParams& PockParams) //---------------------------------------------------------------------------- static bool -AssignDefaultFeed( ICurveComposite* pCrv, const PocketParams& PockParams) +AssignMaxFeed( ICurveComposite* pCrv, const PocketParams& PockParams) { // controllo dei parametri - if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0) + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // assegno la Feed massima ad ogni sottocurva di pCrv for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) - pCrv->SetCurveTempProp( u, int( GetMaxFeed( PockParams)), 0) ; + pCrv->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ; + + return true ; +} + +//--------------------------------------------------------------------------- +static bool +AssignMinFeed( ICurveComposite* pCrv, const PocketParams& PockParams) +{ + // controllo dei parametri + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) + return false ; + + // assegno la Feed minima ad ogni sottocurva di pCrv + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) + pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; + + return true ; +} + +//--------------------------------------------------------------------------- +static bool +AssignCustomFeed( ICurveComposite* pCrv, const PocketParams& PockParams, double dFeed) +{ + // controllo dei parametri + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) + return false ; + // La Feed deve essere compresa tra la minima e la massima + dFeed = Clamp( dFeed, GetMinFeed( PockParams), GetMaxFeed( PockParams)) ; + + // assegno la Feed ad ogni sottocurva di pCrv + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) + pCrv->SetCurveTempParam( u, dFeed, 0) ; return true ; } @@ -111,7 +146,7 @@ static bool GetFeedForParam( double& dPar, const PocketParams& PockParams, double& dFeed) { /* - feed + Feed ^ | GetFeed() + --------------\ @@ -122,7 +157,7 @@ GetFeedForParam( double& dPar, const PocketParams& PockParams, double& dFeed) | * \ GetFeed() * GetSideStep() / Diam + * * | * * - 0--------------+------+---------------> Tool Working Arc + 0--------------+------+---------------> Length of working angle GetSideStep() Diam */ @@ -145,6 +180,7 @@ GetFeedForParam( double& dPar, const PocketParams& PockParams, double& dFeed) return true ; } + //---------------------------------------------------------------------------- static bool AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURVEPOVECTOR& vLAbove, @@ -157,11 +193,11 @@ AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURV // controllo se il Flag per assegnare la Feed è attivo if ( ! PockParams.bCalcFeed) - return AssignDefaultFeed( pCompo, PockParams) ; + return AssignMaxFeed( pCompo, PockParams) ; // inzialmente setto la feed Minima alla curva - for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) - pCompo->SetCurveTempProp( u, int( GetMinFeed( PockParams)), 0) ; + for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) + pCompo->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; // se è un link tra livelli diversi, allora esco ( con Feed Minima ) if ( bIsLink) { @@ -222,8 +258,11 @@ AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURV pSfrRectUp->GetCurveClassification( *vAddedLinks[l], EPS_SMALL, ccClass) ; for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { if (( ccClass[i].nClass == CRVC_IN && bIsDown) || - ( ccClass[i].nClass == CRVC_OUT && ! bIsDown)) - vAllInt.emplace_back( GetCurveComposite( vAddedLinks[l]->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; + ( ccClass[i].nClass == CRVC_OUT && ! bIsDown)) { + PtrOwner pCrvInt( ConvertCurveToComposite( vAddedLinks[l]->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; + if ( ! IsNull( pCrvInt) || pCrvInt->IsValid()) + vAllInt.emplace_back( Release( pCrvInt)) ; + } } } } @@ -299,14 +338,293 @@ AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURV if ( ! bIsLink) { for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { if ( IsEven( u) == bFMax) - pCompo->SetCurveTempProp( u, int( GetMaxFeed( PockParams)) , 0) ; + pCompo->SetCurveTempParam( u, GetMaxFeed( PockParams) , 0) ; else - pCompo->SetCurveTempProp( u, int( GetMinFeed( PockParams)), 0) ; + pCompo->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; } } return true ; } +//---------------------------------------------------------------------------- +static bool +CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll) +{ + // controllo dei parametri + if (( pCrv == nullptr || pCrvOri == nullptr || dToll < EPS_SMALL)) + return false ; + nStat = 1 ; // 0 -> no overlap | 1 -> overlap + + // controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati + const double nMAX = 10.0 ; + for ( int i = 0 ; i <= nMAX ; ++i) { + double dPar = i / nMAX ; + Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ; + if ( ! pCrvOri->IsPointOn( ptC, dToll)) { + nStat = 0 ; + return true ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig, + const PocketParams& PockParams) +{ + // se non rischiesto il calcolo della Feed, lascio quella standard + if ( ! PockParams.bCalcFeed) + return AssignMaxFeed( pCrv, PockParams) ; + + // controllo se qualche curva passa sopra ad un lato aperto... + if ( pCrvOF_orig != nullptr ) { + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + const ICurve* pCrv_u = pCrv->GetCurve( u) ; + if ( pCrv_u == nullptr) + return false ; + 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 ; + pCrv->SetCurveTempParam( u, dFeed, 0) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs, bool bIsLink, + const ICRVCOMPOPOVECTOR& vLinks_done, const ICurveComposite* pCrv_orig, + const PocketParams& PockParams, double dToll) +{ + // controllo la validità della curva + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) + return false ; + + // controllo se il Flag per assegnare la Feed è attivo + if ( ! PockParams.bCalcFeed) + return AssignMaxFeed( pCrv, PockParams) ; + + // imposto di Default la Feed minima per ogni sottocurva + for ( int u = 0 ; u < int( pCrv->GetCurveCount()) ; ++ u) + pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ; + + // se non ho una superificie svuotata, allora esco ( con Feed Minima) + if ( pSrfRemoved_offs == nullptr || ! pSrfRemoved_offs->IsValid() || pSrfRemoved_offs->GetChunkCount() == 0) { + // controllo eventuali sovrapposizioni con lati aperti + AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + return true ; + } + + // clono la superificie ( valida) + PtrOwner pSrf_Removed_offs_clone( CloneSurfFlatRegion( pSrfRemoved_offs)) ; + if ( IsNull( pSrf_Removed_offs_clone) || ! pSrf_Removed_offs_clone->IsValid() || + pSrf_Removed_offs_clone->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 + 1500 * EPS_SMALL, 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)) + 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) + 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 + for ( int u = 0 ; u < PCrv_sez->GetCurveCount() ; ++ u) + PCrv_sez->SetCurveTempParam( u, dCurrFeed, 0) ; + // aggiungo la nuova curva con la Feed regolata a quella finale + pCrv_new->AddCurve( Release( PCrv_sez)) ; + } + + // sotituisco con quanto calcolato + 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( CloneCurveComposite( pCrv)) ; + if ( ! pCrv_before->TrimEndAtParam( aInfo.IciA[0].dU)) + pCrv_before->Clear() ; // se troppo piccolo, elimino + // tratto successivo + PtrOwner pCrv_after( CloneCurveComposite( pCrv)) ; + 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 ; + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + double dParam ; pCrv->GetCurveTempParam( u, dParam, 0) ; + if ( abs( dParam - GetMinFeed( PockParams)) < 5 * EPS_SMALL) + 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) ; + while ( bFound) { + PtrOwner pCrv_Crv( pCrv->CopyParamRange( dParS, dParE)) ; + double dLen = EPS_SMALL ; pCrv_Crv->GetLength( dLen) ; + if ( dLen > dToll + 5 * EPS_SMALL) + 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 + 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) { + double dLen = EPS_SMALL ; + pCrv->GetCurve( u)->GetLength( dLen) ; + if ( dLen < dToll + 5 * EPS_SMALL) { + PtrOwner pCrvCompo( CloneCurveComposite( pCrv)) ; + 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) ; + } + } + else + pCrv->SetCurveTempProp( u, GetMinFeed( PockParams), 0) ; + } + } + } + + // controllo eventuali sovrapposizioni con lati aperti + AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveComposite* pCrv ) +{ + // controllo della curva corrente + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) + return false ; + + // controllo se il Flag per assegnare la Feed è attivo + if ( ! PockParams.bCalcFeed) + return AssignMaxFeed( pCrv, PockParams) ; + + switch ( PockParams.nType) { + case POCKET_SPIRALIN : + if ( nOptType == 0) { // Spirale dall'Esterno + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + if ( u == 0) // prima circonferenza + pCrv->SetCurveTempProp( 0, GetMinFeed( PockParams), 0) ; + else // semi cerchi in tangenza + pCrv->SetCurveTempProp( u, GetMaxFeed( PockParams), 0) ; + } + } + else if ( nOptType == 1) { // Trapezoidi + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) + pCrv->SetCurveTempProp( u, GetMinFeed( PockParams), 0) ; + } + break ; + /* NB. Essendo la funzione CalcSpiral richiamata sia per lo SpiralIN che per lo SpiralOUT le curve sono sempre + orientate nello stesso modo, solamente alla fine viene invertita la curva finale per la svuotatura... */ + case POCKET_SPIRALOUT : + if ( nOptType == 0) { // Spiral verso l'esterno + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + if ( u > pCrv->GetCurveCount() - 3) // prime semi circonferenze + pCrv->SetCurveTempProp( u, GetMinFeed( PockParams), 0) ; + else + pCrv->SetCurveTempProp( u, GetMaxFeed( PockParams), 0) ; + } + } + else if ( nOptType == 1) { // Trapezoidi + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) + pCrv->SetCurveTempProp( u, GetMinFeed( PockParams), 0) ; + } + break ; + default : + break ; + } + + return true ; +} + //---------------------------------------------------------------------------- static bool IsPointInsideSfr( const ISurfFlatRegion* pSfr, const Point3d& pt, bool& bIsInside) @@ -343,7 +661,6 @@ IsPointInsideSfr( const ISurfFlatRegion* pSfr, const Point3d& pt, bool& bIsInsid return true ; } - //---------------------------------------------------------------------------- static bool GetCurvesForOptimizedPocketing( const ISurfFlatRegion* pSfr, ICRVCOMPOPOVECTOR& vCrvExtOrig) @@ -686,8 +1003,8 @@ ExtendPathOnOpenEdge( ICurveComposite* pCrvPath, const PocketParams& PockParams, // recupero il punto iniziale della curva Point3d ptMidOpen ; if ( bEndOrStart) { - if ( ! pCrvPath->GetEndPoint( ptMidOpen)) - return false ; + if ( ! pCrvPath->GetEndPoint( ptMidOpen)) + return false ; } else { if ( ! pCrvPath->GetStartPoint( ptMidOpen)) @@ -697,7 +1014,8 @@ ExtendPathOnOpenEdge( ICurveComposite* pCrvPath, const PocketParams& PockParams, Point3d ptOut = ptMidOpen + vtMidOut * ( PockParams.dRad + PockParams.dOpenMinSafe) ; // aggiungo al ritorno l'uscita pCrvPath->AddLine( ptOut, bEndOrStart) ; - pCrvPath->SetCurveTempProp( ( bEndOrStart ? pCrvPath->GetCurveCount() - 1 : 0), 2, 0) ; // nProp 2 per le curve LeadIn/Out + pCrvPath->SetCurveTempProp( ( bEndOrStart ? pCrvPath->GetCurveCount() - 1 : 0), TMP_PROP_CRV_OPEN_SIDE, 0) ; // nProp 2 per le curve LeadIn/Out + pCrvPath->SetCurveTempParam( ( bEndOrStart ? pCrvPath->GetCurveCount() - 1 : 0), GetMinFeed( PockParams) , 0) ; // Feed minima return true ; } @@ -905,18 +1223,67 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, con return false ; pSfrInc->Clear() ; - // creo la Fat Curve dalla curva *pCrv - PtrOwner pSfrInc_tmp( GetSurfFlatRegionFromFatCurve( pCrv->Clone(), dRad + EPS_SMALL, false, false)) ; - if ( IsNull( pSfrInc_tmp) || ! pSfrInc_tmp->IsValid()) - return false ; - pSfrInc->CopyFrom( pSfrInc_tmp) ; // pSfrInc ha sempre normale Z_AX ! - - // se la curva è chiusa, allora tutto il bordo è aperto - if ( pCrv->IsClosed()) { + // se la curva è chiusa, allora la regione di incidenza è già definita + if ( pCrv->IsClosed()) { + PtrOwner pSfrInc_tmp( GetSurfFlatRegionFromFatCurve( pCrv->Clone(), dRad + EPS_SMALL, false, false)) ; + if ( IsNull( pSfrInc_tmp) || ! pSfrInc_tmp->IsValid()) + return false ; pSfrInc->CopyFrom( pSfrInc_tmp) ; - return pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0 ; + return ( pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0) ; } + // creo la curva di Offset esterna ( deve esistere ed essere valida) + OffsetCurve OffsCrv ; + PtrOwner pOffsExt( CreateCurveComposite()) ; + if ( IsNull( pOffsExt) || + ! OffsCrv.Make( pCrv, dRad, ICurve::OFF_FILLET) || + ! pOffsExt.Set( OffsCrv.GetLongerCurve()) || + IsNull( pOffsExt)) + return false ; + + // creo la curva di Offset interna ( se esiste e valida...) + PtrOwner pOffsInt( CreateCurveComposite()) ; + if ( IsNull( pOffsInt)) + return false ; + if ( OffsCrv.Make( pCrv, - dRad, ICurve::OFF_FILLET)) { + PtrOwner pMyCrv( OffsCrv.GetLongerCurve()) ; + if ( ! IsNull( pMyCrv) && pMyCrv->IsValid()) + pOffsInt.Set( Release( pMyCrv)) ; + } + + // recupero gli estremi della curva aperta corrente + Point3d pt1 ; pCrv->GetEndPoint( pt1) ; + Point3d pt4 ; pCrv->GetStartPoint( pt4) ; + + // creo la regione dalle curve + PtrOwner pCrvExtLoopSurfInc( CreateCurveComposite()) ; + if ( IsNull( pCrvExtLoopSurfInc) || + ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsExt)) || + ! pCrvExtLoopSurfInc->AddLine( pt1)) + return false ; + Point3d pt5 ; pCrvExtLoopSurfInc->GetStartPoint( pt5) ; + if ( ! IsNull( pOffsInt) && pOffsInt->IsValid()) { + Point3d pt2 ; pOffsInt->GetEndPoint( pt2) ; + Point3d pt3 ; pOffsInt->GetStartPoint( pt3) ; + if ( ! pCrvExtLoopSurfInc->AddLine( pt2) || + ! pOffsInt->Invert() || + ! pCrvExtLoopSurfInc->AddCurve( Release( pOffsInt)) || + ! pCrvExtLoopSurfInc->AddLine( pt4) || + ! pCrvExtLoopSurfInc->AddLine( pt5)) + return false ; + } + else { + if ( ! pCrvExtLoopSurfInc->AddLine( pt4) || + ! pCrvExtLoopSurfInc->AddLine( pt5)) + return false ; + } + // per sicurezza... + pCrvExtLoopSurfInc->Close() ; + + // creo la regione + if ( ! pSfrInc->AddExtLoop( Release( pCrvExtLoopSurfInc))) + return false ; + return ( pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0) ; } @@ -1036,28 +1403,6 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI } pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; // passo al tratto offsettato successivo } - // 9) creo la regione squadrata da rimuovere alla regione di incidenza - OffsetCurve OffsCrvRect ; - if ( ! OffsCrvRect.Make( vpCrvs[cl], dDiamJ * 0.5, ICurve::OFF_FILLET)) - return false ; - // 10) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti - PtrOwner pOffLongestCrvRect( OffsCrvRect.GetLongerCurve()) ; - while ( ! IsNull( pOffLongestCrvRect)) { - - // 11) creo la regione di incidenza di tale curva ( "Curva a rettangolo") - PtrOwner pSfrRect( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrvRect), dDiamJ * 0.5, true, false)) ; - if ( IsNull( pSfrRect) || ! pSfrRect->IsValid()) - return false ; - // inverto se necessario - if ( AreOppositeVectorApprox( pSfrRect->GetNormVersor(), pSfrInc->GetNormVersor())) - pSfrRect->Invert() ; - - // 12) aggiorno la regione di incidenza - if ( ! pSfrInc->Subtract( *pSfrRect)) - return false ; - - pOffLongestCrvRect.Set( OffsCrvRect.GetLongerCurve()) ; // passo al tratto offsettato successivo - } } } @@ -1142,10 +1487,9 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI break ; } } - } // se bordo esterno inserisco il bordo esterno - return pCrvBorder->AddCurve( Release( pCrvNewBorder)) ; + return ( pCrvBorder->AddCurve( Release( pCrvNewBorder))) ; } // altrimenti la spezzo il loop della regione di incidenza nei punti iniziali e finali della curva aperta originale @@ -1317,27 +1661,281 @@ CheckForRemovingIsland( const ICurveComposite* pCrvIslandBorder, double dOffs, b //---------------------------------------------------------------------------- static bool -ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams) +GetPocketCurvesByCloseEdges( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvCompoRes, bool& bAllRemoved) +{ + // controllo parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + bAllRemoved = false ; + + // controllo se la superficie si annulla con un controOffset del raggio utensile + PtrOwner pSfrCheck( CloneSurfFlatRegion( pSfrChunk)) ; + if ( IsNull( pSfrCheck) || ! pSfrCheck->IsValid()) + return false ; + pSfrCheck->Offset( - PockParams.dRad + 200 * EPS_SMALL, ICurve::OFF_FILLET) ; + if ( pSfrCheck->IsValid() && pSfrCheck->GetChunkCount() > 0) + return true ; // se la superficie non si annulla, allora non ricavo nessuna curva + /* + NB. Si poteva calcolare la Fat curve del raggio utensile dell'Offset di tutti i chiusi e vedere + se l'unione di queste regioni copriva interamente il Chunk attuale... così facendo rischio di + trascurare delle parti che spariscono facendo il primo Offset dei chiusi; il controllo va fatto + quindi con un contro-offset della regione complessiva + */ + + // controllo se il Chunk ha delle isole + bool bHasIslands = ( pSfrChunk->GetLoopCount( 0) > 1) ; + + // recupero il Loop esterno + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) + return false ; + // recupero i tratti con proprietà uniformi + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvExtLoop, PockParams, vpCrvs) ; + if ( vpCrvs.size() > 1) { // unisco il primo e l'ultimo se estremi compatibili + // NB. GetHomogeneousParts() cambia il punto di inizio nel lato chiuso più lungo ( se presente) + Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ; + Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ; + if ( AreSamePointApprox( ptS, ptE)) { + vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ; + vpCrvs.erase( vpCrvs.end() - 1) ; + } + } + // controllo se il loop Esterno è uniforme ( quindi tutto chiuso o tutto aperto) + bool bExtAllClose = false ; + bool bExtAllOpen = false ; + if ( int( vpCrvs.size()) == 1) { + if ( vpCrvs[0]->GetTempProp( 0) == 0) + bExtAllClose = true ; + else + bExtAllOpen = true ; + } + // NB. Se regione estena tutta chiusa o aperta e senza isole... allora non faccio nulla ( es caso trapezi) + // Se tutta chiusa -> Chunk non svuotabile, il contro-offset del raggio utensile annulla la regione + // Se tutta aperta -> La regione è definita mediante Offset esterno del contorno aperto + if ( ( bExtAllClose || bExtAllOpen) && ! bHasIslands) + return true ; + + // scorro i chiusi e sottraggo la regione da loro creata mediante l'utensile + ICRVCOMPOPOVECTOR vCrvOffs ; // salvo il vettore di curve offsettate del raggio utensile + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + if ( vpCrvs[i]->GetTempProp( 0) == 0) { // se tratto chiuso... + OffsetCurve OffsCrv ; // con offset verso l'interno + if ( OffsCrv.Make( vpCrvs[i], - PockParams.dRad, ICurve::OFF_FILLET)) { + PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; + while ( ! IsNull( pOffLongestCrv)) { + // salvo la curva corrente + vCrvOffs.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; + // passo alla successiva + pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; + } + } + } + } + + /* + Casi gestiti : + 1) La curva esterna è tutta chiusa o tutta aperta e al suo interno ci sono delle isole uniformi + ( quindi ogni isola può essere solo aperta o chiusa) : + - se la curva esterna è tutta aperta, allora la regione da creare è formata da tutte le isole chiuse + e il percorso da seguire sarà un offset verso l'esterno di questa regione + - se la curva esterna è tutta chiusa, allora la regione è definita da questa loop esterno e + come loop interni vengono inserite tutte le isole chiuse; le curva da seguire sono ricavate + da un'offset verso l'interno della regione + 2) La curva esterna non è uniforme, quindi presenta sia tratti chiusi che tratti aperti : + - se non ci sono isole, allora ho già ricavato le curve + - se ci sono isole non faccio nulla ( meglio estendere i lati aperti del loop esterno e + delle isole mediante la funzione AdjustContourWithOpenEdges() + */ + + // creo la regione finale il cui Offset mi genera le curve di pocketing da seguire ( Offset positivo o negativo) + // NB. Le isole potrebbero unirsi tra di loro mediante gli Offset + PtrOwner pSfrToOffset( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrToOffset)) + return false ; + if ( bExtAllClose) // se il loop esterno è chiuso, lo aggiungo + pSfrToOffset->AddExtLoop( pCrvExtLoop->Clone()) ; //AAAAAAAAAAAAAAA + + // se ho delle isole e il loop esterno è uniforme ( tutto aperto o chiuso) + if ( bHasIslands && ( bExtAllClose || bExtAllOpen)) { + for ( int i = 1 ; i < pSfrChunk->GetLoopCount( 0) ; ++ i) { + // controllo uniformità dell'isola + int nCurrTmpProp = -1 ; + int nPrecTmpProp = -1 ; + bool bIsMixed = false ; + PtrOwner pCrvIsl( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, i))) ; + if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid()) + return false ; + for ( int u = 0 ; u < pCrvIsl->GetCurveCount() && ! bIsMixed ; ++ u) { + pCrvIsl->GetCurveTempProp( u, nCurrTmpProp, 0) ; + bIsMixed = ( u != 0 && nCurrTmpProp != nPrecTmpProp) ; + nPrecTmpProp = nCurrTmpProp ; + } + // se proprità non uniformi -> tutta chiusa ( isole non uniformi non sono definite) + if ( bIsMixed) { + for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) + pCrvIsl->SetTempProp( u, 0) ; + nCurrTmpProp = 0 ; // aggiorno il Flag + } + // se isola chiusa + if ( nCurrTmpProp == 0) { + OffsetCurve OffsCrv ; // con Offset interno ( senso orario) + if ( OffsCrv.Make( pCrvIsl, - PockParams.dRad, ICurve::OFF_FILLET)) { + PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; + while ( ! IsNull( pOffLongestCrv)) { + // salvo la curva corrente + vCrvOffs.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; + // passo alla successiva + pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; + } + } + if ( bExtAllClose) { // se ho inserito il loop esterno + // inserisco la curva come isola + if ( ! pSfrToOffset->AddIntLoop( Release( pCrvIsl))) + return false ; + } + else { + // le isole saranno da loop esterni + pCrvIsl->Invert() ; // seguo il percorso di lavoro + if ( ! pSfrToOffset->AddExtLoop( Release( pCrvIsl))) + return false ; + } + } + } + } + + // vettore di curve temporanee ( da confrontare con la regione limite) + ICRVCOMPOPOVECTOR vCrvCompoRes_tmp ; + + if ( ! bHasIslands) { // se non avevo isole... + // restituisco le curve di svuotatura calcolate dai chiusi del loop esterno + for ( int i = 0 ; i < int( vCrvOffs.size()) ; ++ i) + vCrvCompoRes_tmp.emplace_back( Release( vCrvOffs[i])) ; + bAllRemoved = true ; // aggiornamento Flag + } + else { // se avevo isole + // i percorsi sono definiti dall'Offset della regione rimossa + // NB. Se ho inserito solo isole, allora l'Offset va verso l'esterno + // Se ho inserito sia il loop esterno che le isole, allora l'Offset è interno + double dOffs = PockParams.dRad ; + if ( bExtAllClose) + dOffs *= -1 ; + pSfrToOffset->Offset( dOffs, ICurve::OFF_FILLET) ; + if ( pSfrToOffset->IsValid() && pSfrToOffset->GetChunkCount() > 0) { + for ( int c = 0 ; c < pSfrToOffset->GetChunkCount() ; ++ c) + for ( int l = 0 ; l < pSfrToOffset->GetLoopCount( c) ; ++ l) + vCrvCompoRes_tmp.emplace_back( ConvertCurveToComposite( pSfrToOffset->GetLoop( c, l))) ; + bAllRemoved = true ; + } + } + // se non ho ottenuto curve, allora ho finito + if ( vCrvCompoRes_tmp.empty()) + return true ; + + // per tutte le curve inserite, devo tenere solamente quelle esterne alla superficie limite + if ( PockParams.SfrLimit.IsValid()) { // se esiste, allora classifico + ICRVCOMPOPOVECTOR vCrvCompoRes_tmp_Splitted ; + for ( int i = 0 ; i < int( vCrvCompoRes_tmp.size()) ; ++ i) { + CRVCVECTOR ccClass ; + if ( PockParams.SfrLimit.GetCurveClassification( *vCrvCompoRes_tmp[i], EPS_SMALL, ccClass)) { + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + if ( ccClass[j].nClass == CRVC_OUT) { + PtrOwner pCrvRes( ConvertCurveToComposite( vCrvCompoRes_tmp[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ; + if ( ! IsNull( pCrvRes) && pCrvRes->IsValid()) + vCrvCompoRes_tmp_Splitted.emplace_back( Release( pCrvRes)) ; + } + } + } + } + // se non ho curve, allora esco + if ( vCrvCompoRes_tmp_Splitted.empty()) + return true ; + // altrimenti aggiorno il vettore di curve con quelle solo esterne alla regione limite + swap( vCrvCompoRes_tmp, vCrvCompoRes_tmp_Splitted) ; + } + + // imposto le Feed per tali curve e aggiungo eventuale entrata da fuori + for ( int i = 0 ; i < int( vCrvCompoRes_tmp.size()) ; ++ i) { + // per ora è default ( sono passate singole)... + /* + Idea : Feed proporzionale al minimo Offset per annullare la regione ? + -> Massimo parametro sui bisettori di VORONOI (?) + */ + AssignMinFeed( vCrvCompoRes_tmp[i], PockParams) ; + // ricavo punto di inizio e vettore tangente + Point3d ptStart ; vCrvCompoRes_tmp[i]->GetStartPoint( ptStart) ; + Vector3d vtStart ; vCrvCompoRes_tmp[i]->GetStartDir( vtStart) ; + // recupero il punto di caduta dell'utensile + Point3d ptFall = ptStart - vtStart * ( PockParams.dRad + PockParams.dOpenMinSafe) ; + // controllo che il tool non sia interno alla regione limite + PtrOwner pCrvToolShape( CreateCurveArc()) ; + if ( IsNull( pCrvToolShape) || ! pCrvToolShape->Set( ptFall, Z_AX, PockParams.dRad - 100 * EPS_SMALL)) + return false ; + CRVCVECTOR ccClass ; + if ( PockParams.SfrLimit.GetCurveClassification( *pCrvToolShape, EPS_SMALL, ccClass) && + int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) { + vCrvCompoRes_tmp[i]->AddLine( ptFall, false) ; + vCrvCompoRes_tmp[i]->SetCurveTempProp( 0, TMP_PROP_CRV_OPEN_SIDE, 0) ; // nProp 2 per le curve LeadIn/Out + vCrvCompoRes_tmp[i]->SetCurveTempParam( 0, GetMinFeed( PockParams) , 0) ; // Feed minima + } + else { // se trovo intersezione, provo a ruotare di 90° + vtStart.Rotate( Z_AX, ANG_RIGHT) ; // verso sinistra + ptFall = ptStart + vtStart * ( PockParams.dRad + PockParams.dOpenMinSafe) ; + if ( ! pCrvToolShape->Set( ptFall, Z_AX, PockParams.dRad - 100 * EPS_SMALL)) + return false ; + ccClass.clear() ; + if ( PockParams.SfrLimit.GetCurveClassification( *pCrvToolShape, EPS_SMALL, ccClass) && + int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) { + vCrvCompoRes_tmp[i]->AddLine( ptFall, false) ; + vCrvCompoRes_tmp[i]->SetCurveTempProp( 0, TMP_PROP_CRV_OPEN_SIDE, 0) ; // nProp 2 per le curve LeadIn/Out + vCrvCompoRes_tmp[i]->SetCurveTempParam( 0, GetMinFeed( PockParams) , 0) ; // Feed massima + } + } + // imposto il flag di curva singola + vCrvCompoRes_tmp[i]->SetTempProp( TMP_PROP_SINGLE_CURVE, 0) ; //nProp per curva singola + // inserisco la curva nel vettore finale + vCrvCompoRes.emplace_back( Release( vCrvCompoRes_tmp[i])) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, + bool& bSkipPocket) { // controllo parametri : if ( pSfr == nullptr || ! pSfr->IsValid()) return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati + bSkipPocket = false ; // NB. Tutti i Loop che presentano dei lati aperti possono essere estesi ; sia per loop esterni che per isole... // I lati aperti vanno estesi seguendo lo geometria dei lati chiusi adiacenti e tenendo conto delle isole chiuse // vicine ad essi - // NB. Se ho una lavorazione precedente, allora estendo i lati aperti delle quantità relative alla lavorazione - // precedente ( l'attuale infatti svuoterà quello che rimane da svuotare proprio da questa lavorazione) - // Vedi GetNewSfrByAnotherPocketing() - // creo la superficie da restituire... ( questa superficie sarà estesa presso i lati aperti) PtrOwner pSrfFinal( CreateSurfFlatRegion()) ; if ( IsNull( pSrfFinal)) return false ; + int nChunkOneCurve = 0 ; // numero di chunk rimovibili mediante una sola curva di Offset + int nChunk = pSfr->GetChunkCount() ; // numero complessivo di Chunk da svuotare + // per ogni Chunck della superificie ottenuta... - for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) { + for ( int c = 0 ; c < nChunk ; ++ c) { + + // 0) controllo se seguendo i chiusi posso svuotare l'interno chunk + PtrOwner pSfrChunk( pSfr->CloneChunk( c)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + bool bIsAllRemoved = false ; + GetPocketCurvesByCloseEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; + if ( bIsAllRemoved) { // se ho rimosso tutto, allora passo la chunk successivo + ++ nChunkOneCurve ; // aumento il contatore + continue ; + } // vettore delle isole che userò ( le isole aperte piccole sono trascurate) ICRVCOMPOPOVECTOR vCrvToTIsland ; @@ -1446,6 +2044,11 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams) } } + // se ho rimosso tutti i Chunk con una singola curva... + bSkipPocket = ( nChunk == nChunkOneCurve) ; + if ( bSkipPocket) + return true ; + // restituisco la superficie aggiornata ricavata if ( ! pSrfFinal->IsValid()) return false ; @@ -1666,7 +2269,7 @@ SetSpecialPtStartForOpenEdges( const ICurveComposite* pCrvOrig, const Frame3d& f //---------------------------------------------------------------------------- static bool -AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParams& PockParams, +AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvLoops, INTVECTOR& vIndex, bool& bSomeOpen) { // controllo dei parametri @@ -1907,7 +2510,7 @@ SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& P // cambio il suo punto d'inizio dell'Offset attuale if ( SetPtStartForPath( vCrvOffsAct[i], PockParams, pSrfToWork, ptEndPrec, frPocket, ptStart, vtMidOut, bMidOut, nOffs, - ( int( vCrvOrigChunkLoops.size()) < i ? Get( vCrvOrigChunkLoops[i]) : nullptr))) + ( int( vCrvOrigChunkLoops.size()) < i) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) vCrvOffsAct[i]->GetStartPoint( ptStart) ; else return false ; @@ -2177,6 +2780,9 @@ CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, dou if ( pMCrv->GetCurveCount() == 0) return false ; + // assegno la Feed + AssignFeedSpiralOpt( 0, PockParams, pMCrv) ; + // calcolo l'eventuale percorso di ritorno Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; @@ -3999,7 +4605,7 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU { // controllo dei parametri - if ( vFirstOffs.size() == 0 || ( int)vCrvs.size() < ( int)vFirstOffs.size()) + if ( vFirstOffs.empty() || int( vCrvs.size()) < int( vFirstOffs.size())) return false ; pSrfToCut->Clear() ; @@ -4007,13 +4613,14 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU PtrOwner pSrfExtern( CreateSurfFlatRegion()) ; if ( IsNull( pSrfExtern)) return false ; - for ( int i = 0 ; i < int( vFirstOffs.size()) ; ++ i) { if ( i == 0) pSrfExtern->AddExtLoop( vFirstOffs[i]->Clone()) ; else { PtrOwner pCrvIntLoop( vFirstOffs[i]->Clone()) ; - if( IsNull( pCrvIntLoop) || ! pCrvIntLoop->Invert() || ! pSrfExtern->AddIntLoop( pCrvIntLoop->Clone())) + if ( IsNull( pCrvIntLoop) || + ! pCrvIntLoop->Invert() || + ! pSrfExtern->AddIntLoop( Release( pCrvIntLoop))) return false ; } } @@ -4029,18 +4636,20 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU // 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) { + 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 ================================ - if ( i <= ( int)vLinks.size() && ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { - + // ( 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()) ; @@ -4062,6 +4671,9 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU } // ================== OFFSET ============================= + // Feed + if ( ! AssignFeedSpiral( vCrvs[i], pSrfTool_Offs, false, vLinks_done, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) + return false ; // aggiorno la superificie svuotata PtrOwner pCrvOffs_i( CloneCurveComposite( vCrvs[i])) ; @@ -4069,10 +4681,10 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU 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( Release( pSrfToolRegOffi)) ; - else - pSrfTool_Offs->Add( *pSrfToolRegOffi) ; + if ( ! pSrfTool_Offs->IsValid() || pSrfTool_Offs->GetChunkCount() == 0) + pSrfTool_Offs.Set( Release( pSrfToolRegOffi)) ; + else + pSrfTool_Offs->Add( *pSrfToolRegOffi) ; } } @@ -5283,7 +5895,9 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // aggiorno il collegamento vLinks[i+1].Set( Release( pCrvLink)) ; + } + } return true ; @@ -5455,6 +6069,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int else return true ; } + } // porto la superficie nel frame corrente @@ -5640,29 +6255,6 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int return true ; } -//---------------------------------------------------------------------------- -static bool -CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll) -{ - // controllo dei parametri - if (( pCrv == nullptr || pCrvOri == nullptr || dToll < EPS_SMALL)) - return false ; - nStat = 1 ; // 0 -> no overlap | 1 -> overlap - - // controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati - const double nMAX = 10.0 ; - for ( int i = 0 ; i <= nMAX ; ++i) { - double dPar = i / nMAX ; - Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ; - if ( ! pCrvOri->IsPointOn( ptC, dToll)) { - nStat = 0 ; - return true ; - } - } - - return true ; -} - //---------------------------------------------------------- static bool CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, const PocketParams& PockParams, @@ -5897,8 +6489,8 @@ CalcZigZag( const ISurfFlatRegion* pSrfZigZag, const PocketParams& PockParams, I pSrfZigZag->GetCurveClassification( *pLine, EPS_SMALL, ccClass) ; for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { if ( ccClass[j].nClass == CRVC_IN) { // memorizzo il segmento - Section currSec; - currSec.bActive = true; + Section currSec ; + currSec.bActive = true ; PtrOwner pSeg( GetCurveLine( pLine->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ; if ( IsNull( pSeg)) continue ; @@ -6186,9 +6778,11 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo - // se il chunk presenta dei lati aperti, estendo la curva che ho trovato per un LeadIn - if ( bOptimizedTrap) // se caso a trapezio + if ( bOptimizedTrap) { // se caso a trapezio AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, PockParams) ; + AssignFeedSpiralOpt( 1, PockParams, pMCrv) ; + pMCrv->SetTempProp( TMP_PROP_OPT_TRAPEZOID, 0) ; + } else if ( bSomeOpen) { // se presenza di lati aperti if ( ! ExtendPathOnOpenEdge( pMCrv, PockParams, pSrfChunk->GetNormVersor(), vtMidOut, false)) return false ; @@ -6197,7 +6791,9 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; ++ nReg ; // incremento il numero di regione progressiva + } + } return true ; @@ -6248,6 +6844,12 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo + if ( bOptimizedTrap) { // se caso a trapezio + AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, PockParams) ; + AssignFeedSpiralOpt( 1, PockParams, pMCrv) ; + pMCrv->SetTempProp( TMP_PROP_OPT_TRAPEZOID, 0) ; + } + // inverto i percorsi, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato) pMCrv->Invert() ; pRCrv->Invert() ; @@ -6435,7 +7037,7 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con return false ; // riporto le superfici ideali nel sistema di riferimento globale ( Ogni chunk verrà poi messo nel suo frame) - for ( int i = 0 ; i < ( int)vSrfFlat.size() ; ++ i) + for ( int i = 0 ; i < int( vSrfFlat.size()) ; ++ i) vSrfFlat[i]->ToGlob( frLoc) ; // ------------------------------------------------------------------ @@ -6464,12 +7066,12 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con // passi in Y int nYStep = static_cast( ceil(( dDimY + 2 * dExtra) / PockParams.dSideStep)) ; double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; - --nYStep ; + -- nYStep ; // vettore dei segmenti al di sotto della linea corrente ICURVEPOVECTOR vLineUnder ; - ICURVEPOVECTOR vLineAbove ; - ICRVCOMPOPOVECTOR vCrvLink ; + ICURVEPOVECTOR vCrvNull ; + ICRVCOMPOPOVECTOR vCrvCompoNull ; // calcolo le linee di svuotatura const double EXP_LEN = 1.0 ; @@ -6481,13 +7083,18 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) return false ; + // linea come composita per Feed ( la dovrò spezzare) + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // vettore di tutti i segmenti lineari che si formano nello step nYStep ICURVEPOVECTOR vAddedLines ; // riempio il vettore di segmenti CRVCVECTOR ccClassSeg ; pSrfIdeal->GetCurveClassification( *pLine, EPS_SMALL, ccClassSeg) ; - for ( int w = 0 ; w < int( ccClassSeg.size()) ; ++w) { + for ( int w = 0 ; w < int( ccClassSeg.size()) ; ++ w) { if ( ccClassSeg[w].nClass == CRVC_IN) { PtrOwner pCrvSeg( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ; @@ -6500,14 +7107,24 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con ! pCrvSeg->TrimEndAtParam( duF)) pCrvSeg.Set( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ; + // aggiungo il segmento al vettore dei tratti correnti + vAddedLines.emplace_back( pCrvSeg->Clone()) ; + + // trasformo il tratto lineare in curve composita per il calcolo della Feed PtrOwner pCrvSegCompo( CreateCurveComposite()) ; if ( IsNull( pCrvSegCompo)) return false ; pCrvSegCompo->AddCurve( Release( pCrvSeg)) ; + // calcolo la Feed + AssignFeedZigZagOneWay( pCrvSegCompo, false, vCrvNull, vLineUnder, vCrvCompoNull, PockParams) ; pCrvSegCompo->ToGlob( frPocket) ; vCrvCompoRes.emplace_back( Release( pCrvSegCompo)) ; } } + // i tratti lineari correnti diventano i precedenti + vLineUnder.clear() ; + for ( int u = 0 ; u < int( vAddedLines.size()) ; ++ u) + vLineUnder.emplace_back( Release( vAddedLines[u])) ; } } @@ -6554,8 +7171,14 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double if ( myParams.SfrLimit.IsValid()) myParams.SfrLimit.ToLoc( frLoc) ; // modifico la superficie da svuotare estendendo i lati aperti - if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams)) + bool bSkipPocket = false ; // se la superficie si svuota mediante curve singole di primo Offset dei chiusi + if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams, vCrvCompoRes, bSkipPocket)) return false ; + // se ottengo delle curve si svuotatura di primo Offset, le riporto in globale + for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) + vCrvCompoRes[i]->ToGlob( frLoc) ; + if ( bSkipPocket) // se tali curva rimuovono tutta la regione, allora non faccio nulla + return true ; // riporto tutto nel frame originale pSfrAdj->ToGlob( frLoc) ; if ( myParams.SfrLimit.IsValid())