diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index d206308..2c2fd39 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -55,7 +55,6 @@ struct PocketParams { double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag bool bOptOffsets = true ; // flag per evitare Offset non necessari - bool bOptOffsetsAdv = false ; // flag per evitare Offset coperti da curve di MedialAxis in SpiralIn/Out bool bAboveHead = true ; // flag per testa da sopra ( Z+) bool bSmooth = false ; // curve smussate bool bInvert = false ; // inversione dei percorsi @@ -76,7 +75,7 @@ struct PocketParams { double dOpenEdgeRad = 0. ; // raggio effettivo di estensione degli aperti } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket -static double BIARC_MAX_LEN = 200. ; // massima lunghezza oltre la quale il biarco viene smussato +static double TOL_REMOVE_OFFSET = 2. ; // tolleranza per controllo materiale lasciato da un Offset typedef vector VICRVCOMPOPOVECTOR ; //--------------------------------------------------------------------------- @@ -4657,14 +4656,10 @@ CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPO for ( int j = 0 ; j < int( ccClass.size()) ; ++j ) { // se ho intersezione spezzo il segmento if ( ccClass[j].nClass == CRVC_OUT) { - Point3d ptS ; - pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; - double dOffS ; - vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ; - Point3d ptE ; - pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; - double dOffE ; - vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ; + Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; + double dOffS ; vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ; + Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; + double dOffE ; vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ; // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( vOffIslands[i]->CopyParamRange( dOffS, dOffE)) ; PtrOwner pCrvB( vOffIslands[i]->CopyParamRange( dOffE, dOffS)) ; @@ -4692,235 +4687,195 @@ CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPO return true ; } -//----------------------------------------------------------------------------- -static bool -ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) -{ - - // controllo dei parametri - if ( pBiArcLink == nullptr) - return false ; - if ( dToll > 1. - 10. * EPS_SMALL || dToll < 10. * EPS_SMALL) - return false ; - pNewBiArc->Clear() ; - - // dominio - double dUS, dUE ; - pBiArcLink->GetDomain( dUS, dUE) ; - - // prendo i due archi della curva BiArco - PtrOwner pArc1( pBiArcLink->CopyParamRange( dUS, ( dUS + dUE) / 2.)) ; - PtrOwner pArc2( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2., dUE)) ; - if ( IsNull( pArc1) || ! pArc1->IsValid() || IsNull( pArc2) || ! pArc2->IsValid()) - return false ; - - // primo pezzo - pArc1->GetDomain( dUS, dUE) ; - PtrOwner pArc1A( pArc1->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll)) ; // Arc1 - PtrOwner pArc1B( pArc1->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE)) ; // Arc2 - Point3d pt1A, pt1B ; - pArc1A->GetEndPoint( pt1A) ; - pArc1B->GetStartPoint( pt1B) ; - PtrOwner pLine1( CreateBasicCurveLine()) ; - pLine1->Set( pt1A, pt1B) ; - - // secondo pezzo - pArc2->GetDomain( dUS, dUE) ; - PtrOwner pArc2A( pArc2->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll)) ; // Arc1 - PtrOwner pArc2B( pArc2->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE)) ; // Arc2 - Point3d pt2A, pt2B ; - pArc2A->GetEndPoint( pt2A) ; - pArc2B->GetStartPoint( pt2B) ; - PtrOwner pLine2( CreateBasicCurveLine()) ; - pLine2->Set( pt2A, pt2B) ; - - // ricostruisco il nuovo link - if ( ! pNewBiArc->AddCurve( Release( pArc1A)) || - ! pNewBiArc->AddCurve( Release( pLine1)) || - ! pNewBiArc->AddCurve( Release( pArc1B)) || - ! pNewBiArc->AddCurve( Release( pArc2A)) || - ! pNewBiArc->AddCurve( Release( pLine2)) || - ! pNewBiArc->AddCurve( Release( pArc2B))) - return false ; - - return true ; -} - //------------------------------------------------------------------------------ static bool -CalcSpecialSmoothBiArc( const ICurveComposite* pCrvBiArc, const ICRVCOMPOPOVECTOR& vOffIslands, - const PocketParams& PockParams, ICurveComposite* pCrvLink) +CalcSpecialBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, + const Vector3d& vtEnd, const PocketParams& PockParams, + ICurveComposite* pCrvLink) { - // controllo della curva - if ( pCrvBiArc == nullptr || ! pCrvBiArc->IsValid() || - pCrvLink == nullptr) + // controllo dei parametri + if ( pCrvLink == nullptr) return false ; pCrvLink->Clear() ; - // controllo che la lunghezza sia sufficiente - double dLen ; pCrvBiArc->GetLength( dLen) ; - if ( dLen < 2 * PockParams.dRad + 50 * EPS_SMALL) + + // parametro di estensione in tangenza + double dLenExtension = PockParams.dRad / 2. ; + + // determino i punti della curva + PNTVECTOR vPnts = { ptStart, ptStart + ( dLenExtension * vtStart), + ptEnd - ( dLenExtension * vtEnd), ptEnd} ; + int nInd = 1 ; + static const double COS_TOL = cos( 130 * DEGTORAD) ; + // se primo angolo minore della tolleranza, aggiungo un punto + Vector3d vtPrev = vPnts[nInd] - vPnts[nInd-1] ; vtPrev.Normalize() ; + Vector3d vtNext = vPnts[nInd+1] - vPnts[nInd] ; vtNext.Normalize() ; + double dCos = vtPrev * vtNext ; + if ( dCos < COS_TOL) { + Point3d ptA = vPnts[nInd] + dLenExtension * GetRotate( vtStart, Z_AX, ANG_RIGHT) ; + Point3d ptB = vPnts[nInd] - dLenExtension * GetRotate( vtStart, Z_AX, ANG_RIGHT) ; + if ( SqDist( ptA, vPnts[nInd+1]) < SqDist( ptB, vPnts[nInd+1])) + vPnts.insert( vPnts.begin() + nInd + 1, ptA) ; + else + vPnts.insert( vPnts.begin() + nInd + 1, ptB) ; + ++ nInd ; + } + ++ nInd ; + // se secondo angolo maggiore della tolleranza, aggiungo un punto + vtPrev = vPnts[nInd] - vPnts[nInd-1] ; vtPrev.Normalize() ; + vtNext = vPnts[nInd+1] - vPnts[nInd] ; vtNext.Normalize() ; + dCos = vtPrev * vtNext ; + if ( dCos < COS_TOL) { + Point3d ptA = vPnts[nInd] + dLenExtension * GetRotate( - vtEnd, Z_AX, ANG_RIGHT) ; + Point3d ptB = vPnts[nInd] - dLenExtension * GetRotate( - vtEnd, Z_AX, ANG_RIGHT) ; + if ( SqDist( ptA, vPnts[nInd-1]) < SqDist( ptB, vPnts[nInd-1])) + vPnts.insert( vPnts.begin() + nInd + 1, ptA) ; + else + vPnts.insert( vPnts.begin() + nInd + 1, ptB) ; + } + + // definisco raccordo a ZigZag ( Lineare) + PtrOwner pZigZagLink( CreateCurveComposite()) ; + if ( IsNull( pZigZagLink)) return false ; - // costruisco il tratto lineare - double dULineS, dULineE ; - Point3d ptLineS, ptLineE ; - if ( ! pCrvBiArc->GetParamAtLength( PockParams.dRad, dULineS) || - ! pCrvBiArc->GetPointD1D2( dULineS, ICurve::FROM_MINUS, ptLineS) || - ! pCrvBiArc->GetParamAtLength( dLen - PockParams.dRad, dULineE) || - ! pCrvBiArc->GetPointD1D2( dULineE, ICurve::FROM_MINUS, ptLineE)) - return false ; - // costruisco il collegamento lineare - PtrOwner pLine( CreateCurveComposite()) ; - if ( IsNull( pLine) || - ! CalcBoundedLink( ptLineS, ptLineE, vOffIslands, pLine)) - return false ; - // creo i due raccordi - PtrOwner pCrvStartJoint( pCrvBiArc->CopyParamRange( 0., dULineS)) ; - PtrOwner pCrvEndJoint( pCrvBiArc->CopyParamRange( dULineE, pCrvBiArc->GetCurveCount())) ; - if ( IsNull( pCrvStartJoint) || IsNull( pCrvEndJoint) || - ! pCrvStartJoint->IsValid() || ! pCrvEndJoint->IsValid()) - return false ; - // definisco il BiArco speciale - if ( ! pCrvLink->AddCurve( Release( pCrvStartJoint)) || - ! pCrvLink->AddCurve( Release( pLine)) || - ! pCrvLink->AddCurve( Release( pCrvEndJoint))) - return false ; - // smusso - ModifyCurveToSmoothed( pCrvLink, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; - return true ; + bool bFirst = true ; + for ( const Point3d& ptNew : vPnts) { + if ( bFirst) { + bFirst = false ; + pZigZagLink->AddPoint( ptNew) ; + } + else + pZigZagLink->AddLine( ptNew) ; + } + + // Smusso il raccordo a ZigZag + ModifyCurveToSmoothed( pZigZagLink, PockParams, .4, .4, true) ; + pCrvLink->CopyFrom( pZigZagLink) ; + return ( pCrvLink != nullptr && pCrvLink->IsValid() && pCrvLink->GetCurveCount() > 0) ; } //------------------------------------------------------------------------------ static bool CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, - const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vOffIslands, + const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vCrvBorders, const PocketParams& PockParams, ICurveComposite* pCrvLink, bool& bSpecial) { + // controllo parametri + if ( pCrvLink == nullptr) + return false ; + pCrvLink->Clear() ; + // se senza smusso, ritorno tratto lineare bSpecial = false ; if ( ! PockParams.bSmooth) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; - // creo il BiArc che unisce i due punti - double dAngStart, dAngEnd ; - vtStart.GetAngleXY( X_AX, dAngStart) ; - vtEnd.GetAngleXY( X_AX, dAngEnd) ; - PtrOwner pBiArcLink ; - if ( dParMeet != 0) - pBiArcLink.Set( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet)) ; - else { - PtrOwner pCrvCir( CreateBasicCurveArc()) ; - if ( IsNull( pCrvCir)) - return false ; - pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, PockParams.bInvert ? 360 : - 360, 0, Z_AX) ; - pBiArcLink.Set( pCrvCir->Clone()) ; - pCrvLink->AddCurve( pBiArcLink->Clone()) ; - return true ; - } - if ( IsNull( pBiArcLink)) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; - - // se BiArco troppo grande allora lo modifico (ne tengo una copia per eventuale gestione speciale) - PtrOwner pCrvBiArc_clone( ConvertCurveToComposite( pBiArcLink->Clone())) ; - double dLenBiArc ; pBiArcLink->GetLength( dLenBiArc) ; - if ( dLenBiArc > BIARC_MAX_LEN) { - PtrOwner pCrvNewBiArcS( CreateBasicCurveComposite()) ; - ModifyBiArc( pBiArcLink, 0.2, pCrvNewBiArcS) ; - pBiArcLink.Set( pCrvNewBiArcS) ; - } - - // creo la nuova curva formata inizialmente dai tratti di archi - PtrOwner pCompo( GetCurveComposite( pBiArcLink->Clone())) ; - if ( IsNull( pCompo)) - return false ; - PtrOwner pCompoHelp( GetCurveComposite( pBiArcLink->Clone())) ; - if ( IsNull( pCompoHelp)) + // inizializzo la curva di Link da restituire + PtrOwner pMyCrvLink( CreateCurveComposite()) ; + if ( IsNull( pMyCrvLink)) return false ; - // scorro tutte le curve per controllare le intersezioni ... - for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) { + // controllo se la distanza lineare tra i due punti è maggiore della tolleranza... + static double dSqTol = 4 * PockParams.dRad * PockParams.dRad + PockParams.dSideStep * PockParams.dSideStep ; + if ( SqDist( ptStart, ptEnd) > dSqTol) + bSpecial = ( CalcSpecialBoundedSmoothedLink( ptStart, vtStart, ptEnd, vtEnd, PockParams, pMyCrvLink)) ; + if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) { + // ...in caso negativo creo il Biarco ( se parametro a zero, allora circonferenza) + double dAngStart ; vtStart.GetAngleXY( X_AX, dAngStart) ; + double dAngEnd ; vtEnd.GetAngleXY( X_AX, dAngEnd) ; + if ( dParMeet > EPS_ZERO) + pMyCrvLink.Set( ConvertCurveToComposite( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet))) ; + else { + PtrOwner pCrvCir( CreateBasicCurveArc()) ; + if ( IsNull( pCrvCir)) + return false ; + if ( pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, PockParams.bInvert ? 360 : -360, 0, Z_AX)) + pMyCrvLink.Set( ConvertCurveToComposite( Release( pCrvCir))) ; + } + } + if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + // se il BiArco creato è troppo piccolo, lo approssimo ad un tratto lineare + BBox3d bBox3 ; + if ( pMyCrvLink->GetLocalBBox( bBox3)) { + double dRadBB ; + if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + } + + // il link ottenuto non deve uscire dalle curve di bordo ( Loop esterno ed Isole) + // curva di test + PtrOwner pCompoTest( CloneCurveComposite( pMyCrvLink)) ; + if ( IsNull( pCompoTest) || ! pCompoTest->IsValid()) + return false ; + // curva ausiliaria + PtrOwner pCompoHelp( CloneCurveComposite( pMyCrvLink)) ; + if ( IsNull( pCompoHelp) || ! pCompoHelp->IsValid()) + return false ; + + // scorro tutte le curve le curve di bordo + for ( const ICurveComposite* pCrvBorder : vCrvBorders) { + // calcolo eventuali intersezioni CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ; + IntersCurveCurve intCC( *pCompoTest, *pCrvBorder) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; - if ( ! pCompoHelp->Clear()) - return false ; - // per ogni intersezione j con l'offset dell'isola i - for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + // pulisco la curva ausiliaria + pCompoHelp->Clear() ; + + // analizzo le intersezioni + for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { // se ho intersezione spezzo il segmento - if ( ccClass[j].nClass == CRVC_OUT && int( ccClass.size()) > 1) { - Point3d ptS ; - pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; - double dOffS ; - vOffIslands[i]->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ; - Point3d ptE ; - pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; - double dOffE ; - vOffIslands[i]->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ; + if ( ccClass[i].nClass == CRVC_OUT && int( ccClass.size()) > 1) { + // recupero eventuali punti di intersezioni e parametri + Point3d ptS ; pCompoTest->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_PLUS, ptS) ; + double dOffS ; pCrvBorder->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ; + Point3d ptE ; pCompoTest->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptE) ; + double dOffE ; pCrvBorder->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ; // recupero i due possibili percorsi e uso il più corto - PtrOwner pCrvA( vOffIslands[i]->CopyParamRange( dOffS, dOffE)) ; - PtrOwner pCrvB( vOffIslands[i]->CopyParamRange( dOffE, dOffS)) ; - + PtrOwner pCrvA( pCrvBorder->CopyParamRange( dOffS, dOffE)) ; + PtrOwner pCrvB( pCrvBorder->CopyParamRange( dOffE, dOffS)) ; if ( IsNull( pCrvA) || IsNull( pCrvB)) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; - + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; - - if ( j != 0) { + // definisco il nuovo bordo mediante la curva ausiliaria + if ( i != 0) { if ( dLenA < dLenB) { if ( ! pCompoHelp->AddCurve( Release( pCrvA))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } // se non interseco else { - if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + if ( ! pCompoHelp->AddCurve( pCompoTest->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } - - pCompo->Clear() ; - if ( ! pCompo->AddCurve( pCompoHelp->Clone())) - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) + // la curva di test diventa la curva ausiliaria + pCompoTest->Clear() ; + if ( ! pCompoTest->AddCurve( pCompoHelp->Clone())) + if ( ! CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink)) return false ; } + // La curva necessita di un ulteriore smusso, in quanto tagliata su un bordo + ModifyCurveToSmoothed( pCompoTest, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; - // controllo le dimensioni del BiArco - BBox3d bBox3 ; - if ( pCompo->GetLocalBBox( bBox3)) { - double dRadBB ; - // se troppo piccolo, lo approssimo con un segmento - if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) { - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) - return false ; - return true ; - } - // se troppo grande, lo approssimo con un segmento - if ( bBox3.GetRadius( dRadBB) && dRadBB > 3 * PockParams.dRad) { - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) - return false ; - return true ; - } - } - - PtrOwner pCrvCompo_noSmooth( pCompo->Clone()) ; - if ( ! ModifyCurveToSmoothed( pCompo, PockParams, 0.05, 0.05, true) || - ! pCompo->IsValid()) - pCompo.Set( pCrvCompo_noSmooth) ; - pCrvLink->AddCurve( Release( pCompo)) ; - + // restituisco il Link + if ( IsNull( pCompoTest) || ! pCompoTest->IsValid() || pCompoTest->GetCurveCount() == 0) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + pCrvLink->AddCurve( Release( pCompoTest)) ; return true ; } @@ -4962,7 +4917,9 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) dLenPercE = 0. ; } - double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; + #if 0 // nel caso volessi estendere anche prima del punto finale + double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; + #endif double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : PockParams.dRad) ; dLenE = 0 ; @@ -5083,12 +5040,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! AssignFeedSpiral( vOffs[i], pSfrTool, false, bFirstOffs, pSfrForOpenEdges, 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)) { + PtrOwner pSrfToolOffs( GetSurfFlatRegionFromFatCurve( vOffs[i]->Clone() , PockParams.dRad + 5 * EPS_SMALL, false, false, 10 * EPS_SMALL, false)) ; + if ( ! IsNull( pSrfToolOffs)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) - pSfrTool.Set( pSrfToolRegOffi) ; + pSfrTool.Set( pSrfToolOffs) ; else - pSfrTool->Add( *pSrfToolRegOffi) ; + pSfrTool->Add( *pSrfToolOffs) ; } vOffs[i]->SetTempProp( nProp0, 0) ; vOffs[i]->SetTempProp( nProp1, 1) ; @@ -5109,12 +5066,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& ! AssignFeedSpiral( pCrvLink, pSfrTool, true, false, pSfrForOpenEdges, 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)) { + PtrOwner pSfrToolLink( GetSurfFlatRegionFromFatCurve( pCrvLink->Clone(), PockParams.dRad + 10 * EPS_SMALL, false, false, 10 * EPS_SMALL, false)) ; + if ( ! IsNull( pSfrToolLink)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) - pSfrTool.Set( pSrfToolRegLinki) ; - else - pSfrTool->Add( *pSrfToolRegLinki) ; + pSfrTool.Set( pSfrToolLink) ; + else + pSfrTool->Add( *pSfrToolLink) ; } // risetto il Link come curva composita ... pCrvLink->SetTempProp( nProp0, 0) ; @@ -5134,8 +5091,108 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& //---------------------------------------------------------------------------- static bool -RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, - ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) +ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICRVCOMPOPOVECTOR& vOffsFirstCurve, + const Point3d& ptToGo, const PocketParams& PockParams, + int& nInd, Point3d& ptCloser, bool& bFirstOffs) +{ + /* + E' richiesto che le curve di Offset presentino le seguenti TempProps : + - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] + - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] + [per SPIRAL le proprietà sono ricavate automaticamente] + */ + + // controllo dei parametri + nInd = -1 ; + if ( vOffs.empty()) + return true ; + + // scorro tutte le curve di Offset + int nFlag ; + struct OffsPtMinDist { + int nInd = 0 ; + double dSqDist = INFINITO - 1 ; + Point3d ptMinDist = P_INVALID ; + bool bInVsOut = true ; + bool bFirstOffs = false ; + } ; + vector vOffsPtMinDist( vOffs.size()) ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + // indice dell'Offset + vOffsPtMinDist[i].nInd = i ; + // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + bool bSkip = false ; + for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) + bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; // prima iterazione + if ( bSkip) { + vOffsPtMinDist[i].bFirstOffs = true ; + continue ; + } + } + // Controllo se il punto da raggiungere è interno o esterno alla curva + // NB. cerco di privilegiare le curve che presentano il punto da raggiungere al loro esterno; + // in questo modo riesco a creare le curve a ricciolo + int nSide ; + DistPointCurve DistPtCrv( ptToGo, *vOffs[i]) ; + bool bFirstBorderIsland = false ; + if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { + // nel caso Spiral + if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { + // InVsOut + vOffsPtMinDist[i].bInVsOut = ( ( ! PockParams.bInvert && nSide == MDS_LEFT) || + ( PockParams.bInvert && nSide == MDS_RIGHT)) ; + // controllo se la curva in questione è di primo Offset + Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; + for ( int j = 0 ; j < int( vOffsFirstCurve.size()) ; ++ j) { + if ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) { + vOffsPtMinDist[i].bFirstOffs = true ; + // controllo se Isola o di bordo + double dArea = 0. ; + vOffs[i]->GetAreaXY( dArea) ; + bFirstBorderIsland = ( ( ! PockParams.bInvert && dArea < 0.) || + ( PockParams.bInvert && dArea > 0.)) ; + // se isola di primo Offset, InVsOut va invertito + if ( bFirstBorderIsland) + vOffsPtMinDist[i].bInVsOut = ( ! vOffsPtMinDist[i].bInVsOut) ; + break ; + } + } + } + // nel caso Conformal + else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + if ( nSide != vOffs[i]->GetTempProp( 1)) + vOffsPtMinDist[i].bInVsOut = false ; + } + // recupero il punto a minima distanza e la distanza + DistPtCrv.GetMinDistPoint( EPS_SMALL, vOffsPtMinDist[i].ptMinDist, nFlag) ; + DistPtCrv.GetSqDist( vOffsPtMinDist[i].dSqDist) ; + // se il punto da raggiungere è interno alla curva, aggiungo una penalità ( euristica) + if ( vOffsPtMinDist[i].bInVsOut) { + vOffsPtMinDist[i].dSqDist += PockParams.dRad + PockParams.dRad + + PockParams.dSideStep + PockParams.dSideStep ; + } + // se curva di bordo esterno, aggiungo un'altra penalità ( euristica) + if ( vOffsPtMinDist[i].bFirstOffs && ! bFirstBorderIsland) + vOffsPtMinDist[i].dSqDist *= 2. ; + } + } + // ordino il vettore in base alle distanze calcolate + sort( vOffsPtMinDist.begin(), vOffsPtMinDist.end(), []( const OffsPtMinDist& a, const OffsPtMinDist& b) { + return a.dSqDist < b.dSqDist ; + }) ; + // recupero la curva migliore + OffsPtMinDist& BestOffs = vOffsPtMinDist[0] ; + nInd = BestOffs.nInd ; + ptCloser = BestOffs.ptMinDist ; + bFirstOffs = BestOffs.bFirstOffs ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, + ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { /* E' richiesto che le curve di Offset presentino le seguenti TempProps : @@ -5153,70 +5210,22 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs // scorro tutti i Chunk della regione ICRVCOMPOPOVECTOR vCrvCurl ; for ( int nC = 0 ; nC < pSfrUncleared->GetChunkCount() ; ++ nC) { - // recupero il centroide del Chunk da rimuovere Point3d ptCentroid ; pSfrUncleared->GetChunkCentroid( nC, ptCentroid) ; - /* 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 + ... cerco la più vicina tra le rimanenti */ + // recupero la curva migliore 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 ; + Point3d ptCloser ; bool bFirstOffs = false ; - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { - // recupero il punto iniziale della curva - Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; - // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca - if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { - bool bSkip = false ; - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) - bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; - if ( bSkip) - continue ; - } - // se la curva contiene il centroide, allora la salto; l'idea è che il ricciolo sia esterno - // alla curva - int nSide ; - bool bCurrFirstOffs = false ; - DistPointCurve DistPtCrv( ptCentroid, *vOffs[i]) ; - if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { - // nel caso Spiral - if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { - // controllo se la curva in questione è di primo Offset, in questo caso devo determinare - // se MDS_LEFT o MDS_RIGHT - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bCurrFirstOffs ; ++ j) - bCurrFirstOffs = ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) ; - // se non è di primo Offset, allora ho già la classificazione MDS_ - if ( ! bCurrFirstOffs) { - if ( nSide == ( ! PockParams.bInvert ? MDS_LEFT : MDS_RIGHT)) - continue ; - } - // se di primo Offset allora non controllo MDS_ - /* NB. Se fosse esterna al loop 0 allora non ha senso, esattamente come se fosse interna alla isole - * La cosa si complica se avessi più Offset, Ma dato che cerco la cura più vicina dovrei - * considerare in automatico le curve di Offset appartenenti al chunk in esame */ - } - // nel caso Conformal - 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 ; - bFirstOffs = bCurrFirstOffs ; - DistPtCrv.GetMinDistPoint( EPS_SMALL, ptCloser, nFlag) ; - } - } - // se non ho trovato alcun indice, salto il Chunk nC-esimo + if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, + nInd, ptCloser, bFirstOffs)) + return false ; + // se nessun indice trovato, salto il chunk if ( nInd == -1) continue ; @@ -5235,7 +5244,6 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs if ( ! bFirstOffs) bIsSmoothCrv = ( PockParams.bSmooth && pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; else - // controllo se la sottocurva è un raccordo di Offset bIsSmoothCrv = ( pCrv->GetTempProp( 1) > 0) ; // clono la curva di Offset corrente ( in questo modo non modifico l'originale) @@ -5249,74 +5257,82 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs Point3d pt1, pt2, ptMain ; // paramtro di uscita e di ingresso dall'Offset attuale per creazione della curva a ricciolo double dURef1, dURef2 ; + // numero di curve dell'offset corrente + int nCrvNumber = ( pMyOffs->GetCurveCount()) ; // 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" + // 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) { + vt2 = V_INVALID ; + // cerco la prima sottocurva che non sia di raccordo in precedenza + for ( int i = ( nCrv + nCrvNumber - 1) % nCrvNumber ; ( i % nCrvNumber) == i ; -- i) { + // recupero la sottocurva const ICurve* pCrvPrec = pMyOffs->GetCurve( i) ; if ( pCrvPrec == nullptr || ! pCrvPrec->IsValid()) break ; + // se non di raccordo 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 ; + dURef1 = ( i + 1) % nCrvNumber ; break ; } } - if ( ! vt1.IsValid()) - continue ; - 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 ; + bIsSmoothCrv = ( vt1.IsValid()) ; + if ( bIsSmoothCrv) { + // cerco la prima sottocurva che non sia di raccordo in sucessione + for ( int i = ( nCrv + nCrvNumber + 1) % nCrvNumber ; ( i % nCrvNumber) == i ; ++ i) { + // recupero la sottocurva + const ICurve* pCrvSucc = pMyOffs->GetCurve( i) ; + if ( pCrvSucc == nullptr || ! pCrvSucc->IsValid()) + break ; + // se non di raccordo + 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 % nCrvNumber) ; + break ; + } } } - 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 ; + bIsSmoothCrv = bIsSmoothCrv && ( vt2.IsValid()) ; + if ( bIsSmoothCrv) { + // 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) ; + bIsSmoothCrv = ( ILL.GetCrossIntersCount() == 1) ; + if ( bIsSmoothCrv) { + IntCrvCrvInfo aInfo ; + bIsSmoothCrv = ( ( ILL.GetIntCrvCrvInfo( 0, aInfo)) && + pCrvCurl->AddPoint( pt1) && + pCrvCurl->AddLine( aInfo.IciA[0].ptI)) ; + if ( bIsSmoothCrv) + ptMain = aInfo.IciA[0].ptI ; } } - else - continue ; } - // se invece non è di raccordo, allora ho già lo spigolo vivo - else { + // se non è di raccordo, allora ho già lo spigolo vivo + if ( ! bIsSmoothCrv) { + pCrvCurl->Clear() ; // definisco il versore entrante ed uscente // definisco il punto di entrata e di uscita ( sono coincidenti) dURef1 = dURef ; @@ -5353,14 +5369,12 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vtDir, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc1, bSpecial) || ! CalcBoundedSmoothedLink( ptCentroid, vtDir, ptMain, vt2, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc2, bSpecial)) continue ; - // aggiorno la curva a ricciolo if ( ! pCrvCurl->AddCurve( Release( pCrvBiArc1)) || ! pCrvCurl->AddCurve( Release( pCrvBiArc2)) || ! pCrvCurl->IsValid()) continue ; } - // controllo se devo raccordarmi con Offset if ( bIsSmoothCrv) pCrvCurl->AddLine( pt2) ; @@ -5374,9 +5388,8 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs return false ; pSfrChunk->Subtract( *pSfrFatCurl) ; - // se la curva a ricciolo non svuota il Chunk nC-esimo -> percorro il bordo di tale Chunk + // controllo se la regione è tutta rimossa 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))) ; @@ -5386,6 +5399,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs pCompoChunkBorder->Invert() ; DistPointCurve distPtChunkBorder( ptCloser, *pCompoChunkBorder) ; Point3d ptCloserOnChunk ; + int nFlag ; if ( ! distPtChunkBorder.GetMinDistPoint( EPS_SMALL, ptCloserOnChunk, nFlag)) continue ; // cambio il punto di inizio della curva su tale punto @@ -5503,44 +5517,72 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { + // ricavo il punto inziale della curva corrente Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; - int nNextInd = -1 ; // indice della curva successiva - double dMinDist = INFINITO ; // distanza tra questa curva e la successiva - Point3d ptStartNext ; // punto iniziale della curva successiva // tra le curve successive cerco la curva interna e più vicina ad essa + int nNextInd = -1 ; // indice della curva successiva + double dMinDist = INFINITO ; // distanza tra questa curva e la successiva + Point3d ptStartNext ; // punto iniziale della curva successiva + bool bMinDistAtSmooth = false ; // se punto a minima distanza su curva di smusso for ( int j = i + 1 ; j < int( vOffs.size()) ; ++ j) { IntersCurveCurve IntCC( *vOffs[i], *vOffs[j]) ; CRVCVECTOR ccClass ; // se interna if ( IntCC.GetCurveClassification( 1, EPS_SMALL, ccClass) && - int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_IN) { + int( ccClass.size()) == 1 && + ( ( ! PockParams.bInvert && ccClass[0].nClass == CRVC_IN) || + ( PockParams.bInvert && ccClass[0].nClass == CRVC_OUT))) { // calcolo la distanza minima tra essa int nFlag ; + double dPar = 0. ; Point3d ptClosest ; - if ( DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptClosest, nFlag)) { - double dCurrDist = SqDist( ptS, ptClosest) ; - if ( dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nNextInd = j ; - ptStartNext = ptClosest ; + DistPointCurve DistPtCrv( ptS, *vOffs[j]) ; + if ( DistPtCrv.GetParamAtMinDistPoint( EPS_SMALL, dPar, nFlag)) { + // controllo se la curva ottenuta è di raccordo, in caso positivo considero come + // punto più vicino il suo punto finale ( per avere poi successivamente Link tra + // Offset in tangenza ) + const ICurve* pCrv = vOffs[j]->GetCurve( static_cast( floor( dPar))) ; + if ( pCrv != nullptr && pCrv->IsValid()) { + if ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) + pCrv->GetEndPoint( ptClosest) ; + else + DistPtCrv.GetMinDistPoint( EPS_SMALL, ptClosest, nFlag) ; + double dCurrDist = SqDist( ptS, ptClosest) ; + if ( dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nNextInd = j ; + ptStartNext = ptClosest ; + bMinDistAtSmooth = ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; + } } } } } + // se non ho trovato nessuna curva interna... cerco semplicemente la curva più vicina if ( nNextInd == -1) { for ( int j = i + 1 ; j < int( vOffs.size()) ; ++ j) { int nFlag ; + double dPar = 0. ; Point3d ptClosest ; - if ( DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptClosest, nFlag)) { - double dCurrDist = SqDist( ptS, ptClosest) ; - if ( dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nNextInd = j ; - ptStartNext = ptClosest ; + DistPointCurve DistPtCrv( ptS, *vOffs[j]) ; + if ( DistPtCrv.GetParamAtMinDistPoint( EPS_SMALL, dPar, nFlag)) { + const ICurve* pCrv = vOffs[j]->GetCurve( static_cast( floor( dPar))) ; + if ( pCrv != nullptr && pCrv->IsValid()) { + if ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) + pCrv->GetEndPoint( ptClosest) ; + else + DistPtCrv.GetMinDistPoint( EPS_SMALL, ptClosest, nFlag) ; + double dCurrDist = SqDist( ptS, ptClosest) ; + if ( dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nNextInd = j ; + ptStartNext = ptClosest ; + bMinDistAtSmooth = ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; + } } } } @@ -5571,7 +5613,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con return false ; // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset double dLenPercS = ( i == 0 ? 0. : 10 * EPS_SMALL) ; - double dLenPercE = 10 * EPS_SMALL ; + double dLenPercE = ( bMinDistAtSmooth ? 0. : 10 * EPS_SMALL) ; if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, dLenPercS, dLenPercE, pCrvLink) || ! pCrvLink->IsValid()) { // se non sono riuscito, cerco una strada più semplice ripristinando le curve @@ -5618,8 +5660,8 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con //---------------------------------------------------------------------------- static bool -CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, - const int nIter, const PocketParams& PockParams, bool& bInsert) +CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* pCrvOffs, + double dOffs, double dOffsPrec, int nIter, const PocketParams& PockParams, bool& bInsert) { // controllo dei parametri @@ -5636,70 +5678,51 @@ CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, double dMaxOffs ; if ( ! CalcCurveLimitOffset( *pCrvOffs, dMaxOffs)) return false ; - // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive - if ( dMaxOffs < PockParams.dRad - dOffs + 5 * EPS_SMALL) { + // controllo se l'Offset rimuove materiale + if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < EPS_SMALL) { bInsert = false ; return true ; } - } - else - return true ; - - // se non richiesto percorso avanzato - if ( ! PockParams.bOptOffsetsAdv) - return true ; - - OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad - if ( ! OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) - return false ; - - // controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis - if ( OffsCrv.GetCurveCount() > 1) - return true ; - - PtrOwner pCrvOffLonger( OffsCrv.GetLongerCurve()) ; - if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid()) - return true ; - - // Immagine del tool con centro nel centroide della zona da svuotare - Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ; - PtrOwner pCrvTool( CreateCurveArc()) ; - if( IsNull( pCrvTool)) - return false ; - pCrvTool->SetXY( ptC, PockParams.dRad - 5 * EPS_SMALL) ; - - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ; - intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ; - if ( int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) { - // centroide - bInsert = false ; - return true ; - } - - // recupero la PolyLine per altezza e lunghezza del Box2D ( rettangolo) - PolyLine pl ; - if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl)) - return true ; - Vector3d vtX ; - double dLen = 0 ; double dHeight = 0 ; - if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight)) - return true ; - - // frame locale, recupero DimX e DimY - Frame3d frLoc ; frLoc.Set( ptC, Z_AX, vtX) ; - if ( ! frLoc.IsValid()) - return true ; - BBox3d bBox ; - frLoc.Invert() ; - pCrvOffLonger->GetBBox( frLoc, bBox) ; - double dDimX = bBox.GetDimX() ; - double dDimY = bBox.GetDimY() ; - - // se dimensioni accettabili, inserisco - if ( dDimX < 2 * PockParams.dRad - 100 * EPS_SMALL || dDimY < 4 * PockParams.dRad - 100 * EPS_SMALL) { - bInsert = false ; - return true ; + // controllo se l'Offset rimuove una quantità minima di materiale + else if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < TOL_REMOVE_OFFSET) { + // inizializzo la curva di bordo della regione non svuotata + PtrOwner pCrvBorder( CreateCurveComposite()) ; + if ( IsNull( pCrvBorder)) + return false ; + // recupero la regione non svuotata e calcolo la curva di bordo + PtrOwner pSfrA( pSfrAct->CreateOffsetSurf( - dOffsPrec - PockParams.dRad, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrA)) + return false ; + if ( AreOppositeVectorApprox( pSfrA->GetNormVersor(), Z_AX)) + pSfrA->Invert() ; + for ( int nC = 0 ; nC < pSfrA->GetChunkCount() ; ++ nC) { + PtrOwner pSfrChunk( pSfrA->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + PtrOwner pSfrB( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrB) || ! pSfrB->AddExtLoop( pCrvOffs->Clone())) + return false ; + if ( AreOppositeVectorApprox( pSfrB->GetNormVersor(), Z_AX)) + pSfrB->Invert() ; + if ( pSfrB->Intersect( *pSfrChunk) && pSfrB->IsValid()) { + if ( ! pCrvBorder.Set( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0)))) + return false ; + break ; + } + } + if ( pCrvBorder->IsValid()) { + // controllo se l'utensile posizionato nel centroide rimuove la regione + Point3d ptCentroid ; pCrvBorder->GetCentroid( ptCentroid) ; + PtrOwner pCrvArc( CreateCurveArc()) ; + if ( IsNull( pCrvArc)) + return false ; + pCrvArc->Set( ptCentroid, Z_AX, PockParams.dRad - 10 * EPS_SMALL) ; + IntersCurveCurve ICC( *pCrvBorder, *pCrvArc) ; + CRVCVECTOR ccClass ; + bInsert = ( ! ICC.GetCurveClassification( 0, EPS_SMALL, ccClass) || + int( ccClass.size()) != 1 || ccClass[0].nClass != CRVC_IN) ; + } + } } return true ; @@ -5809,7 +5832,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co pCrvCompoBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; - if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, nIter, PockParams, bInsert)) + if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert)) return false ; if ( bInsert) vOffs.emplace_back( Release( pCrvCompoBorder)) ; @@ -5909,7 +5932,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; if ( GetUnclearedRegionAndSetFeed( vOffsFirstCurve, vOffs, vLinks, pSfrOrig, PockParams, pSfrUncleared)) { // modifico i percorsi - if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) + if ( ! RemoveUnclearedRegions( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) return false ; } @@ -7737,7 +7760,7 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const ISurfFlatR return false ; if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, pSfrOrig, PockParams, pSfrUncleared)) { // estendo i percorsi di Offset se richiesto - if ( ! RemoveExtraParts( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) + if ( ! RemoveUnclearedRegions( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) return false ; } @@ -7759,18 +7782,16 @@ AddLeadInLeadOutToCurveConformalPaths( const ISurfFlatRegion* pSfrOrig, const IS } // ricavo le curve aperte della superficie di pocketing + ICRVCOMPOPOVECTOR vCrvLoops ; + if ( ! GetSfrCrvCompoLoops( pSfrPock, vCrvLoops)) + return false ; ICRVCOMPOPOVECTOR vCrvOpenEdge ; - { - ICRVCOMPOPOVECTOR vCrvLoops ; - if ( ! GetSfrCrvCompoLoops( pSfrPock, vCrvLoops)) - return false ; - for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { - ICRVCOMPOPOVECTOR vpCrvs ; - GetHomogeneousParts( vCrvLoops[i], PockParams, vpCrvs) ; - for ( int j = 0 ; j < int( vpCrvs.size()) ; ++ j) { - if ( vpCrvs[j]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) - vCrvOpenEdge.emplace_back( Release( vpCrvs[j])) ; - } + for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( vCrvLoops[i], PockParams, vpCrvs) ; + for ( int j = 0 ; j < int( vpCrvs.size()) ; ++ j) { + if ( vpCrvs[j]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) + vCrvOpenEdge.emplace_back( Release( vpCrvs[j])) ; } } @@ -8466,8 +8487,14 @@ GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pS } } // concateno se necessario ( per tolleranza Offset) + int nTempProp0 = ( ! vCrvOffsInside.empty() ? vCrvOffsInside[0]->GetTempProp( 0) : TEMP_PROP_INVALID) ; + int nTempProp1 = ( ! vCrvOffsInside.empty() ? vCrvOffsInside[0]->GetTempProp( 1) : TEMP_PROP_INVALID) ; if ( ! ChainCompoCurves( vCrvOffsInside)) return false ; + for ( auto& CrvCompo : vCrvOffsInside) { + CrvCompo->SetTempProp( nTempProp0, 0) ; + CrvCompo->SetTempProp( nTempProp1, 1) ; + } // se ho trovato delle curve interne if ( ! bStop) { // inserisco le curva ricavate all'iterazione nIter nel vettore