diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 38ff6db..10ce91b 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -28,8 +28,10 @@ #include "/EgtDev/Include/EGkCurveLocal.h" #include "/EgtDev/Include/EGkMedialAxis.h" #include "/EgtDev/Include/EGkLinePntTgCurve.h" +#include "/EgtDev/Include/EGkOffsetCurve.h" #include + using namespace std ; //---------------------------------------------------------------------------- @@ -37,62 +39,389 @@ using namespace std ; //---------------------------------------------------------------------------- // variabili d'appoggio ( per non passare troppi parametri tra le funzioni secondarie) -static int s_nType = 0 ; -static double s_dRad = 0 ; -static bool s_bSmooth = false ; +struct PocketParams { + int nType = POCKET_SPIRALIN ; + double dRad = 0. ; // raggio utensile + double dRad_prec = -1. ; // raggio utensile della lavorazione precedente + double dSideStep = 0. ; // step + double dSideStep_prec = -1. ; // step della lavorazione precedente + double dRadialOffset = 0. ; // offset radiale + double dRadialOffset_prec = -1. ; // offset radiale precedente + double dOpenEdgeRad = 0. ; // massimo raggio per estensione lati aperti + double dOpenMinSafe = 0. ; // estensione minima di sicurezza + 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 in SpiralIn/Out + bool bOptOffsetsAdv = false ; // flag per evitare Offset coperti da curve di MedialAxis in SpiralIn/Out + bool bAboveHead = false ; // flag per testa da sopra ( Z+) + double dSafeZ = 0. ; // safe Z + bool bSmooth = false ; // curve smussate + bool bInvert = false ; // inversione dei percorsi + Point3d ptStart = P_INVALID ; // punto d'inizio + Point3d ptEnd = P_INVALID ; // punto di fine + SurfFlatRegion SrfLimit ; // superficie limite per estensione lati aperti + bool bCalcFeed = false ; // flag per calcolo della Feed + double dFeed = 1000 ; // feed di riferimento per frazione +} ; + +static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket //---------------------------------------------------------------------------- static bool -AdjustContourStart( ICurveComposite* pCompo) +GetCurvesForOptimizedPocketing( const ISurfFlatRegion* pSfr, ICRVCOMPOPOVECTOR& vCrvOEWithFlags) { - // creo un vettore di indici che definisce l'ordine delle curve chiuse in base alla lunghezza - INTVECTOR vInd ; vInd.reserve( pCompo->GetCurveCount()) ; - // vettore di indici già utilizzati - INTVECTOR vIndUsed ; vIndUsed.reserve( pCompo->GetCurveCount()) ; + vCrvOEWithFlags.clear() ; - double dMaxLen = -INFINITO ; // lunghezza massima - int nCurrInd = 0 ; // indice della curva scelta - bool bStop = false ; // flag per stoppare la ricerca della curva - - // mettendo chiuse tutte le curve ( in questo caso non servono i lati aperti) - for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { - pCompo->SetCurveTempProp( u, 0, 0) ; - pCompo->SetCurveTempProp( u, 0, 1) ; + // controllo parametri : + if ( pSfr == nullptr || ! pSfr->IsValid()) { + vCrvOEWithFlags.emplace_back( CreateCurveComposite()) ; + return true ; // <- se superficie non valida, allora non ho curve da salvare } - // miglioro la curva per la ricerca - pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; - // scorro tutte le curve - for ( int c = 0 ; c < pCompo->GetCurveCount() && ! bStop ; ++ c) { - bStop = true ; - for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { - int nProp_i ; - // se la curva i-esima non è già stata considerata ed è aperta... - if ( find( vIndUsed.begin(), vIndUsed.end(), i) == vIndUsed.end() && - pCompo->GetCurveTempProp( i, nProp_i, 0) && nProp_i == 0) { + // ricavo tutti i Loop esterni della superficie con i lati Aperti/Chiusi + for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) { + PtrOwner pCrvCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( c, 0))) ; + if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid()) + return false ; + vCrvOEWithFlags.emplace_back( Release( pCrvCompoLoop)) ; + } - // ricavo la curva i-esima - const ICurve* pCrv_i( pCompo->GetCurve( i)) ; - double dLen_i ; + return true ; - if ( pCrv_i->GetLength( dLen_i) && dLen_i > dMaxLen) { // se di lunghezza maggiore alla soglia... - dMaxLen = dLen_i ; - nCurrInd = i ; - bStop = false ; +} + +//---------------------------------------------------------------------------- +static bool +GetCoeffLinArc( const ICurveArc* pArc, double dDiam, double& dSubArc) +{ + + // controllo parametri + if ( pArc == nullptr || ! pArc->IsValid()) + return false ; + + Point3d ptMid ; + if ( ! pArc->GetMidPoint( ptMid)) + return false ; + + // creo l'ombra del tool nel punto medio + PtrOwner pCrvTool( CreateCurveArc()) ; + pCrvTool->Set( ptMid, Z_AX, dDiam) ; + if ( ! pCrvTool->IsValid()) + return false ; + + // effettuo la classificazione + IntersCurveCurve intCC( *pArc, *pCrvTool) ; + CRVCVECTOR ccClass ; + if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) && + int( ccClass.size()) == 3 && + ccClass[1].nClass == CRVC_IN) { + Point3d ptS, ptE ; + pCrvTool->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ; + pCrvTool->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_PLUS, ptE) ; + Vector3d vtS = ptS - pArc->GetCenter() ; + Vector3d vtE = ptE - pArc->GetCenter() ; + double dTheta ; + vtS.GetAngle( vtE, dTheta) ; + dTheta = abs( dTheta) ; + dSubArc = pArc->GetRadius() * DEGTORAD * dTheta ; + } + else + return false ; + + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCompo, + const ICRVCOMPOPOVECTOR& vOtherCrv, PocketParams PockParams, double& dPar) +{ + + // ==================== INFO ================================================================ + // pCrvCheck -> sottocurva di pCrvCompo su cui cercare il parametro ideale per ingresso + // vOtherCrv -> tutte le altre curve che non devono essere intersecate durante l'ingresso + // ( questo vettore è stato riempito con tutti loop della superificie da + // lavorare, i quali Offset non hanno generato alcuna curva di pCrvCheck ) + // ========================================================================================== + + // controllo dei parametri + if ( pCrvCheck == nullptr || ! pCrvCheck->IsValid() || + pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) + return false ; + + // clono le curve + PtrOwner pCrv( pCrvCheck->Clone()) ; + PtrOwner pCompo( CloneCurveComposite( pCrvCompo)) ; + if ( IsNull( pCrv) || IsNull( pCompo)) + return false ; + ICRVCOMPOPOVECTOR vCrvNoInters ; + for ( int i = 0 ; i < ( int)vOtherCrv.size() ; ++ i) + vCrvNoInters.emplace_back( ConvertCurveToComposite( vOtherCrv[i]->Clone())) ; + + // ricavo l'estrusione della curva composita + Vector3d vtExtr ; + if ( ! pCompo->GetExtrusion( vtExtr)) + vtExtr = Z_AX ; + // ricavo il centroide o il punto iniziale della curva composita + Point3d ptCen ; + if ( ! pCompo->GetCentroid( ptCen)) + if ( ! pCompo->GetStartPoint( ptCen)) + return false ; + + // creo un frame locale per creare l'ombra del tool e intersecarla con la curva + Frame3d frLoc ; + frLoc.Set( ptCen, vtExtr) ; + + // porto le curve in questo sistema di riferimento + pCrv->ToLoc( frLoc) ; + pCompo->ToLoc( frLoc) ; + for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++i) + vCrvNoInters[i]->ToLoc( frLoc) ; + + // fisso il diametro del tool ( più grande per sicurezza ) + double dDiam = ( 2 * PockParams.dRad ) + 2 * PockParams.dRadialOffset ; + double dLen ; + if ( ! pCrv->GetLength( dLen)) + return false ; + double dSubArc = -1 ; + if ( pCrv->GetType() == CRV_ARC) { + PtrOwner pCrvArc( GetCurveArc( pCrv->Clone())) ; + if ( IsNull( pCrvArc) || ! GetCoeffLinArc( pCrvArc, dDiam, dSubArc)) + return false ; + } + double dDiv = dSubArc < 0 ? dDiam : dSubArc ; + double dMaxInt = floor( dLen / dDiv) ; + + int nDen = 2 ; // intervalli in cui suddivido la curva + dMaxInt = max( 2.0, dMaxInt) ; // così se entra una volta controllo sempre dParT = 0.5 + + while ( nDen < dMaxInt + EPS_SMALL) { // EPS_SMALL per comprendere l'uguaglianza + + for ( int i = 1 ; i < nDen ; ++i) { + + if ( int( i % nDen) == 0) + continue ; + + double dNum = 1.0 * i ; + double dParT = dNum / nDen ; + Point3d ptTest ; + Vector3d vtPerpIn ; + + if ( pCrv->GetPointD1D2( dParT, ICurve::FROM_PLUS, ptTest, &vtPerpIn)) { + + PtrOwner pCompoClone( CloneCurveComposite( pCompo)) ; + if ( IsNull( pCompoClone)) + return false ; + double dU ; + pCompoClone->GetParamAtPoint( ptTest, dU) ; + pCompoClone->ChangeStartPoint( dU) ; + + // se chiuso + if ( pCrv->GetTempProp() == 0) { + // se la curva è chiusa sposto il centro verso l'interno. + // Devo essere sicuro di essere su una curva di Offset interno, altrimenti potrebbe essere valido + // il punto trovato, però facendo poi il primo offeset tale punto potrebbe diventare un punto + // di convergenza tra più chunks... + vtPerpIn.Normalize() ; + vtPerpIn.Rotate( Z_AX, 0, 1) ; // cos( pi/2) = 0, sin( pi/2) = 1 + vtPerpIn *= (( PockParams.dRad + PockParams.dRadialOffset - 50 * EPS_SMALL)) ; + ptTest = ptTest + vtPerpIn ; + + // creo una circonferenza ( ombra del tool ) centrata su ptTest + PtrOwner pCrvToolShape( CreateCurveArc()) ; + pCrvToolShape->Set( ptTest, Z_AX, 0.5 * dDiam) ; + if ( ! pCrvToolShape->IsValid()) + return false ; + + // interseco la curva composita con l'ombra del tool + CRVCVECTOR ccClass ; + IntersCurveCurve intCC( *pCompoClone, *pCrvToolShape) ; + + if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { + // se ho solo due intersezioni, controllo di non intersecare isole ( In-Out-In) + if ( int( ccClass.size() == 3)) { + bool bOk = true ; + for ( int j = 0 ; j < ( int)vCrvNoInters.size() && bOk ; ++ j) { + + IntersCurveCurve intCCI( *vCrvNoInters[j], *pCrvToolShape) ; + if ( intCCI.GetCurveClassification( 0, EPS_SMALL, ccClass)) { + + if (( int)ccClass.size() > 1) + bOk = false ; + } + else + return false ; + } + if ( bOk) { + dPar = dParT ; + return true ; + } + } + } + else + return false ; + } + // se aperto + else { + dPar = dParT ; + return true ; } } } - vIndUsed.push_back( nCurrInd) ; - vInd.push_back( nCurrInd) ; - dMaxLen = -INFINITO ; + + ++nDen ; } - // ora che ho riempito il vettore di indici lo scorro e cerco di entrare in questi lati chiusi secondo l'ordine - for ( int i = 0 ; i < ( int)vInd.size() ; ++ i) { - pCompo->ChangeStartPoint( vInd[0] + 0.5) ; - // in questo caso mi fermo al primo per semplicità - break ; + return false ; +} + +//---------------------------------------------------------------------------- +static bool +AdjustContourStart( ICurveComposite* pCompo, PocketParams PockParams, const ICRVCOMPOPOVECTOR& vCrvIsl, + bool bOrder, Point3d ptRef) +{ + // se cerco semplicemente il tratto lineare chiuso più lungo ... + if ( ! bOrder) { + // la priorità è essagnata ai tratti lineari chiusi + int i = 0 ; // <--- indice della curva corrente + int nMax = - 1 ; + double dLenMax = 0 ; + const ICurve* pCrv = pCompo->GetFirstCurve() ; + while ( pCrv != nullptr) { + double dLen ; + if ( pCrv->GetType() == CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { + dLenMax = dLen ; + nMax = i ; + } + ++ i ; + pCrv = pCompo->GetNextCurve() ; + } + // se non trovato o troppo corto, cerco il tratto chiuso più lungo in generale + if ( nMax < 0 || dLenMax < 2 * ( 2 * PockParams.dRad)) { + i = 0 ; + pCrv = pCompo->GetFirstCurve() ; + while ( pCrv != nullptr) { + double dLen ; + if ( pCrv->GetType() != CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { + dLenMax = dLen ; + nMax = i ; + } + ++ i ; + pCrv = pCompo->GetNextCurve() ; + } + } + // controllo che il tratto chiuso più lungo trovato sia sufficientemente lungo + if ( dLenMax < 10 * EPS_SMALL) { + // se troppo piccolo allora lo imposto aperto + pCompo->SetCurveTempProp( nMax, 0, 1) ; + // spezzo la curva nel primo tratto aperto sufficientemente lungo + for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { + double dLen ; pCompo->GetCurve( u)->GetLength( dLen) ; + if ( dLen > 10 * EPS_SMALL) { + nMax = u ; + continue ; + } + } + } + + // se non trovato, imposto il punto iniziale a mentà del primo tratto + if ( nMax == -1) { + pCompo->ChangeStartPoint( 0.5) ; + return true ; + } + pCompo->ChangeStartPoint( nMax + 0.5) ; + } + // se invece sto cercando di entrare da un lato chiuso per una svuotatura, allora riordino i lati + // chiusi a seconda della lunghezza, e a partire dal più lungo cerco un parametro su tale curva che mi consenta + // un'entrata sufficientemente distante da isole e da altre curve della curva stessa su cui cerco l'entrata ... + else { + + // se ho un punto di riferimento, allora come prima cosa controllo il lato chiuso più vicino + if ( ptRef.IsValid()) { + double dMinDist = INFINITO ; + int nIndCrvMinDist = - 1 ; + for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { + DistPointCurve DPC( ptRef, *pCompo->GetCurve( u)) ; + double dCurrDist = INFINITO ; + if ( DPC.GetDist( dCurrDist) && dCurrDist < dMinDist) { + nIndCrvMinDist = u ; + dMinDist = dCurrDist ; + } + } + // se avessi curve alla stessa distanza ( circa) non controllo le altre, mi accontento della + // prima curva trovata + if ( nIndCrvMinDist != -1) { + // controllo che il lato chiuso sia sufficientemente lungo + double dLen = 0. ; + pCompo->GetCurve( nIndCrvMinDist)->GetLength( dLen) ; + if ( dLen > 2 * PockParams.dRad + 2 * PockParams.dRadialOffset + 500 * EPS_SMALL) { + pCompo->ChangeStartPoint( nIndCrvMinDist + 0.5) ; + return true ; + } + } + } + + // creo un vettore di indici che definisce l'ordine delle curve chiuse in base alla lunghezza + INTVECTOR vInd ; vInd.reserve( pCompo->GetCurveCount()) ; + + // vettore di indici già utilizzati + INTVECTOR vIndUsed ; vIndUsed.reserve( pCompo->GetCurveCount()) ; + + double dMaxLen = -INFINITO ; + int nCurrInd = 0 ; + bool bStop = false ; + + for ( int c = 0 ; c < pCompo->GetCurveCount() && ! bStop ; ++ c) { + bStop = true ; + for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { + + int nProp_i ; + // se la curva i-esima non è già stata considerata ed è chiusa... + if ( find( vIndUsed.begin(), vIndUsed.end(), i) == vIndUsed.end() && + pCompo->GetCurveTempProp( i, nProp_i, 0) && nProp_i == 0) { + + // creo la curva i-esima + const ICurve* pCrv_i( pCompo->GetCurve( i)) ; + double dLen_i ; + + if ( pCrv_i->GetLength( dLen_i) && dLen_i > dMaxLen) { // se di lunghezza maggiore alla soglia... + dMaxLen = dLen_i ; + nCurrInd = i ; + bStop = false ; + } + } + } + vIndUsed.push_back( nCurrInd) ; + vInd.push_back( nCurrInd) ; + dMaxLen = -INFINITO ; + } + + if ( vInd.empty()) { + // se questa condizione fosse vera allora non sono riuscito ad entrare da nessun lato aperto in precedenza e non + // ho nemmeno un lato chiuso disponibile per entrare... ( forzo l'entrata a metà del primo lato) + pCompo->ChangeStartPoint( 0.5) ; + return true ; + } + + // ora che ho riempito il vettore di indici lo scorro e cerco di entrare in questi lati chiusi secondo l'ordine + bool bOk = false ; + for ( int i = 0 ; i < int( vInd.size()) && !bOk ; ++ i) { + const ICurve* pCrv( pCompo->GetCurve( vInd[i])) ; + double dPar ; + if ( GetParamForPtStartOnEdge( pCrv, pCompo, vCrvIsl, PockParams, dPar)) { + pCompo->ChangeStartPoint( vInd[i] + dPar) ; + bOk = true ; + } + } + + if ( ! bOk) { + // se non riesco ad entrare da nessun lato chiuso, considerando che in precedenza ho già provato ad + // entrare da tutti i lati aperti... + pCompo->ChangeStartPoint( vInd[0] + 0.5) ; + return true ; + } } return true ; @@ -100,10 +429,2395 @@ AdjustContourStart( ICurveComposite* pCompo) //---------------------------------------------------------------------------- static bool -ModifyCurveToSmoothed( ICurveComposite* pCrv, double dRightLen, double dLeftLen, bool bAsParam) +GetHomogeneousParts( ICurveComposite* pCrvCompo, PocketParams PockParams, ICRVCOMPOPOVECTOR& vpCrvs) +{ + + // controllo dei parametri + vpCrvs.clear() ; + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) // se curva non valida + return true ; + + // la curva ha sia tratti aperti che tratti chiusi, quindi sposto l'inizio a metà del tratto più lungo ( se richisto)... + ICRVCOMPOPOVECTOR vCrvNULL ; + AdjustContourStart( pCrvCompo, PockParams, vCrvNULL, false, P_INVALID) ; + + // estraggo parti con proprietà uniforme in un vettore ( vpCrvs) + int nCurrTempProp ; + int nParStart = 0 ; + for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { + int nTempProp ; + pCrvCompo->GetCurveTempProp( i, nTempProp) ; + if ( i == 0) { + nCurrTempProp = nTempProp ; + nParStart = i ; + } + else if ( nCurrTempProp != nTempProp) { + PtrOwner pCrv( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, i))) ; + if ( IsNull( pCrv)) + return false ; + pCrv->SetTempProp( nCurrTempProp) ; + vpCrvs.emplace_back( Release( pCrv)) ; + nCurrTempProp = nTempProp ; + nParStart = i ; + } + } + // ultima curva... + PtrOwner pCrv( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, pCrvCompo->GetCurveCount()))) ; + if ( IsNull( pCrv)) + return false ; + pCrv->SetTempProp( nCurrTempProp) ; + vpCrvs.emplace_back( Release( pCrv)) ; + + return true ; +} + +//--------------------------------------------------------------------------- +static bool +CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, const Vector3d& vtTanE_, + const double dRad, ISurfFlatRegion* pSfrInc) +{ + // controllo dei parametri + if ( pCrv == nullptr || ! pCrv->IsValid()) + 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()) { + pSfrInc->CopyFrom( pSfrInc_tmp) ; + return pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0 ; + } + + // 1) *** + // La regione di incidenza non deve avere un bordo distante dRad dagli estremi del tratto aperto + // per questo motivo, creo due FlatRegion a rettangolo che andrò a sottrarre alla pSfrInc_tmp + // ( tolgo i semi-dischi agli estremi ) + + // 2) *** + // La regione di incidenza deve seguire seguire in tangenza il percorso agli estremi del tratto + // aperto corrente, creo due FlatRegion a rettangolo, orientate come le tangenza dei chiusi che andrò + // a sottrarre alla pSfrInc_tmp + + + // 1) *** + + // Rettangolo all'inizio + Vector3d vtTanS ; pCrv->GetStartDir( vtTanS) ; + Point3d ptS ; pCrv->GetStartPoint( ptS) ; + Vector3d vtOut = vtTanS ; vtOut.Rotate( Z_AX, - 90) ; + PtrOwner pCrvRectSBorder( CreateCurveComposite()) ; + if ( IsNull( pCrvRectSBorder)) + return false ; + pCrvRectSBorder->AddPoint( ptS + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRectSBorder->AddLine( ptS - ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRectSBorder->AddLine( ptS - ( dRad + 500 * EPS_SMALL) * vtOut - vtTanS * ( dRad + 500 * EPS_SMALL)) ; + pCrvRectSBorder->AddLine( ptS + ( dRad + 500 * EPS_SMALL) * vtOut - vtTanS * ( dRad + 500 * EPS_SMALL)) ; + pCrvRectSBorder->Close() ; + PtrOwner pSfrRectStart( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrRectStart) || + ! pSfrRectStart->AddExtLoop( Release( pCrvRectSBorder)) || + ! pSfrRectStart->IsValid()) + return false ; + if ( AreOppositeVectorApprox( pSfrInc->GetNormVersor(), pSfrRectStart->GetNormVersor())) + pSfrRectStart->Invert() ; + + // Rettangolo alla fine + Vector3d vtTanE ; pCrv->GetEndDir( vtTanE) ; + Point3d ptE ; pCrv->GetEndPoint( ptE) ; + vtOut = vtTanE ; vtOut.Rotate( Z_AX, - 90) ; + PtrOwner pCrvRectEBorder( CreateCurveComposite()) ; + if ( IsNull( pCrvRectEBorder)) + return false ; + pCrvRectEBorder->AddPoint( ptE + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRectEBorder->AddLine( ptE - ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRectEBorder->AddLine( ptE - ( dRad + 500 * EPS_SMALL) * vtOut + vtTanE * ( dRad + 500 * EPS_SMALL)) ; + pCrvRectEBorder->AddLine( ptE + ( dRad + 500 * EPS_SMALL) * vtOut + vtTanE * ( dRad + 500 * EPS_SMALL)) ; + pCrvRectEBorder->Close() ; + PtrOwner pSfrRectEnd( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrRectEnd) || + ! pSfrRectEnd->AddExtLoop( Release( pCrvRectEBorder)) || + ! pSfrRectEnd->IsValid()) + return false ; + if ( AreOppositeVectorApprox( pSfrInc->GetNormVersor(), pSfrRectEnd->GetNormVersor())) + pSfrRectEnd->Invert() ; + + // 2) *** + + // Rettangolo all'inizio + Vector3d vtTanCS = vtTanS_ ; + Vector3d vtTanCE = vtTanE_ ; + PtrOwner pCrvRect_TanCLS_Border( CreateCurveComposite()) ; + if ( IsNull( pCrvRect_TanCLS_Border)) + return false ; + pCrvRect_TanCLS_Border->AddPoint( ptS) ; + pCrvRect_TanCLS_Border->AddLine( ptS + ( 1.5 * dRad + 500 * EPS_SMALL) * vtTanCS) ; + vtOut = vtTanCS ; vtOut.Rotate( Z_AX, - 90) ; + pCrvRect_TanCLS_Border->AddLine( ptS + ( 1.5 * dRad + 500 * EPS_SMALL) * vtTanCS + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRect_TanCLS_Border->AddLine( ptS + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRect_TanCLS_Border->Close() ; + PtrOwner pSfrRectCLStart( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrRectCLStart) || + ! pSfrRectCLStart->AddExtLoop( Release( pCrvRect_TanCLS_Border)) || + ! pSfrRectCLStart->IsValid()) + return false ; + if ( AreOppositeVectorApprox( pSfrInc->GetNormVersor(), pSfrRectCLStart->GetNormVersor())) + pSfrRectCLStart->Invert() ; + + // Rettangolo alla fine + PtrOwner pCrvRect_TanCLE_Border( CreateCurveComposite()) ; + if ( IsNull( pCrvRect_TanCLE_Border)) + return false ; + pCrvRect_TanCLE_Border->AddPoint( ptE) ; + pCrvRect_TanCLE_Border->AddLine( ptE + ( 1.5 * dRad + 500 * EPS_SMALL) * vtTanCE) ; + vtOut = vtTanCE ; vtOut.Rotate( Z_AX, 90) ; + pCrvRect_TanCLE_Border->AddLine( ptE + ( 1.5 * dRad + 500 * EPS_SMALL) * vtTanCE + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRect_TanCLE_Border->AddLine( ptE + ( dRad + 500 * EPS_SMALL) * vtOut) ; + pCrvRect_TanCLE_Border->Close() ; + PtrOwner pSfrRectCLEEnd( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrRectCLEEnd) || + ! pSfrRectCLEEnd->AddExtLoop( Release( pCrvRect_TanCLE_Border)) || + ! pSfrRectCLEEnd->IsValid()) + return false ; + if ( AreOppositeVectorApprox( pSfrInc->GetNormVersor(), pSfrRectCLStart->GetNormVersor())) + pSfrRectCLStart->Invert() ; + + // alla superficie di incidenza, sottraggo i due rettangoli ricavati + if ( ! pSfrInc->Subtract( *pSfrRectStart) || + ! pSfrInc->Subtract( *pSfrRectEnd)) + return false ; + + // tolgo ora i rettangoli per le tangenze ai chiusi + pSfrInc->Subtract( *pSfrRectCLStart) ; + pSfrInc->Subtract( *pSfrRectCLEEnd) ; + + return pSfrInc->IsValid() && pSfrInc->GetChunkCount() > 0 ; +} + +//---------------------------------------------------------------------------- +static bool +AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvIsland, + const double dParS, const double dParE, const Vector3d& vtTanS, + const Vector3d& vtTanE, const double dRad, const double dDiamJ, + PocketParams PockParams, ICurveComposite* pCrvBorder) +{ + /* parametri : + pCrvCompo -> curva originaria di bordo + vCrvIsland -> vettore delle isole all'interno di pCrvCompo + pCrvOpenOffs -> tratto aperto corrente già Offsettato verso l'esterno + dParS -> parametro sulla pCrvCompo per l'inizio del tratto aperto + dParE -> parametro sulla pCrvCompo per la fine del tratto aperto + vtTanS -> vettore di tangenza finale tratto chiuso precedente + vtTanE -> vettore di tangenza iniziale ( invertito ) del tratto chiuso successivo + dRad -> raggio di Offset per la regione di incidenza + dDiamJ -> ampiezza delle curve a fagiolo per estendere la regione di incidenza + pCrvRes -> curva da restituire ( inizialmente è il tratto aperto sulla pCrvCompo ; + questa curva sarà l'estensione del lato aperto, adattandosi alla geometria + dei chiusi ( non posso vedere solo i chiusi adiacenti all'aperto, devo considerare TUTTI i chiusi + della pCrvCompo + pStmVol -> Volume di svuotatura + pStm_Part -> Part corrente + */ + + // controllo la validità dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0 || + pCrvBorder == nullptr || ! pCrvBorder->IsValid() || pCrvBorder->GetCurveCount() == 0) + return false ; + + // definisco la regione di incidenza + PtrOwner pSfrInc( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrInc) || + ! CreateSurfFrIncidence( pCrvBorder, vtTanS, vtTanE, dRad + 75 * EPS_SMALL, pSfrInc)) + return false ; + + // creo un vettore con tutte le curve che potrebbero cadere, in parte, nella regione di incidenza + ICRVCOMPOPOVECTOR vCrvToCheck ; + for ( int i = 0 ; i < int( vCrvIsland.size()) ; ++ i) + vCrvToCheck.emplace_back( vCrvIsland[i]->Clone()) ; // aggiungo le isole + // se la curva originale non è tutta Aperta -> devo aggiungere anche essa nelle curve da controllare + bool bIsAllOpen = abs( abs( dParE - dParS) - pCrvCompo->GetCurveCount()) < EPS_SMALL ; + if ( ! bIsAllOpen) { + // recupero il tratto di curva prima e dopo dell'aperto corrente + PtrOwner pCompoOther( ConvertCurveToComposite( pCrvCompo->CopyParamRange( dParE, dParS))) ; + if ( IsNull( pCompoOther) || ! pCompoOther->IsValid()) + return false ; + vCrvToCheck.emplace_back( Release( pCompoOther)) ; // aggiungo il bordo + } + + // controllo se la curva è un'isola ( normale del piano -Z_AX) + bool bIsIsland = false ; + double dArea ; Plane3d plCheck ; + if ( ! pCrvCompo->GetArea( plCheck, dArea)) + return false ; + bIsIsland = AreSameVectorEpsilon( plCheck.GetVersN(), - Z_AX, 10 * EPS_SMALL) ; + + // scorro il vettore creato... + for ( int c = 0 ; c < int( vCrvToCheck.size()) ; ++ c) { + // 1) recupero la curva corrente + PtrOwner pCrvCurr( CloneCurveComposite( vCrvToCheck[c])) ; + if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid()) + return false ; + // 2) ricavo i tratti con proprietà uniformi ( Aperti/Chiusi ) + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! GetHomogeneousParts( pCrvCurr, PockParams, vpCrvs)) + return false ; + // 3) considero solo i tratti chiusi + for ( int cl = 0 ; cl < int( vpCrvs.size()) ; ++ cl) { + if ( vpCrvs[cl]->GetTempProp() == 1) + continue ; + // 4) effettuo l'Offset della curva di metà dDiamJ + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( vpCrvs[cl], - dDiamJ * 0.5 - 20 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + // 5) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti + PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; + while ( ! IsNull( pOffLongestCrv)) { + // 6) creo la regione di incidenza di tale curva ( "Curva a fagiolo") + PtrOwner pSfrBean( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrv), dDiamJ * 0.5, false, false)) ; + if ( IsNull( pSfrBean) || ! pSfrBean->IsValid()) + return false ; + // inverto se necessario + if ( AreOppositeVectorApprox( pSfrBean->GetNormVersor(), pSfrInc->GetNormVersor())) + pSfrBean->Invert() ; + // 7) se la "Regione a fagiolo" non influenza la regione di incidenza, la transcuro + bool bDiscard = true ; + for ( int cI = 0 ; cI < pSfrInc->GetChunkCount() && bDiscard ; ++ cI) + for ( int cB = 0 ; cB < pSfrBean->GetChunkCount() && bDiscard ; ++ cB) + bDiscard = ( pSfrInc->GetChunkSimpleClassification( cI, *pSfrBean, cB) != REGC_INTERS) ; + if ( ! bDiscard) { + // 8) aggiorno la regione di incidenza + if ( ! pSfrInc->Add( *pSfrBean)) + return false ; + } + pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; // passo al tratto offsettato successivo + } + } + } + + // ATTENZIONE ! + // L'algoritmo di allargamento presso i lati aperti è Euristico; io mi estendo a seconda della geometria del + // lato aperto al di fuori del volume di svuotatura... Devo controllare di non rovinare delle zone al di fuori di + // esso ! + if ( PockParams.SrfLimit.IsValid()) { + pSfrInc->Offset( 50 * EPS_SMALL, ICurve::OFF_FILLET) ; + if ( ! pSfrInc->Subtract( PockParams.SrfLimit)) + return false ; + // può capitare che la regione Limite mi crei più Chunk sulla pSfrInc + // I chunk da togliere sono tutti quelli che si sono separati dalla pCrvBorder + // NB. Il mio obiettivo è quello di avere un'unica curva con estremi i due tratti aperti estremanti + if ( pSfrInc->GetChunkCount() > 1) { // se ottengo più chunks + PtrOwner pNewSfrInc( CreateSurfFlatRegion()) ; + if ( IsNull( pNewSfrInc)) + return false ; + // ricavo i punti iniziali e finali della curva di bordo + Point3d ptS, ptE ; + if ( ! pCrvBorder->GetStartPoint( ptS) || ! pCrvBorder->GetEndPoint( ptE)) + return false ; + // per ogni Chunk ( > 1 ) + for ( int i = 0 ; i < pSfrInc->GetChunkCount() ; ++ i) { + // bordo esterno + PtrOwner pCrvEL( ConvertCurveToComposite( pSfrInc->GetLoop( i, 0))) ; + if ( IsNull( pCrvEL) || ! pCrvEL->IsValid()) + return false ; + // se estremi in comune, la curva cercata è la seguente + if ( pCrvEL->IsPointOn( ptS, 300 * EPS_SMALL) && pCrvEL->IsPointOn( ptE, 300 * EPS_SMALL)) { + if ( ! pNewSfrInc->IsValid()) // se la nuova regione di incidenza è vuota... + pNewSfrInc.Set( pSfrInc->CloneChunk( i)) ; // aggiorno... + else // se la nuova regione di incidenza non è vuota... + if ( ! pNewSfrInc->Add( * pSfrInc->CloneChunk( i))) // aggiungo... + return false ; + } + } + // definisco quindi la nuova regione di incidenza + if ( ! pNewSfrInc->IsValid()) + return false ; + pSfrInc.Set( Release( pNewSfrInc)) ; + } + } + + // dalla regione di incidenza devo estrarre il tratto di bordo che ha per estremi i lati chiusi + // ( stando al di fuori, quindi estendendomi all'esterno, della regione da svuotare ) + PtrOwner pCrvNewBorder( ConvertCurveToComposite( pSfrInc->GetLoop( 0, 0))) ; + if ( IsNull( pCrvNewBorder) || ! pCrvNewBorder->IsValid()) + return false ; + // imposto la curva come tutta aperta + for ( int u = 0 ; u < pCrvNewBorder->GetCurveCount() ; ++ u) + pCrvNewBorder->SetCurveTempProp( u, 1, 0) ; + + // se la curva originale era tutta aperta... ( il nuovo lato è il loop esterno della regione di incidenza) + if ( bIsAllOpen) { + // pulisco la curva originale + pCrvBorder->Clear() ; + if ( bIsIsland) { // se isola inserisco il loop interno della regione + pCrvNewBorder.Set( ConvertCurveToComposite( pSfrInc->GetLoop( 0, 1))) ; + if ( IsNull( pCrvNewBorder) || ! pCrvNewBorder->IsValid()) + return false ; + // imposto la curva come tutta aperta ( gira come girava già l'isola) + for ( int u = 0 ; u < pCrvNewBorder->GetCurveCount() ; ++ u) + pCrvNewBorder->SetCurveTempProp( u, 1, 0) ; + } + // se bordo esterno inserisco il bordo esterno + return pCrvBorder->AddCurve( Release( pCrvNewBorder)) ; + } + + // altrimenti la spezzo il loop della regione di incidenza nei punti iniziali e finali della curva aperta originale + Point3d ptStart ; pCrvBorder->GetStartPoint( ptStart) ; + Point3d ptEnd ; pCrvBorder->GetEndPoint( ptEnd) ; + double dUTrimS = -1 ; double dUTrimE = -1 ; + pCrvNewBorder->GetParamAtPoint( ptStart, dUTrimS, 10000 * EPS_SMALL) ; + pCrvNewBorder->GetParamAtPoint( ptEnd, dUTrimE, 10000 * EPS_SMALL) ; + + // pulisco la curva originale + pCrvBorder->Clear() ; + if ( ! pCrvBorder->AddCurve( pCrvNewBorder->CopyParamRange( dUTrimS, dUTrimE)) || + ! pCrvBorder->IsValid()) { + // se la curva non originaria di lato aperto non era chiusa... + if ( ! pCrvBorder->IsClosed() && pCrvNewBorder->IsClosed()) { + // cerco il punto più vicino al ptStart del chiuso sulla nuova curva di bordo aperta + Point3d ptMinDist ; + int nFlag ; + if ( ! DistPointCurve( ptStart, *pCrvNewBorder).GetMinDistPoint( EPS_SMALL, ptMinDist, nFlag)) + return false ; + // cambio il punto iniziale della border in ptMinDist + double dUTmp ; + if ( ! pCrvNewBorder->GetParamAtPoint( ptMinDist, dUTmp) || + ! pCrvNewBorder->ChangeStartPoint( dUTmp)) + return false ; + // cerco il punto più vicino al ptEnd del chiuso sulla curva di bordo aperta + if ( ! DistPointCurve( ptEnd, *pCrvNewBorder).GetMinDistPoint( EPS_SMALL, ptMinDist, nFlag)) + return false ; + // ricavo il parametro sulla curva + if ( ! pCrvNewBorder->GetParamAtPoint( ptMinDist, dUTmp)) + return false ; + if ( dUTmp < EPS_SMALL) + dUTmp = pCrvNewBorder->GetCurveCount() - 5 * EPS_SMALL ; + // copio la curva tra questi due parametri + PtrOwner pCrvTmp( ConvertCurveToComposite( pCrvNewBorder->CopyParamRange( 0., dUTmp))) ; + if ( IsNull( pCrvTmp) || ! pCrvTmp->IsValid()) + return false ; + // raccordo con il chiuso mediante due tratto lineare + pCrvTmp->AddLine( ptStart, false) ; + pCrvTmp->AddLine( ptEnd, true) ; + // restituisco + pCrvBorder->CopyFrom( pCrvTmp) ; + return true ; + } + pCrvBorder->CopyFrom( pCrvCompo) ; + } + + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvIsl, const double dDiam, + const double dOffR, const double dStep, PocketParams PockParams) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // raggio di riferimento per offset + double dOutEdge = 0.5 * dDiam ; + if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_ZIGZAG) + dOutEdge = max( dOutEdge, dDiam - dStep) ; + double dRad = dOutEdge + dOffR ; + if ( abs( PockParams.dOpenEdgeRad) > 0 && PockParams.dOpenEdgeRad < dRad) + dRad = PockParams.dOpenEdgeRad ; + + // ricavo i tratti omogenei + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! GetHomogeneousParts( pCrvCompo, PockParams, vpCrvs)) + return false ; + // NB. Il primo tratto è la prima metà del tratto aperto più lungo ( se esiste ) + + // Offset esterno per CurveJ + double dDiamJ = 1.05 * ( dDiam) + 2 * dOffR ; + if ( abs( PockParams.dOpenEdgeRad) > 0) + dDiamJ = 100 * EPS_SMALL ; + // NB. 1.05 serve per eccedere leggermente, in modo che il contro-offset della prima curva di svuotatura presenti + // dei piccoli archi tra i chiusi e gli aperti ( in modo da svuotare bene lungo il chiuso) + + // curva finale da restituire + PtrOwner pCrvCompo_final( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo_final)) + return false ; + + // parametro iniziale del tratto corrente, sulla curva originale + double dParS = 0. ; + // scorro tutti i tratti omogenei nel vettore + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + // recupero la proprietà della curva composita + int nCurrTmpProp = vpCrvs[i]->GetTempProp() ; + // aggiorno i parametri del lato aperto corrente sulla curva originale + double dParE = dParS + 1. * vpCrvs[i]->GetCurveCount() ; + // se aperta + if ( nCurrTmpProp == 1) { + // ricavo la tangenze dei lati chiusi agli estremi di questa curva + Vector3d vtTanS = V_INVALID ; + Vector3d vtTanE = V_INVALID ; + if ( i != 0) { + if ( ! vpCrvs[i-1]->GetEndDir( vtTanS) || // tangente finale del chiuso precedente + ! vpCrvs[( i + 1) % int( vpCrvs.size())]->GetStartDir( vtTanE)) // tangente iniziale del chiuso successivo... + return false ; + vtTanE.Invert() ; // invertita + } + if ( ! AdjustOpenEdge( pCrvCompo, vCrvIsl, dParS, dParE, vtTanS, vtTanE, dRad, dDiamJ, PockParams, vpCrvs[i])) + return false ; + } + // assegno le proprietà di lato Aperto/Chiuso per la curva corrente + for ( int u = 0 ; u < vpCrvs[i]->GetCurveCount() ; ++ u) + vpCrvs[i]->SetCurveTempProp( u, nCurrTmpProp, 0) ; + // aggiungo la curva ricavata ( se chiusa -> la copio, se aperta -> copio l'estesa) + if ( ! pCrvCompo_final->AddCurve( vpCrvs[i]->Clone())) { + // per sicurezza, se gli estremi non coincidono, creo un piccolo raccordo lineare + Point3d ptH ; vpCrvs[i]->GetStartPoint( ptH) ; + if ( ! pCrvCompo_final->AddLine( ptH) || + ! pCrvCompo_final->SetCurveTempProp( pCrvCompo_final->GetCurveCount() - 1, 1, 0) || + ! pCrvCompo_final->AddCurve( vpCrvs[i]->Clone())) + return false ; + } + // aggiorno + dParS = dParE ; + } + // non dovrebbe esserci un gap, ma meglio prevenire problemi + pCrvCompo_final->Close() ; + // sostituisco + pCrvCompo->Clear() ; + pCrvCompo->CopyFrom( pCrvCompo_final) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CheckForRemovingIsland( const ICurveComposite* pCrvIslandBorder, double dOffs, bool bRemove) +{ + // controllo dei parametri + // NB. La curva dell'isola gira in senso orario, quindi l'offset va fatto in positivo + if ( pCrvIslandBorder == nullptr || ! pCrvIslandBorder->IsValid() || dOffs < EPS_SMALL) + return false ; + bRemove = false ; + + // controllo se l'isola è tutta aperta + for ( int u = 0 ; u < pCrvIslandBorder->GetCurveCount() ; ++ u) { + const ICurve* pCrv_u = pCrvIslandBorder->GetCurve( u) ; + if ( pCrv_u == nullptr) + return false ; + int nTmpProp0 = pCrv_u->GetTempProp( 0) ; + // se trovo una sottocurva che non è aperta, esco + if ( nTmpProp0 != 1) + return true ; + } + + // tutte le curva sono aperte, effettuo un offset per vedere se l'isola è da tenere + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCrvIslandBorder, dOffs, ICurve::OFF_FILLET)) + return false ; + + // nel caso l'Offset sparisca, all'ora l'isola non è necessaria + if ( OffsCrv.GetCurveCount() == 0) + bRemove = true ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams PockParams) +{ + // controllo parametri : + if ( pSfr == nullptr || ! pSfr->IsValid()) + return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati + + // 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 ; + + // per ogni Chunck della superificie ottenuta... + for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) { + + // vettore delle isole che userò ( le isole aperte piccole sono trascurate) + ICRVCOMPOPOVECTOR vCrvToTIsland ; + // Flag per sapere se c'è stata almeno una modifica in un loop + bool bIsChunkModified = false ; + + // 1) ricavo il Loop esterno + PtrOwner pCrvEL( ConvertCurveToComposite( pSfr->GetLoop( c, 0))) ; + if ( IsNull( pCrvEL) || ! pCrvEL->IsValid()) + return false ; + + // 2) creo un vettore di curve con le isole del Chunk + ICRVCOMPOPOVECTOR vCrvIsl ; + for ( int l = 1 ; l < pSfr->GetLoopCount( c) ; ++ l) { + PtrOwner pCrvIL( ConvertCurveToComposite( pSfr->GetLoop( c, l))) ; + if ( IsNull( pCrvIL) || ! pCrvIL->IsValid()) + return false ; + vCrvIsl.emplace_back( Release( pCrvIL)) ; + } + + // 3) se la curva esterna presenta dei lati aperti -> devo modificarla + bool bSomeOpen = false ; + int nProp0 = -1 ; + for ( int u = 0 ; u < pCrvEL->GetCurveCount() && ! bSomeOpen ; ++ u) + if ( pCrvEL->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) + bSomeOpen = true ; + if ( bSomeOpen) { // se trovo dei lati aperti + // 3.1) sistemo la superificie + if ( ! AdjustContourWithOpenEdges( pCrvEL, vCrvIsl, PockParams.dRad_prec > 0 ? 2 * PockParams.dRadialOffset_prec : 2 * PockParams.dRad, + PockParams.dRadialOffset_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset, + PockParams.dRad_prec > 0 ? PockParams.dSideStep_prec : PockParams.dSideStep, + PockParams)) + return false ; + bIsChunkModified = true ; // la curva è stata modificata + } + + // 4) Controllo i bordi delle isole ottenute + // NB. L'isola può essere tutta aperta o tutta chiusa ( se non uniforme, passo a tutta chiusa ) + // La definizione di isola con proprietà non uniformi non è definita... + for ( int i = 0 ; i < int( vCrvIsl.size()) ; ++ i) { + // controllo uniformità + int nCurrTmpProp = -1 ; + int nPrecTmpProp = -1 ; + bool bIsMixed = false ; + PtrOwner pCrvIsl( ConvertCurveToComposite( vCrvIsl[i]->Clone())) ; + 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 + if ( bIsMixed) { + for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) + pCrvIsl->SetTempProp( u, 0) ; + nCurrTmpProp = 0 ; // aggiorno il Flag + bIsChunkModified = true ; // la curva è stata modificata + } + // se curva tutta aperta, controllo se l'isola può essere trascurata + if ( nCurrTmpProp == 1) { + bool bRemove = false ; + if ( ! CheckForRemovingIsland( pCrvIsl, PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec + PockParams.dRadialOffset_prec : 2 * PockParams.dRad, + bRemove)) + return false ; + if ( bRemove) + continue ; + } + for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) + pCrvIsl->SetCurveTempProp( u, 0, 0) ; // lascio tutto chiuso, ho già esteso + vCrvToTIsland.emplace_back( pCrvIsl->Clone()) ; // entra nelle curve della regione da svuotare + } + + // 6) Se c'è stata almeno una modifica di lato aperto al chunk (c-esimo), devo ricreare il Chunk + // nuovi loop ricavati ( Chunk dopo Chunk creo la superficie finale) + if ( bIsChunkModified) { + + SurfFlatRegionByContours SfrBC ; // per sicurezza analizzo ancora i Loop + pCrvEL->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + SfrBC.AddCurve( Release( pCrvEL)) ; // <--- Loop esterno + for ( int i = 0 ; i < ( int)vCrvToTIsland.size() ; ++ i) { + vCrvToTIsland[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + SfrBC.AddCurve( Release( vCrvToTIsland[i])) ; // <--- isole "valide" + } + + // ricavo il nuovo Chunk + PtrOwner pNewChunk( SfrBC.GetSurf()) ; + if ( IsNull( pNewChunk) || ! pNewChunk->IsValid()) + return false ; + + // aggiungo il Chunk alla superficie finale + if ( pSrfFinal->GetChunkCount() == 0) + pSrfFinal.Set( pNewChunk) ; + else + if ( ! pSrfFinal->Add( *pNewChunk)) + return false ; + } + // se il Chunk c-esimo non è mai stato modificato... + else { + // aggiungo il Chunk alla superficie finale + if ( pSrfFinal->GetChunkCount() == 0) + pSrfFinal.Set( pSfr->CloneChunk( c)) ; + else + if ( ! pSrfFinal->Add( *pSfr->CloneChunk( c))) + return false ; + } + } + + // restituisco la superficie aggiornata ricavata + if ( ! pSrfFinal->IsValid()) + return false ; + pSfr->Clear() ; + pSfr->CopyFrom( pSrfFinal) ; + + return pSrfFinal->IsValid() && pSrfFinal->GetChunkCount() > 0 ; + +} + +// *************************************************************************** +// ------------- SCELTA DEL PUNTO INIZIALE ----------------------------------- +// *************************************************************************** +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +static bool +GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOtherCrv, + const Frame3d& frPocket, PocketParams PockParams, Point3d& ptMid, Vector3d& vtMidOrt) +{ + // recupero il vettore estrusione + Vector3d vtExtr = Z_AX ; + pCompo->GetExtrusion( vtExtr) ; + // verifico se tutti i lati sono aperti + bool bAllOpen = true ; + const ICurve* pMyCrv = pCompo->GetFirstCurve() ; + while ( pMyCrv != nullptr) { + if ( pMyCrv->GetTempProp() != 1) { + bAllOpen = false ; + break ; + } + pMyCrv = pCompo->GetNextCurve() ; + } + // salvo il punto iniziale e la direzione d'uscita del primo lato aperto valido che trovo + // NB. Il primo valido non significa il migliore, potrebbe infatti essere il lato aperto più lungo + // ma essere all'interno del grezzo... cerco di dare priorità ai lati sul grezzo + + // flag per la presenza di un primo lato aperto valido per entrare + bool bFirstOpenValid = false ; + Point3d ptFirstOpenValid = P_INVALID ; + Vector3d vtFirstOpenValid = V_INVALID ; + // richiedo lunghezza superiore a diametro utensile più doppio offset radiale + double dRefLen = ( bAllOpen ? 0 : ( 2 * PockParams.dRad) + 2 * PockParams.dRadialOffset - EPS_SMALL) ; + double dMaxLen = dRefLen ; + // ciclo sulle singole curve + bool bFound = false ; + const ICurve* pPrevCrv = pCompo->GetLastCurve() ; + double dLenPrev = 0 ; + if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) + pPrevCrv->GetLength( dLenPrev) ; + const ICurve* pCrv = pCompo->GetFirstCurve() ; + int nPriorityOpenEdge = -1 ; + while ( pCrv != nullptr) { + // analizzo la curva successiva + const ICurve* pNextCrv = pCompo->GetNextCurve() ; + bool bNextOk = ( pNextCrv != nullptr) ; + if ( ! bNextOk) + pNextCrv = pCompo->GetFirstCurve() ; + double dLenNext = 0 ; + if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) + pNextCrv->GetLength( dLenNext) ; + ++ nPriorityOpenEdge ; + // verifico la curva corrente + if ( pCrv->GetTempProp() == 1) { + // contributo dalle entità adiacenti (se non tutte aperte) + double dLenAgg = 0 ; + if ( ! bAllOpen) { + if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) { + Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ; + Vector3d vtStart ; pCrv->GetStartDir( vtStart) ; + dLenAgg += max( 0.4, vtPrevEnd * vtStart) * dLenPrev ; + } + if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) { + Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ; + Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ; + dLenAgg += max( 0.4, vtEnd * vtNextStart) * dLenNext ; + } + } + // entità corrente + double dLen = 0 ; + if ( pCrv->GetLength( dLen)) { + const double LEN_TOL = 1 ; + // se di lunghezza praticamente uguale + if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) { + Point3d ptTest ; + pCrv->GetMidPoint( ptTest) ; + if (( PockParams.bAboveHead && ptTest.z > ptMid.z + 100 * EPS_SMALL) || + ( ! PockParams.bAboveHead && ptTest.z < ptMid.z - 100 * EPS_SMALL) || + ( abs( ptTest.z - ptMid.z) < 100 * EPS_SMALL && ptTest.y < ptMid.y - 100 * EPS_SMALL)) { + dMaxLen = max( dMaxLen, dLen + dLenAgg) ; + ptMid = ptTest ; + // vettore ortogonale verso l'esterno (ruotato -90deg attorno a estrusione) + pCrv->GetMidDir( vtMidOrt) ; + vtMidOrt.Rotate( vtExtr, 0, -1) ; + } + } + // se più lunga ( o non già trovata) + else if ( dLen + dLenAgg > dMaxLen || !bFound) { + dMaxLen = dLen + dLenAgg ; + double dParIn ; + // cerco il parametro di tale curva (0 < dParIn < 1) migliore per l'entrata + if ( GetParamForPtStartOnEdge( pCrv, pCompo, vOtherCrv, PockParams, dParIn)) { + pCrv->GetPointD1D2( dParIn, ICurve::FROM_PLUS, ptMid) ; + PtrOwner pCompoClone( CloneCurveComposite( pCompo)) ; + if ( IsNull( pCompoClone)) + return false ; + double dU ; + pCompoClone->GetParamAtPoint( ptMid, dU) ; + pCompoClone->ChangeStartPoint( dU) ; + pCompoClone->GetStartDir( vtMidOrt) ; + vtMidOrt.Rotate( vtExtr, 0, -1) ; + // salvo l'indice di questo lato aperto se si tratta del primo valido + if ( ! bFirstOpenValid) { + bFirstOpenValid = true ; + ptFirstOpenValid = ptMid ; + vtFirstOpenValid = vtMidOrt ; + } + // controllo se questa quantità è effettivamente fuori dal grezzo + // ( privilegio i lati aperti che sono effettivamente sul bordo del grezzo) + // punto iniziale nel sistema di riferimento globale + Point3d ptStart ; pCompoClone->GetStartPoint( ptStart) ; + ptStart.ToGlob( frPocket) ; + // vettore d'uscita nel sistema di riferimento globale + Vector3d vtMidOut = vtMidOrt ; + vtMidOut.ToGlob( frPocket) ; + // ricavo la SafeZ + double dSafeZ = PockParams.dSafeZ ; + Point3d ptOut = ptStart + vtMidOut * ( PockParams.dRad + PockParams.dRadialOffset + + ( PockParams.dRad + max( dSafeZ, PockParams.dOpenMinSafe))) ; + // controllo l'elevazione sopra a quel punto ( qui è un bel mistero...) + // double dElev = 0. ; + // if ( ! GetElevation( m_nPhase, ptOut, frPocket.VersZ(), m_TParams.m_dDiam, m_TParams.m_dLen, + // frPocket.VersZ(), dElev)) + // return false ; + // se non vi è elevazione, il lato aperto trovato è il privilegiato + //if ( dElev < EPS_SMALL) { + // bFound = true ; + // if ( nPriorityOpenEdge > -1) + // return true ; + //} + } + } + dLenPrev = dLen ; + } + } + else + dLenPrev = 0 ; + // vado alla successiva + pPrevCrv = pCrv ; + pCrv = ( bNextOk ? pNextCrv : nullptr) ; + } + + // se non ho trovato un lato aperto valido fuori dal grezzo, ma ho trovato un lato aperto + // generico accettabile + if ( ! bFound && bFirstOpenValid) { + ptMid = ptFirstOpenValid ; + vtMidOrt = vtFirstOpenValid ; + bFound = true ; + } + + return bFound ; +} + +//---------------------------------------------------------------------------- +static bool +SetSpecialPtStartForOpenEdges( const ICurveComposite* pCrvOrig, const Frame3d& frPocket, + PocketParams PockParams, ICurveComposite* pCrvCompo, Point3d& ptStart, + Vector3d& vtMidOut, bool& bMidOut) +{ + // controllo dei parametri + if ( pCrvOrig == nullptr || ! pCrvOrig->IsValid() || + ! frPocket.IsValid() || + pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // cerco il lato aperto più lungo + double dLenRef = ( 2 * PockParams.dRad) - 50 * EPS_SMALL ; + for ( int u = 0 ; u < pCrvOrig->GetCurveCount() ; ++ u) { + if ( pCrvOrig->GetCurve( u)->GetTempProp( 0) == 0) + continue ; // escludo le chiuse + // ricavo la curva u-esima aperta + const ICurve* pCrvOpen = pCrvOrig->GetCurve( u) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + // ricavo la lunghezza di tale curva + double dLen = 0. ; + pCrvOpen->GetLength( dLen) ; + if ( dLen > dLenRef) { + Point3d ptSTmp ; + Vector3d vtMidOutTmp ; + if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) { + int nFlag ; + if ( DistPointCurve( ptSTmp, *pCrvCompo).GetMinDistPoint( EPS_SMALL, ptStart, nFlag)) { + vtMidOutTmp.Normalize() ; + vtMidOutTmp.Rotate( Z_AX, - 90) ; + vtMidOut = vtMidOutTmp ; + bMidOut = true ; + } + } + } + } + return bMidOut ; +} + +//---------------------------------------------------------------------------- +static bool +SetPtStartForPath( ICurveComposite* pCrvOffsAct, PocketParams PockParams, const ISurfFlatRegion* pSrfToWork, + const Point3d& ptEndPrec, const Frame3d& frPocket, Point3d& ptStart, + Vector3d& vtMidOut, bool& bMidOut, int nOffs, ICurveComposite* pCrvOrig) +{ + // ============================= INFO ============================================================== + // pCrvOffsAct -> Curva di Offset su cui cercare ptStart, vtMidOut, bMidOpen + // pSrfToWork -> Superificie originaria da lavorare + // ( questa superificie ha i flag di lati aperti/chiusi settati nei loops) + // ================================================================================================= + + // controllo dei parametri + if ( pCrvOffsAct == nullptr || ! pCrvOffsAct->IsValid() || pCrvOffsAct->GetCurveCount() == 0 || + pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) + return false ; + + // clono le curva su cui devo entrare + PtrOwner pCrv( CloneCurveComposite( pCrvOffsAct)) ; + if ( IsNull( pCrv)) + return false ; + + bool bSomeOpen = false ; // flag per presenza di lati aperti + + // creo un vettore di Loops della superificie, ordinati + ICRVCOMPOPOVECTOR vCrvLoops ; + for ( int l = 0 ; l < pSrfToWork->GetLoopCount( 0) ; ++ l) + vCrvLoops.emplace_back( ConvertCurveToComposite( pSrfToWork->GetLoop( 0, l))) ; + + // creo un vettore di indici. Questi indici si riferiscono alle posizioni di vCrvLoops i quali offset + // hanno generato delle curve sulla pCrv ( curva da cui devo entrare ) + INTVECTOR vIndex ; + int nInd = -1 ; // indice della prima curva che non è "raccordo" di Offset + + // scorro tutte le curve presenti in pCrv ( curva da cui devo entrare) + for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) { + + // nProp0 -> #curva il cui Offset ha generato la curva i-esima di pCrv + int nProp0 ; pCrv->GetCurveTempProp( i, nProp0, 0) ; + // nProp1 -> #loop che contiene la curva espressa in nProp0 + int nProp1 ; pCrv->GetCurveTempProp( i, nProp1, 1) ; + + if ( nProp0 > 0) { // se questa curva non è un "raccordo" di Offset + // controllo per maggiore sicurezza che effettivamente nProp1 sia un indice valido per il vettore dei Loops e + // che nProp0 non sia maggiore del numero di curve del loop nProp1-esimo del vettore dei Loops della pSrfToWork + if ( nProp1 >= 0 && nProp1 < int( vCrvLoops.size()) && nProp0 < vCrvLoops[nProp1]->GetCurveCount()) { + // aggiorno il vettore di indici ... + if ( find( vIndex.begin(), vIndex.end(), nProp1) == vIndex.end()) + vIndex.push_back( nProp1) ; + // aggiorno la proprietà della curva da cui devo entrare + int nTempProp ; vCrvLoops[nProp1]->GetCurveTempProp( nProp0 - 1, nTempProp, 0) ; + pCrv->SetCurveTempProp( i, nTempProp, 0) ; + // se la curva è aperta, aggiorno il Flag + if ( nTempProp == 1 && ! bSomeOpen) + bSomeOpen = true ; + // salvo l'indice della prima curva trovata che non è un "raccordo" di Offset + if ( nInd == -1) + nInd = i ; + } + else + pCrv->SetCurveTempProp( i, 0, 0) ; + } + else { + pCrv->SetCurveTempProp( i, -2, 0) ; + pCrv->SetCurveTempProp( i, -2, 1) ; + } + } + + // scorro tutte le curve incerte ( che derivano da raccordi ) + if ( nInd != -1) + pCrv->ChangeStartPoint( nInd) ; // la prima curva non è un "raccordo" di Offset + + + for ( int i = 1 ; i < pCrv->GetCurveCount() ; ++ i) { + double dLen = 0. ; + if ( pCrv->GetCurve( i)->GetLength( dLen) && dLen < 0.025 * ( 2 * PockParams.dRad)) + pCrv->SetCurveTempProp( i, 0, 0) ; + else { + int nTmpProp0, nTmpProp1 ; + if (( pCrv->GetCurveTempProp( i, nTmpProp0, 0) && nTmpProp0 == -2) && + ( pCrv->GetCurveTempProp( i, nTmpProp1, 1) && nTmpProp1 == -2)) { + // copio la temp prop della curva precedente + pCrv->SetCurveTempProp( i, pCrv->GetCurve( i-1)->GetTempProp(), 0) ; + // se troppo corta, allora chiusa + if ( pCrv->GetCurve( i)->GetLength( dLen) && dLen < 0.01 * ( 2 * PockParams.dRad)) + pCrv->SetCurveTempProp( i, 0, 0) ; + } + } + } + + // se ho dei lati aperti... + double dLenMax = EPS_SMALL ; + int nCrvForMax = 0 ; + if ( bSomeOpen) { + // ... e sono al primo Step, cerco la curva Aperta più lunga ( scelgo la prima che trovo) ... + if ( ! ptEndPrec.IsValid()) { + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + int nTmpProp = 0 ; + double dLenAct = EPS_SMALL ; + if ( pCrv->GetCurveTempProp( u, nTmpProp, 0) && nTmpProp == 1 && + pCrv->GetCurve( u)->GetLength( dLenAct) && dLenAct > dLenMax) { + dLenMax = dLenAct ; + nCrvForMax = u ; + } + } + // il punto iniziale della curva sarà il punto iniziale della sottocurva trovata + pCrv->ChangeStartPoint( nCrvForMax) ; + } + // ... se invece non sono al primo Step, cerco la prima curva aperta più vicina al punto finale + else { + int nIndClosesOpenCrv = -1 ; + double dMinDist = INFINITO ; + for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { + if ( pCrv->GetCurve( u)->GetTempProp( 0) == 1) { + DistPointCurve DPC( ptEndPrec, *pCrv->GetCurve( u)) ; + double dCurrDist = INFINITO ; + if ( DPC.GetDist( dCurrDist) && dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nIndClosesOpenCrv = u ; + } + } + } + // il punto iniziale della curva sarà il punto iniziale della sottocurva trovata + pCrv->ChangeStartPoint( nIndClosesOpenCrv) ; + } + } + + // creo un vettore con tutti i Loops della pSwfToWork per i quali, mediante l'Offset, non hanno + // generato alcuna curva presente nella pCrv ( quella da cui devo entrare) + ICRVCOMPOPOVECTOR vOtherCrv ; + for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { + bool bOk = true ; + for ( int j = 0 ; j < int( vIndex.size()) && bOk ; ++ j) { + if ( i == vIndex[j]) + bOk = false ; + } + if ( bOk) + vOtherCrv.emplace_back( ConvertCurveToComposite( vCrvLoops[i]->Clone())) ; + } + + // cerchiamo un punto valido per l'entrata ... + bMidOut = false ; + if ( bSomeOpen) { // se ho dei lati aperti, cerco un parametro ideale per entrare + bool bOK = false ; + if ( nOffs == 1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { + // in questo caso le curve a fagiolo dei lati aperti a sinistra e a destra potrebbero + // intersecarsi tra loro -> risulta difficile calcolare il versore direzione d'uscita + bOK = SetSpecialPtStartForOpenEdges( pCrvOrig, frPocket, PockParams, pCrvOffsAct, ptStart, vtMidOut, bMidOut) ; + } + if ( ! bOK) + bMidOut = GetParamOnOpenSide( pCrv, vOtherCrv, frPocket, PockParams, ptStart, vtMidOut) ; + } + if ( bMidOut) { // se ho trovato e valido, allora imposto il punto inziale trovato + const double LEN_OUT = 5 ; + double dPar ; int nFlag ; + bMidOut = ( DistPointCurve( ptStart + LEN_OUT * vtMidOut, *pCrv).GetParamAtMinDistPoint( 0, dPar, nFlag) + && pCrv->ChangeStartPoint( dPar)) ; + } + if ( ! bMidOut) // alla peggio, ordino i lati lunghi per lunghezza e cerco un'entrata valida + AdjustContourStart( pCrv, PockParams, vOtherCrv, true, ptEndPrec) ; + + // ora che ho deciso quale sia il punto iniziale, lo imposto effettivamente sulla curva di Offset passata alla funzione + pCrv->GetStartPoint( ptStart) ; + pCrvOffsAct->Clear() ; + pCrvOffsAct->CopyFrom( pCrv) ; + + return true ; +} + +// *************************************************************************** +//---------------------------- CASI OTTIMIZZATI ------------------------------ +// *************************************************************************** + +//---------------------------------------------------------------------------- +static bool +GetOptCrvIndex( const ICRVCOMPOPOVECTOR& vCrvOEWithFlags, ISurfFlatRegion* pSrfChunkFinal, + int& nIndex) +{ + // controllo dei parametri + if ( int( vCrvOEWithFlags.size()) == 0 || pSrfChunkFinal == nullptr || ! pSrfChunkFinal->IsValid()) + return false ; + + // cerco la curva originale del chunk (cc)-esimo ( per casi ottimizzati) + if ( int( vCrvOEWithFlags.size()) == 1) + nIndex = 0 ; + else { + for ( int k = 0 ; k < ( int)vCrvOEWithFlags.size() ; ++k) { + CRVCVECTOR ccClass ; + if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[k], EPS_SMALL, ccClass)) { + bool bIsThis = true ; + for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++kk) { + if ( ccClass[kk].nClass == CRVC_OUT) + bIsThis = false ; + } + if ( bIsThis) { + nIndex = k ; + break ; + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +OptimizedSpiralCirle( const ICurveComposite* pCrvCompo, const double dToll, double& dRad, + Point3d& ptC, bool& bIsCirlce) +{ + /* restituisce il centro e il raggio di una circonfereza che approssima pCrvCompo */ + + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || dToll < EPS_SMALL) + return false ; + dRad = 0. ; + ptC = P_INVALID ; + bIsCirlce = false ; + + // se aperta, non è un cerchio e non è piana, esco + Plane3d plPock ; + if ( ! pCrvCompo->IsClosed() || ! pCrvCompo->IsFlat( plPock)) + return true ; + + // creo un sistema di riferimento centrato sulla curva + Point3d ptCentroid ; + Vector3d vtN ; + Frame3d frCurr ; + if ( ! pCrvCompo->GetCentroid( ptCentroid) || + ! pCrvCompo->GetExtrusion( vtN) || + ! frCurr.Set( ptCentroid, vtN) || + ! frCurr.IsValid()) + return false ; + + // porto la curva nel sistema di riferimento corrente ( dopo averla clonata) + PtrOwner pCrvLoc( CloneCurveComposite( pCrvCompo)) ; + if ( IsNull( pCrvLoc) || ! pCrvLoc->IsValid() || ! pCrvLoc->ToLoc( frCurr)) + return false ; + + // approssimo la curva locale con una PolyLine + PolyLine pL ; + if ( ! pCrvLoc->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, pL) || + pL.GetPointNbr() == 0) + return false ; + + // salvo i punti ottenuti ( il punto finale sarà contenuto due volte) + PNTVECTOR vPts ; + Point3d ptNext ; + pL.GetFirstPoint( ptNext) ; + vPts.push_back( ptNext) ; + while ( pL.GetNextPoint( ptNext)) { + vPts.push_back( Media( vPts.back(), ptNext)) ; // inserisco il punto medio + vPts.push_back( ptNext) ; // inserisco il punto successivo + } + + // per ogni coppia di punti calcolo la distanza massima e minima dal centro del cerchio locale ( ORIG) + double dMaxDist = 0. ; + double dMinDist = INFINITO ; + for ( int i = 0 ; i < int( floor( 0.5 * int( vPts.size()))) ; i = i + 2) { + PtrOwner pSeg( CreateCurveLine()) ; + if ( IsNull( pSeg) || ! pSeg->Set( vPts[i], vPts[i+1])) + return false ; + DistPointCurve DPC( ORIG, *pSeg) ; + double dCurrDist = 0. ; + if ( DPC.GetDist( dCurrDist) && dCurrDist < dMinDist) + dMinDist = dCurrDist ; + dCurrDist = Dist( ORIG, vPts[i]) ; + if ( dCurrDist > dMaxDist) + dMaxDist = dCurrDist ; + } + + // controllo se la distanza tra minima e massima sono simili ( in base alla tolleranza) + if ( abs( dMaxDist - dMinDist) > dToll) + return true ; + + // imposto i parametri per la circonferenza + dRad = 0.5 * ( dMaxDist + dMinDist) ; + ptC = ptCentroid ; + bIsCirlce = true ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad, + PocketParams PockParams, ICurveComposite* pMCrv, ICurveComposite* pRCrv) +{ + /* calcola il percorso di a spirale assieme al percorso di ritorno */ + + // raggio della circonferenza esterna + if ( dOutRad < 10 * EPS_SMALL) + return false ; + + // imposto versore estrusione sulle curve composite + pMCrv->SetExtrusion( vtN) ; + pRCrv->SetExtrusion( vtN) ; + + // creo e inserisco la circonferenza esterna + PtrOwner pArc( CreateCurveArc()) ; + if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dOutRad)) + return false ; + + // creo la superificie per la Feed + PtrOwner pSrfRemoved( CreateSurfFlatRegion()) ; + if ( IsNull( pSrfRemoved)) + return false ; + ICRVCOMPOPOVECTOR vLinksDone ; + + Vector3d vtDir = pArc->GetStartVersor() ; + pMCrv->AddCurve( Release( pArc)) ; + + // se richiesta percorrenza invertita + if ( PockParams.bInvert) + pMCrv->Invert() ; + + // se raggio esterno maggiore dell'interno + if ( dOutRad > dIntRad + 10 * EPS_SMALL) { + + // aggiungo le semicirconferenze della spirale ( devono essere in numero dispari) + int nStep = int( ceil( ( dOutRad - dIntRad) / ( 0.5 * PockParams.dSideStep))) ; + if ( nStep % 2 == 0) + nStep += 1 ; + double dStep = ( dOutRad - dIntRad) / nStep ; + for ( int i = 1 ; i <= nStep ; ++ i) { + if ( ! ( i % 2 == 0)) + pMCrv->AddArcTg( ptCen - vtDir * ( dOutRad - i * dStep)) ; + else + pMCrv->AddArcTg( ptCen + vtDir * ( dOutRad - i * dStep)) ; + } + + // aggiungo la circonferenza interna + pMCrv->AddArcTg( ptCen + vtDir * dIntRad) ; + pMCrv->AddArcTg( ptCen - vtDir * dIntRad) ; + } + + // verifico il percorso di lavoro + if ( pMCrv->GetCurveCount() == 0) + return false ; + + // calcolo l'eventuale percorso di ritorno + Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; + Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; + Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ; + if ( ! AreSamePointApprox( ptStart, ptEnd)) { + PtrOwner pArc2( CreateCurveArc()) ; + if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) + return false ; + pRCrv->AddCurve( Release( pArc2)) ; + // inverto e eventualmente sistemo archi + pRCrv->Invert() ; + } + + return true ; +} + +//---------------------------------------------------- +static bool +CalcTrapezoidSpiralLocalFrame( ICurveComposite* pCrvTrap, const Vector3d& vtDir, Frame3d& frLoc) +{ + // cerco i lati paralleli a vtDir + int nBaseId = -1 ; + for ( int i = 0 ; i < pCrvTrap->GetCurveCount() ; i ++) { + Vector3d vtEdge ; + pCrvTrap->GetCurve( i)->GetStartDir( vtEdge) ; + if ( AreSameOrOppositeVectorApprox( vtEdge, vtDir)) { + nBaseId = i ; + break ; + } + } + if ( nBaseId != 0 && nBaseId != 1) + return false ; + + // imposto come lato iniziale per la curva uno dei lati paralleli a vtDir + pCrvTrap->ChangeStartPoint( nBaseId) ; + Point3d ptOrig ; pCrvTrap->GetStartPoint( ptOrig) ; + Vector3d vtX ; pCrvTrap->GetStartDir( vtX) ; + return frLoc.Set( ptOrig, Z_AX, vtX) ; +} + +//---------------------------------------------------------------------------- +static bool +GetBoxCrvOptTrap( const int nCrv, const ICurveComposite* pCrvCompo, const double dDiam, int& nType, + ICurveComposite* pCrvBox) +{ + nType = - 1 ; + // prendo la curva + const ICurve* pCrvCurr = pCrvCompo->GetCurve( nCrv) ; + if ( pCrvCurr == nullptr) + return false ; + // controllo se lineare, altrimenti passo alla successiva + if ( pCrvCurr->GetType() != CRV_LINE) + return true ; + // prendo la direzione del tratto lineare + Vector3d vtDir ; pCrvCurr->GetStartDir( vtDir) ; + // prendo il punto iniziale + Point3d ptStart ; pCrvCurr->GetStartPoint( ptStart) ; + // creo il riferimento basato su questo tratto + Frame3d frTrap ; frTrap.Set( ptStart, Z_AX, vtDir) ; + if ( ! frTrap.IsValid()) + return false ; + // porto la curva Compo ( clonandola) nel frame e calcolo il suo BBox + BBox3d BBox ; + PtrOwner pCrvCompo_c( CloneCurveComposite( pCrvCompo)) ; + if ( IsNull( pCrvCompo_c) || ! pCrvCompo_c->IsValid() || + ! pCrvCompo_c->ToLoc( frTrap) || + ! pCrvCompo_c->GetLocalBBox( BBox)) + return false ; + // controllo dimY e dimX per il box + bool bDimYOk = BBox.GetDimY() < dDiam + TOL_TRAPEZOID && BBox.GetMin().y > - TOL_TRAPEZOID ; + bool bDimXOk = BBox.GetDimX() < dDiam + TOL_TRAPEZOID && BBox.GetMin().y > - TOL_TRAPEZOID ; + // controllo dimensioni ammissibili + if ( ! bDimXOk && ! bDimYOk) + return true ; // se nessuna + else if ( ! bDimXOk) + nType = 1 ; // se dimY + else if ( ! bDimYOk) + nType = 0 ; // se dimX + else + nType = 2 ; // se entrambe + + // creo il rettangolo del Box + pCrvBox->Clear() ; + pCrvBox->AddPoint( BBox.GetMin()) ; + pCrvBox->AddLine( BBox.GetMin() + BBox.GetDimX() * X_AX) ; + pCrvBox->AddLine( BBox.GetMax()) ; + pCrvBox->AddLine( BBox.GetMax() - BBox.GetDimX() * X_AX) ; + pCrvBox->Close() ; + + // determino il punto inziale della curva + if ( nType == 0) + pCrvBox->ChangeStartPoint( 1.) ; + + pCrvBox->ToGlob( frTrap) ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +PreparareTrapezoidTwoBases( const ICurveComposite* pCrvCompo, const double dDiam, const int nType, int& nBase, + int& nSecondBase, bool& bOk, ICurveComposite* pCrvTrap) +{ + // controllo parametri + if ( pCrvCompo == nullptr) + return false ; + bOk = false ; + + // le parti tra le due basi devono essere tutte omogenee ( o tutte aperte o tutte chiuse) + // pCrvTest0 sarà la parte destra, pCrvTest1 la parte sinistra + Point3d ptSB0, ptSB1 ,ptEB0, ptEB1 ; + PtrOwner pCrvTest0( CloneCurveComposite( pCrvCompo)) ; + PtrOwner pCrvTest1( CloneCurveComposite( pCrvCompo)) ; + pCrvCompo->GetCurve( nBase)->GetStartPoint( ptSB0) ; + pCrvCompo->GetCurve( nBase)->GetEndPoint( ptEB0) ; + pCrvCompo->GetCurve( nSecondBase)->GetStartPoint( ptSB1) ; + pCrvCompo->GetCurve( nSecondBase)->GetEndPoint( ptEB1) ; + pCrvTest0->ChangeStartPoint( nBase) ; + pCrvTest1->ChangeStartPoint( nSecondBase) ; + double dUTrim0, dUTrim1 ; + pCrvTest0->GetParamAtPoint( ptSB1, dUTrim0) ; + pCrvTest1->GetParamAtPoint( ptSB0, dUTrim1) ; + pCrvTest0->TrimStartEndAtParam( 1, dUTrim0) ; + pCrvTest1->TrimStartEndAtParam( 1, dUTrim1) ; + // controllo che la parte destra si uniforme per le TmpProp + for ( int u = 0 ; u < pCrvTest0->GetCurveCount() - 1 ; ++ u) { + int nPropAct, nPropSucc ; + if ( pCrvTest0->GetCurveTempProp( u, nPropAct, 0) && + pCrvTest0->GetCurveTempProp( u + 1, nPropSucc, 0) && + nPropAct != nPropSucc) + return true ; // se TmpProp diverse => non è un caso ottimizzato + } + // controllo che la parte sinistra sia uniforme per le TmpProp + for ( int u = 0 ; u < pCrvTest1->GetCurveCount() - 1 ; ++ u) { + int nPropAct, nPropSucc ; + if ( pCrvTest1->GetCurveTempProp( u, nPropAct, 0) && + pCrvTest1->GetCurveTempProp( u + 1, nPropSucc, 0) && + nPropAct != nPropSucc) + return true ; // se TmpProp diverse => non è un caso ottimizzato + } + + // se lato destro aperto ( estendo il punto finale della base principale e il punto iniziale + // della base secondaria fino al lato destro del box) + bool bCopyRight = false ; + if ( pCrvTest0->GetCurve( 0)->GetTempProp( 0) == 1) { + if ( nType == 0) { + pCrvTrap->GetCurve( 0)->GetStartPoint( ptEB0) ; + pCrvTrap->GetCurve( 1)->GetStartPoint( ptSB1) ; + } + else { + pCrvTrap->GetCurve( 0)->GetEndPoint( ptEB0) ; + pCrvTrap->GetCurve( 1)->GetEndPoint( ptSB1) ; + } + } + // se lato destro chiuso + else + bCopyRight = true ; + // se lato sinistro aperto ( estendo il punto finale della base secondaria e il punto iniziale + // della base primaria dino al lato sinistro del box) + bool bCopyLeft = false ; + if ( pCrvTest1->GetCurve( 0)->GetTempProp( 0) == 1) { + if ( nType == 0) { + pCrvTrap->GetCurve( 2)->GetEndPoint( ptEB1) ; + pCrvTrap->GetCurve( 0)->GetStartPoint( ptSB0) ; + } + else { + pCrvTrap->GetCurve( 1)->GetEndPoint( ptEB1) ; + pCrvTrap->GetCurve( 2)->GetEndPoint( ptSB0) ; + } + } + // se lato sinistro chiuso + else + bCopyLeft = true ; + + // creo la curva da restituire + pCrvTrap->Clear() ; + pCrvTrap->AddPoint( ptSB0) ; + pCrvTrap->AddLine( ptEB0) ; + nBase = 0 ; + if ( bCopyRight) + pCrvTrap->AddCurve( Release( pCrvTest0)) ; + else { + pCrvTrap->AddLine( ptSB1) ; + pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, 1, 0) ; // aperta + } + nSecondBase = pCrvTrap->GetCurveCount() ; + pCrvTrap->AddLine( ptEB1) ; + if ( bCopyLeft) + pCrvTrap->AddCurve( Release( pCrvTest1)) ; + else { + pCrvTrap->Close() ; + pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, 1, 0) ; // aperta + } + + // verifico dimensione x della svuotatura nel caso tutto chiuso + if ( bCopyLeft && bCopyRight) { + double dLen0 = 0, dLen2 = 0 ; + pCrvTrap->GetCurve( nBase)->GetLength( dLen0) ; + pCrvTrap->GetCurve( nSecondBase)->GetLength( dLen2) ; + if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) { + pCrvTrap->Clear() ; + return true ; + } + } + + bOk = true ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTrap, + Frame3d& frTrap, PocketParams PockParams, double& dPocketSize, int& nBase, int& nSecondBase) +{ + // controllo parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // diametro reale da tenere in considerazione + double dDiam = 2 * PockParams.dRad + 2 * PockParams.dRadialOffset ; + + pCrvTrap->Clear() ; // resterà vuota se il caso non è ottimizzato + nBase = -1 ; + nSecondBase = -1 ; + + // se la curva è già un trapezio, non sempre devo adattarla... + Point3d pt ; Vector3d vtDir, vtB2, vtOtherDir ; + if ( pCrvCompo->IsATrapezoid( 100 * EPS_SMALL, pt, vtDir, vtOtherDir, vtB2)) { + pCrvTrap->AddCurve( pCrvCompo->Clone()) ; + // se parallelogramma scelgo come base i lati lunghi + Vector3d vtL2( - vtDir + vtOtherDir + vtB2) ; + if ( AreSameOrOppositeVectorApprox( vtOtherDir, vtL2)) { + if ( vtOtherDir.Len() > vtDir.Len()) + swap( vtDir, vtOtherDir) ; + } + vtDir.Normalize() ; + Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ; + dPocketSize = vtOrtho.Len() ; + // eventuale approssimazione della curva con polyline per ottenere la stessa curva calcolata in ICurveComposite::IsATrapezoid + if ( pCrvCompo->GetCurveCount() > 4) { + PolyLine PL ; + if ( ! pCrvCompo->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + return false ; + pCrvTrap->FromPolyLine( PL) ; + } + if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap)) + return false ; + bool bBaseOpen = false ; + bBaseOpen = ( pCrvTrap->GetCurve( 0)->GetTempProp( 0) == 1 || pCrvTrap->GetCurve( 2)->GetTempProp( 0) == 1) ; + // controllo dimensioni della svuotatura + if ( ! ( bBaseOpen && dPocketSize < dDiam + EPS_SMALL) && + abs( dPocketSize - dDiam) > EPS_SMALL) { + pCrvTrap->Clear() ; + return true ; + } + // recupero flag aperto/chiuso dei lati + if ( pCrvTrap->GetCurve( 1)->GetTempProp( 0) == 0 && pCrvTrap->GetCurve( 3)->GetTempProp( 0) == 0) { + double dLen0, dLen2 ; + pCrvTrap->GetCurve( 0)->GetLength( dLen0) ; + pCrvTrap->GetCurve( 2)->GetLength( dLen2) ; + if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) + pCrvTrap->Clear() ; + } + + // imposto le basi + nBase = 0 ; + nSecondBase = 2 ; + return true ; + } + + // controllo il numero di lati chiusi e salvo i loro indici + int nClosedSide = 0 ; + INTVECTOR vIndClosedSides ; + for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { + int nTmpProp ; + if ( pCrvCompo->GetCurveTempProp( u, nTmpProp, 0) && nTmpProp == 0) { + ++ nClosedSide ; + vIndClosedSides.push_back( u) ; + } + } + + // se tutti lati aperti + switch ( nClosedSide) { + // TUTTI I LATI SONO APERTI + case 0 : { + // ricavo il box minimo della curva aperta ( passo dalla polyLine) + PolyLine PL ; Point3d ptCen ; double dWidth ; + if ( ! pCrvCompo->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || + ! PL.GetMinAreaRectangleXY( ptCen, vtDir, dWidth, dPocketSize)) + return false ; + // controllo dimY ( dHeight), se troppo estesa, non è un caso ottimizzato + if ( dPocketSize > dDiam + TOL_TRAPEZOID) + return true ; + // inverto il frame attuale + frTrap.Set( ptCen, Z_AX, vtDir) ; + if ( ! frTrap.IsValid()) + return false ; + // creo il rettangolo del Box + pCrvTrap->AddPoint( Point3d( - 0.5 * dWidth, - 0.5 * dPocketSize, 0)) ; + pCrvTrap->AddLine( Point3d( 0.5 * dWidth, - 0.5 * dPocketSize, 0)) ; + pCrvTrap->AddLine( Point3d( 0.5 * dWidth, 0.5 * dPocketSize, 0)) ; + pCrvTrap->AddLine( Point3d( - 0.5 * dWidth, 0.5 * dPocketSize, 0)) ; + pCrvTrap->Close() ; + pCrvTrap->ToGlob( frTrap) ; + Point3d ptNewOrig ; pCrvTrap->GetStartPoint( ptNewOrig) ; + frTrap.Set( ptNewOrig, Z_AX, vtDir) ; + // imposto tutte le 4 curve come aperte + for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, 1, 0) ; + // imposto le basi + nBase = 0 ; + nSecondBase = 2 ; + } + break ; + // 1 LATO CHIUSO ( LINEARE) + case 1 : { + int nType = -1 ; + if ( ! GetBoxCrvOptTrap( vIndClosedSides[0], pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + if ( nType != -1) { + // imposto tutte le curve come aperte tranne la prima ( estendo il solo lato chiuso come base del Box) + for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, u == 0 ? 0 : 1, 0) ; + // memorizzo la dimensione di svuotatura + pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; + // imposto le basi + nBase = 0 ; + nSecondBase = 2 ; + } + } + break ; + // 2 LATI CHIUSI ( LINEARI, CONSECUTIVI O PARALLELI) + case 2 : { + // controllo se entrambi sono lineari + if ( pCrvCompo->GetCurve( vIndClosedSides[0])->GetType() == CRV_LINE && + pCrvCompo->GetCurve( vIndClosedSides[0])->GetType() == CRV_LINE) { + // se lineari, ricavo i punti estremanti e le direzioni + Point3d ptS0 ; pCrvCompo->GetCurve( vIndClosedSides[0])->GetStartPoint( ptS0) ; + Point3d ptS1 ; pCrvCompo->GetCurve( vIndClosedSides[1])->GetStartPoint( ptS1) ; + Point3d ptE0 ; pCrvCompo->GetCurve( vIndClosedSides[0])->GetEndPoint( ptE0) ; + Point3d ptE1 ; pCrvCompo->GetCurve( vIndClosedSides[1])->GetEndPoint( ptE1) ; + Vector3d vtDir0 ; pCrvCompo->GetCurve( vIndClosedSides[0])->GetStartDir( vtDir0) ; + Vector3d vtDir1 ; pCrvCompo->GetCurve( vIndClosedSides[1])->GetStartDir( vtDir1) ; + // CASO PARALLELI ( la base è indifferente) + if ( AreOppositeVectorEpsilon( vtDir0, vtDir1, 5 * EPS_SMALL)) { + int nType = -1 ; + // prendo come base il primo chiuso + if ( ! GetBoxCrvOptTrap( vIndClosedSides[0], pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + if ( nType != -1) { + // memorizzo la dimensione di svuotatura + pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; + // controllo che la distanza tra i due chiusi sia effettivamente circa il raggio + double dDist = 0. ; + DistPointCurve DPL( ptS0, *pCrvCompo->GetCurve( vIndClosedSides[1]), false) ; + if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) { + // imposto tutte le curve di indice dispari aperte + for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, u % 2 == 0 ? 0 : 1, 0) ; + // imposto le basi + nBase = 0 ; + nSecondBase = 2 ; + } + else + pCrvTrap->Clear() ; + } + } + // CASO CONSECUTIVI + bool bOk_0_1 = AreSamePointApprox( ptS1, ptE0) ; // chiuso1 . chiuso0 + bool bOk_1_0 = AreSamePointApprox( ptS0, ptE1) ; // chiuso0 . chiuso1 + if ( bOk_0_1 || bOk_1_0) { + // provo con il primo lato + int nType = -1 ; + // prendo come base il primo chiuso + if ( ! GetBoxCrvOptTrap( vIndClosedSides[0], pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + if ( nType == -1) { + // provo con l'altro + if ( ! GetBoxCrvOptTrap( vIndClosedSides[1], pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + if ( nType != -1) { + // spaw tra gli indici e flags + swap( vIndClosedSides[0], vIndClosedSides[1]) ; + swap( bOk_0_1, bOk_1_0) ; + } + } + Point3d ptH1, ptH2 ; + if ( nType == 1 || nType == 2) { + double dLen1 ; pCrvCompo->GetCurve( vIndClosedSides[1])->GetLength( dLen1) ; + pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; + // i lati inclinati chiusi definiscono il Box + if ( abs( dLen1 * ( vtDir0 ^ vtDir1).Len() - dPocketSize) < TOL_TRAPEZOID) { + // creo la curva a trapezio + if ( bOk_0_1) { + pCrvTrap->GetCurve( 2)->GetEndPoint( ptH1) ; + pCrvTrap->GetCurve( 3)->GetEndPoint( ptH2) ; + pCrvTrap->Clear() ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ; + pCrvTrap->AddLine( ptH1) ; + pCrvTrap->AddLine( ptH2) ; + pCrvTrap->Close() ; + pCrvTrap->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, u < 2 == 0 ? 0 : 1, 0) ; + } + else { + pCrvTrap->GetCurve( 0)->GetEndPoint( ptH1) ; + pCrvTrap->GetCurve( 1)->GetEndPoint( ptH2) ; + pCrvTrap->Clear() ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ; + pCrvTrap->AddLine( ptH1) ; + pCrvTrap->AddLine( ptH2) ; + pCrvTrap->AddLine( ptS1) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ; + pCrvTrap->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + pCrvTrap->SetCurveTempProp( 0, 0, 0) ; + for ( int u = 1 ; u < pCrvTrap->GetCurveCount() -1 ; ++ u) + pCrvTrap->SetCurveTempProp( u, 1, 0) ; + pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() -1, 0, 0) ; + } + // imposto le basi + nBase = 0 ; + nSecondBase = pCrvTrap->GetCurveCount() - 2 ; + } + else + pCrvTrap->Clear() ; + } + else if ( nType == 0) { + if ( bOk_0_1) { + pCrvTrap->GetCurve( 0)->GetEndPoint( ptH1) ; + pCrvTrap->GetCurve( 1)->GetEndPoint( ptH2) ; + pCrvTrap->Clear() ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ; + pCrvTrap->AddLine( ptH1) ; + pCrvTrap->AddLine( ptH2) ; + pCrvTrap->Close() ; + pCrvTrap->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, u < 2 == 0 ? 0 : 1, 0) ; + pCrvTrap->ChangeStartPoint( 1.) ; + // imposto le basi + nBase = 0 ; + nSecondBase = pCrvTrap->GetCurveCount() - 2 ; + } + else { + pCrvTrap->GetCurve( 0)->GetEndPoint( ptH1) ; + pCrvTrap->GetCurve( 1)->GetEndPoint( ptH2) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ; + pCrvTrap->AddLine( ptH1) ; + pCrvTrap->AddLine( ptH2) ; + pCrvTrap->AddLine( ptS1) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ; + pCrvTrap->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + pCrvTrap->SetCurveTempProp( 0, 0, 0) ; + for ( int u = 1 ; u < pCrvTrap->GetCurveCount() -1 ; ++ u) + pCrvTrap->SetCurveTempProp( u, 1, 0) ; + pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() -1, 0, 0) ; + pCrvTrap->ChangeStartPoint( 1.) ; + // imposto le basi + nBase = 0 ; + nSecondBase = pCrvTrap->GetCurveCount() - 2 ; + } + } + } + } + } + break ; + // 3 LATI CHIUSI ( LINEARI e CONSECUTIVI) + case 3 : { + // prendo i 3 lati chiusi + const ICurve* pCrv0 = pCrvCompo->GetCurve( vIndClosedSides[0]) ; + const ICurve* pCrv1 = pCrvCompo->GetCurve( vIndClosedSides[1]) ; + const ICurve* pCrv2 = pCrvCompo->GetCurve( vIndClosedSides[2]) ; + if ( pCrv0 == nullptr || pCrv1 == nullptr || pCrv2 == nullptr) + return false ; + // controllo che siano lineari + if ( pCrv0->GetType() == CRV_LINE && pCrv1->GetType() == CRV_LINE && pCrv2->GetType() == CRV_LINE) { + // prendo i punti iniziali e finali + Point3d ptStart0 ; pCrv0->GetStartPoint( ptStart0) ; + Point3d ptEnd0 ; pCrv0->GetEndPoint( ptEnd0) ; + Point3d ptStart1 ; pCrv1->GetStartPoint( ptStart1) ; + Point3d ptEnd1 ; pCrv1->GetEndPoint( ptEnd1) ; + Point3d ptStart2 ; pCrv2->GetStartPoint( ptStart2) ; + Point3d ptEnd2 ; pCrv2->GetEndPoint( ptEnd2) ; + + // controllo che siano consecutivi e cambio l'ordine se necessario + bool bOk = true ; + if ( AreSamePointApprox( ptEnd0, ptStart1) && AreSamePointApprox( ptEnd1, ptStart2)) + ; + else if ( AreSamePointApprox( ptEnd1, ptStart2) && AreSamePointApprox( ptEnd2, ptStart0)) { + swap( vIndClosedSides[0], vIndClosedSides[1]) ; + swap( vIndClosedSides[1], vIndClosedSides[2]) ; + } + else if ( AreSamePointApprox( ptEnd2, ptStart0) && AreSamePointApprox( ptEnd0, ptStart1)) { + swap( vIndClosedSides[0], vIndClosedSides[2]) ; + swap( vIndClosedSides[2], vIndClosedSides[1]) ; + } + else // se non consecutivi + bOk = false ; + + // se i tre lati sono ( mediante lo swap) consecutivi... + if ( bOk) { + // controllo se la dimensione Y del lato 1 è valida ( il resto è gestito di seguito) + int nType = -1 ; + if ( ! GetBoxCrvOptTrap( vIndClosedSides[1], pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + if ( nType == 1) { + // bisgna controllare la lunghezza dei chiusi + double dLen0 ; pCrvCompo->GetCurve( vIndClosedSides[0])->GetLength( dLen0) ; + double dLen2 ; pCrvCompo->GetCurve( vIndClosedSides[2])->GetLength( dLen2) ; + pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; + Vector3d vtDir0 ; pCrvCompo->GetCurve( vIndClosedSides[0])->GetStartDir( vtDir0) ; + Vector3d vtDir1 ; pCrvCompo->GetCurve( vIndClosedSides[1])->GetStartDir( vtDir1) ; + Vector3d vtDir2 ; pCrvCompo->GetCurve( vIndClosedSides[2])->GetStartDir( vtDir2) ; + // i lati inclinati chiusi definiscono il Box + if ( abs( dLen2 * ( vtDir1 ^ vtDir2).Len() - dPocketSize) < TOL_TRAPEZOID && + abs( dLen0 * ( vtDir1 ^ vtDir0).Len() - dPocketSize) < TOL_TRAPEZOID) { + // creo la curva a trapezio + pCrvTrap->Clear() ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[0])->Clone()) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[1])->Clone()) ; + pCrvTrap->AddCurve( pCrvCompo->GetCurve( vIndClosedSides[2])->Clone()) ; + pCrvTrap->Close() ; + for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) + pCrvTrap->SetCurveTempProp( u, u < 3 ? 0 : 1 , 1) ; + pCrvTrap->ChangeStartPoint( 1.) ; + // imposto le basi + nBase = 0 ; + nSecondBase = pCrvTrap->GetCurveCount() - 2 ; + } + } + } + } + } + } + + + // se non ho trovato delle basi, allora cerco in maniera generale un trapezoide ( se esiste) + if ( nBase == -1) { + bool bOK = false ; + for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && !bOK ; ++ u) { + // cerco un lato chiuso ( esiste per forza) + if ( pCrvCompo->GetCurve( u)->GetTempProp( 0) == 0) { + // controllo se il lato corrente può essere una base + int nType = -1 ; + if ( ! GetBoxCrvOptTrap( u, pCrvCompo, dDiam, nType, pCrvTrap)) + return false ; + // se è una base valida + if ( nType != -1) { + // ricavo la dimensione di svuotatura + pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; + // ricavo la sua direzione iniziale + Vector3d vtBaseDir ; pCrvCompo->GetCurve( u)->GetStartDir( vtBaseDir) ; + // ricavo il suo punto iniziale + Point3d ptBaseStart ; pCrvCompo->GetCurve( u)->GetStartPoint( ptBaseStart) ; + // ricavo il suo punto finale + Point3d ptBaseEnd ; pCrvCompo->GetCurve( u)->GetEndPoint( ptBaseEnd) ; + // cerco il lato chiuso lineare parallelo ad esso e distante circa dPocketSize + for ( int uu = 0 ; uu < pCrvCompo->GetCurveCount() && !bOK ; ++ uu) { + if ( uu == u || + pCrvCompo->GetCurve( uu)->GetType() != CRV_LINE || + pCrvCompo->GetCurve( uu)->GetTempProp() != 0) + continue ; + Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( uu)->GetStartDir( vtSecondBaseDir) ; + if ( ! AreOppositeVectorEpsilon( vtBaseDir, vtSecondBaseDir, 5 * EPS_SMALL)) + continue ; + Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( uu)->GetStartPoint( ptSecondBaseStart) ; + double dDist = 0. ; + DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( uu), false) ; + if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) { + nBase = u ; + nSecondBase = uu ; + if ( ! PreparareTrapezoidTwoBases( pCrvCompo, dDiam, nType, nBase, nSecondBase, bOK, pCrvTrap)) + return false ; + } + } + } + } + } + } + + // la curva a trapezio deve evere almeno 4 lati + if ( pCrvTrap->GetCurveCount() < 4 || nBase == -1 || nSecondBase == -1) { + pCrvTrap->Clear() ; + return true ; + } + + // ricostruisco il frame del trapezio + Point3d ptS ; pCrvTrap->GetStartPoint( ptS) ; + Vector3d vtS ; pCrvTrap->GetStartDir( vtS) ; + if ( ! frTrap.Set( ptS, Z_AX, vtS) || ! frTrap.IsValid()) + return false ; + + // se parametro MaxOptSize non compatibile => non è ottimizzato + if ( PockParams.dMaxOptSize > EPS_SMALL && dPocketSize > PockParams.dMaxOptSize) + pCrvTrap->Clear() ; + + return true ; +} + +//---------------------------------------------------- +static bool +SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed, + const ICurveComposite* pCrvPocket, PocketParams PockParams) +{ + // parametri + double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; + double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; + double dRad = 0.5 * dDiam + dOffsR ; + + // calcolo gli offset dei lati obliqui + PtrOwner pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ; + pLineS->SimpleOffset( - dRad) ; + pLineS->Invert() ; + PtrOwner pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ; + pLineE->SimpleOffset( - dRad) ; + pLineE->Invert() ; + + Point3d ptS, ptE ; + pLineS->GetEndPoint( ptS) ; + pLineE->GetStartPoint( ptE) ; + Vector3d vtS, vtE ; + pLineS->GetStartDir( vtS) ; + pLineE->GetStartDir( vtE) ; + + PtrOwner pLineLink( CreateCurveLine()) ; + pLineLink->Set( ptS, ptE) ; + + pMCrv->Clear() ; + if ( ! pMCrv->AddCurve( Release( pLineS))) + return false ; + + // creo raccordi + bool bUseBiArcs = false ; + Vector3d vtDir, vtDir2 ; + pLineLink->GetStartDir( vtDir) ; + pCrvPocket->GetCurve( bEvenClosed ? 1 : 0)->GetStartDir( vtDir2) ; + + if ( Dist( ptS, ptE) > 500 * EPS_SMALL && AreSameOrOppositeVectorApprox( vtDir, vtDir2)) { + + Point3d ptCrv1, ptCrv2 ; + pLineLink->GetPointD1D2( 0.3, ICurve::FROM_MINUS, ptCrv1) ; + pLineLink->GetPointD1D2( 0.7, ICurve::FROM_MINUS, ptCrv2) ; + + // primo raccordo + double dAng ; + vtS.GetAngleXY( X_AX, dAng) ; + PtrOwner pBiArc1( GetBiArc( ptS, - dAng, ptCrv1, bEvenClosed ? 90 : 0, 0.5)) ; + + // secondo raccordo + vtE.Invert() ; + vtE.GetAngleXY( X_AX, dAng) ; + PtrOwner pBiArc2( GetBiArc( ptE, - dAng, ptCrv2, bEvenClosed ? - 90 : 180, 0.5)) ; + pBiArc2->Invert() ; + + if ( ! IsNull( pBiArc1) && ! IsNull( pBiArc2)) { + bUseBiArcs = true ; + pMCrv->AddCurve( Release( pBiArc1)) ; + pMCrv->AddLine( ptCrv2) ; + pMCrv->AddCurve( Release( pBiArc2)) ; + } + } + + // se non è stato possibile creare raccordo, unisco linearmente + if ( ! bUseBiArcs) + pMCrv->AddCurve( Release( pLineLink)) ; + + if ( ! pMCrv->AddCurve( Release( pLineE))) + return false ; + + // setto temp prop per ricordare curve aggiuntive per pulire angoli + pMCrv->SetCurveTempProp( 0, 1) ; + pMCrv->SetCurveTempProp( pMCrv->GetCurveCount() - 1, 1) ; + + return true ; +} + +//------------------------------------------------------ +static bool +CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSecondBase, + bool bStart, double dYCoord, double& dXCoord, double dPocketSize, + PocketParams PockParams) +{ + // parametri + double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; + double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; + double dRad = 0.5 * dDiam + dOffsR ; + + // recupero la curva di interesse + int nCrvId = ( bStart ? nSecondBase : nBase) + 1 ; + int nProp = - 1 ; + if ( ! pCrvPocket->GetCurveTempProp( nCrvId, nProp)) + return false ; + // se open + if ( nProp == 1) { + Point3d pt1, pt2 ; + pCrvPocket->GetCurve( nCrvId)->GetStartPoint( pt1) ; + pCrvPocket->GetCurve( nCrvId)->GetEndPoint( pt2) ; + if ( bStart) + dXCoord = min( pt1.x, pt2.x) ; + else + dXCoord = max( pt1.x, pt2.x) ; + } + // se closed + else { + // creo la curva destra/sinistra + int nLast = bStart ? pCrvPocket->GetCurveCount() : nSecondBase ; + PtrOwner pCrvSide( ConvertCurveToComposite( pCrvPocket->CopyParamRange( nCrvId, nLast))) ; + if ( IsNull( pCrvSide)) + return false ; + // Offsetto la curva + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCrvSide, - dRad, ICurve::OFF_FILLET)) + return false ; + if ( OffsCrv.GetCurveCount() == 0) { + // controllo se avevo una circonferenza + if ( pCrvSide->GetCurveCount() == 1 && pCrvSide->GetFirstCurve()->GetType() == CRV_ARC) { + Point3d ptS ; pCrvSide->GetStartPoint( ptS) ; + dXCoord = ptS.x ; + } + else { + Point3d ptS ; pCrvSide->GetStartPoint( ptS) ; + Point3d ptE ; pCrvSide->GetEndPoint( ptE) ; + dXCoord = bStart ? max( ptS.x, ptE.x) + dRad : min( ptS.x, ptE.x) - dRad ; + } + } + else if ( OffsCrv.GetCurveCount() == 1) { + // controllo se la curva interseca la linea di svuotatura a YCoord + PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrvOffs)) + return false ; + PtrOwner pLineMid( CreateCurveLine()) ; + if ( IsNull( pLineMid)) + return false ; + pLineMid->Set( Point3d( - 3000, dYCoord, 0), Point3d( 3000, dYCoord, 0)) ; + IntersCurveCurve intCC( *pLineMid, *pCrvOffs) ; + IntCrvCrvInfo ccClass ; + if ( intCC.GetIntersCount() != 0) { + // se ho almeno una intersezione + if ( intCC.GetIntCrvCrvInfo( 0, ccClass)) + dXCoord = ccClass.IciA[0].ptI.x ; + else + return false ; + } + else { + // se non ho intersezioni... + // prendo il box della curva + BBox3d Box3d ; + pCrvSide->GetLocalBBox( Box3d) ; + // creo la linea limitie verticale + PtrOwner pCrvVertLine( CreateCurveLine()) ; + if ( IsNull( pCrvVertLine)) + return false ; + if ( bStart) + pCrvVertLine->SetPDL( Box3d.GetMax() + 5 * TOL_TRAPEZOID * Y_AX, - 90 , 2 * dPocketSize) ; + else + pCrvVertLine->SetPDL( Box3d.GetMin() - 5 * TOL_TRAPEZOID * Y_AX, 90, 2 * dPocketSize) ; + // intersechiamo + IntersCurveCurve intCC2( *pCrvVertLine, *pCrvSide) ; + if ( intCC2.GetOverlaps()) { + if ( bStart) + dXCoord = Box3d.GetMax().x + dRad ; + else + dXCoord = Box3d.GetMin().x - dRad ; + } + else { + dXCoord = bStart ? -INFINITO : INFINITO ; + for ( int i = 0 ; i < intCC2.GetIntersCount() ; ++ i) { + IntCrvCrvInfo ccClass2 ; + if ( intCC2.GetIntCrvCrvInfo( i, ccClass2)) { + if ( bStart) + dXCoord = max( dXCoord, Box3d.GetMax().x + sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ; + else + dXCoord = min( dXCoord, Box3d.GetMin().x - sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ; + } + } + } + } + } + else + return false ; + } + return true ; +} + +//---------------------------------------------------- +static bool +SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed, + PocketParams PockParams, const ICurveComposite* pCrvPocket) +{ + // parametri + double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; + double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; + double dRad = 0.5 * dDiam + dOffsR ; + + // calcolo gli offset dei lati obliqui + PtrOwner pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ; + pLineS->SimpleOffset( - dRad) ; + pLineS->Invert() ; + PtrOwner pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ; + pLineE->SimpleOffset( - dRad) ; + pLineE->Invert() ; + + Point3d ptS, ptE ; + pLineS->GetEndPoint( ptS) ; + pLineE->GetStartPoint( ptE) ; + Vector3d vtS, vtE ; + pLineS->GetStartDir( vtS) ; + pLineE->GetStartDir( vtE) ; + + PtrOwner pLineLink( CreateCurveLine()) ; + pLineLink->Set( ptS, ptE) ; + + pMCrv->Clear() ; + if ( ! pMCrv->AddCurve( Release( pLineS))) + return false ; + + // creo raccordi + bool bUseBiArcs = false ; + Vector3d vtDir, vtDir2 ; + pLineLink->GetStartDir( vtDir) ; + pCrvPocket->GetCurve( bEvenClosed ? 1 : 0)->GetStartDir( vtDir2) ; + + if ( Dist( ptS, ptE) > 500 * EPS_SMALL && AreSameOrOppositeVectorApprox( vtDir, vtDir2)) { + + Point3d ptCrv1, ptCrv2 ; + pLineLink->GetPointD1D2( 0.3, ICurve::FROM_MINUS, ptCrv1) ; + pLineLink->GetPointD1D2( 0.7, ICurve::FROM_MINUS, ptCrv2) ; + + // primo raccordo + double dAng ; + vtS.GetAngleXY( X_AX, dAng) ; + PtrOwner pBiArc1( GetBiArc( ptS, - dAng, ptCrv1, bEvenClosed ? 90 : 0, 0.5)) ; + + // secondo raccordo + vtE.Invert() ; + vtE.GetAngleXY( X_AX, dAng) ; + PtrOwner pBiArc2( GetBiArc( ptE, - dAng, ptCrv2, bEvenClosed ? - 90 : 180, 0.5)) ; + pBiArc2->Invert() ; + + if ( ! IsNull( pBiArc1) && ! IsNull( pBiArc2)) { + bUseBiArcs = true ; + pMCrv->AddCurve( Release( pBiArc1)) ; + pMCrv->AddLine( ptCrv2) ; + pMCrv->AddCurve( Release( pBiArc2)) ; + } + } + + // se non è stato possibile creare raccordo, unisco linearmente + if ( ! bUseBiArcs) + pMCrv->AddCurve( Release( pLineLink)) ; + + if ( ! pMCrv->AddCurve( Release( pLineE))) + return false ; + + // setto temp prop per ricordare curve aggiuntive per pulire angoli + pMCrv->SetCurveTempProp( 0, 1) ; + pMCrv->SetCurveTempProp( pMCrv->GetCurveCount() - 1, 1) ; + + return true ; +} + +//---------------------------------------------------- +static bool +AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket, + PocketParams PockParams, bool bStart) +{ + // parametri + double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; + double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; + double dRad = 0.5 * dDiam + dOffsR ; + + PtrOwner pCompo( CreateCurveComposite()) ; + if ( ! bStart) + pMCrv->Invert() ; + + Point3d ptTmp ; + pMCrv->GetStartPoint( ptTmp) ; + double dYCoord = ptTmp.y ; // quota verticale del percorso di svuotatura + pCrvPocket->GetCurve( 2)->GetStartPoint( ptTmp) ; + double dPocketSize = ptTmp.y ; + + int nCrvId = ( bStart ? 3 : 1) ; + PtrOwner pLine( GetCurveLine( pCrvPocket->GetCurve( nCrvId)->Clone())) ; + pLine->SimpleOffset( - dRad) ; + + Point3d ptP1, ptP2 ; + pLine->GetStartPoint( ptP1) ; + pLine->GetEndPoint( ptP2) ; + if ( ! bStart) + swap( ptP1, ptP2) ; + + int nProp2 ; + // lato opposto a quello di riferimento aperto + if ( pCrvPocket->GetCurveTempProp( 2, nProp2) && nProp2 != 0) { + + // caso 1 : pLine ha un estremo sopra e uno sotto il percorso di svuotatura pMCrv + if ( ptP2.y < dYCoord && dYCoord < ptP1.y) { + + // creo tratto da ptP2 a ptP1 + pCompo->AddPoint( ptP2) ; + pCompo->AddLine( ptP1) ; + + // trovo il punto di pMCrv da cui ripartire per non lasciare aree residue + pLine->SimpleOffset( - 0.5 * dDiam) ; + pLine->ExtendStartByLen( EPS_SMALL) ; + pLine->ExtendEndByLen( EPS_SMALL) ; + IntersCurveCurve intCC( *pLine, *pCrvPocket) ; + if ( intCC.GetIntersCount() == 0) + return false ; + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( 0, aInfo) ; + double dDeltaX = sqrt( max( 0., dDiam * dDiam / 4 - dYCoord * dYCoord)) ; + if ( ! bStart) + dDeltaX *= -1 ; + Point3d ptCrv( aInfo.IciA[0].ptI.x + dDeltaX, dYCoord) ; + + double dPar = 0 ; + if ( ! pMCrv->GetParamAtPoint( ptCrv, dPar)) { + dPar = 0.5 ; + pMCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptCrv) ; + } + if ( ! pMCrv->TrimStartAtParam( dPar)) + pMCrv->Clear() ; + + if ( ptP1.y > dPocketSize) { + // se ptP1 è esterno alla svuotatura scambio i punti in modo da usare ptP2 per il biarco ( così da non farlo fuoriuscire troppo) + swap( ptP1, ptP2) ; + pCompo->Invert() ; + } + + // creo biarco fra ptP1 e ptCrv + Vector3d vtDir ; + pCompo->GetStartDir( vtDir) ; + double dAng ; + vtDir.GetAngleXY( X_AX, dAng) ; + PtrOwner pBiArc( GetBiArc( ptP1, - dAng, ptCrv, bStart ? 0 : 180, 0.8)) ; + + bool bUseBiArc = false ; + if ( ! IsNull( pBiArc)) { + // verifico che con il biarco non si oltrepassi il lato obliquo chiuso della svuotatura + IntersCurveCurve intCC2( *pBiArc, *pCompo) ; + if ( intCC2.GetIntersCount() == 1) + bUseBiArc = true ; + } + if ( bUseBiArc) + pCompo->AddCurve( Release( pBiArc)) ; + else { + double dParLine = ( dYCoord - ptP2.y) / ( ptP1.y - ptP2.y) ; + Point3d ptOnLine = Media( ptP2, ptP1, dParLine) ; + pCompo->AddLine( ptOnLine) ; + pCompo->AddLine( ptCrv) ; + } + } + + // caso 2 : pLine è completamente sopra/sotto la linea di svuotatura + else { + // se è sopra modifiche per ricondurmi al caso in cui è sotto + if ( ptP2.y > dYCoord) { + pLine->Invert() ; + swap( ptP1, ptP2) ; + } + + // trovo l'intersezione fra il prolungamento della linea e pMCrv + if ( bStart) + pLine->ExtendStartByLen( 1000) ; + else + pLine->ExtendEndByLen( 1000) ; + IntersCurveCurve intCC ( *pLine, *pMCrv) ; + if ( intCC.GetIntersCount() == 0) + return false ; + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( 0, aInfo) ; + Point3d ptInt ; + ptInt = aInfo.IciA[0].ptI ; + double dPar = 0 ; + pMCrv->GetParamAtPoint( ptInt, dPar) ; + if ( ! pMCrv->TrimStartAtParam( dPar)) + pMCrv->Clear() ; + + pCompo->AddPoint( ptP2) ; + pCompo->AddLine( ptInt) ; + } + } + + // se il lato opposto a quello di riferimento � chiuso bisogna distinguere i casi + else { + bool bStartPnt = false ; + if ( ptP2.y < dYCoord) { + bStartPnt = pCompo->AddPoint( ptP2) ; + } + else { + Vector3d vtDir ; + pLine->GetStartDir( vtDir) ; + if ( bStart) + vtDir.Invert() ; + Point3d ptP2N = ptP2 - dDiam / 2 * abs( vtDir.x / vtDir.y) * vtDir ; + if ( ptP2N.y < dYCoord) + bStartPnt = pCompo->AddPoint( ptP2N) ; + } + if ( bStartPnt) { + Point3d ptCrv ; + pMCrv->GetStartPoint( ptCrv) ; + pCompo->AddLine( ptCrv) ; + } + } + + // setto temp prop per ricordare che è curva aggiuntiva per pulire angoli + for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) + pCompo->SetCurveTempProp( i, 1) ; + + pMCrv->AddCurve( Release( pCompo), false) ; + if ( ! bStart) + pMCrv->Invert() ; // ripristino la direzione originaria + + return true ; +} + +//---------------------------------------------------- +static bool +CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double dPocketSize, int nBase, + int nSecondBase, PocketParams PockParams, ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap) +{ + // parametri + double dDiam = 2 * PockParams.dRad ; + double dOffsR = PockParams.dRadialOffset ; + + bOptimizedTrap = false ; + Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; + + // recupero le temp prop + INTVECTOR vnProp( 4, 0) ; + if ( pCrvPocket->GetCurveCount() == 4) { + for ( int i = 0 ; i < 4 ; i ++) + pCrvPocket->GetCurveTempProp( i, vnProp[i]) ; + } + else { + vnProp[1] = pCrvPocket->GetCurve( 1)->GetTempProp() ; + vnProp[3] = pCrvPocket->GetCurve( nSecondBase + 1)->GetTempProp() ; + } + + // passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli + // (possibilmente aperto) e centro nel punto iniziale del lato + pCrvPocket->ToLoc( frTrap) ; + + // calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso) + double dLen0, dLen1, dLen2, dLen3, dMaxLarg = 0. ; + pCrvPocket->GetCurve( nBase)->GetLength( dLen0) ; + pCrvPocket->GetCurve( nSecondBase)->GetLength( dLen2) ; + bool bRealTrap = pCrvPocket->GetCurveCount() == 4 ; + for ( int i = 0 ; i < 4 && bRealTrap ; ++ i) + bRealTrap = pCrvPocket->GetCurve( i)->GetType() == CRV_LINE ; + if ( bRealTrap) { + pCrvPocket->GetCurve( nBase + 1)->GetLength( dLen1) ; + pCrvPocket->GetCurve( nSecondBase + 1)->GetLength( dLen3) ; + // calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso) + Point3d ptOrig ; pCrvPocket->GetCurve( 1)->GetStartPoint( ptOrig) ; + Vector3d vtX ; pCrvPocket->GetCurve( 1)->GetStartDir( vtX) ; + Frame3d frDim ; frDim.Set( ptOrig, Z_AX, vtX) ; frDim.Invert() ; + BBox3d b3Dim ; pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ; + dMaxLarg = ( vnProp[0] != 0 ? b3Dim.GetDimY() : dPocketSize) ; + } + + + // calcolo percorso di svuotatura + // se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale + if (( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) && + ((( vnProp[0] != 0 && vnProp[2] != 0) && ( vnProp[3] == 0 && vnProp[1] == 0) && ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) || + (( vnProp[1] != 0 && vnProp[3] != 0) && ( vnProp[0] == 0 && vnProp[2] == 0) && ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) { + if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, vnProp[0] == 0, pCrvPocket, PockParams)) { + pMCrv->Clear() ; + return false ; + } + } + else { + // trovo la quota Y per centro del Tool + double dYCoord ; + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 0) // se base principale chiusa + dYCoord = 0.5 * dDiam + dOffsR ; + else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 0) // se base principale aperta e secondaria chiusa + dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ; + else // se entrambi i lati paralleli sono aperti mi posiziono a metà della svuotatura + dYCoord = 0.5 * dPocketSize ; + + double dXCoordStart, dXCoordEnd ; + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, + dPocketSize, PockParams)) + return false ; + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, + dPocketSize, PockParams)) + return false ; + if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL) + return false ; + Point3d ptStart( dXCoordStart, dYCoord) ; + Point3d ptEnd( dXCoordEnd, dYCoord) ; + + if ( bRealTrap && AreSamePointEpsilon( ptStart, ptEnd, 500 * EPS_SMALL) && ( vnProp[0] != 0 || vnProp[2] != 0)) { + Vector3d vtDir1, vtDir3 ; + pCrvPocket->GetCurve( 1)->GetStartDir( vtDir1) ; + pCrvPocket->GetCurve( 3)->GetStartDir( vtDir3) ; + // gestisco il caso speciale di un parallelogramma in cui anche l'altra dimensione della svuotatura è pari al diametro utensile + if ( AreOppositeVectorApprox( vtDir1, vtDir3)) { + PtrOwner pLine1( GetCurveLine( pCrvPocket->GetCurve( 1)->Clone())) ; + PtrOwner pLine3( GetCurveLine( pCrvPocket->GetCurve( 3)->Clone())) ; + if ( IsNull( pLine1) || IsNull( pLine3)) + return false ; + if ( ! pLine1->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset) || + ! pLine3->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset)) + return false ; + + Point3d ptS, ptE ; + if ( vtDir3 * X_AX > EPS_SMALL) { + pLine1->GetStartPoint( ptS) ; + pLine3->GetStartPoint( ptE) ; + } + else { + pLine1->GetEndPoint( ptE) ; + pLine3->GetEndPoint( ptS) ; + } + + if ( vnProp[0] != 0) { + pMCrv->AddPoint( ptS) ; + if ( vnProp[2] != 0) + pMCrv->AddLine( ptE) ; + else + pMCrv->AddLine( ptStart) ; + } + else { + pMCrv->AddPoint( ptE) ; + if ( vnProp[0] != 0) + pMCrv->AddLine( ptS) ; + else + pMCrv->AddLine( ptStart) ; + pMCrv->Invert() ; + } + + pMCrv->SetCurveTempProp( 0, 1) ; + } + } + else { + if ( ! pMCrv->AddPoint( ptStart)) + return true ; + if ( ! pMCrv->AddLine( ptEnd)) + return true ; + + // aggiustamenti al percorso per rimuovere materiale residuo negli angoli + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 1 || + pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 1) { + + Frame3d frOpen ; + bool bSwitch = false ; + // Base principale chiusa e base Secondaria aperta + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 0) { + pCrvPocket->ChangeStartPoint( nSecondBase) ; + // oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto) + Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ; + Point3d ptORIG ; + if ( vtDir.y > 0) + pCrvPocket->GetCurve( nBase)->GetEndPoint( ptORIG) ; + else + pCrvPocket->GetCurve( nBase)->GetStartPoint( ptORIG) ; + frOpen.Set( ptORIG, Z_AX, -X_AX) ; + if ( ! frOpen.IsValid()) + return false ; + pCrvPocket->ToLoc( frOpen) ; + pMCrv->ToLoc( frOpen) ; + pMCrv->Invert() ; + bSwitch = true ; + } + + if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == 0 && + ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, true)) { + pMCrv->Clear() ; + return false ; + } + if ( pCrvPocket->GetCurve( 1)->GetTempProp( 0) == 0 && + ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, false)) { + pMCrv->Clear() ; + return false ; + } + + if ( bSwitch) { + pCrvPocket->ToGlob( frOpen) ; + pMCrv->ToGlob( frOpen) ; + pMCrv->Invert() ; + } + + } + } + } + + if ( pMCrv->GetCurveCount() == 0) + return true ; + + pMCrv->ToGlob( frTrap) ; + + if ( ! PockParams.bInvert) { + pMCrv->Invert() ; + // inverto le proprietà in modo che nProp3 sia sempre legata al punto iniziale e nProp1 a quello finale + swap( vnProp[1], vnProp[3]) ; + } + // segno i lati aperti come temp prop della curva + int nOpenEdges = vnProp[0] + vnProp[1] * 2 + vnProp[2] * 4 + vnProp[3] * 8 ; + pMCrv->SetTempProp( nOpenEdges, 0) ; + pMCrv->SetExtrusion( vtExtr) ; + + bOptimizedTrap = true ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ModifyCurveToSmoothed( ICurveComposite* pCrv, PocketParams PockParams, double dRightLen, double dLeftLen, bool bAsParam) { // se non richiesto non faccio nulla - if ( ! s_bSmooth) + if ( ! PockParams.bSmooth) return true ; // controllo parametri @@ -320,7 +3034,8 @@ ModifyCurveToSmoothed( ICurveComposite* pCrv, double dRightLen, double dLeftLen, //---------------------------------------------------------------------------- static bool -CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, ICRVCOMPOPOVECTOR& vOffIslands, ICurveComposite* pCrvLink) +CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPOVECTOR& vOffIslands, + ICurveComposite* pCrvLink) { // pulisco pCrvLink->Clear() ; @@ -475,11 +3190,11 @@ ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) //------------------------------------------------------------------------------ static bool CalcBoundedSmootedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, - const Vector3d& vtEnd, double dParMeet, ICRVCOMPOPOVECTOR& vOffIslands, - ICurveComposite* pCrvLink) + const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vOffIslands, + PocketParams PockParams, ICurveComposite* pCrvLink) { // se senza smusso, ritorno tratto lineare - if ( ! s_bSmooth) + if ( ! PockParams.bSmooth) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; // creo il BiArc che unisce i due punti @@ -590,7 +3305,7 @@ CalcBoundedSmootedLink( const Point3d& ptStart, const Vector3d& vtStart, const P } // smusso e restituisco - ModifyCurveToSmoothed( pCompo, 0.05, 0.05, true) ; + ModifyCurveToSmoothed( pCompo, PockParams, 0.05, 0.05, true) ; pCrvLink->AddCurve( Release( pCompo)) ; return true ; @@ -598,8 +3313,8 @@ CalcBoundedSmootedLink( const Point3d& ptStart, const Vector3d& vtStart, const P //---------------------------------------------------------------------------- static bool -CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, ICRVCOMPOPOVECTOR& vOffsCL, - ICRVCOMPOPOVECTOR& vFirstOffset, ICurveComposite* pCrvLink, double dLenPercS, +CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOMPOPOVECTOR& vOffsCL, + const ICRVCOMPOPOVECTOR& vFirstOffset, PocketParams PockParams, ICurveComposite* pCrvLink, double dLenPercS, double dLenPercE, int nMaxIter) { // controllo i parametri @@ -635,19 +3350,22 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, ICRVCOMPOPOVE if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) dLenPercE = 0 ; } - double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : s_dRad) ; - double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : s_dRad) ; + double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; + double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : PockParams.dRad) ; dLenE = 0 ; // calcolo i possibili BiArchi tra le due curve int nIter = 0 ; + if ( ! PockParams.bSmooth) + nMaxIter = 1 ; + // taglio la curva al massimo nMaxIter-volte e mi fermo al taglio più opportuno while ( nIter < nMaxIter) { // calcolo il BiArco PtrOwner ptBiArc( CreateBasicCurveComposite()) ; - if ( ! CalcBoundedSmootedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, ptBiArc) || + if ( ! CalcBoundedSmootedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, PockParams, ptBiArc) || ptBiArc->GetCurveCount() == 0) return false ; @@ -701,16 +3419,16 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, ICRVCOMPOPOVE //---------------------------------------------------------- static bool GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICURVEPOVECTOR& vLinks, - ISurfFlatRegion* pSrfToCut) + const ICurveComposite* pCrv_orig, PocketParams PockParams, ISurfFlatRegion* pSrfToCut) { // controllo dei parametri - if ( vFirstOffs.empty() || vCrvs.size() < vFirstOffs.size()) + if ( vFirstOffs.size() == 0 || ( int)vCrvs.size() < ( int)vFirstOffs.size()) return false ; pSrfToCut->Clear() ; // 1) creo la regione esterna - PtrOwner pSrfExtern( CreateBasicSurfFlatRegion()) ; + PtrOwner pSrfExtern( CreateSurfFlatRegion()) ; if ( IsNull( pSrfExtern)) return false ; @@ -724,25 +3442,26 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU } } + // ---- le seguenti regioni sono distinte per calcolar emeglio la Feed ---- // 2) Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links - PtrOwner pSrfTool_Offs( CreateBasicSurfFlatRegion()) ; - PtrOwner pSrfTool_Links( CreateBasicSurfFlatRegion()) ; - PtrOwner pSrfTool( CreateBasicSurfFlatRegion()) ; + PtrOwner pSrfTool_Offs( CreateSurfFlatRegion()) ; + PtrOwner pSrfTool_Links( CreateSurfFlatRegion()) ; + PtrOwner pSrfTool( CreateSurfFlatRegion()) ; if ( IsNull( pSrfTool_Offs) || IsNull( pSrfTool_Links) || IsNull( pSrfTool)) return false ; // creo un vettore che conterrà solamente i Link percorsi fino ad Ora ICRVCOMPOPOVECTOR vLinks_done ; - for ( int i = ( s_nType == POCKET_SPIRALIN ? 0 : ( int)vCrvs.size() - 1) ; - ( s_nType == POCKET_SPIRALIN ? i < int( vCrvs.size()) : i >= 0) ; - ( s_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()) { + if ( i <= ( int)vLinks.size() && ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { - // prendo il Link i-esimo come composita ( potrebbe essere tratto lineare) - PtrOwner pCompoLink_i( CreateBasicCurveComposite()) ; + // Feed + PtrOwner pCompoLink_i( CreateCurveComposite()) ; if ( IsNull( pCompoLink_i)) return false ; pCompoLink_i->AddCurve( vLinks[i]->Clone()) ; @@ -751,7 +3470,7 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU PtrOwner pCrvLink_i( vLinks[i]->Clone()) ; if ( IsNull( pCrvLink_i)) return false ; - PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( Release( pCrvLink_i), s_dRad + 5 * EPS_SMALL, false, false)) ; + PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( Release( pCrvLink_i), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; if ( ! IsNull( pSrfToolRegLinki)) { if ( ! pSrfTool_Links->IsValid() || pSrfTool_Links->GetChunkCount() == 0) pSrfTool_Links.Set( GetBasicSurfFlatRegion( Release( pSrfToolRegLinki))) ; @@ -767,20 +3486,21 @@ GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICU } // ================== OFFSET ============================= - // aggiorno la superficie svuotata - PtrOwner pCrvOffs_i( CloneBasicCurveComposite( vCrvs[i])) ; + + // aggiorno la superificie svuotata + PtrOwner pCrvOffs_i( CloneCurveComposite( vCrvs[i])) ; if ( IsNull( pCrvOffs_i)) return false ; - PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( Release( pCrvOffs_i) , s_dRad + 5 * EPS_SMALL, false, 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( GetBasicSurfFlatRegion( 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) ; } } - // 3) Calcolo la superficie svuotata + // 3) Calcolo la superificie svuotata pSrfTool.Set( pSrfTool_Offs) ; pSrfTool->Add( *pSrfTool_Links) ; @@ -825,7 +3545,7 @@ RemoveFirstLoopFromSfr( ISurfFlatRegion* pSrfOrig) //---------------------------------------------------------------------------- static bool RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECTOR& vOffsFirstCurve, - int& nOptFlag, Point3d& ptCentroid, ICurveComposite* pCrvPath) + PocketParams PockParams, int& nOptFlag, Point3d& ptCentroid, ICurveComposite* pCrvPath) { // nOptFlag : 0 -> non faccio nulla | 1 -> svuoto con un centroide | 2 -> svuoto con un percorso @@ -867,7 +3587,7 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT if ( pSrfBiggerChunk->GetArea( dAreaExt) && dAreaExt < 10 * EPS_SMALL) { if ( ! RemoveFirstLoopFromSfr( pSrfChunkToCutClone)) return false ; - if( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) + if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) break ; continue ; } @@ -881,7 +3601,7 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT PtrOwner pCrvToolShape( CreateBasicCurveArc()) ; if ( IsNull( pCrvToolShape)) return false ; - pCrvToolShape->SetXY( ptC, s_dRad + 5 * EPS_SMALL) ; + pCrvToolShape->SetXY( ptC, PockParams.dRad + 5 * EPS_SMALL) ; PtrOwner pSrfTool( CreateBasicSurfFlatRegion()) ; if ( IsNull( pSrfTool) || ! pSrfTool->AddExtLoop( Release( pCrvToolShape)) || ! pSrfTool->IsValid()) @@ -952,7 +3672,7 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT continue ; } // smusso la curva - ModifyCurveToSmoothed( pCrvMedAx, 0.025, 0.025, true) ; + ModifyCurveToSmoothed( pCrvMedAx, PockParams, 0.025, 0.025, true) ; // se curva valida la inserisco nel vettore, altrimenti forzo il centroide if ( pCrvMedAx->IsValid()) vCrvCoMedAxi.emplace_back( pCrvMedAx->Clone()) ; @@ -963,7 +3683,7 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT } // 3) guardo quale regione svuoto con questa curva - PtrOwner pSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrvMedAx), s_dRad + 5 * EPS_SMALL, false, false)) ; + PtrOwner pSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrvMedAx), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; if ( IsNull( pSrfRemoved) || ! pSrfRemoved->IsValid()) break ; @@ -1011,7 +3731,7 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT if ( IsNull( pCrvLink)) return false ; - if ( ! CalcBoundedSmootedLink( ptS, vtS, ptE, vtE, 0.5, vOffsFirstCurve, pCrvLink)) + if ( ! CalcBoundedSmootedLink( ptS, vtS, ptE, vtE, 0.5, vOffsFirstCurve, PockParams, pCrvLink)) if ( ! CalcBoundedLink( ptS, ptE, vOffsFirstCurve, pCrvLink)) return false ; @@ -1020,7 +3740,8 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT } if ( ! AreSamePointEpsilon( ptEOriginal, ptSOriginal, EPS_SMALL) && - ! CalcBoundedSmootedLink( ptEOriginal, vtEOriginal, ptSOriginal, vtSOriginal, 0.5, vOffsFirstCurve, pCrvCoBackLink) && + ! CalcBoundedSmootedLink( ptEOriginal, vtEOriginal, ptSOriginal, vtSOriginal, 0.5, vOffsFirstCurve, + PockParams, pCrvCoBackLink) && ! CalcBoundedLink( ptEOriginal, ptSOriginal, vOffsFirstCurve, pCrvCoBackLink)) return false ; @@ -1053,7 +3774,8 @@ RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECT if ( IsNull( pCrvPath1)) return false ; - if ( ! CalcBoundedSmootedLink( ptClosestOnPath, vtTanCpt, vPtCentroid[i], vtTanCpt, 0, vOffsFirstCurve, pCrvPath1) && + if ( ! CalcBoundedSmootedLink( ptClosestOnPath, vtTanCpt, vPtCentroid[i], vtTanCpt, 0, + vOffsFirstCurve, PockParams, pCrvPath1) && ! CalcBoundedLink( ptClosestOnPath, vPtCentroid[i], vOffsFirstCurve, pCrvPath1)) return false ; @@ -1181,7 +3903,8 @@ CutLinkToClosestPoint( ICURVEPOVECTOR& vCurves, ICRVCOMPOPOVECTOR& vOffs, const //------------------------------------------------------------------------------ static bool -CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) { +CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) +{ // controllo parametri ingresso if ( vOffs.empty()) @@ -1292,7 +4015,8 @@ CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) { //---------------------------------------------------------------------------- static bool -GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, Point3d& ptC, +GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, + PocketParams PockParams, Point3d& ptC, bool bCir, ICRVCOMPOPOVECTOR& VFirstOff, ICurveComposite* pCrvNewCurve) { // creazione dei due possibili percorsi per raggiungere il centroide @@ -1317,7 +4041,7 @@ GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* } // creo la circonferenza - if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0, VFirstOff, pPath1)) + if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0, VFirstOff, PockParams, pPath1)) return false ; Vector3d vtS_cir ; pPath1->GetStartDir( vtS_cir) ; Vector3d vtS_CrvH1 ; pCrvH1->GetEndDir( vtS_CrvH1) ; @@ -1330,7 +4054,7 @@ GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* return false ; double dUCrvS ; - ModifyCurveToSmoothed( pPath1, 0.075, 0.075, true) ; + ModifyCurveToSmoothed( pPath1, PockParams, 0.075, 0.075, true) ; if ( pPath1->IsClosed()) { pPath1->GetParamAtPoint( ptCrvS, dUCrvS) ; pPath1->ChangeStartPoint( dUCrvS) ; @@ -1362,8 +4086,8 @@ GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* } // creo i due Biarchi - if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanS, 0.5, VFirstOff, pPath1) || - ! CalcBoundedSmootedLink( ptE, vtTanS, ptS, vtTanS, 0.5, VFirstOff, pPath2)) + if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanS, 0.5, VFirstOff, PockParams, pPath1) || + ! CalcBoundedSmootedLink( ptE, vtTanS, ptS, vtTanS, 0.5, VFirstOff, PockParams, pPath2)) return false ; // creo la nuova curva con il doppio Biarco @@ -1383,8 +4107,8 @@ GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* //---------------------------------------------------------------------------- static bool ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICurveComposite* pPath1, - ICurveComposite* pPath2, ICRVCOMPOPOVECTOR& vOffsCL) { - + PocketParams PockParams, ICurveComposite* pPath2, ICRVCOMPOPOVECTOR& vOffsCL) +{ // controllo parametri if ( pCrv == nullptr) return false ; @@ -1403,13 +4127,13 @@ ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICu while ( ! bFound && nIter < 45) { vTanE.Rotate( Z_AX, 90 - nIter) ; // vettore perpendicolare PtrOwner pLine( CreateCurveLine()) ; - pLine->SetPVL( ptHS, vTanE, ( 2 * s_dRad) / 3 - 5 * EPS_SMALL) ; // segmento uscente + pLine->SetPVL( ptHS, vTanE, ( 2 * PockParams.dRad) / 3 - 5 * EPS_SMALL) ; // segmento uscente CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pLine, *pCrv) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if (( int)ccClass.size() > 1) // se intersezione con parte precedente inverto la direzione - pLine->SetPVL( ptHS, - vTanE, ( 2 * s_dRad) / 3 - 5 * EPS_SMALL) ; + pLine->SetPVL( ptHS, - vTanE, ( 2 * PockParams.dRad) / 3 - 5 * EPS_SMALL) ; if ( IsNull( pLine) || ! pLine->IsValid()) break ; @@ -1440,7 +4164,7 @@ ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICu ! pCrvTwoSeg->AddCurve( pLine1->Clone())) return false ; - ModifyCurveToSmoothed( pCrvTwoSeg, 0.2, 0.2, true) ; + ModifyCurveToSmoothed( pCrvTwoSeg, PockParams, 0.2, 0.2, true) ; PtrOwner ptNewCrv( CreateCurveComposite()) ; if ( ptNewCrv->AddCurve( pPath1->Clone()) && @@ -1485,8 +4209,9 @@ ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICu //---------------------------------------------------------------------------- static bool -GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, ICurveComposite* pCrvPath, - ICRVCOMPOPOVECTOR& VFirstOff, ICRVCOMPOPOVECTOR& VoffsCl, ICurveComposite* pCrvNewCurve) +GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, ICurveComposite* pCrvPath, + ICRVCOMPOPOVECTOR& VFirstOff, ICRVCOMPOPOVECTOR& VoffsCl, PocketParams PockParams, + ICurveComposite* pCrvNewCurve) { // inizializzo i due possibili percorsi PtrOwner pPath1( CreateCurveComposite()) ; @@ -1514,10 +4239,10 @@ GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCr } // creo i due Biarchi - if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0.5, VFirstOff, pPath1)) + if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0.5, VFirstOff, PockParams, pPath1)) if ( ! CalcBoundedLink( ptS, ptE, VFirstOff, pPath1)) return false ; - if ( ! CalcBoundedSmootedLink( ptH, vtH, ptS, vtTanS, 0.5, VFirstOff, pPath2)) + if ( ! CalcBoundedSmootedLink( ptH, vtH, ptS, vtTanS, 0.5, VFirstOff, PockParams, pPath2)) if ( ! CalcBoundedLink( ptH, ptS, VFirstOff, pPath2)) return false ; @@ -1530,7 +4255,7 @@ GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCr return false ; // cerco di togliere le auto intersezioni tra i biarchi e le curve di Medial Axis - if ( ! ManageSmoothAndAutoInters( pCrvToAdd, pCrvPath, pPath1, pPath2, VoffsCl)) + if ( ! ManageSmoothAndAutoInters( pCrvToAdd, pCrvPath, pPath1, PockParams, pPath2, VoffsCl)) return false ; // curva finale @@ -1547,7 +4272,7 @@ GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCr pCrvToAdd->GetStartPoint( ptHE) ; pCrvToAdd->GetStartDir( vtHE) ; PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; - if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper)) + if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, PockParams, pCrvBiArcHelper)) if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper)) return false ; @@ -1567,7 +4292,7 @@ GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCr pCrvH2->GetStartPoint( ptHE) ; pCrvH2->GetStartDir( vtHE) ; PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; - if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper)) + if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, PockParams, pCrvBiArcHelper)) if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper) ) return false ; @@ -1698,9 +4423,10 @@ ChoosePath( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nP, //---------------------------------------------------------------------------- static bool RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsClosedCurves, - ICRVCOMPOPOVECTOR& vOffsFirstCurve, ICURVEPOVECTOR& vLinks) + ICRVCOMPOPOVECTOR& vOffsFirstCurve, ICURVEPOVECTOR& vLinks, PocketParams PockParams) { + // controllo parametri if ( pSrfToCut == nullptr || vOffs.empty()) return true ; @@ -1726,7 +4452,7 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP // ricavo il flag // ptGoTo è il centroide, pCrvPath è la curva da seguire per svuotare la regione ( nel caso non bastasse il centroide) - if ( ! RemoveExtraPartByMedialAxis( pSrfChunkToCut, vOffsFirstCurve, nOptFlag, ptGoTo, pCrvPath) || + if ( ! RemoveExtraPartByMedialAxis( pSrfChunkToCut, vOffsFirstCurve, PockParams, nOptFlag, ptGoTo, pCrvPath) || nOptFlag == 0) continue ; @@ -1771,7 +4497,7 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP return false ; if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) - if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, bFound, vOffsFirstCurve, ptCrvNewLink)) + if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, PockParams, ptGoTo, bFound, vOffsFirstCurve, ptCrvNewLink)) continue ; } else if ( nOptFlag == 2) { // se svuoto con curva di medial Axis... @@ -1779,7 +4505,8 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP bool bSucc = true ; bool bSuccI = true ; // ricavo il nuovo Offset con la curva di medial Axis aggiunta - if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLink)) + if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, + PockParams, ptCrvNewLink)) bSucc = false ; PtrOwner pCrvPathI( pCrvPath->Clone()) ; @@ -1789,7 +4516,8 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP return false ; // ricavo il nuovo Offset con la curva di medial Axis Invertita aggiunta - if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLinkI)) + if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, + PockParams, ptCrvNewLinkI)) bSuccI = false ; // scelgo il miglior percorso ottenuto ( sempre verificando che siano validi...) @@ -1815,7 +4543,7 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP return false ; if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) - if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, true, vOffsFirstCurve, ptCrvNewOffs)) + if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, PockParams, ptGoTo, true, vOffsFirstCurve, ptCrvNewOffs)) continue ; } else if ( nOptFlag == 2) { // nel caso aggiungo un medial Axis non agli estremi di un Offset @@ -1823,7 +4551,8 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP bool bSucc = true ; bool bSuccI = true ; // come prima controllo il percorso normal ed invertito - if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffs)) + if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, + PockParams, ptCrvNewOffs)) bSucc = false ; PtrOwner pCrvPathI( pCrvPath->Clone()) ; @@ -1832,7 +4561,8 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP if ( IsNull( ptCrvNewOffsI)) return false ; - if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffsI)) + if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, + PockParams, ptCrvNewOffsI)) bSuccI = false ; int nC = 0 ; // se entrambi i percorsi sono validi allora li confronto @@ -1854,20 +4584,232 @@ RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMP return true ; } +//---------------------------------------------------------------------------- +static bool +CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, PocketParams PockParams, + const ICRVCOMPOPOVECTOR& vOffsClosedCurves, const ICRVCOMPOPOVECTOR& vOffsFirstCurve) +{ + // controllo dei parametri + if ( vOffs.empty() || vOffsFirstCurve.empty()) + return false ; + vLinks.clear() ; + vLinks.resize( int( vOffs.size())) ; + + // 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 curva successive cerco la curva interna e più vicina ad essa + 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) { + // calcolo la distanza minima tra essa + int nFlag ; + 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 ; + } + } + } + } + // 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 ; + 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 ; + } + } + } + } + // se non ho trovato nessuna curva, errore + if ( nNextInd == -1) + return false ; + + // scambio la curva i+1 esima con la j-esima ( se non sono già in ordine) + if ( nNextInd != i + 1) + swap( vOffs[nNextInd], vOffs[i+1]) ; + + // cambio il suo punto iniziale nel punto più vicino tovato + double dUS ; + if ( ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUS, EPS_SMALL)) + return false ; + vOffs[i+1]->ChangeStartPoint( dUS) ; + + // accorcio la curva per raccordarmi in tangenza con la successiva + if ( int( vOffs.size()) > 1) { + // clono le curve i ed i+1 esime ( nel caso non riuscissi ad accorciarle o raccordarle ) + PtrOwner pCrv_i( CloneCurveComposite( vOffs[i])) ; + PtrOwner pCrv_ii( CloneCurveComposite( vOffs[i+1])) ; + if ( IsNull( pCrv_i) || IsNull( pCrv_ii) || ! pCrv_i->IsValid() || ! pCrv_ii->IsValid()) + return false ; + // creo la curva che le collegherà + PtrOwner pCrvLink( CreateCurveComposite()) ; + if ( IsNull( pCrvLink)) + return false ; + // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset + if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsClosedCurves, vOffsFirstCurve, PockParams, pCrvLink, + i == 0 ? 0 : 0.01, 0.01, 2)) { + // se non sono riuscito, cerco una strada più semplice + // ripristino le curve + pCrvLink->Clear() ; + vOffs[i].Set( Release( pCrv_i)) ; // chiuso + vOffs[i+1].Set( Release( pCrv_ii)) ; // chiuso + // recupero i vettori tangente iniziali ( le curve sono chiuse ) + Vector3d vtS, vtE ; + if ( ! vOffs[i]->GetStartDir( vtS) || ! vOffs[i+1]->GetStartDir( vtE)) + return false ; + // creo il bi-arco tra esse + if ( CalcBoundedSmootedLink( ptS, vtS, ptStartNext, vtE, 0.5, vOffsFirstCurve, PockParams, pCrvLink)) + vLinks[i + 1].Set( pCrvLink) ; // aggiorno il collegamento + else + return false ; + + continue ; // passo alla curva i+1 esima successiva + } + + // per sicurezza aggiorno i nuovi punti e i nuovi parametri + double dUNewS, dUNewE ; + if ( ! pCrvLink->GetStartPoint( ptS) || + ! pCrvLink->GetEndPoint( ptStartNext) || + ! vOffs[i]->GetParamAtPoint( ptS, dUNewS) || + ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUNewE)) + return false ; + + // imposto il punto iniziale della curva successiva ( i+1 esima) + vOffs[i+1]->ChangeStartPoint( dUNewE) ; + PtrOwner pCrvNewOffs( CloneCurveComposite( vOffs[i])) ; + if ( dUNewS > EPS_SMALL) { + pCrvNewOffs.Set( ConvertCurveToComposite( vOffs[i]->CopyParamRange( 0, dUNewS))) ; + // sostituisco la curva i esima con quella tagliata + vOffs[i].Set( pCrvNewOffs) ; + } + + // aggiorno il collegamento + vLinks[i+1].Set( Release( pCrvLink)) ; + } + + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, const int nOffsCount, + const int nIter, const Vector3d& vtN, PocketParams PockParams, bool& bInsert) +{ + + // controllo dei parametri + if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || dOffs < EPS_SMALL) + return false ; + bInsert = true ; // di base inserisco + + // controllo se richiesta ottimizzazione sul numero di Offsets + if ( ! PockParams.bOptOffsets) + return true ; + + if ( nIter != 0) { // controllo se sono almeno al secondo offset... + + // per ogni curva controllo se il controOffset + 5 * EPS_SMALL genera una regione ... + OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad + if ( OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) { + // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive + if ( OffsCrv.GetCurveCount() == 0) { + bInsert = false ; + return true ; + } + } + else + return true ; + + // controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis + if ( ! PockParams.bOptOffsetsAdv || 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, vtN, 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 < 2 * 2 * PockParams.dRad - 100 * EPS_SMALL) { + bInsert = false ; + return true ; + } + } + + return true ; +} //---------------------------------------------------------------------------- static bool -CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSmooth, int& nReg, Point3d& ptStart, - ICurveComposite* pMCrv, ICurveComposite* pRCrv) +CalcSpiral( const ISurfFlatRegion* pSrfPock, PocketParams PockParams, int& nReg, Point3d& ptStart, + ICurveComposite* pCrvOEWithFlags, ICurveComposite* pMCrv, ICurveComposite* pRCrv, + bool& bOptimizedTrap) { - // inizializzo i risultati pMCrv->Clear() ; pRCrv->Clear() ; - // Offset corrente - double dOffs = dRad ; + // Offset corrente ( il primo è definito dal raggio utensile) + double dOffs = PockParams.dRad ; // recupero il versore normale della superficie, ruotandola nel piano XY PtrOwner pSrfToWork( pSrfPock->Clone()) ; @@ -1878,6 +4820,71 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSm Vector3d vtExtr = pSrfToWork->GetNormVersor() ; Point3d ptCen ; pSrfToWork->GetCentroid( ptCen) ; Frame3d frPocket ; frPocket.Set( ptCen, vtExtr) ; + + // CONTROLLO PER CASI OTTIMIZZATI + bool bHasIsland = ( pSrfPock->GetLoopCount( 0) > 1) ; + + // se non ho isole e curva valida allora controllo casi ottimizzati + if ( ! bHasIsland && pCrvOEWithFlags != nullptr) { + + // --------------------------- caso spirale --------------------------------------- + + PtrOwner pCrvBorder( ConvertCurveToComposite( pSrfPock->GetLoop( 0, 0))) ; + if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) + return false ; + pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + pCrvBorder->SetExtrusion( pSrfPock->GetNormVersor()) ; // setto l'estrusione della curva + Vector3d vtN = pSrfPock->GetNormVersor() ; // vettore normale per caso circonferenza + Point3d ptCen ; double dRad ; + bool bIsCircle = false ; + if ( ! OptimizedSpiralCirle( pCrvBorder, 50 * EPS_SMALL, dRad, ptCen, bIsCircle)) + return false ; + if ( bIsCircle) { + double dIntRad = 0 ; + if ( nReg == 0) { + bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, PockParams, pMCrv, pRCrv) ; + if ( bOk) { + pMCrv->GetStartPoint( ptStart) ; + nReg = 1 ; + return true ; + } + else + return false ; + } + else + return true ; + } + + // -------------------------- caso trapezoide --------------------------------------- + + PtrOwner pCrvTrap( CreateCurveComposite()) ; + if ( IsNull( pCrvTrap)) + return false ; + Frame3d frTrap ; + double dPocketSize ; + int nBase, nSecondBase ; + pCrvOEWithFlags->ToLoc( frPocket) ; + if ( ! GetTrapezoidFromShape( pCrvOEWithFlags, pCrvTrap, frTrap, PockParams, dPocketSize, nBase, nSecondBase)) + return false ; + pCrvOEWithFlags->ToGlob( frPocket) ; + if ( pCrvTrap->IsValid()) { + pCrvTrap->SetExtrusion( vtExtr) ; + if ( nReg == 0) { + CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParams, pMCrv, pRCrv, bOptimizedTrap) ; + if ( bOptimizedTrap) { + pMCrv->ToGlob( frPocket) ; + pRCrv->ToGlob( frPocket) ; + nReg = 1 ; + return true ; + } + } + else + return true ; + } + + } + + // porto la superficie nel frame corrente pSrfToWork->ToLoc( frPocket) ; // ciclo di offset verso l'interno @@ -1923,10 +4930,13 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSm return false ; if ( j > 0) // inverto l'orientamento delle curve interne ( offset delle isole trovate) pCrvCompoBorder->Invert() ; - // inserisco nel vettore degli Offset - vOffs.emplace_back( Release( pCrvCompoBorder)) ; - // salvo le curve di Offset esterne della prima iterazione - if ( nIter == 0) { // salvo il bordo per i link ( non invertiti) + // controllo quali regioni di Offset possono essere sostituite + bool bInsert = true ; + if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, int( vOffs.size()), nIter, vtExtr, PockParams, bInsert)) + return false ; + if ( bInsert) + vOffs.emplace_back( Release( pCrvCompoBorder)) ; + if ( nIter == 0) { // salvo il bordo per i link ( non invertiti, devo sapere IN/OUT) PtrOwner pCrvCompoExtBorder( ConvertCurveToComposite( pSfrOffsVR->GetLoop( i, j))) ; vOffsFirstCurve.emplace_back( Release( pCrvCompoExtBorder)) ; } @@ -1934,17 +4944,17 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSm } // controllo se serve un raggio più piccolo di svuotatura - bool bSmallRad = ( nIter == 0 ? dOffs < dRad + EPS_ZERO : dOffs - dOffsPrec < dRad + EPS_ZERO) ; + bool bSmallRad = ( nIter == 0 ? dOffs < PockParams.dRad + EPS_ZERO : dOffs - dOffsPrec < PockParams.dRad + EPS_ZERO) ; // se ho trovato dei chunk, allora aggiorno l'Offset per la passata successiva if ( nChunks > 0) { // memorizzo il valore di Offset per l'iterazione successiva dOffsPrec = dOffs ; - dOffs += dStep ; + dOffs += PockParams.dSideStep ; } // se devo usare un Offset più piccolo... else if ( ! bSmallRad) - dOffs = dOffsPrec + ( nIter == 0 ? dRad : dRad) ; // superfluo, effettivamente non ho l'offset radiale + dOffs = dOffsPrec + ( nIter == 0 ? PockParams.dRad + PockParams.dRadialOffset : PockParams.dRad) ; // superfluo, effettivamente non ho l'offset radiale // altrimenti ho finito la regione da svuotare... else break ; @@ -1957,166 +4967,61 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSm return true ; // cambio il punto iniziale della prima Curva di Offset - AdjustContourStart( vOffs[0]) ; - - // smusso le curve di offset ( ad eccezione della prima, se richisto) - ICRVCOMPOPOVECTOR vOffsClosedCurves( vOffs.size()) ; // vettore con tutte le curve di Offset Chiuse - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { - if ( i != 0) { - ModifyCurveToSmoothed( vOffs[i], s_dRad / 8, s_dRad / 8, false) ; - vOffs[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; - } - vOffsClosedCurves[i].Set( vOffs[i]->Clone()) ; - // NB. Salvo questo vettore in quanto il BiArco di raccordo tra la curva (i)-esima e la (i+1)-esima potrebbe - // intersecare altre curve oltre queste due. ( CutCurveToConnect( ...)) - } - - for ( int i = 0 ; i < int( vOffsFirstCurve.size()) ; ++ i) { - if ( i != 0) - ModifyCurveToSmoothed( vOffsFirstCurve[i], s_dRad / 8, s_dRad / 8, false) ; - vOffsFirstCurve[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; - } - - // riordino le curve cambiando il loro punto di inizio e creando poi i collegamenti - int nClosestInd = -1 ; int nFlag ; - double dDist = INFINITO ; - Point3d ptHelp ; - ICURVEPOVECTOR vLinks( vOffs.size()) ; - - for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { - - // prendo il punto iniziale - Point3d ptS ; - if ( ! vOffs[i]->GetStartPoint( ptS)) - return false ; - - // setto i default delle variabili - if ( ! DistPointCurve( ptS, *vOffs[i+1]).GetMinDistPoint( EPS_SMALL, ptHelp, nFlag)) - return false ; - dDist = INFINITO ; - - // scorro le curve successive - for ( int j = i + 1 ; j <= int( vOffs.size()) - 1 ; ++ j) { - - // cerco il punto più vicino della curva - Point3d ptE ; - if ( ! DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptE, nFlag)) - return false ; - - // memorizzo l'indice della curva più vicina ( aggiornando il valore della distanza) - if ( dDist > Dist( ptS, ptE) ) { - dDist = Dist( ptS, ptE) ; - nClosestInd = j ; - ptHelp.Set( ptE.x, ptE.y, ptE.z) ; - } - } - - // 1) scambio la curva i con la curva più vicina trovata ( se non è la successiva) - if ( nClosestInd != i + 1) { - PtrOwner ptoCCHelp( Release( vOffs[i + 1])) ; - vOffs[i + 1].Set( vOffs[nClosestInd]) ; - vOffs[nClosestInd].Set( ptoCCHelp) ; - } - - // 2) cambio il suo punto iniziale ( nel punto più vicino trovato)... - double dU ; - Point3d ptNE( ptHelp.x, ptHelp.y, ptHelp.z) ; - if ( ! vOffs[i + 1]->GetParamAtPoint( ptNE, dU)) - return false ; - vOffs[i + 1]->ChangeStartPoint( dU) ; - - // 2.1) Accorcio la curva per raccordarla con la successiva ... - if (( int)vOffs.size() > 1) { // se ho almeno un Offset - // copio le curve (i)-esime e (i+1)-esime - double dUNS, dUNE ; - PtrOwner pCrvTest( CreateCurveComposite()) ; // possibile collegamento tra la curva i ed i+1 - if ( IsNull( pCrvTest)) - return false ; - PtrOwner pOff_i0( CloneCurveComposite( vOffs[i])) ; - PtrOwner pOff_i1( CloneCurveComposite( vOffs[i + 1])) ; - // cerco di tagliare le curve e di raccordarle ( -> ottenendo il collegamento) - // NB. se la curva di offset è la prima, non devo tagliarla, accorcio solo le successive ( se non bordi di isole) ... - if ( ! s_bSmooth || ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsClosedCurves, vOffsFirstCurve, pCrvTest, ( i == 0 ? 0 : 0.01), 0.01, 2)) { - // se non sono riuscito ad accorcirle, ritorno alla configurazione iniziale - PtrOwner pCrvLink( CreateCurveComposite()) ; - if ( IsNull( pCrvLink)) - return false ; - // vettori tangenti per raccordo - Vector3d vS, vE ; - vOffs[i].Set( pOff_i0) ; - vOffs[i+1].Set( pOff_i1) ; - if ( ! vOffs[i]->GetStartDir( vS) || ! vOffs[i+1]->GetStartDir( vE)) - return false ; - // calcolo il raccordo - if ( CalcBoundedSmootedLink( ptS, vS, ptNE, vE, 0.5, vOffsFirstCurve, pCrvLink)) - vLinks[i + 1].Set( pCrvLink) ; // aggiorno il collegamento - else - return false ; - // passo alla successiva - continue ; - } - - // ricavo i parametri nei punti scelti - if ( ! pCrvTest->GetStartPoint( ptS) || - ! pCrvTest->GetEndPoint( ptNE) || - ! vOffs[i]->GetParamAtPoint( ptS, dUNS) || - ! vOffs[i+1]->GetParamAtPoint( ptNE, dUNE)) - return false ; - - // imposto il nuovo punto inziale della curva successiva - vOffs[i+1]->ChangeStartPoint( dUNE) ; - PtrOwner pCrvNewOffS( CloneCurveComposite( vOffs[i])) ; - if ( IsNull( pCrvNewOffS) || ! pCrvNewOffS->IsValid()) - return false ; - if ( dUNS > EPS_SMALL) { // se parametro di trim sufficientemente grande - pCrvNewOffS.Set( GetCurveComposite( vOffs[i]->CopyParamRange( 0, dUNS))) ; - // sostituisco la curva i-esima con quella tagliata - vOffs[i]->Clear() ; - vOffs[i].Set( pCrvNewOffS) ; - } - // aggiorno il collegamento - vLinks[i+1].Set( pCrvTest) ; - } - } - - // 3) controllo eventuali parti non svuotate... - PtrOwner pSrfToCut( CreateSurfFlatRegion()) ; - if ( IsNull( pSrfToCut)) + Point3d ptRef = PockParams.ptEnd ; ptRef.ToLoc( frPocket) ; + Point3d ptNewStart ; + Vector3d vtMidOut ; + bool bMidOut ; + pCrvOEWithFlags->ToLoc( frPocket) ; + if ( SetPtStartForPath( vOffs[0], PockParams, pSrfToWork, ptRef, frPocket, ptStart, vtMidOut, bMidOut, + int( vOffs.size()), pCrvOEWithFlags)) + vOffs[0]->GetStartPoint( ptNewStart) ; + else return false ; - if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, pSrfToCut)) { - // 4) Modifico i percorsi - if ( ! RemoveExtraParts( pSrfToCut, vOffs, vOffsClosedCurves, vOffsFirstCurve, vLinks)) - return false ; + pCrvOEWithFlags->ToGlob( frPocket) ; + + // se richiesta inversione + for ( int i = 0 ; i < int( vOffs.size()) && PockParams.bInvert ; ++ i) + vOffs[i]->Invert() ; + + // smusso le curve di offset ( ad eccezione della prima) + ICRVCOMPOPOVECTOR vOffsClosedCurves( vOffs.size()) ; // vettore con tutte le curve di Offset Chiuse + double dSmoothPar = PockParams.dRad / 8 ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + if ( i != 0) + ModifyCurveToSmoothed( vOffs[i], PockParams, dSmoothPar, dSmoothPar, false) ; + vOffs[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + vOffsClosedCurves[i].Set( vOffs[i]->Clone()) ; } - // calcolo il percorso di ritorno - if (( int)vOffs.size() >= 2) { - pRCrv->Clear() ; - // punto inziale e finale | vettore tangente iniziale e finale - Point3d ptStart ; vOffs.back()->GetEndPoint( ptStart) ; - Point3d ptEnd ; vOffs.front()->GetStartPoint( ptEnd) ; - Vector3d vtStart ; vOffs.back()->GetEndDir( vtStart) ; - Vector3d vtEnd ; vOffs.front()->GetStartDir( vtEnd) ; + // setto il punto iniziale della svuotatura + double dNewUS ; + vOffs[0]->GetParamAtPoint( ptNewStart, dNewUS) ; + vOffs[0]->ChangeStartPoint( dNewUS) ; + vOffs[0]->SetTempParam( 0., 0) ; // prima iterazione - // calcolo il ritorno ( garantendo che non esca dalla svuotatura) - PtrOwner pCrvLink( CreateCurveComposite()) ; - if ( CalcBoundedSmootedLink( ptStart, vtStart, ptEnd, vtEnd, 0.5, vOffsFirstCurve, pCrvLink)) { - pRCrv->AddCurve( Release( pCrvLink)) ; - pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ; - } - else + // riordino le curve cambiando e creo i collegamenti + ICURVEPOVECTOR vLinks( vOffs.size()) ; + if ( ! CreateSpiralPocketingPath( vOffs, vLinks, PockParams, vOffsClosedCurves, vOffsFirstCurve)) + return false ; + + // controllo eventuali parti non svuotate... + pCrvOEWithFlags->ToLoc( frPocket) ; + PtrOwner pSrfToCut( CreateSurfFlatRegion()) ; + if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, pCrvOEWithFlags, PockParams, pSrfToCut)) { + // Modifico i percorsi + if ( ! RemoveExtraParts( pSrfToCut, vOffs, vOffsClosedCurves, vOffsFirstCurve, vLinks, PockParams)) return false ; - } // creo il percorso di lavoro a partire dalla raccolta degli offset e dei collegamenti for ( int i = 0 ; i < int( vOffs.size()) ; ++i) { // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { + int nCrvsCount0 = pMCrv->GetCurveCount() ; // accodo nel percorso di lavorazione if ( ! pMCrv->AddCurve( vLinks[i]->Clone())) return false ; - } + } pMCrv->AddCurve( vOffs[i]->Clone()) ; } @@ -2129,8 +5034,9 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSm // riporto tutto nel sistema di riferimento originale pMCrv->ToGlob( frPocket) ; - pRCrv->ToGlob( frPocket) ; ptStart.ToGlob( frPocket) ; + vtMidOut.ToGlob( frPocket) ; + pCrvOEWithFlags->ToGlob( frPocket) ; return true ; } @@ -2160,10 +5066,11 @@ CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nSt //---------------------------------------------------------- static bool -CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, ICurveComposite* pCrvLink) +CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, PocketParams PockParams, + ICurveComposite* pCrvLink) { // se non richiesto, esco - if ( ! s_bSmooth) + if ( ! PockParams.bSmooth) return true ; // controllo dei parametri @@ -2247,23 +5154,23 @@ CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, ICurveComposite* pCrvTempLink->GetLastCurve()->GetLength( dLenI_e) ; // raccordo pSeg1 con pCrvLink - double dTollLeft = 1 - ( dLen1 - ( ( 2 * s_dRad) / 16)) / dLen1 ; // % parametro sinistro per smusso - double dTollRight = ( ( 2 * s_dRad) / 16) / dLenI_s ; // % parametro destro di smusso + double dTollLeft = 1 - ( dLen1 - ( ( 2 * PockParams.dRad) / 16)) / dLen1 ; // % parametro sinistro per smusso + double dTollRight = ( ( 2 * PockParams.dRad) / 16) / dLenI_s ; // % parametro destro di smusso PtrOwner pCrv_Seg1_Isl( CreateCurveComposite()) ; // curva unione di pSeg1 e pCrvLink smussata pCrv_Seg1_Isl->AddCurve( pCrvH1->Clone()) ; pCrv_Seg1_Isl->AddCurve( pCrvTempLink->Clone()) ; - ModifyCurveToSmoothed( pCrv_Seg1_Isl, dTollLeft, dTollRight, true) ; + ModifyCurveToSmoothed( pCrv_Seg1_Isl, PockParams, dTollLeft, dTollRight, true) ; // raccordo questa curva con pSeg2 double dUS_1IH, dUE_1IH, dToTLen ; pCrv_Seg1_Isl->GetDomain( dUS_1IH, dUE_1IH) ; // dominio della curva smussata tra pSeg1 e PCrvLink pCrv_Seg1_Isl->GetLength( dToTLen) ; // nuova lunghezza della curva smussata tra pSeg1 e pCrvLink - dTollLeft = 1 - ( dLenI_e - ( ( 2 * s_dRad) / 16)) / dLenI_e ; // % paramtro sinistro per smusso - dTollRight = ( ( 2 * s_dRad) / 16) / dLen2 ; // % parametro destro per smusso + dTollLeft = 1 - ( dLenI_e - ( ( 2 * PockParams.dRad) / 16)) / dLenI_e ; // % paramtro sinistro per smusso + dTollRight = ( ( 2 * PockParams.dRad) / 16) / dLen2 ; // % parametro destro per smusso PtrOwner pCrv_smoothed( CreateCurveComposite()) ; // curva unione del primo smusso con pSeg2 pCrv_smoothed->AddCurve( pCrv_Seg1_Isl->Clone()) ; pCrv_smoothed->AddCurve( pCrvH2->Clone()) ; - ModifyCurveToSmoothed( pCrv_smoothed, dTollLeft, dTollRight, true) ; + ModifyCurveToSmoothed( pCrv_smoothed, PockParams, dTollLeft, dTollRight, true) ; // recupero i parametri del nuovo collegamento che si è creato dallo smusso pCrvH1->Clear() ; @@ -2308,7 +5215,8 @@ CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, ICurveComposite* //---------------------------------------------------------------------------- static bool -CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double dStep, bool bFromInfill) +CalcZigZag( const ISurfFlatRegion* pSrfZigZag, PocketParams PockParams, ICRVCOMPOPOVECTOR& vpCrvs, + bool bFromInfill) { // check parametri @@ -2334,12 +5242,12 @@ CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double int nYStep ; double dYStep ; if ( ! bFromInfill) { - nYStep = static_cast< int >( ceil(( dDimY - 30 * EPS_SMALL) / dStep)) ; + nYStep = static_cast< int >( ceil(( dDimY - 30 * EPS_SMALL) / PockParams.dSideStep)) ; dYStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ; } else { - nYStep = static_cast< int >( floor(( dDimY + 30 * EPS_SMALL) / dStep)) ; - dYStep = dStep ; + nYStep = static_cast< int >( floor(( dDimY + 30 * EPS_SMALL) / PockParams.dSideStep)) ; + dYStep = PockParams.dSideStep ; } int nRef = (( nYStep + ( 1)) % 2) ; @@ -2504,7 +5412,7 @@ CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double return false ; // aggiorno il link - if ( ! CalcZigZagLink( pSeg1, pSeg2, pCrvLink)) + if ( ! CalcZigZagLink( pSeg1, pSeg2, PockParams, pCrvLink)) return false ; // aggiorno il vettore delle curve ZigZag @@ -2626,14 +5534,11 @@ CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double return true ; } - - - //---------------------------------------------------------------------------- static bool -AddSpiralIn( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSmooth, ICRVCOMPOPOVECTOR& vCrvCompoRes) +AddSpiralIn( const ISurfFlatRegion* pSrfPock, PocketParams PockParams, + const ICRVCOMPOPOVECTOR& vCrvOrig, ICRVCOMPOPOVECTOR& vCrvCompoRes) { - // ciclo sui chunk della superficie da svuotare for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { @@ -2642,7 +5547,7 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bS if ( IsNull( pSrfChunk)) return false ; - const int MAX_REGS = 50 ; + const int MAX_REGS = 50 ; // massimo numero di regioni create dal primo offset int nReg = 0 ; // chunk nuovo corrente da svuotare // ciclo su tutte le regioni che posso ottenere col primo Offset del chunk c-esimo @@ -2655,8 +5560,15 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bS int nRegTot = nReg ; Point3d ptStart ; + bool bOptimizedTrap = false ; + + // cerco la curva originale del chunk cc-esimo ( per casi ottimizzati) + int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk cc-esimo + if ( ! GetOptCrvIndex( vCrvOrig, pSrfChunk, nInd)) + return false ; + // calcolo il percorso di svuotatura - if ( ! CalcSpiral( pSrfChunk, dRad, dStep, bSmooth, nRegTot, ptStart, pMCrv, pRCrv)) + if ( ! CalcSpiral( pSrfChunk, PockParams, nRegTot, ptStart, vCrvOrig[nInd], pMCrv, pRCrv, bOptimizedTrap)) return false ; // se terminate le regioni, esco @@ -2665,18 +5577,19 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bS // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; - ++nReg ; + ++ nReg ; // incremento il numero di regione progressiva } + } return true ; } //---------------------------------------------------------------------------- -bool -AddSpiralOut( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool bSmooth, ICRVCOMPOPOVECTOR& vCrvCompoRes) +static bool +AddSpiralOut( const ISurfFlatRegion* pSrfPock, PocketParams PockParams, + const ICRVCOMPOPOVECTOR& vCrvOrig, ICRVCOMPOPOVECTOR& vCrvCompoRes) { - // ciclo sui chunk della superficie da svuotare for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { @@ -2690,16 +5603,23 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool b while ( nReg < MAX_REGS) { - // calcolo la spirale dall'interno all'esterno - PtrOwner pMCrv( CreateCurveComposite()) ; - PtrOwner pRCrv( CreateCurveComposite()) ; - if ( IsNull( pMCrv) || IsNull( pRCrv)) - return false ; + // calcolo la spirale dall'interno all'esterno + PtrOwner pMCrv( CreateCurveComposite()) ; + PtrOwner pRCrv( CreateCurveComposite()) ; + if ( IsNull( pMCrv) || IsNull( pRCrv)) + return false ; - int nRegTot = nReg ; - Point3d ptStart ; + int nRegTot = nReg ; + Point3d ptStart ; + bool bOptimizedTrap = false ; - if ( ! CalcSpiral( pSrfChunk, dRad, dStep, bSmooth, nRegTot, ptStart, pMCrv, pRCrv)) + // cerco la curva originale del chunk cc-esimo ( per casi ottimizzati) + int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk cc-esimo + if ( ! GetOptCrvIndex( vCrvOrig, pSrfChunk, nInd)) + return false ; + + // calcolo il percorso di svuotatura + if ( ! CalcSpiral( pSrfChunk, PockParams, nRegTot, ptStart, vCrvOrig[nInd], pMCrv, pRCrv, bOptimizedTrap)) return false ; // se terminate le regioni, esco @@ -2712,7 +5632,7 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool b // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; - ++nReg ; + ++ nReg ; } } @@ -2720,12 +5640,12 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, bool b } //---------------------------------------------------------------------------- -bool -AddZigZag( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, double dAngle, bool bSmooth, ICRVCOMPOPOVECTOR& vCrvCompoRes) +static bool +AddZigZag( const ISurfFlatRegion* pSrfPock, PocketParams PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { // Offset della regione per curva ZigZag - double dOffs = dRad ; + double dOffs = PockParams.dRad ; // ciclo su tutti i chunks della superficie originale for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { @@ -2739,7 +5659,7 @@ AddZigZag( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, double dA Frame3d frPocket ; Point3d ptCen ; pSrfChunk->GetCentroid( ptCen) ; frPocket.Set( ptCen, pSrfChunk->GetNormVersor()) ; - frPocket.Rotate( ptCen, pSrfChunk->GetNormVersor(), dAngle) ; + frPocket.Rotate( ptCen, pSrfChunk->GetNormVersor(), PockParams.dAngle) ; // porto la superficie nel nuovo sistema di riferimento pSrfChunk->ToLoc( frPocket) ; @@ -2759,7 +5679,7 @@ AddZigZag( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, double dA if ( IsNull( pSrfZigZagChunk)) return false ; // calcolo i percorsi di ZigZag - if ( ! CalcZigZag( pSrfZigZagChunk, vpCrvs, dStep, false)) + if ( ! CalcZigZag( pSrfZigZagChunk, PockParams, vpCrvs, false)) return false ; // aggiorno il vettore delle curve risultati for ( int u = 0 ; u < int( vpCrvs.size()) ; ++ u) { @@ -2851,11 +5771,10 @@ OptimizeChunkOneWay( ISurfFlatRegion* pSrfOrig, ISURFFRPOVECTOR& vSrfIdeal) //---------------------------------------------------------------------------- static bool -AddOneWay( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, double dAngle, bool bSmooth, - ICRVCOMPOPOVECTOR& vCrvCompoRes) +AddOneWay( const ISurfFlatRegion* pSrfPock, PocketParams PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { - double dOffs = dRad ; + double dOffs = PockParams.dRad ; double dExtra = 0. ; // copio la regione da svuotare @@ -2896,14 +5815,14 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, double dRad, double dStep, double dA Frame3d frPocket ; Point3d ptCen ; pSrfIdeal->GetCentroid( ptCen) ; frPocket.Set( ptCen, pSrfIdeal->GetNormVersor()) ; - frPocket.Rotate ( ptCen, pSrfIdeal->GetNormVersor(), dAngle) ; + frPocket.Rotate ( ptCen, pSrfIdeal->GetNormVersor(), PockParams.dAngle) ; pSrfIdeal->ToLoc( frPocket) ; BBox3d b3Pocket ; pSrfIdeal->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // passi in Y - int nYStep = static_cast( ceil(( dDimY + 2 * dExtra) / dStep)) ; + int nYStep = static_cast( ceil(( dDimY + 2 * dExtra) / PockParams.dSideStep)) ; double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; --nYStep ; @@ -2965,29 +5884,53 @@ CalcPocketing( const ISurfFlatRegion *pSfr, double dRad, double dStep, double dA dStep < EPS_SMALL || ( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN && nType != POCKET_SPIRALOUT)) return false ; + // pulizia vettore delle curve elementari vCrvCompoRes.clear() ; + // assegno dati di modulo - s_nType = nType ; - s_dRad = dRad ; - s_bSmooth = bSmooth ; + PocketParams myParams ; + myParams.nType = nType ; + myParams.dRad = dRad ; + myParams.bSmooth = bSmooth ; + myParams.dAngle = dAngle ; + myParams.dSideStep = dStep ; + + // ------------ gestione dei lati aperti ------------------- + // 1) salvo le curve originali per casi ottimizzati + ICRVCOMPOPOVECTOR vCrvOEWithFlags ; + if ( ! GetCurvesForOptimizedPocketing( pSfr, vCrvOEWithFlags)) + return false ; + + // 2) modifico la supericie in base alle proprietà di lato aperto/chiuso + Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ; + Vector3d vtN = pSfr->GetNormVersor() ; + Frame3d frLoc ; + if ( ! frLoc.Set( ptCenter, vtN)) + return false ; + PtrOwner pSfrAdj( CloneSurfFlatRegion( pSfr)) ; + if ( IsNull( pSfrAdj) || + ! pSfrAdj->ToLoc( frLoc) || + ! ModifySurfByOpenEdges( pSfrAdj, myParams) || + ! pSfrAdj->ToGlob( frLoc)) + return false ; // calcolo delle curve elementari della superficie switch ( nType) { case POCKET_ZIGZAG : - if ( ! AddZigZag( pSfr, dRad, dStep, dAngle, bSmooth, vCrvCompoRes)) + if ( ! AddZigZag( pSfr, myParams, vCrvCompoRes)) return false ; break ; case POCKET_ONEWAY : - if ( ! AddOneWay( pSfr, dRad, dStep, dAngle, bSmooth, vCrvCompoRes)) + if ( ! AddOneWay( pSfr, myParams, vCrvCompoRes)) return false ; break ; case POCKET_SPIRALIN : - if ( ! AddSpiralIn( pSfr, dRad, dStep, bSmooth, vCrvCompoRes)) + if ( ! AddSpiralIn( pSfrAdj, myParams, vCrvOEWithFlags, vCrvCompoRes)) return false ; break ; case POCKET_SPIRALOUT : - if ( ! AddSpiralOut( pSfr, dRad, dStep, bSmooth, vCrvCompoRes)) + if ( ! AddSpiralOut( pSfrAdj, myParams, vCrvOEWithFlags, vCrvCompoRes)) return true ; break ; } @@ -3104,8 +6047,8 @@ AdjustLinkSameY( ICurveComposite* pCrvLink, bool& bSplit) //---------------------------------------------------------------------------- static bool -AdjustLinkDifferentY( const ICurve* pCrvSegPrec, const ICurve* pCrvSegSucc, const ICurveComposite* pCrvLink, - bool& bSplit) +AdjustLinkDifferentY( const ICurve* pCrvSegPrec, const ICurve* pCrvSegSucc, + const ICurveComposite* pCrvLink, PocketParams PockParams, bool& bSplit) { // controllo dei parametri if ( pCrvLink == nullptr || ! pCrvLink->IsValid()) @@ -3158,7 +6101,7 @@ AdjustLinkDifferentY( const ICurve* pCrvSegPrec, const ICurve* pCrvSegSucc, cons PtrOwner pSfrTrap_c( CloneSurfFlatRegion( pSfrTrap)) ; if ( IsNull( pSfrTrap_c)) return false ; - if ( ! pSfrTrap->Offset( - s_dRad / 5, ICurve::OFF_CHAMFER)) + if ( ! pSfrTrap->Offset( - PockParams.dRad / 5, ICurve::OFF_CHAMFER)) pSfrTrap.Set( pSfrTrap_c) ; // se il Link interseca questa regione, allora va eliminato @@ -3171,7 +6114,7 @@ AdjustLinkDifferentY( const ICurve* pCrvSegPrec, const ICurve* pCrvSegSucc, cons //---------------------------------------------------------------------------- static bool -AdjustLinkZigZagInfill( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vNewCrv) +AdjustLinkZigZagInfill( ICurveComposite* pCrvCompo, PocketParams PockParams, ICRVCOMPOPOVECTOR& vNewCrv) { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) @@ -3224,7 +6167,7 @@ AdjustLinkZigZagInfill( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vNewCrv) // se il Link collega due tratti a quote diverse else { if ( ! AdjustLinkDifferentY( pCrvCompo->GetCurve( u - 1), pCrvCompo->GetCurve( u + pCrvLink->GetCurveCount()), - pCrvLink, bSplit)) + pCrvLink, PockParams, bSplit)) return false ; } // aggiorno @@ -3265,8 +6208,10 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool if ( pSfr == nullptr || ! pSfr->IsValid() || dStep < EPS_SMALL) return false ; vCrvCompoRes.clear() ; - s_bSmooth = false ; - s_dRad = dStep / 2 ; + + PocketParams myParams ; + myParams.bSmooth = false ; + myParams.dRad = 0.5 * dStep ; // vettore con i percorsi a ZigZag ICRVCOMPOPOVECTOR vpCrvs ; @@ -3278,7 +6223,7 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; // calcolo i percorsi a ZigZag - if ( ! CalcZigZag( pSfrChunk, vpCrvs, dStep, true)) + if ( ! CalcZigZag( pSfrChunk, myParams, vpCrvs, true)) return false ; if ( bRemoveOverlapLink) { @@ -3289,7 +6234,7 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool // sistemo le curve ottenute, aggiustando i Links for ( int u = 0 ; u < int( vCrvFinal.size()) ; ++ u) { ICRVCOMPOPOVECTOR vNewCrv ; - if ( ! AdjustLinkZigZagInfill( vCrvFinal[u], vNewCrv)) + if ( ! AdjustLinkZigZagInfill( vCrvFinal[u], myParams, vNewCrv)) return false ; for ( int uu = 0 ; uu < int( vNewCrv.size()) ; ++ uu) vpCrvs.emplace_back( Release( vNewCrv[uu])) ; @@ -3299,8 +6244,8 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool // inserisco i percorsi da ritornare for ( int u = 0 ; u < int( vpCrvs.size()) ; ++ u) { if ( bSmooth) { - s_bSmooth = true ; - ModifyCurveToSmoothed( vpCrvs[u], s_dRad / 16, s_dRad / 16, false) ; + myParams.bSmooth = true ; + ModifyCurveToSmoothed( vpCrvs[u], myParams, myParams.dRad / 16, myParams.dRad / 16, false) ; } vCrvCompoRes.emplace_back( Release( vpCrvs[u])) ; }