diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 13f3896..616b585 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -19,6 +19,7 @@ #include "BiArcs.h" #include "SurfFlatRegion.h" #include "GeoConst.h" +#include "Voronoi.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkCalcPocketing.h" @@ -68,14 +69,15 @@ struct PocketParams { double dFeed = 1000 ; // feed di riferimento per frazione double dToolFeed = 1000 ; // feed del tool // ------------------------------------------------------- - bool bAllClosed = true ; // flag per indicare se tutti i bordi sono chiusi + bool bAllClosed = true ; // flag per indicare se tutti i bordi della *pSfr da svuotare sono chiusi + bool bAllOpen = true ; // flag per indicare se tutti i bordi della *pSfr da svuotare sono aperti double dOffsExtra = 2. ; // Offset aggiuntivo per percosi a ZigZag/OneWay se richieste le curve di bordo Frame3d frLocXY ; // frame per conti nel piano XY int nOffsType = ICurve::OFF_FILLET ; // tipologia di Offset per estensione degli aperti double dOpenEdgeRad = 0. ; // raggio effettivo di estensione degli aperti } ; - static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket +typedef vector VICRVCOMPOPOVECTOR ; //--------------------------------------------------------------------------- @@ -397,6 +399,8 @@ AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig } } } + else + AssignMaxFeed( pCrv, PockParams) ; return true ; } @@ -706,12 +710,38 @@ ResetCurveTempProps( ICurveComposite* pCrvCompo) //---------------------------------------------------------------------------- static bool -IsChunkAllClosed( const ISurfFlatRegion* pSfr, int nChunk, bool& bAllClose) +GetSfrCrvCompoLoops( const ISurfFlatRegion* pSfr, ICRVCOMPOPOVECTOR& vCrvCompo) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + vCrvCompo.clear() ; + + // scorro i Chunk della superficie + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { + // scorro i loop del Chunk nC-esimo + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { + // recupero il Loop come curva composita + PtrOwner pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; + if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) + return false ; + // inserisco la curva nel vettore + vCrvCompo.emplace_back( Release( pCrvLoop)) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +IsChunkAllHomogeneous( const ISurfFlatRegion* pSfr, int nChunk, bool& bAllClose, bool& bAllOpen) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || nChunk < 0 || nChunk > pSfr->GetChunkCount()) return false ; bAllClose = true ; + bAllOpen = true ; // scorro tutti i loop del Chunk for ( int nL = 0 ; nL < pSfr->GetLoopCount( nChunk) ; ++ nL) { @@ -722,9 +752,11 @@ IsChunkAllClosed( const ISurfFlatRegion* pSfr, int nChunk, bool& bAllClose) // scorro le curve semplici int nCurrProp = TEMP_PROP_INVALID ; for ( int nU = 0 ; nU < pCrvLoop->GetCurveCount() ; ++ nU) { - bAllClose = ( pCrvLoop->GetCurveTempProp( nU, nCurrProp, 0) && + bAllClose = ( bAllClose && pCrvLoop->GetCurveTempProp( nU, nCurrProp, 0) && nCurrProp == TEMP_PROP_CLOSE_EDGE) ; - if ( ! bAllClose) + bAllOpen = ( bAllOpen && pCrvLoop->GetCurveTempProp( nU, nCurrProp, 0) && + nCurrProp == TEMP_PROP_OPEN_EDGE) ; + if ( ! bAllClose && ! bAllOpen) return true ; } } @@ -734,24 +766,78 @@ IsChunkAllClosed( const ISurfFlatRegion* pSfr, int nChunk, bool& bAllClose) //---------------------------------------------------------------------------- static bool -IsSfrAllClosed( const ISurfFlatRegion* pSfr, bool& bAllClose) +IsSfrAllHomogeneous( const ISurfFlatRegion* pSfr, bool& bAllClose, bool& bAllOpen) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; bAllClose = true ; + bAllOpen = true ; // ciclo sui Chunk della regione for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { - if ( ! IsChunkAllClosed( pSfr, nC, bAllClose)) + bool bChunkClose = true ; + bool bChunkOpen = true ; + if ( ! IsChunkAllHomogeneous( pSfr, nC, bChunkClose, bChunkOpen)) return false ; - if ( ! bAllClose) + bAllClose = ( bAllClose && bChunkClose) ; + bAllOpen = ( bAllOpen && bChunkOpen) ; + if ( ! bAllClose && ! bAllClose) return true ; } return true ; } +//---------------------------------------------------------------------------- +static bool +IsSfrChunkMadeOnlyByClosedIslands( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParams, + bool& bOK, ICRVCOMPOPOVECTOR& vCrvIsl) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + vCrvIsl.clear() ; + bOK = false ; + + // se non esistono isole + if ( pSfrChunk->GetLoopCount( 0) == 1) + return true ; + + // controllo il loop esterno + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) + return false ; + for ( int i = 0 ; i < pCrvExtLoop->GetCurveCount() ; ++ i) { + int nTmpProp = TEMP_PROP_INVALID ; + if ( pCrvExtLoop->GetCurveTempProp( i, nTmpProp, 0) && nTmpProp == TEMP_PROP_CLOSE_EDGE) + return true ; + } + + // controllo le Isole + bool bOkIsl = true ; + for ( int i = 1 ; i < pSfrChunk->GetLoopCount( 0) && bOkIsl ; ++ i) { + // recupero l'isola + PtrOwner pCrvIsl( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, i))) ; + if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid()) + return false ; + // controllo le sue TmpProps + for ( int i = 0 ; i < pCrvIsl->GetCurveCount() && bOkIsl ; ++ i) { + int nTmpProp = TEMP_PROP_INVALID ; + bOkIsl = ( pCrvIsl->GetCurveTempProp( i, nTmpProp, 0) && nTmpProp == TEMP_PROP_CLOSE_EDGE) ; + } + if ( bOkIsl) + vCrvIsl.emplace_back( Release( pCrvIsl)) ; + } + + if ( ! bOkIsl) + vCrvIsl.clear() ; + else + bOK = true ; + + return true ; +} + //---------------------------------------------------------------------------- static bool ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams, @@ -838,7 +924,7 @@ AdjustContourStart( ICurveComposite* pCompo, const PocketParams& PockParams) pCrv = pCompo->GetNextCurve() ; } // se non trovato o troppo corto, cerco il tratto chiuso più lungo in generale ( non lineare) - if ( nMax < 0 || dLenMax < 2. * PockParams.dRad + 2 * PockParams.dRadialOffset) { + if ( nMax < 0 || dLenMax < 1.25 * PockParams.dRad) { i = 0 ; pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { @@ -903,6 +989,24 @@ GetHomogeneousParts( ICurveComposite* pCrvCompo, const PocketParams& PockParams, return true ; } +//---------------------------------------------------------------------------- +static bool +GetFirstOffsCrvFromSfr( const ISurfFlatRegion* pSfr, double dOffs, ICRVCOMPOPOVECTOR& vCrvFirstOffs) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + vCrvFirstOffs.clear() ; + + // creo la regione mediante Offset + PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( dOffs, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) + return false ; + + // inserisco le curve orientante + return ( GetSfrCrvCompoLoops( pSfrOffs, vCrvFirstOffs)) ; +} + //--------------------------------------------------------------------------- static bool CreateSurfFrIncidence( const ICurveComposite* pCrv, const PocketParams& PockParams, @@ -1725,8 +1829,8 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara //---------------------------------------------------------------------------- static bool -ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, - bool& bSkipPocket) +ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCalcSingleCrv, + ICRVCOMPOPOVECTOR& vCrvCompoRes, bool& bSkipPocket) { // controllo parametri : if ( pSfr == nullptr || ! pSfr->IsValid()) @@ -1734,7 +1838,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP bSkipPocket = false ; // controllo se esistono dei lati aperti - if ( ! IsSfrAllClosed( pSfr, PockParams.bAllClosed)) + if ( ! IsSfrAllHomogeneous( pSfr, PockParams.bAllClosed, PockParams.bAllOpen)) return false ; // se lati tutti chiusi, allora non devo fare nulla if ( PockParams.bAllClosed) @@ -1766,16 +1870,16 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; - bool bIsAllRemoved = false ; - GetPocketCurvesByClosedEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; - if ( bIsAllRemoved) { - // se ho rimosso tutto, allora passo la chunk successivo - ++ nChunkOneCurve ; - continue ; + + if ( bCalcSingleCrv) { + bool bIsAllRemoved = false ; + GetPocketCurvesByClosedEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; + if ( bIsAllRemoved) { + // se ho rimosso tutto, allora passo la chunk successivo + ++ nChunkOneCurve ; + continue ; + } } - // controllo se la lavorazione ammatte estensione da aperti - if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) - continue ; // vettore delle isole che userò ( le isole aperte piccole sono trascurate) ICRVCOMPOPOVECTOR vCrvToTIsland ; @@ -1892,6 +1996,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP } } + // se ho ottenuto delle curve singole, allora le provo a concatenare // ( tenendo solo le curve al di fuori della superficie limite ( con Offset del raggio del tool) // potrei doverle riconcatenare @@ -1922,12 +2027,32 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP return true ; // restituisco la superficie aggiornata ricavata - if ( PockParams.nType != POCKET_CONFORMAL_ZIGZAG) { - if ( ! pSrfFinal->IsValid()) - return false ; - pSfr->Clear() ; - pSfr->CopyFrom( pSrfFinal) ; + if ( ! pSrfFinal->IsValid()) + return false ; + // chiudo le isole che risultano ambigue + for ( int nC = 0 ; nC < pSrfFinal->GetChunkCount() ; ++ nC) { + for ( int nL = 1 ; nL < pSrfFinal->GetLoopCount( nC) ; ++ nL) { + // controllo uniformità + int nCurrTmpProp = TEMP_PROP_INVALID ; + int nPrecTmpProp = TEMP_PROP_INVALID ; + bool bIsMixed = false ; + PtrOwner pCrvIsl( ConvertCurveToComposite( pSrfFinal->GetLoop( nC, nL))) ; + if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid()) + return false ; + for ( int nU = 0 ; nU < pCrvIsl->GetCurveCount() && ! bIsMixed ; ++ nU) { + pCrvIsl->GetCurveTempProp( nU, nCurrTmpProp, 0) ; + bIsMixed = ( nU != 0 && nCurrTmpProp != nPrecTmpProp) ; + nPrecTmpProp = nCurrTmpProp ; + } + // se proprità non uniformi -> tutta chiusa + if ( bIsMixed) { + for ( int nU = 0 ; nU < pCrvIsl->GetCurveCount() ; ++ nU) + pSrfFinal->SetCurveTempProp( nC, nL, nU, TEMP_PROP_CLOSE_EDGE) ; + } + } } + pSfr->Clear() ; + pSfr->CopyFrom( pSrfFinal) ; return ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) ; } @@ -4170,9 +4295,8 @@ CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPO return false ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; - if ( dLenA < dLenB) { - pCompoHelp->AddCurve( Release( pCrvA)) ; - } + if ( dLenA < dLenB) + pCompoHelp->AddCurve( Release( pCrvA)) ; else { pCrvB->Invert() ; pCompoHelp->AddCurve( Release( pCrvB)) ; @@ -4535,7 +4659,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& // ================= LINK ================================ int nLink_Ind = ( bFollowOrder ? i + 1 : i) ; - // ( Il primo link è nullo, inatti non vi è nessun raccordo per raggiungere il primo Offset) + // ( Il primo link è nullo, infatti non vi è nessun raccordo per raggiungere il primo Offset) if ( nLink_Ind < int( vLinks.size()) && ! IsNull( vLinks[nLink_Ind]) && vLinks[nLink_Ind]->IsValid()) { @@ -4577,6 +4701,13 @@ static bool RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { + /* + E' richiesto che le curve di Offset presentino le seguenti TempProps : + - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] + - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] + [per SPIRAL le proprietà sono ricavate automaticamente] + */ + // se non ho nessuna superficie valida da svuotare, allora esco if ( pSfrUncleared == nullptr) return false ; @@ -4608,7 +4739,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) bSkip = ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) ; else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) - bSkip = vOffs[i]->GetTempProp( 0) == 0 ; + bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; } if ( bSkip) continue ; @@ -4621,7 +4752,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs continue ; } else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { - if ( nSide != vOffs[i]->GetTempProp( 1)) + if ( nSide == vOffs[i]->GetTempProp( 1)) continue ; } } @@ -4903,8 +5034,6 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con vLinks.clear() ; vLinks.resize( int( vOffs.size())) ; - vector VT ; - // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { @@ -5115,81 +5244,6 @@ CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, return true ; } -//---------------------------------------------------------------------------- -static bool -ExtendGuideByIteration( ICurveComposite* pCompoTempGuide, const ICurveComposite* pCompoPerimeter, - bool bInverted) -{ - // controllo dei parametri - if ( pCompoTempGuide == nullptr || ! pCompoTempGuide->IsValid() || - pCompoPerimeter == nullptr || ! pCompoPerimeter->IsValid()) - return false ; - - const double EXTENSION_VAL = 1000. ; - - // ricavo il punto finale della guida - Point3d ptEndGuide ; pCompoTempGuide->GetEndPoint( ptEndGuide) ; - // direzione finale della guida - Vector3d vtEndGuide ; pCompoTempGuide->GetEndDir( vtEndGuide) ; - // creo un segmento diretto come il chiuso - PtrOwner pSeg( CreateCurveLine()) ; - if ( IsNull( pSeg) || - ! pSeg->Set( ptEndGuide, ptEndGuide + EXTENSION_VAL * vtEndGuide)) - return false ; - // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta - IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; - // se l'unica intersezione è il punto iniziale del segmento, allora non estendo la guida - // ( vale anche nel caso di intersezione con Overlap) - if ( ICC.GetIntersCount() == 1) { - IntCrvCrvInfo aInfo ; - if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { - if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) - return true ; - } - } - // passo alla PolyLine del perimetro - PolyLine PL ; - pCompoPerimeter->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, PL) ; - // cerco il punto più esterno rispetto alla direzione del chiuso - Point3d ptPoly ; - PL.GetFirstPoint( ptPoly) ; - while ( PL.GetNextPoint( ptPoly)) { - if ( ! pSeg->Set( ptEndGuide, ptEndGuide + ( ptPoly - ptEndGuide) * EXTENSION_VAL)) - return false ; - // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta - IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; - // se una intersezione, allora di Overlap con punto iniziale e finale definito - if ( ICC.GetIntersCount() == 1) { - IntCrvCrvInfo aInfo ; - if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { - if ( aInfo.bOverlap) { - if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide) && - AreSamePointApprox( aInfo.IciB[1].ptI, ptPoly)) - return ( pCompoTempGuide->AddLine( ptPoly)) ; - } - else { - if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) - return ( pCompoTempGuide->AddLine( ptPoly)) ; - } - } - } - // se più di una intersezione, allora il perimetro deve essere tutto Interno al segmento - // ( Out nel caso in cui ho le curve invertite) - IntCrvCrvInfo aInfo ; - bool bOk = true ; - for ( int i = 0 ; i < ICC.GetIntersCount() && bOk ; ++ i) { - bOk = ( ICC.GetIntCrvCrvInfo( i, aInfo)) ; - bOk = ( aInfo.bOverlap || - ( aInfo.IciB[0].nPrevTy != ( ! bInverted ? CRVC_OUT : CRVC_IN) && - aInfo.IciB[0].nNextTy != ( ! bInverted ? CRVC_OUT : CRVC_IN))) ; - } - if ( bOk) - return ( pCompoTempGuide->AddLine( ptPoly)) ; - } - - return true ; -} - //---------------------------------------------------------------------------- static bool IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const PocketParams& PockParams, @@ -5218,445 +5272,10 @@ IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const Po } } - // controlloo che la curva abbia esattamente due tratti omogenei + // controllo che la curva abbia esattamente due tratti omogenei bOk = ( int( vpCrvs.size()) == 2) ; if ( ! bOk) vpCrvs.clear() ; - return true ; - -} - -//---------------------------------------------------------------------------- -static bool -CalcCrvGuideConformalZigZag( const ISurfFlatRegion* pSfrChunk, PocketParams& PockParams, ICurveComposite* pCompoGuide, - ICurveComposite* pCompoClass, ICurveComposite* pCompoClass_UR) -{ - /* - NB. La curva di classificazione pCompoClass è una curva chiusa che deriva dall'estensione - presso i lati aperti con un tool di ragggio a max( dRad / 8, PockParams.dSideStep / 2). - NB. La curva di classificazione pCompoClass_UR è la curva mediante la quale i Biarchi di - raccordo ( curve a racciolo non devono uscire) ; in questo caso l'estensione della - curva è paragonabile a quella di un tool con raggio - max( dRad / 8, PockParams.dSideStep / 2) + PockParams.Rad - in questo modo il controOffset della regione definisce correttamente la curva per la classificazione - */ - - - // controllo dei parametri - if ( pCompoGuide == nullptr || pCompoClass == nullptr || pCompoClass_UR == nullptr || - pSfrChunk == nullptr || ! pSfrChunk->IsValid()) - return false ; - pCompoGuide->Clear() ; - pCompoClass->Clear() ; - pCompoClass_UR->Clear() ; - - // la superficie deve avere un Chunk e non avere isole - if ( pSfrChunk->GetChunkCount() > 1 || pSfrChunk->GetLoopCount( 0) > 1) - return true ; - - // ricavo la curva di bordo ( la curva che definisce il perimetro) - PtrOwner pCompoPerimeter( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; - if ( IsNull( pCompoPerimeter) || ! pCompoPerimeter->IsValid()) - return false ; - // controllo che sia formata da esattamente due tratti omogenei - bool b2HP = false ; - ICRVCOMPOPOVECTOR vpCrvs ; - if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs)) - return false ; - if ( ! b2HP) - return true ; - - // allargo curva di Bordo secondo le specifiche di una lavorazione a SpiralIn - double dRad = PockParams.dRad ; - int nOffsType = PockParams.nOffsType ; - PockParams.dRad = max( dRad / 8, PockParams.dSideStep / 2) ; - PockParams.nOffsType = ICurve::OFF_CHAMFER ; - ICRVCOMPOPOVECTOR vCrvEmpty ; - if ( ! AdjustContourWithOpenEdges( pCompoPerimeter, vCrvEmpty, PockParams)) - return false ; - PockParams.dRad = dRad ; - PockParams.nOffsType = nOffsType ; - - // reucupero ora i due tratti uniformi ( della curva allargata) - if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs) || - ! b2HP) - return false ; - - // la guida inizialmente è data dal tratto chiuso - // il perimetro coincide con il tratto aperto - PtrOwner pCompoTempGuide( Release( vpCrvs[0])) ; - if ( IsNull( pCompoTempGuide) || ! pCompoTempGuide->IsValid()) - return false ; - - // estendo la curva nel suo tratto finale ed iniziale - for ( int i = 0 ; i < 2 ; ++ i) { - if ( ! ExtendGuideByIteration( pCompoTempGuide, vpCrvs[1], ( i == 1))) - return false ; - // se la guida diventa diventa chiusa, allora esco - if ( ! pCompoTempGuide->IsValid() || pCompoTempGuide->IsClosed()) - return true ; - pCompoTempGuide->Invert() ; - vpCrvs[1]->Invert() ; - } - - // tratto iniziale - Vector3d vtStart ; pCompoTempGuide->GetStartDir( vtStart) ; - Point3d ptStart ; pCompoTempGuide->GetStartPoint( ptStart) ; - PtrOwner pLineStart( CreateCurveLine()) ; - if ( IsNull( pLineStart) || ! pLineStart->Set( ptStart - 1000. * vtStart, ptStart)) - return false ; - // tratto finale ( potrebbe intersecare il tratto iniziale) - Vector3d vtEnd ; pCompoTempGuide->GetEndDir( vtEnd) ; - Point3d ptEnd ; pCompoTempGuide->GetEndPoint( ptEnd) ; - PtrOwner pLineEnd( CreateCurveLine()) ; - if ( IsNull( pLineEnd) || ! pLineEnd->Set( ptEnd, ptEnd + 1000. * vtEnd)) - return false ; - IntersCurveCurve ICC( *pLineStart, *pLineEnd) ; - if ( ICC.GetIntersCount() > 0) { - IntCrvCrvInfo aInfo ; - if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { - pLineStart->TrimStartAtParam( aInfo.IciA[0].dU) ; - pLineEnd->TrimEndAtParam( aInfo.IciB[0].dU) ; - } - } - // le due estensioni vanno tagliate presso i bordi dei lati aperti estesi - IntersCurveCurve ICCLS( *pLineStart, *vpCrvs[1]) ; - if ( ICCLS.GetIntersCount() > 0) { - IntCrvCrvInfo aInfo ; - for ( int i = 0 ; i < ICCLS.GetCrossIntersCount() ; ++ i) { - if ( ICCLS.GetIntCrvCrvInfo( i, aInfo)) { - if ( ! AreSamePointApprox( aInfo.IciA[ aInfo.bOverlap ? 1 : 0].ptI, ptStart)) - pLineStart->ModifyStart( aInfo.IciA[aInfo.bOverlap ? 1 : 0].ptI) ; - } - } - } - IntersCurveCurve ICCLE( *pLineEnd, *vpCrvs[1]) ; - if ( ICCLE.GetIntersCount() > 0) { - IntCrvCrvInfo aInfo ; - for ( int i = 0 ; i < ICCLE.GetCrossIntersCount() ; ++ i) { - if ( ICCLE.GetIntCrvCrvInfo( 0, aInfo)) { - if ( ! AreSamePointApprox( aInfo.IciA[0].ptI, ptEnd)) - pLineEnd->ModifyEnd( aInfo.IciA[0].ptI) ; - } - } - } - pCompoTempGuide->AddCurve( Release( pLineStart), false) ; - pCompoTempGuide->AddCurve( Release( pLineEnd), true) ; - - // recupero la curva guida - pCompoGuide->CopyFrom( pCompoTempGuide) ; - - // recupero la curva di classificazione ( abballendola) - PolyLine PL ; - pCompoPerimeter->ApproxWithLines( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ; - PL.RemoveAlignedPoints( 500 * EPS_SMALL) ; - pCompoPerimeter->Clear() ; - pCompoPerimeter->FromPolyLine( PL) ; - pCompoPerimeter->RemoveSmallDefects( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, true) ; - pCompoPerimeter->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; - pCompoClass->CopyFrom( pCompoPerimeter) ; - ResetCurveTempProps( pCompoClass) ; - - // creo la curva di classificazione per le regioni non svuotate - dRad = PockParams.dRad ; - PockParams.dRad = max( dRad / 8, PockParams.dSideStep / 2) + dRad ; - PtrOwner pCompoClassUnclearedRegion( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; - if ( IsNull( pCompoClassUnclearedRegion) || ! pCompoClassUnclearedRegion->IsValid() || - ! AdjustContourWithOpenEdges( pCompoClassUnclearedRegion, vCrvEmpty, PockParams)) - return false ; - PockParams.dRad = dRad ; - if ( pCompoClassUnclearedRegion->IsValid()) { - OffsetCurve OffsCrv ; - if ( ! OffsCrv.Make( pCompoClassUnclearedRegion, - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) - return false ; - PtrOwner pMyCrv( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; - if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) - return false ; - pCompoClass_UR->CopyFrom( pMyCrv) ; - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -AdapthLinkToOffsBySmooth( ICurveComposite* pCrvLink, ICurveComposite* pCrvOffsPrec, - ICurveComposite* pCrvOffsSucc, const PocketParams& PockParams) -{ - // controllo dei parametri - if ( pCrvLink == nullptr || pCrvOffsPrec == nullptr || pCrvOffsSucc == nullptr || - ! pCrvLink->IsValid() || ! pCrvOffsPrec->IsValid() || ! pCrvOffsSucc->IsValid()) - return false ; - - // clono la curva di Link ( in modo da non rovinare l'originale) - PtrOwner pCrvMyLink( CloneCurveComposite( pCrvLink)) ; - if ( IsNull( pCrvMyLink) || ! pCrvMyLink->IsValid()) - return false ; - - // aggiungo la curva finale dell'Offset precedente e la curva iniziale dell'Offset successivo - // al tratto di Link - PtrOwner pCrvPrec( pCrvOffsPrec->GetLastCurve()->Clone()) ; - PtrOwner pCrvSucc( pCrvOffsSucc->GetFirstCurve()->Clone()) ; - if ( IsNull( pCrvPrec) || IsNull( pCrvSucc) || - ! pCrvPrec->IsValid() || ! pCrvSucc->IsValid()) - return false ; - // assegno proprietà di invalidità delle curve - pCrvPrec->SetTempProp( TEMP_PROP_INVALID, 1) ; - pCrvSucc->SetTempProp( TEMP_PROP_INVALID, 1) ; - // aggiungo - if ( ! pCrvMyLink->AddCurve( Release( pCrvPrec), false) || - ! pCrvMyLink->AddCurve( Release( pCrvSucc), true)) - return false ; - - // estendo la curva, in modo da non perdere i tratti estremi - const double EXT_LEN = 1000. ; - if ( ! pCrvMyLink->AddLineTg( EXT_LEN, false) || - ! pCrvMyLink->AddLineTg( EXT_LEN, true)) - return false ; - - // smusso il Link - double dSmoothParam = PockParams.dRad / 8. ; - ModifyCurveToSmoothed( pCrvMyLink, PockParams, dSmoothParam, dSmoothParam, false) ; - - // rimuovo la prima e l'ultima curva ( e quella invalida) - delete( pCrvMyLink->RemoveFirstOrLastCurve( false)) ; // tratto lineare - delete( pCrvMyLink->RemoveFirstOrLastCurve( true)) ; // tratto lineare - const ICurve* pCrvFirst = pCrvMyLink->GetFirstCurve() ; - if ( pCrvFirst != nullptr && pCrvFirst->GetTempProp( 1) == TEMP_PROP_INVALID) // sottocurva di Offs - delete( pCrvMyLink->RemoveFirstOrLastCurve( false)) ; - const ICurve* pCrvLast = pCrvMyLink->GetLastCurve() ; - if ( pCrvLast != nullptr && pCrvLast->GetTempProp( 1) == TEMP_PROP_INVALID) // sottocurva di Offs - delete( pCrvMyLink->RemoveFirstOrLastCurve( true)) ; - - // recupero punto iniziale e finale del Link - Point3d ptS ; pCrvMyLink->GetStartPoint( ptS) ; - Point3d ptE ; pCrvMyLink->GetEndPoint( ptE) ; - // recupero i paramtri sulle curve di Offset - double dUTrim ; - if ( ! pCrvOffsPrec->GetParamAtPoint( ptS, dUTrim, 500 * EPS_SMALL) || - ! pCrvOffsPrec->TrimEndAtParam( dUTrim)) - return false ; - if ( ! pCrvOffsSucc->GetParamAtPoint( ptE, dUTrim, 500 * EPS_SMALL) || - ! pCrvOffsSucc->TrimStartAtParam( dUTrim)) - return false ; - pCrvLink->CopyFrom( pCrvMyLink) ; - return true ; -} - -//---------------------------------------------------------------------------- -static bool -AddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, - ICRVCOMPOPOVECTOR& vCrvCompoRes) -{ - /* - Calcolo ottimizzato di svuotatura mediante Offset progressivi di una guida, raccordati - rispetto al bordo della superficie di Pocketing mediante logica ZigZag - */ - - // controllo dei parametri - if ( pSfr == nullptr || ! pSfr->IsValid()) - return false ; - vCrvCompoRes.clear() ; - - // ciclo sui chunk della regione - for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { - // recupero il Chunk nC-esimo - PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; - if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) - return false ; - - // recupero il massimo Offset del Chunk nC-esimo - double dMaxOffs ; - pSfrChunk->GetMaxOffset( dMaxOffs) ; - // se inferiore del Tool ( ho già svuotato tale Chunk in precedenza) - if ( dMaxOffs < PockParams.dRad + 200 * EPS_SMALL) - continue ; - - // ricavo la guida ideale e la curva su cui tagliare gli Offset a partire dal Chunk nC-esimo - PtrOwner pCrvGuideExt( CreateCurveComposite()) ; - PtrOwner pCrvClass( CreateCurveComposite()) ; - PtrOwner pCrvClassUR( CreateCurveComposite()) ; - if ( IsNull( pCrvGuideExt) || IsNull( pCrvClass) || - ! CalcCrvGuideConformalZigZag( pSfr, PockParams, pCrvGuideExt, pCrvClass, pCrvClassUR)) - return false ; - // se non è stata trovata una guida ideale, allora passo al Chunk successivo - if ( ! pCrvGuideExt->IsValid() || pCrvGuideExt->GetCurveCount() == 0 || - ! pCrvClass->IsValid() || pCrvClass->GetCurveCount() == 0 || - ! pCrvClassUR->IsValid() || pCrvClassUR->GetCurveCount() == 0) { - return true ; - } - - // memorizzo le curve di Offset tagliate a seconda dalla geometria del perimetro - ICRVCOMPOPOVECTOR vOffs ; - const int MAX_ITER = 100 ; - double dOffs = PockParams.dRad + PockParams.dRadialOffset ; - for ( int i = 0 ; i < MAX_ITER ; ++ i) { - OffsetCurve OffsCrv ; - if ( ! OffsCrv.Make( pCrvGuideExt, - dOffs, ICurve::OFF_FILLET)) - return false ; - // se invece ne ottengo più di una, controllo se è necessaria - if ( OffsCrv.GetCurveCount() > 1) { - // recupero le curve extra ( tutte tranne la più lunga) - for ( int j = 0 ; j < OffsCrv.GetCurveCount() - 1 ; ++ j) { - // recupero la curva più corta - PtrOwner pCrvShorter( ConvertCurveToComposite( OffsCrv.GetShorterCurve())) ; - if ( ! IsNull( pCrvShorter) && pCrvShorter->IsValid()) { - // controllo se è davvero necessaria per non lasciare materiale - bool bSkip = false ; - if ( pCrvShorter->IsClosed()) { - CheckIfOffsetIsNecessary( pCrvShorter, ( i == 0 ? dOffs : PockParams.dSideStep), - i, PockParams, bSkip) ; - if ( bSkip) - return true ; - } - } - } - } - // se non ottengo nessuna curva, allora ho finito - PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; - if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid()) - break ; - // se ottengo una curva chiusa, lavorazione non ammessa - if ( pCrvOffs->IsClosed()) - return true ; - // la inverto se numero di Offset progressivo dispari - if ( ( ! IsEven( i) && ! PockParams.bInvert) || - ( IsEven( i) && PockParams.bInvert)) - pCrvOffs->Invert() ; - // classifico la curva rispetto al perimetro, devo tenere solo le parti interne - CRVCVECTOR ccClass ; - IntersCurveCurve ICC( *pCrvOffs, *pCrvClass) ; - if ( ! ICC.GetCurveClassification( 0, EPS_SMALL, ccClass)) - return true ; - // se curva tutta esterna ho finito - if ( int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) - break ; - // scorro tutte le classificazioni ottenute - for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { - // tengo quelle strettamente interne - if ( ccClass[j].nClass == CRVC_IN) { - // recupero la porzione di Offset - PtrOwner pCrvOffs_Int( pCrvOffs->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; - if ( ! IsNull( pCrvOffs_Int) && pCrvOffs_Int->IsValid()) { - // salvo come prima proprietà temporanea, il numero di Offset progressivo - pCrvOffs_Int->SetTempProp( i, 0) ; - // salvo come seconda proprietà temporanea il lato esterno - pCrvOffs_Int->SetTempProp( ( ! IsEven( i) && ! PockParams.bInvert) || - ( IsEven( i) && PockParams.bInvert) ? - MDS_LEFT : MDS_RIGHT, 1) ; - // salvo la curva - vOffs.emplace_back( ConvertCurveToComposite( Release( pCrvOffs_Int))) ; - } - } - } - dOffs += PockParams.dSideStep ; - } - // se non ho ottenuto Offset, passo al Chunk successivo - if ( vOffs.empty()) - return true ; - - // inverto il vettore degli Offset, in modo da partire dal più esterno fino ad arrivare al - // più interno - reverse( vOffs.begin(), vOffs.end()) ; - - // calcolo la lunghezza del semiperimetro della curva di classificazione - // ( serve per decidere il tratto di curva di raccordo) - double dHalfLenPerimeter ; - pCrvClass->GetLength( dHalfLenPerimeter) ; - dHalfLenPerimeter /= 2. ; - - // creo il vettore dei Link e definisco la tolleranza di Join tra Offset e Link - ICURVEPOVECTOR vLinks( int( vOffs.size())) ; - Point3d ptSplit ; // punto dal quale smussare tutti i percorsi - for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { - // recupero il parametro iniziale del raccordo sulla curva di perimetro - Point3d ptS ; vOffs[i]->GetEndPoint( ptS) ; - double dUS ; pCrvClass->GetParamAtPoint( ptS, dUS) ; - if ( vOffs[i]->GetTempProp( 0) == 0) - ptSplit = ptS ; - // recupero il parametro finale del raccordo sulla curva di perimetro - Point3d ptE ; vOffs[i+1]->GetStartPoint( ptE) ; - double dUE ; pCrvClass->GetParamAtPoint( ptE, dUE) ; - // recupero il tratto di curva di interesse - PtrOwner pCrvJoint( ConvertCurveToComposite( pCrvClass->CopyParamRange( dUS, dUE))) ; - if ( ! IsNull( pCrvJoint) && pCrvJoint->IsValid()) { - double dLen ; - pCrvJoint->GetLength( dLen) ; - if ( dLen > dHalfLenPerimeter) { - pCrvJoint.Set( ConvertCurveToComposite( pCrvClass->CopyParamRange( dUE, dUS))) ; - pCrvJoint->Invert() ; - } - // solo se non siamo in presenza di curve di primo Offset, aggiungo al Link l'ultima - // curva dell'Offset precedente e la prima curva dell'Offset successivo - if ( vOffs[i]->GetTempProp( 0) > 0 || vOffs[i+1]->GetTempProp( 0) > 0) { - if ( ! AdapthLinkToOffsBySmooth( pCrvJoint, vOffs[i], vOffs[i+1], PockParams)) - return false ; - } - vLinks[i+1].Set( Release( pCrvJoint)) ; - } - } - - // smusso tutte le curve di Offset ( tranne quelle generate alla prima iterazione) - double dSmoothParam = PockParams.dRad / 8. ; - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { - if ( vOffs[i]->GetTempProp( 0) > 0) - ModifyCurveToSmoothed( vOffs[i], PockParams, dSmoothParam, dSmoothParam, false) ; - } - - // determino la regione piana dove sono contenute le zone non svuotate ( se esistono) - PtrOwner pSfrFirstOffs( CloneSurfFlatRegion( pSfrChunk)) ; - if ( IsNull( pSfrFirstOffs) || ! pSfrFirstOffs->IsValid() || - ! pSfrFirstOffs->Offset( - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) - return false ; - ICRVCOMPOPOVECTOR vCrvFirstOffs ; - for ( int nC_ = 0 ; nC_ < pSfrFirstOffs->GetChunkCount() ; ++ nC_) - vCrvFirstOffs.emplace_back( ConvertCurveToComposite( pSfrFirstOffs->GetLoop( nC_, 0))) ; - // inizializzo la regione contenente le parti non svuotate - PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; - if ( IsNull( pSfrUncleared)) - return false ; - // calcolo la Feed e la regione contenente le parti non svuotate - if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vOffs, vLinks, pCrvClass, PockParams, pSfrUncleared)) { - // Modifico i percorsi - vCrvFirstOffs.clear() ; - vCrvFirstOffs.emplace_back( Release( pCrvClassUR)) ; - if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vCrvFirstOffs, PockParams)) - return false ; - } - - // creo il percorso di svuotatura - PtrOwner pCompoTempPath( CreateCurveComposite()) ; - if ( IsNull( pCompoTempPath)) - return false ; - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { - if ( ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { - if ( ! pCompoTempPath->AddCurve( Release( vLinks[i]))) - return false ; - } - if ( ! IsNull( vOffs[i]) && vOffs[i]->IsValid()) { - if ( ! pCompoTempPath->AddCurve( Release( vOffs[i]))) - return false ; - } - } - - // se la curva finale di Pocketing è valida, allora la resituisco - if ( pCompoTempPath->IsValid()) { - // semplifico le curve mediante uniformità delle Feeds - SimplifyCurveByFeeds( pCompoTempPath, PockParams, 10 * EPS_SMALL) ; - // aggiugno il tratto iniziale e finale per entrate da fuori - Vector3d vtStart ; pCompoTempPath->GetStartDir( vtStart) ; - vtStart.Invert() ; - bool bExt = false ; - if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtStart, false, bExt)) - return false ; - Vector3d vtEnd ; pCompoTempPath->GetEndDir( vtEnd) ; - if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtEnd, true, bExt)) - return false ; - // sostituisco la curva - if ( pCompoTempPath->IsValid()) - vCrvCompoRes.emplace_back( Release( pCompoTempPath)) ; - } - } return true ; } @@ -6714,7 +6333,8 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio return false ; // determino ora il punto di inizio, il tratto per il LeadIn bool bIsChunkClosed = false ; - if ( ! IsChunkAllClosed( pSfrPock, nC, bIsChunkClosed)) + bool bIsChunkAllOpen = false ; + if ( ! IsChunkAllHomogeneous( pSfrPock, nC, bIsChunkClosed, bIsChunkAllOpen)) return false ; if ( ! bIsChunkClosed) { if ( ! AdvanceExtendCurves( vClosedOffs_nC, pSfrOrig, PockParams)) @@ -6796,8 +6416,9 @@ AddZigZag( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketPar // controllo esistenza di lati aperti per il Chunk attuale bool bIsChunkClosed = true ; + bool bIsChunkAllOpen = true ; if ( ! PockParams.bAllClosed) { - if ( ! IsChunkAllClosed( pSrfPock, nChunkInd, bIsChunkClosed)) + if ( ! IsChunkAllHomogeneous( pSrfPock, nChunkInd, bIsChunkClosed, bIsChunkAllOpen)) return false ; // se il Chunk originale aveva lati aperti, estendo il percorso a ZigZag for ( int nU = 0 ; nU < int( vpCrvs.size()) ; ++ nU) { @@ -7013,6 +6634,1379 @@ AddOneWay( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketPar return true ; } +//---------------------------------------------------------------------------- +static bool +GetSfrByOpenEdgeExtension( const ISurfFlatRegion* pSfrOrig, PocketParams& PockParams, + double dOffs, int nOffsType, ISurfFlatRegion* pSfrExtended) +{ + // controllo dei parametri + if ( pSfrOrig == nullptr || ! pSfrOrig->IsValid()) + return false ; + + // recupero raggio utensile e tipo di offset corrente + double dMyRad = PockParams.dRad ; + int nMyOffsType = PockParams.nOffsType ; + + // parametri per superficie di classificazione + PockParams.dRad = dOffs ; + PockParams.nOffsType = nOffsType ; + + // estensine presso i lati aperti + ICRVCOMPOPOVECTOR vCrvEmpty ; + bool bSkipPocket ; + pSfrExtended->CopyFrom( pSfrOrig) ; + if ( pSfrExtended == nullptr || ! pSfrExtended->IsValid() || + ! ModifySurfByOpenEdges( pSfrExtended, PockParams, false, vCrvEmpty, bSkipPocket)) + return false ; + + // riporto i parametri originari + PockParams.dRad = dMyRad ; + PockParams.nOffsType = nMyOffsType ; + + return ( pSfrExtended != nullptr && pSfrExtended->IsValid()) ; +} + +//---------------------------------------------------------------------------- +static bool +SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurveComposite* pCrvLink, + const PocketParams& PockParams, bool bSmoothLeft, bool bSmoothRight, double dSmoothPar, double dTol) +{ + + // controllo dei parametri + if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || + pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid() || + pCrvLink == nullptr || ! pCrvLink->IsValid()) + return false ; + + /* + - Data la curva di Link, come prima cosa aggiungo l'ultima curva dell'Offset precedente + e la prima curva dell'Offset successivo. + - Effettuo lo Smusso del Link + - Rimvuovo la prima e l'ultima curva del Link smussato ( Gli estremi del link non vengono + modificati durante l'operazione di smusso + */ + + // curva precedente e successiva + PtrOwner pCrvBef( pCrvOffs0->GetLastCurve()->Clone()) ; + PtrOwner pCrvAft( pCrvOffs1->GetFirstCurve()->Clone()) ; + if ( IsNull( pCrvBef) || IsNull( pCrvAft) || + ! pCrvBef->IsValid() || ! pCrvAft->IsValid()) + return false ; + // estendo il Link + pCrvLink->AddCurve( Release( pCrvBef), false, dTol) ; + pCrvLink->AddCurve( Release( pCrvAft), true, dTol) ; + // smusso + ModifyCurveToSmoothed( pCrvLink, PockParams, dSmoothPar, dSmoothPar, false) ; + // toglo gli estremi + pCrvLink->RemoveFirstOrLastCurve( false) ; + pCrvLink->RemoveFirstOrLastCurve( true) ; + // modifico Offset0 per raccordarlo al nuovo Link + Point3d ptS ; pCrvLink->GetStartPoint( ptS) ; + double dUE ; pCrvOffs0->GetParamAtPoint( ptS, dUE, dTol) ; + if ( ! bSmoothLeft && pCrvOffs0->IsClosed()) + pCrvOffs0->ChangeStartPoint( dUE) ; + else + pCrvOffs0->TrimEndAtParam( dUE) ; + // modifico Offset1 per raccordarlo al nuovo Link + Point3d ptE ; pCrvLink->GetEndPoint( ptE) ; + double dUS ; pCrvOffs1->GetParamAtPoint( ptE, dUS, dTol) ; + if ( ! bSmoothRight && pCrvOffs1->IsClosed()) + pCrvOffs1->ChangeStartPoint( dUS) ; + else + pCrvOffs1->TrimStartAtParam( dUS) ; + + return true ; +} + +static bool +GetConformalLinkForOpenCrv( const ICurveComposite* pCrvOffs0, const ICurveComposite* pCrvOffs1, + const ICRVCOMPOPOVECTOR& vCrvClassBorder, const PocketParams& PockParams, + double dTol, ICurveComposite* pCrvLink) +{ + // controllo dei parametri + if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || + pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid()) + return false ; + pCrvLink->Clear() ; + + // ricavo gli estremi del Link + Point3d ptLinkS ; pCrvOffs0->GetEndPoint( ptLinkS) ; + Point3d ptLinkE ; pCrvOffs1->GetStartPoint( ptLinkE) ; + // ricavo i parametri sulla curva di bordo che interessa i due estremi ( 1 sola !) + for ( int i = 0 ; i < int( vCrvClassBorder.size()) ; ++ i) { + if ( vCrvClassBorder[i]->IsPointOn( ptLinkS, dTol) && + vCrvClassBorder[i]->IsPointOn( ptLinkE, dTol)) { + double dPar0 ; vCrvClassBorder[i]->GetParamAtPoint( ptLinkS, dPar0, dTol) ; + double dPar1 ; vCrvClassBorder[i]->GetParamAtPoint( ptLinkE, dPar1, dTol) ; + // ricavo le due curve possibili di Link + PtrOwner pCrvLinkA( vCrvClassBorder[i]->CopyParamRange( dPar0, dPar1)) ; + PtrOwner pCrvLinkB( vCrvClassBorder[i]->CopyParamRange( dPar1, dPar0)) ; + // scelgo quella migliore + double dLenA = 0. ; + if ( ! IsNull( pCrvLinkA) && pCrvLinkA->IsValid()) + pCrvLinkA->GetLength( dLenA) ; + double dLenB = 0. ; + if ( ! IsNull( pCrvLinkB) && pCrvLinkB->IsValid()) { + pCrvLinkB->Invert() ; + pCrvLinkB->GetLength( dLenB) ; + } + if ( dLenA > dLenB) { + if ( ! IsNull( pCrvLinkB) && pCrvLinkB->IsValid()) + pCrvLink->CopyFrom( pCrvLinkB) ; + } + else { + if ( ! IsNull( pCrvLinkA) && pCrvLinkA->IsValid()) + pCrvLink->CopyFrom( pCrvLinkA) ; + } + break ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, PocketParams& PockParams, + const ICRVCOMPOPOVECTOR& vCrvClassBorder, const ICRVCOMPOPOVECTOR& vCrvExtendedBorders, + ICurveComposite* pCrvLink) +{ + // controllo validità delle due curve di Offset + if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || + pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid()) + return false ; + pCrvLink->Clear() ; + const double TOL = 150 * EPS_SMALL ; + + // flag per curve di Offset aperte o chiuse + bool bOpen0 = ( ! pCrvOffs0->IsClosed()) ; + bool bOpen1 = ( ! pCrvOffs1->IsClosed()) ; + + // se passo da una curva aperta ad un'altra curva aperta ( uso i bordi di pSfrClass) + if ( bOpen0 && bOpen1) { + // ricavo la curva di Link + if ( ! GetConformalLinkForOpenCrv( pCrvOffs0, pCrvOffs1, vCrvClassBorder, PockParams, TOL, pCrvLink)) + return false ; + // smusso il Link raccordandolo + if ( pCrvLink->IsValid()) + SmoothLinkByOffs( pCrvOffs0, pCrvOffs1, pCrvLink, PockParams, true, true, PockParams.dRad / 8., TOL) ; + } + else { + // clono le due curve di Offset + PtrOwner pCrvOffs0_cl( CloneCurveComposite( pCrvOffs0)) ; + PtrOwner pCrvOffs1_cl( CloneCurveComposite( pCrvOffs1)) ; + if ( IsNull( pCrvOffs0_cl) || IsNull( pCrvOffs1_cl) || ! pCrvOffs0_cl->IsValid() || ! pCrvOffs1_cl->IsValid()) + return false ; + // controllo se gli Offset sono stati ricavati alla prima iterazione + bool bFirstIterOffs0 = ( pCrvOffs0->GetTempProp( 0) == 0) ; + bool bFirstIterOffs1 = ( pCrvOffs1->GetTempProp( 0) == 0) ; + // creo la curva che le collegherà + bool bSmooth = PockParams.bSmooth ; + PockParams.bSmooth = false ; + if ( ! CutCurveToConnect( pCrvOffs0, pCrvOffs1, vCrvExtendedBorders, PockParams, + ( ( bOpen0 || bFirstIterOffs0) ? 0. : 10 * EPS_SMALL), + ( ( bOpen1 || bFirstIterOffs1) ? 0. : 10 * EPS_SMALL), + pCrvLink) || + ! pCrvLink->IsValid()) { + // se curva di Link non valida, cerco una strada più semplice + pCrvLink->Clear() ; + pCrvOffs0->CopyFrom( pCrvOffs0_cl) ; + pCrvOffs1->CopyFrom( pCrvOffs1_cl) ; + // recupero i vettori tangente iniziali ( le curve sono chiuse ) + Vector3d vtS, vtE ; + Point3d ptS, ptE ; + if ( ! pCrvOffs0->GetStartDir( vtS) || ! pCrvOffs1->GetStartDir( vtE) || + ! pCrvOffs0->GetStartPoint( ptS) || ! pCrvOffs1->GetStartPoint( ptE)) + return false ; + // creo il bi-arco tra esse + if ( ! CalcBoundedSmoothedLink( ptS, vtS, ptE, vtE, 0.5, vCrvExtendedBorders, PockParams, pCrvLink) || + ! pCrvLink->IsValid()) + return false ; + } + PockParams.bSmooth = bSmooth ; + SmoothLinkByOffs( pCrvOffs0, pCrvOffs1, pCrvLink, PockParams, ! bFirstIterOffs0, ! bFirstIterOffs1, + PockParams.dRad / 16., TOL) ; + // per sicurezza aggiorno i nuovi punti e i nuovi parametri + double dUNewE ; + Point3d ptStartNext ; + pCrvLink->GetEndPoint( ptStartNext) ; + pCrvOffs1->GetParamAtPoint( ptStartNext, dUNewE) ; + pCrvOffs1->ChangeStartPoint( dUNewE) ; + } + + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +CheckConformalRetractLink( const ICurveComposite* pCrvOffs0, const ICurveComposite* pCrvOffs1, + const ICRVCOMPOPOVECTOR& vCrvClassBorder, const PocketParams& PockParams, + bool& bCalcLink) +{ + // controllo dei parametri + if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || + pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid()) + return false ; + bCalcLink = true ; // di base calcolo il Link + + // recupero gli estremi di un possibile collegamento tra i punti + Point3d ptA ; pCrvOffs0->GetEndPoint( ptA) ; + Point3d ptB ; pCrvOffs1->GetStartPoint( ptB) ; + // se vicini -> no retroazione + if ( SqDist( ptA, ptB) < 4 * PockParams.dRad * PockParams.dRad + 50 * EPS_SMALL) + return true ; + // se distanti + else { + // controllo se sono aperte + bool bOpen_i = ( ! pCrvOffs0->IsClosed()) ; + bool bOpen_ii = ( ! pCrvOffs1->IsClosed()) ; + // se entrambe aperte + if ( bOpen_i && bOpen_ii) { + // calcolo il collegamento tra le due curve + PtrOwner pCrvLink( CreateCurveComposite()) ; + if ( IsNull( pCrvLink) || + ! GetConformalLinkForOpenCrv( pCrvOffs0, pCrvOffs1, vCrvClassBorder, PockParams, + 25 * EPS_SMALL, pCrvLink)) + return false ; + // se Link valido calcolo la sua lunghezza + double dLinkLen = 0. ; + if ( pCrvLink->IsValid()) + pCrvLink->GetLength( dLinkLen) ; + // minima distanza da ptA + DistPointCurve DistPtACrv( ptA, *pCrvOffs1) ; + double dMyDist ; + if ( DistPtACrv.GetSqDist( dMyDist) && + dMyDist < 4 * PockParams.dRad * PockParams.dRad + 50 * EPS_SMALL) { + bCalcLink = ( dLinkLen < 4 * PockParams.dRad) ; + return true ; + } + // minima distanza da ptB + DistPointCurve DistPtBCrv( ptB, *pCrvOffs0) ; + if ( DistPtBCrv.GetSqDist( dMyDist) && + dMyDist < 4 * PockParams.dRad * PockParams.dRad + 50 * EPS_SMALL) { + bCalcLink = ( dLinkLen < 4 * PockParams.dRad) ; + return true ; + } + } + // ... servono altri controlli ??? ( vedere dai casi) + } + + bCalcLink = false ; + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +GetConformalIndices( const VICRVCOMPOPOVECTOR& vCrvOffs, int nMyInd0, int nMyInd1, + const PocketParams& PockParams, const ICRVCOMPOPOVECTOR& vCrvClassBorder, + int& nInd0, int& nInd1) +{ + // controllo che l'indice sia sensato + if ( vCrvOffs.empty() || nMyInd0 < 0 || nMyInd0 >= int( vCrvOffs.size()) || + ( nMyInd1 < 0 || nMyInd1 >= int( vCrvOffs[nMyInd0].size()))) + return false ; + nInd0 = -1 ; + nInd1 = -1 ; + + // il punto di riferimento è il punto finale della curva corrente + Point3d ptRef ; vCrvOffs[nMyInd0][nMyInd1]->GetEndPoint( ptRef) ; + // controllo se la curva è chiusa o aperta + bool bIsClosed = ( vCrvOffs[nMyInd0][nMyInd1]->IsClosed()) ; + // controllo se la curva è di primo Offset ( in questo caso non ho curve successive) + bool bFistOffs = ( nMyInd0 == int( vCrvOffs.size() - 1)) ; + + // scorro le curve di indice successivo + double dLimInfDist = INFINITO ; + int nInd = -1 ; + for ( int i = 0 ; ! bFistOffs && i < int( vCrvOffs[nMyInd0 + 1].size()) ; ++ i) { + // se non attiva, passo alla successiva + if ( vCrvOffs[nMyInd0 + 1][i]->GetTempProp( 0) != TEMP_PROP_CURVE_ACTIVE) + continue ; + // se di topologia differente, passo alla successiva + if ( ( bIsClosed != vCrvOffs[nMyInd0 + 1][i]->IsClosed())) + continue ; + // se richiede retroazione, passo alla successiva + bool bCalcLink = true ; + if ( ! CheckConformalRetractLink( vCrvOffs[nMyInd0][nMyInd1], vCrvOffs[nMyInd0 + 1][i], + vCrvClassBorder, PockParams, bCalcLink)) + return false ; + if ( ! bCalcLink) + continue ; + // se aperta + if ( ! bIsClosed) { + Point3d ptStart ; vCrvOffs[nMyInd0 + 1][i]->GetStartPoint( ptStart) ; + double dDist = SqDist( ptRef, ptStart) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = i ; + } + } + // se chiusa + else { + DistPointCurve DistPtCrv( ptRef, *vCrvOffs[nMyInd0 + 1][i]) ; + MinDistPCInfo aInfo ; + if ( DistPtCrv.GetMinDistInfo( 0, aInfo)) { + double dDist = SqDist( ptRef, aInfo.ptQ) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = i ; + vCrvOffs[nMyInd0 + 1][i]->ChangeStartPoint( aInfo.dPar) ; + } + } + } + } + // se curva trovata, restituisco gli indici + if ( nInd != -1) { + nInd0 = nMyInd0 + 1 ; + nInd1 = nInd ; + return true ; + } + /* se non ho trovato alcuna curva, allora possono verificarsi le seguenti situazioni : + - all'indice successivo ho solo curve di topologia differente + - ho già percorso tutte le curve topologicamente uguali all'indice successivo + - sono una curva di primo Offset + - tutte le curve all'indice succesivo di topologia equivalente richiedono una retroazione + => devo azzerare nInd0 e ricercare la curva di medesima topologia valida più vicina + */ + nInd0 = 0 ; + nInd = -1 ; + for ( ; nInd0 < int( vCrvOffs.size()) ; ++ nInd0) { + nInd1 = 0 ; + dLimInfDist = INFINITO ; + for ( ; nInd1 < int( vCrvOffs[nInd0].size()) ; ++ nInd1) { + // se non attiva, passo alla successiva + if ( vCrvOffs[nInd0][nInd1]->GetTempProp( 0) != TEMP_PROP_CURVE_ACTIVE) + continue ; + // se di topologia differente, passo alla successiva + if ( ( bIsClosed != vCrvOffs[nInd0][nInd1]->IsClosed())) + continue ; + // se aperta + if ( ! bIsClosed) { + Point3d ptStart ; vCrvOffs[nInd0][nInd1]->GetStartPoint( ptStart) ; + double dDist = SqDist( ptRef, ptStart) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = nInd1 ; + } + } + // se chiusa + else { + DistPointCurve DistPtCrv( ptRef, *vCrvOffs[nInd0][nInd1]) ; + MinDistPCInfo aInfo ; + if ( DistPtCrv.GetMinDistInfo( 0, aInfo)) { + double dDist = SqDist( ptRef, aInfo.ptQ) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = nInd1 ; + vCrvOffs[nInd0][nInd1]->ChangeStartPoint( aInfo.dPar) ; + } + } + } + } + // se curva trovata, restituisco gli indici + if ( nInd != -1) { + nInd1 = nInd ; + return true ; + } + } + + /* se non ho trovato alcuna curva, allora possono verificarsi le seguenti situazioni : + - ho solo curve topologicamente differenti dalla mia + - non ho curve attive + => devo azzerare nInd0 e ricercare la curva valida più vicina + */ + nInd0 = 0 ; + dLimInfDist = INFINITO ; + nInd = -1 ; + for ( ; nInd0 < int( vCrvOffs.size()) ; ++ nInd0) { + nInd1 = 0 ; + for ( ; nInd1 < int( vCrvOffs[nInd0].size()) ; ++ nInd1) { + // se non attiva, passo alla successiva + if ( vCrvOffs[nInd0][nInd1]->GetTempProp( 0) != TEMP_PROP_CURVE_ACTIVE) + continue ; + // se la curva successiva è aperta + if ( ! vCrvOffs[nInd0][nInd1]->IsClosed()) { + Point3d ptStart ; vCrvOffs[nInd0][nInd1]->GetStartPoint( ptStart) ; + double dDist = SqDist( ptRef, ptStart) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = nInd1 ; + } + } + // se la curva successiva è chiusa + else { + DistPointCurve DistPtCrv( ptRef, *vCrvOffs[nInd0][nInd1]) ; + MinDistPCInfo aInfo ; + if ( DistPtCrv.GetMinDistInfo( 0, aInfo)) { + double dDist = SqDist( ptRef, aInfo.ptQ) ; + if ( dDist < dLimInfDist) { + dLimInfDist = dDist ; + nInd = nInd1 ; + vCrvOffs[nInd0][nInd1]->ChangeStartPoint( aInfo.dPar) ; + } + } + } + } + // se curva trovata, restituisco gli indici + if ( nInd != -1) { + nInd1 = nInd ; + return true ; + } + } + + // non ho più curve disponibili + nInd0 = -1 ; + nInd1 = -1 ; + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +AdjustCloseEsgesForConformalGuide( ICurveComposite* pCrvCompo, const PocketParams& PockParams) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // se non ho una regione limite, allora non faccio nulla + if ( ! PockParams.SfrLimit.IsValid()) + return true ; + + // piccolo Offset per la superficie di classificazione + PtrOwner pSfrLimit( CloneSurfFlatRegion( &PockParams.SfrLimit)) ; + if ( IsNull( pSfrLimit) || ! pSfrLimit->IsValid() || + ! pSfrLimit->Offset( 100 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + + // recupero le parti omogenee della curva + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvCompo, PockParams, vpCrvs) ; + + // i tratti aperti che fanno overlap con la regione limite diventano chiusi + PtrOwner pCrvFinal( CreateCurveComposite()) ; + if ( IsNull( pCrvFinal)) + return false ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // nuovo curva + PtrOwner pMyCompo( CreateCurveComposite()) ; + if ( IsNull( pMyCompo)) + return false ; + CRVCVECTOR ccClass ; + if ( pSfrLimit->GetCurveClassification( *vpCrvs[i], EPS_SMALL, ccClass)) { + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + // recupero il tratto di curva + PtrOwner pMyCurve( ConvertCurveToComposite( vpCrvs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ; + if ( ! IsNull( pMyCurve) && pMyCurve->IsValid()) { + // se non esterna alla regione limite, il sottotratto deve essere chiuso + if ( ccClass[j].nClass != CRVC_OUT) { + for ( int k = 0 ; k < pMyCurve->GetCurveCount() ; ++ k) + pMyCurve->SetCurveTempProp( k, TEMP_PROP_CLOSE_EDGE, 0) ; + } + if ( ! pMyCompo->AddCurve( Release( pMyCurve))) + return true ; // non faccio nulla... + } + } + } + vpCrvs[i].Set( pMyCompo) ; + } + if ( ! pCrvFinal->AddCurve( Release( vpCrvs[i]))) + return true ; // non faccio nulla... + } + if ( pCrvFinal->IsValid()) + pCrvCompo->CopyFrom( pCrvFinal) ; + + return ( pCrvCompo != nullptr && pCrvCompo->IsValid()) ; + +} + +//---------------------------------------------------------------------------- +static bool +GetConformalBordersCrvs( const ISurfFlatRegion* pSfrOrig, PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvCompo) +{ + // controllo dei parametri + if ( pSfrOrig == nullptr || ! pSfrOrig->IsValid()) + return false ; + vCrvCompo.clear() ; + + /* NB. + La regione da costruire è una FlatRegion dove si estendono i lati aperti di R/2 + ( al contrario della pSfrClass che estende i lati aperti di R/8, questa regione + presenta i Chiusi Offsettati verso l'interno di R + OffsR e gli aperti estesi di R/2 + - Per ottenere questo risultato si estende la regione Originale di R + OffsR + R/2 presso + i lati aperti e successivamente si effettua un Offset interno di (-)R + (-)OffsR + */ + + // estendo la superficie + PtrOwner pSfrExtended( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrExtended) || + ! GetSfrByOpenEdgeExtension( pSfrOrig, PockParams, PockParams.dRad + PockParams.dRad / 2., + ICurve::OFF_CHAMFER, pSfrExtended)) + return false ; + + // contro-offset per delimitarla + if ( ! pSfrExtended->Offset( - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) + return false ; + + // restituisco i Loops + return ( GetSfrCrvCompoLoops( pSfrExtended, vCrvCompo)) ; + +} + +//---------------------------------------------------------------------------- +static bool +ModifyConformalStartPoint( ICurveComposite* pCrvFirst, const PocketParams& PockParams, + const ISurfFlatRegion* pSfrPock) +{ + // controllo dei parametri + if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid() || + pSfrPock == nullptr || ! pSfrPock->IsValid()) + return false ; + + // se la curva è aperta, allora non devo fare nulla + if ( ! pCrvFirst->IsClosed()) + return true ; + + // ricavo i lati aperti della superficie di classificazione + ICRVCOMPOPOVECTOR vCrvOpenEdges ; + for ( int nC = 0 ; nC < pSfrPock->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfrPock->GetLoopCount( nC) ; ++ nL) { + // recupero il Loop + PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrPock->GetLoop( nC, nL))) ; + if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) + return false ; + // recupero le parti omogenee + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvLoop, PockParams, vpCrvs) ; + // recupero le parti interne + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) + vCrvOpenEdges.emplace_back( Release( vpCrvs[i])) ; + } + } + } + // se non ho ricavato tratti aperti, errore + if ( vCrvOpenEdges.empty()) + return false ; + + /* NB. + - Per i casi previsti dalle lavorazioni CONFORMAL devo trovare solo 1 tratto aperto, quindi + considero quello di indice 0 + - Tra la curva pCrvFirst e la curva di lato aperto, devo trovare i punti più vicino + ( per ora l'algoritmo è euristico, bisogna aggiornarlo con VORONOI) + */ + + // Algoritmo Euristico da sostituire con Voronoi : + // 1) Cerco il punto più vicino al lato aperto dato il punto iniziale di pCrvFirst + Point3d ptStart ; pCrvFirst->GetStartPoint( ptStart) ; + DistPointCurve distCalculator0( ptStart, *vCrvOpenEdges[0]) ; + Point3d ptMinDist ; + int nFlag ; + if ( ! distCalculator0.GetMinDistPoint( 0., ptMinDist, nFlag)) + return false ; + // 2) Cerco il punto più vicino su pCrvFirst da ptMinDist + DistPointCurve distCalculator1( ptMinDist, *pCrvFirst) ; + double dMinPar ; + if ( ! distCalculator1.GetParamAtMinDistPoint( 0., dMinPar, nFlag)) + return false ; + // 3) Cambio il punto iniziale di pCrvFirst nel parametro ricavato + pCrvFirst->ChangeStartPoint( dMinPar) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CalcConformalOneWayOffs( VICRVCOMPOPOVECTOR& vvCrvOffs, const PocketParams& PockParams, + const ISurfFlatRegion* pSfrPock, ICRVCOMPOPOVECTOR& vCrvOffs) +{ + // pulizia del vettore degli Offset + vCrvOffs.clear() ; + + // inverto il vettore degli Offset, in modo da partire dalle curve più distanti dai chiusi + reverse( vvCrvOffs.begin(), vvCrvOffs.end()) ; + + // determino il punto iniziale della prima curva di Offset + if ( ! ModifyConformalStartPoint( vvCrvOffs[0][0], PockParams, pSfrPock)) + return false ; + + // le curve di Offset vengono riodinate in base alla loro iterazione nel vettore + for ( int i = 0 ; i < int( vvCrvOffs.size()) ; ++ i) { + for ( int j = 0 ; j < int( vvCrvOffs[i].size()) ; ++ j) { + // se la curva corrente è chiusa, cambio il punto iniziale rispetto alla curva precedente + if ( vvCrvOffs[i][j]->IsClosed()) { + if ( ! vCrvOffs.empty()) { + // ricavo il punto finale della curva precedente + Point3d ptEndPrec ; vCrvOffs.back()->GetEndPoint( ptEndPrec) ; + DistPointCurve DistPtCrv( ptEndPrec, *vvCrvOffs[i][j]) ; + double dParS ; + int nFlag ; + // cambio il punto inziale della curva corrente + if ( DistPtCrv.GetParamAtMinDistPoint( 0, dParS, nFlag)) + vvCrvOffs[i][j]->ChangeStartPoint( dParS) ; + } + } + vCrvOffs.emplace_back( Release( vvCrvOffs[i][j])) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CalcConformalZigZagOffsAndLinks( VICRVCOMPOPOVECTOR& vvCrvOffs, const ISurfFlatRegion* pSfrChunk, + const ISurfFlatRegion* pSfrClass, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvOffs, + ICURVEPOVECTOR& vCrvLink) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid() || + pSfrClass == nullptr || ! pSfrClass->IsValid()) + return false ; + vCrvOffs.clear() ; + vCrvLink.clear() ; + if ( vvCrvOffs.empty()) + return true ; + + // rendo attive tutte le curve di Offset mediante prima TmpProp + for ( int i = 0 ; i < int( vvCrvOffs.size()) ; ++ i) { + for ( int j = 0 ; j < int( vvCrvOffs[i].size()) ; ++ j) + vvCrvOffs[i][j]->SetTempProp( TEMP_PROP_CURVE_ACTIVE, 0) ; + } + + /* NB. curve di vCrvOffs + TempProp0 -> Se l'offset è attivo/non attivo + TempProp1 -> Side {MDS_LEFT, MDS_RIGHT} per identificare l'interno della curva + TempParam0 -> { vuoto } ; verrà utilizzato per la Feed + TempParam1 -> { vuoto } + */ + + // inverto il vettore degli Offset, in modo da partire dalle curve più distanti dai chiusi + reverse( vvCrvOffs.begin(), vvCrvOffs.end()) ; + + // determino il punto iniziale della prima curva di Offset + if ( ! ModifyConformalStartPoint( vvCrvOffs[0][0], PockParams, pSfrChunk)) + return false ; + + /* NB. + I link che collegano due curve di Offset aperte devono partire dalla prima e, seguendo il + bordo della regione di classificazione ( pSfrClass) arrivano alla seconda. + */ + ICRVCOMPOPOVECTOR vCrvSfrClass ; + if ( ! GetSfrCrvCompoLoops( pSfrClass, vCrvSfrClass)) + return false ; + /* NB. + I link che collegano due curve di Offset chiuse tra di loro vengono calcolati esattamente + come per i percorsi SPIRAL, pertanto devo definire un insieme di curve di primo Offset sui + quali smussare i Link per evitare di uscire dalla regione di svuotatura + */ + ICRVCOMPOPOVECTOR vCrvSfrExtended ; + if ( ! GetConformalBordersCrvs( pSfrChunk, PockParams, vCrvSfrExtended)) + return false ; + /* NB. + Se POCKET_CONFORMAL_ZIGZAG : + - vCrvCompoOffs contiene gli Offset ordinati + - vCrvLinks contiene il link che collega l'Offset (i-1)-esimo con l'Offset (i)-esimo + [ per definizione il primo Link è null] + [ se tra due Offset non c'è Link, allora esso sarà null] + Se POCKET_CONFORMAL_ONEWAY + - vCrvCompoOffs contiene gli Offset ordinati + - vCrvLinks è un vettore di null + + vCrvCompoOffs e vCrvLinks avranno la stessa dimensione + */ + + // ------------ Ordino Gli Offset ------------ + int nInd0 = 0 ; + int nInd1 = 0 ; + while ( nInd0 != -1 && nInd1 != -1) { + // inserisco la curva attuale nel vettore degli Offset + vCrvOffs.emplace_back( CloneCurveComposite( vvCrvOffs[nInd0][nInd1])) ; + // salvo come prima TmpProp il numero di Offset che ha generato tale curva + vCrvOffs.back()->SetTempProp( int( vvCrvOffs.size()) - nInd0 - 1, 0) ; + // disattivo tale curva per la ricerca + vvCrvOffs[nInd0][nInd1]->SetTempProp( TEMP_PROP_CURVE_INACTIVE, 0) ; + // cerco la curva successiva per il percorso + int nNextInd0 = -1 ; + int nNextInd1 = -1 ; + if ( ! GetConformalIndices( vvCrvOffs, nInd0, nInd1, PockParams, vCrvSfrClass, nNextInd0, nNextInd1)) + return false ; + // aggiorno gli indici + nInd0 = nNextInd0 ; + nInd1 = nNextInd1 ; + } + // se non ho ottenuto nulla, esco + if ( vCrvOffs.empty()) + return true ; + + // ------------ Definisco i Link ------------ + // per definizione il primo Link è nullo + vCrvLink.resize( 1) ; + // scorro le curve di Offset a coppie + for ( int i = 0 ; i < int( vCrvOffs.size()) - 1 ; ++ i) { + // controllo se bisogna calcolare il Link tra i due Offset + bool bCalcLink = true ; + if ( ! CheckConformalRetractLink( vCrvOffs[i], vCrvOffs[i+1], vCrvSfrClass, PockParams, bCalcLink)) + return false ; + if ( bCalcLink) { + // se link da calcolare, lo ricavo + PtrOwner pCrvLink( CreateCurveComposite()) ; + if ( IsNull( pCrvLink) || + ! GetConformalLink( vCrvOffs[i], vCrvOffs[i+1], PockParams, vCrvSfrClass, vCrvSfrExtended, pCrvLink)) + return false ; + // lo salvo nel vettore dei Link + vCrvLink.emplace_back( Release( pCrvLink)) ; + } + else + vCrvLink.resize( int( vCrvLink.size()) + 1) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvOffs, ICURVEPOVECTOR& vCrvLinks) +{ + // controllo dei parametri + if ( pSfrPock == nullptr || ! pSfrPock->IsValid()) + return false ; + if ( vCrvOffs.empty()) + return true ; + + /* dalla superificie estesa presso i lati aperti, effettuo un Offset interno pari alla somma del + raggio utensile e dell'offset radiale. La ricerca delle zone non svuotate avviene all'interno + di questa regione + */ + ICRVCOMPOPOVECTOR vCrvFirstOffs ; + if ( ! GetFirstOffsCrvFromSfr( pSfrPock, - PockParams.dRad - PockParams.dRadialOffset, vCrvFirstOffs)) + return false ; + // determino eventuale regioni con parti non svuotate e imposto la Feed alle curve + PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrUncleared)) + return false ; + if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, nullptr, PockParams, pSfrUncleared)) { + // estendo i percorsi di Offset se richiesto + if ( ! RemoveExtraParts( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddLeadInToCurveConformalPaths( const ISurfFlatRegion* pSfrOrig, const ISurfFlatRegion* pSfrPock, + const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvPaths) +{ + // controllo dei parametri + if ( pSfrOrig == nullptr || ! pSfrOrig->IsValid() || + pSfrPock == nullptr || ! pSfrPock->IsValid()) + return false ; + for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { + if ( vCrvPaths[i] == nullptr || ! vCrvPaths[i]->IsValid()) + return false ; + } + + // ricavo le curve aperte della superficie di pocketing + ICRVCOMPOPOVECTOR vCrvOpenEdge ; + { + ICRVCOMPOPOVECTOR vCrvLoops ; + if ( ! GetSfrCrvCompoLoops( pSfrPock, vCrvLoops)) + return false ; + for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( vCrvLoops[i], PockParams, vpCrvs) ; + for ( int j = 0 ; j < int( vpCrvs.size()) ; ++ j) { + if ( vpCrvs[j]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) + vCrvOpenEdge.emplace_back( Release( vpCrvs[j])) ; + } + } + } + + // scorro i percorsi ricavati + for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { + // recupero il punto iniziale del percorso + Point3d ptStart ; vCrvPaths[i]->GetStartPoint( ptStart) ; + // se il punto inziale è interno alla superficie originaria + bool bIsInside ; + if ( IsPointInsideSurfFr( ptStart, pSfrOrig, EPS_SMALL, bIsInside) && bIsInside) { + // definizione del segmento per l'entrata + PtrOwner pSeg( CreateCurveLine()) ; + if ( IsNull( pSeg)) + return false ; + double dSqLenMin = INFINITO ; + // ricavo il punto più vicino alle curve aperte della superficie di classificazione + for ( int j = 0 ; j < int( vCrvOpenEdge.size()) ; ++ j) { + DistPointCurve DistPtCrv( ptStart, *vCrvOpenEdge[j]) ; + Point3d ptMinDist ; + int nFlag ; + // controllo se il segmento che congiunge i due estremi non rovina il grezzo + bool bSafe = ( DistPtCrv.GetMinDistPoint( 0, ptMinDist, nFlag)) ; + // se troppo piccolo, non faccio nulla + double dSqSegLen = SqDist( ptStart, ptMinDist) ; + if ( dSqSegLen < SQ_EPS_SMALL) { + pSeg.Set( CreateCurveLine()) ; + break ; + } + // creazione del segmento + if ( bSafe) { + PtrOwner pCurrSeg( CreateCurveLine()) ; + if ( IsNull( pCurrSeg) || ! pCurrSeg->Set( ptMinDist, ptStart)) + return false ; + double dSqSegLen = SqDist( ptStart, ptMinDist) ; + if ( PockParams.SfrLimit.IsValid()) { + PtrOwner pSfrLimit( CloneSurfFlatRegion( &PockParams.SfrLimit)) ; + if ( IsNull( pSfrLimit) || ! pSfrLimit->IsValid() || + ! pSfrLimit->Offset( PockParams.dRad + PockParams.dRadialOffset, ICurve::OFF_FILLET)) + return false ; + // controllo distanza segmento + CRVCVECTOR ccClass ; + bSafe = ( pSfrLimit->GetCurveClassification( *pSeg, EPS_SMALL, ccClass) && + int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; + } + if ( bSafe && dSqSegLen < dSqLenMin) { + dSqLenMin = dSqSegLen ; + pSeg.Set( pCurrSeg) ; + } + } + } + // se segmento trovato, lo aggiungo alla curva + if ( pSeg->IsValid()) { + if ( ! vCrvPaths[i]->AddCurve( Release( pSeg), false, 25 * EPS_SMALL)) + return false ; + vCrvPaths[i]->SetCurveTempParam( 0, GetMinFeed( PockParams), 0) ; + } + } + + // estendo il percorso sul tratto iniziale e finale ( se ammissibile) + Vector3d vtTan ; vCrvPaths[i]->GetStartDir( vtTan) ; + vtTan.Invert() ; + bool bOkExtended ; + if ( ! ExtendPath( vCrvPaths[i], pSfrOrig, PockParams, vtTan, false, bOkExtended)) + return false ; + // se il segmento non ha subito estensione e il primo Offset era chiuso, allora ritento + if ( ! bOkExtended && bIsInside) { + PtrOwner pCrvPathCL( CloneCurveComposite( vCrvPaths[i])) ; + if ( IsNull( pCrvPathCL) || ! pCrvPathCL->IsValid()) + return false ; + pCrvPathCL->ExtendStartByLen( 1.5 * PockParams.dRad) ; + if ( ! ExtendPath( pCrvPathCL, pSfrOrig, PockParams, vtTan, false, bOkExtended)) + return false ; + if ( bOkExtended) + vCrvPaths[i].Set( pCrvPathCL) ; + } + vCrvPaths[i]->GetEndDir( vtTan) ; + if ( ! ExtendPath( vCrvPaths[i], pSfrOrig, PockParams, vtTan, true, bOkExtended)) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ChainConformalOffsWithLinks( ICRVCOMPOPOVECTOR& vCrvOffs, ICURVEPOVECTOR& vCrvLink, + ICRVCOMPOPOVECTOR& vCrvPaths) +{ + // se non ho Offset non devo concatenare nulla + if ( vCrvOffs.empty()) + return true ; + // le curve di Offset devono essere definite e valide + for ( int i = 0 ; i < int( vCrvOffs.size()) ; ++ i) { + if ( vCrvOffs[i] == nullptr || ! vCrvOffs[i]->IsValid()) + return false ; + } + vCrvPaths.clear() ; + + // percorso corrente + PtrOwner pCrvPath( CreateCurveComposite()) ; + if ( IsNull( pCrvPath)) + return false ; + for ( int i = 0 ; i < int( vCrvOffs.size()) - 1 ; ++ i) { + // aggiungo l'Offset corrente + if ( ! pCrvPath->AddCurve( Release( vCrvOffs[i]))) + return false ; + // se il Link per l'Offset successivo è valido, lo aggiungo + if ( ! IsNull( vCrvLink[i+1]) && vCrvLink[i+1]->IsValid()) { + if ( ! pCrvPath->AddCurve( Release( vCrvLink[i+1]))) + return false ; + } + // se Link non valido, ho terminato il percorso corrente + else { + vCrvPaths.emplace_back( Release( pCrvPath)) ; + pCrvPath.Set( CreateCurveComposite()) ; + if ( IsNull( pCrvPath)) + return false ; + } + } + if ( ! pCrvPath->AddCurve( Release( vCrvOffs.back()))) + return false ; + vCrvPaths.emplace_back( Release( pCrvPath)) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ExtendGuideByIteration( ICurveComposite* pCompoTempGuide, const ICurveComposite* pCompoPerimeter, + bool bInverted) +{ + // controllo dei parametri + if ( pCompoTempGuide == nullptr || ! pCompoTempGuide->IsValid() || + pCompoPerimeter == nullptr || ! pCompoPerimeter->IsValid()) + return false ; + + const double EXTENSION_VAL = 1000. ; + + // ricavo il punto finale della guida + Point3d ptEndGuide ; pCompoTempGuide->GetEndPoint( ptEndGuide) ; + // direzione finale della guida + Vector3d vtEndGuide ; pCompoTempGuide->GetEndDir( vtEndGuide) ; + // creo un segmento diretto come il chiuso + PtrOwner pSeg( CreateCurveLine()) ; + if ( IsNull( pSeg) || + ! pSeg->Set( ptEndGuide, ptEndGuide + EXTENSION_VAL * vtEndGuide)) + return false ; + // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta + IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; + // se l'unica intersezione è il punto iniziale del segmento, allora non estendo la guida + // ( vale anche nel caso di intersezione con Overlap) + if ( ICC.GetIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) + return true ; + } + } + // passo alla PolyLine del perimetro + PolyLine PL ; + pCompoPerimeter->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, PL) ; + // cerco il punto più esterno rispetto alla direzione del chiuso + Point3d ptPoly ; + PL.GetFirstPoint( ptPoly) ; + while ( PL.GetNextPoint( ptPoly)) { + if ( ! pSeg->Set( ptEndGuide, ptEndGuide + ( ptPoly - ptEndGuide) * EXTENSION_VAL)) + return false ; + // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta + IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; + // se una intersezione, allora di Overlap con punto iniziale e finale definito + if ( ICC.GetIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + if ( aInfo.bOverlap) { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide) && + AreSamePointApprox( aInfo.IciB[1].ptI, ptPoly)) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + else { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + } + } + // se più di una intersezione, allora il perimetro deve essere tutto Interno al segmento + // ( Out nel caso in cui ho le curve invertite) + IntCrvCrvInfo aInfo ; + bool bOk = true ; + for ( int i = 0 ; i < ICC.GetIntersCount() && bOk ; ++ i) { + bOk = ( ICC.GetIntCrvCrvInfo( i, aInfo)) ; + bOk = ( aInfo.bOverlap || + ( aInfo.IciB[0].nPrevTy != ( ! bInverted ? CRVC_OUT : CRVC_IN) && + aInfo.IciB[0].nNextTy != ( ! bInverted ? CRVC_OUT : CRVC_IN))) ; + } + if ( bOk) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + + return true ; +} + + +//---------------------------------------------------------------------------- +static bool +CalcConformalGuide( const ICurveComposite* pCrvCloseEdge, const ICurveComposite* pCrvOpenEdge, + const PocketParams& PockParams, ICurveComposite* pCrvGuide) +{ + // controllo dei parametri + if ( pCrvCloseEdge == nullptr || ! pCrvCloseEdge->IsValid() || + pCrvOpenEdge == nullptr || ! pCrvOpenEdge->IsValid()) + return false ; + pCrvGuide->Clear() ; + + // creo una copia temporanea delle curve + PtrOwner pCrvCL( CloneCurveComposite( pCrvCloseEdge)) ; + PtrOwner pCrvOP( CloneCurveComposite( pCrvOpenEdge)) ; + if ( IsNull( pCrvCL) || IsNull( pCrvOP) || ! pCrvCL->IsValid() || ! pCrvOP->IsValid()) + return false ; + + // estendo la curva nel suo tratto finale ed iniziale + for ( int i = 0 ; i < 2 ; ++ i) { + if ( ! ExtendGuideByIteration( pCrvCL, pCrvOP, ( i == 1))) + return false ; + if ( ! pCrvCL->IsValid()) + return true ; + pCrvCL->Invert() ; + pCrvOP->Invert() ; + // se la curva diventa chiusa, allora ho la guida + if ( pCrvCL->IsClosed()) { + pCrvGuide->CopyFrom( pCrvCL) ; + if ( i == 1) + pCrvGuide->Invert() ; + return true ; + } + } + + // tratto iniziale + Vector3d vtStart ; pCrvCL->GetStartDir( vtStart) ; + Point3d ptStart ; pCrvCL->GetStartPoint( ptStart) ; + PtrOwner pLineStart( CreateCurveLine()) ; + if ( IsNull( pLineStart) || ! pLineStart->Set( ptStart - 1000. * vtStart, ptStart)) + return false ; + // tratto finale ( potrebbe intersecare il tratto iniziale) + Vector3d vtEnd ; pCrvCL->GetEndDir( vtEnd) ; + Point3d ptEnd ; pCrvCL->GetEndPoint( ptEnd) ; + PtrOwner pLineEnd( CreateCurveLine()) ; + if ( IsNull( pLineEnd) || ! pLineEnd->Set( ptEnd, ptEnd + 1000. * vtEnd)) + return false ; + + // controllo eventuale intersezione + IntersCurveCurve ICC( *pLineStart, *pLineEnd) ; + if ( ICC.GetIntersCount() > 0) { + // se esiste allora spezzo sia il tratto iniziale che finale nel punto di intersezione + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + pLineStart->TrimStartAtParam( aInfo.IciA[0].dU) ; + pLineEnd->TrimEndAtParam( aInfo.IciB[0].dU) ; + } + } + + // le due estensioni vanno tagliate presso i bordi dei lati aperti estesi; rischierei di non + // riuscire a passare presso dei lati aperti vicini ai tratti lineari di estensione + IntersCurveCurve ICCLS( *pLineStart, *pCrvOP) ; + if ( ICCLS.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + for ( int i = 0 ; i < ICCLS.GetCrossIntersCount() ; ++ i) { + if ( ICCLS.GetIntCrvCrvInfo( i, aInfo)) { + if ( ! AreSamePointApprox( aInfo.IciA[ aInfo.bOverlap ? 1 : 0].ptI, ptStart)) + pLineStart->ModifyStart( aInfo.IciA[aInfo.bOverlap ? 1 : 0].ptI) ; + } + } + } + IntersCurveCurve ICCLE( *pLineEnd, *pCrvOP) ; + if ( ICCLE.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + for ( int i = 0 ; i < ICCLE.GetCrossIntersCount() ; ++ i) { + if ( ICCLE.GetIntCrvCrvInfo( 0, aInfo)) { + if ( ! AreSamePointApprox( aInfo.IciA[0].ptI, ptEnd)) + pLineEnd->ModifyEnd( aInfo.IciA[0].ptI) ; + } + } + } + + // aggiungo i tratti lineari di estensione della curva + pCrvCL->AddCurve( Release( pLineStart), false) ; + pCrvCL->AddCurve( Release( pLineEnd), true) ; + + // recupero la curva guida + pCrvGuide->CopyFrom( pCrvCL) ; + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pSfrClass, const PocketParams& PockParam, + VICRVCOMPOPOVECTOR& vCrvOffs) +{ + // controllo dei parametri + if ( pSfrClass == nullptr || ! pSfrClass->IsValid() || + pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + vCrvOffs.clear() ; + + /* NB + vCrvOffs è un vettore di vettori di curve composite. Per ogni Offset progressivo i-esimo + vengono salvate tutte le parti interne j-esime alla pSfrClass. + ( la posizione del vettore ICRVCOMPOPOVECTOR int VICRVCOMPOPOVECTOR è il numero di iterazione + progressiva di Offset) + */ + + /* controllo se il chunk è svuotabile con lavorazione conformal + Sono previsti due casi di lavorazioni conformal : + 1) Non esistono Isole e il bordo esterno è formato da due tratti disomogenei + 2) Esistono solo Isole chiuse e il bordo esterno è tutto aperto + */ + bool bOk = false ; + ICRVCOMPOPOVECTOR vCrvCloseEdges ; // tratti chiusi da cui calcolare gli Offset + + // 1) Non esistono Isole e il bordo esterno è formato da due tratti disomogenei + if ( pSfrChunk->GetLoopCount( 0) == 1) { + // recupero la curva di bordo + ICRVCOMPOPOVECTOR vpCrvs ; + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid() || + ! AdjustCloseEsgesForConformalGuide( pCrvExtLoop, PockParam) || + ! IsCompoMadeBy2DifferentHomogeneousParts( pCrvExtLoop, PockParam, bOk, vpCrvs)) + return false ; + if ( ! bOk) + return true ; + // recupero la guida ideale + PtrOwner pCrvGuide( CreateCurveComposite()) ; + if ( IsNull( pCrvGuide) || + ! CalcConformalGuide( vpCrvs[0], vpCrvs[1], PockParam, pCrvGuide)) + return false ; + if ( ! pCrvGuide->IsValid()) + return true ; + // la guida definisce il tratto chiuso per gli Offsets + vCrvCloseEdges.emplace_back( Release( pCrvGuide)) ; + } + // 2) Esistono solo Isole chiuse e il bordo esterno è tutto aperto + else { + if ( ! IsSfrChunkMadeOnlyByClosedIslands( pSfrChunk, PockParam, bOk, vCrvCloseEdges)) + return false ; + if ( ! bOk) + return true ; + } + + /* Calcolo degli Offsets */ + // Oggetto Voronoi per curve chiuse + Voronoi myVRONI ; + for ( int i = 0 ; i < int( vCrvCloseEdges.size()) ; ++ i) { + vCrvCloseEdges[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + myVRONI.AddCurve( Release( vCrvCloseEdges[i])) ; + } + int MAX_ITER = 1000 ; + int nIter = 0 ; + double dOffs = PockParam.dRad + PockParam.dRadialOffset ; + double dOffsPrec = 0. ; + bool bStopSmallRad = false ; + while ( nIter < MAX_ITER) { + // determino se le curve vanno invertite o meno + // essendo FatCurve, la parte interna alla regione di classificazione è invertita + bool bInvert = false ; + if ( PockParam.nType == POCKET_CONFORMAL_ZIGZAG) + bInvert = ! ( ( ! IsEven( nIter) && ! PockParam.bInvert) || ( IsEven( nIter) && PockParam.bInvert)) ; + else if ( PockParam.nType == POCKET_CONFORMAL_ONEWAY) + bInvert = ! ( PockParam.bInvert) ; + // recupero gli Offset dei tratti chiusi + ICURVEPOVECTOR vFatCrv ; + if ( ! myVRONI.CalcFatCurve( vFatCrv, dOffs, false, false)) + return false ; + // vettore di Curve dentro alla regione di classificazione + ICRVCOMPOPOVECTOR vCrvOffsInside ; + // per tutte le curve ottenute, tengo solo per le parti interne alla regione di classificazione + bool bStop = true ; + for ( int j = 0 ; j < int( vFatCrv.size()) ; ++ j) { + CRVCVECTOR ccClass ; + if ( ! pSfrClass->GetCurveClassification( *vFatCrv[j], EPS_SMALL, ccClass)) + return false ; + for ( int k = 0 ; k < int( ccClass.size()) ; ++ k) { + if ( ccClass[k].nClass == CRVC_IN) { + // almeno una curva in trovata + bStop = false ; + // recupero il tratto di curva + PtrOwner pMyCrv( vFatCrv[j]->CopyParamRange( ccClass[k].dParS, ccClass[k].dParE)) ; + if ( ! IsNull( pMyCrv) && pMyCrv->IsValid()) { + // inverto se necessario + if ( bInvert) + pMyCrv->Invert() ; + // salvo come seconda proprietà temporanea il lato interno + pMyCrv->SetTempProp( bInvert ? MDS_LEFT : MDS_RIGHT, 1) ; + // memorizzo la curva nel vettore + vCrvOffsInside.emplace_back( ConvertCurveToComposite( Release( pMyCrv))) ; + } + } + } + } + // concateno se necessario ( per tolleranza Offset) + if ( ! ChainCompoCurves( vCrvOffsInside)) + return false ; + // controllo se serve un raggio più piccolo di svuotatura + bool bSmallRad = ( nIter == 0 ? dOffs < PockParam.dRad + EPS_ZERO : dOffs - dOffsPrec < PockParam.dRad + EPS_ZERO) ; + // se ho trovato delle curve interne + if ( ! bStop) { + dOffsPrec = dOffs ; + dOffs += PockParam.dSideStep ; + // inserisco le curva ricavate all'iterazione nIter nel vettore + vCrvOffs.resize( ++ nIter) ; // incremento nIter + for ( int i = 0 ; i < int( vCrvOffsInside.size()) ; ++ i) { + vCrvOffsInside[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + vCrvOffs.back().emplace_back( Release( vCrvOffsInside[i])) ; + } + // se devo terminare, interrompo il loop + if ( bStopSmallRad) + break ; + } + // se non ho ricavato curve ma serve un offset del raggio utensile + else if ( ! bSmallRad) { + dOffs = dOffsPrec + ( nIter == 0 ? PockParam.dRad + PockParam.dRadialOffset : PockParam.dRad) ; + bStopSmallRad = true ; + } + else + break ; + } + + // smusso le curve di Offset ( ad eccezione di quelle generate alla prima iterazione) + double dSmoothPar = PockParam.dRad / 8. ; + for ( int i = 1 ; i < int( vCrvOffs.size()) ; ++ i) { + for ( int j = 0 ; j < int( vCrvOffs[i].size()) ; ++ j) + ModifyCurveToSmoothed( vCrvOffs[i][j], PockParam, dSmoothPar, dSmoothPar, false) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetConformalSfrClassChunk( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pSfrClass, + INTVECTOR& vnChunk) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid() || + pSfrClass == nullptr || ! pSfrClass->IsValid()) + return false ; + vnChunk.clear() ; + + // se la superficie di classificazione ha un solo chunk, esco + if ( pSfrClass->GetChunkCount() == 1) { + vnChunk.emplace_back( 0) ; + return true ; + } + + // controllo quali Chunk di pSfrClass intersecano la pSfrChunk + for ( int nC = 0 ; nC < pSfrClass->GetChunkCount() ; ++ nC) { + // recupero il Chunk nC-esimo + PtrOwner pSfrClassChunk( pSfrClass->CloneChunk( nC)) ; + if ( IsNull( pSfrClassChunk) || ! pSfrClass->IsValid()) + return false ; + // controllo se l'intersezione non è vuota + pSfrClassChunk->Intersect( *pSfrChunk) ; + if ( ! IsNull( pSfrClassChunk) && pSfrClassChunk->IsValid()) + vnChunk.push_back( nC) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, + PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) +{ + // controllo dei parametri + if ( pSfrPock == nullptr || ! pSfrPock->IsValid() || + pSfrOrig == nullptr || ! pSfrOrig->IsValid()) + return true ; + + // se superifice tutta aperta, lavoro in SPIRAL_IN + if ( PockParams.bAllOpen) + return ( AddSpiralIn( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; + // se superficie tutta chiusa, lavoro in SPIRAL_OUT + if ( PockParams.bAllClosed) + return ( AddSpiralOut( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; + + // Definisco la superficie di classificazione ( su essa vengono tagliate le curve progressive + // di Offset + /* NB + La superficie di classificazione è ottenuta estendendo di R/4 i lati aperti ( in modo + da compensare il fattore di smusso R/8 sulle curve di Offset) + Dato che questa superficie serve per classficiare le curve di Offset, posso estendere i lati + aperti mediante Offset di tipo Chamfer; in questo modo semplifico la classificazione + */ + PtrOwner pSfrClass( pSfrPock->CreateOffsetSurf( - ( 3. * PockParams.dRad / 4.) - PockParams.dRadialOffset, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrClass) || ! pSfrClass->IsValid()) + return false ; + + // recupero la dimensione del vettore delle curve da resituire ( nel caso dovessi lavorare in SPIRAL_IN) + int nDim = int( vCrvCompoRes.size()) ; + + // scorro i chunk della superficie da lavorare + for ( int nC = 0 ; nC < pSfrPock->GetChunkCount() ; ++ nC) { + // controllo se il Chunk ha tutte proprietà omogenee tra loro + bool bClose, bOpen ; + if ( ! IsChunkAllHomogeneous( pSfrPock, nC, bClose, bOpen)) + return false ; + // recupero il Chunk come regione piana + PtrOwner pSfrChunk( pSfrPock->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + // se Chunk tutto aperto, lo lavoro in SPIRAL_IN + if ( bOpen) { + if ( ! AddSpiralIn( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) + return false ; + } + // se Chunk tutto chiuso, lo lavoro in SPIRAL_OUT + else if ( bClose) { + if ( ! AddSpiralOut( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) + return false ; + } + // se Chunk non omogeneo + else { + // ricavo il Chunk della superficie di classificazione corrente + INTVECTOR vnChunk ; + if ( ! GetConformalSfrClassChunk( pSfrChunk, pSfrClass, vnChunk)) + return false ; + // per tutti i Chunk classificati + for ( int i = 0 ; i < int( vnChunk.size()) ; ++ i) { + // ricavo il chunk di classificazione i-esimo + PtrOwner pSfrClassChunk( pSfrClass->CloneChunk( vnChunk[i])) ; + if ( IsNull( pSfrClassChunk) || ! pSfrClassChunk->IsValid()) + return false ; + // ricavo gli Offset ( se possibili) dei tratti chiusi del Chunk + VICRVCOMPOPOVECTOR vvCrvOffs ; + if ( ! GetConformalOffsets( pSfrChunk, pSfrClassChunk, PockParams, vvCrvOffs)) + return false ; + // se non ottengo Curve di Offset, lavoro in SpiralIn ( il Chunk ha dei lati aperti) + if ( vvCrvOffs.empty()) { + vCrvCompoRes.resize( nDim) ; // pulisco il vettore di curve + // NB. Facendo un offset interno di 3R/4 potrebbero essersi splittati dei Chunks + return ( AddSpiralIn( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; + } + else { + // definisco vettore degli Offset e dei Link + ICRVCOMPOPOVECTOR vCrvOffs ; + ICURVEPOVECTOR vCrvLink ; + // se lavorazione CONFORMAL_ZIGZAG + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { + // ordino le curve di Offset e raccordo + if ( ! CalcConformalZigZagOffsAndLinks( vvCrvOffs, pSfrChunk, pSfrClassChunk, PockParams, vCrvOffs, vCrvLink)) + return false ; + } + // se lavorazione CONFORMAL_ONEWAY + else if ( PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + // ordino le curve di Offset + if ( ! CalcConformalOneWayOffs( vvCrvOffs, PockParams, pSfrChunk, vCrvOffs)) + return false ; + // i Link non esistono + vCrvLink.resize( int( vCrvOffs.size())) ; + } + // estendo i percorsi per eventuali regioni non svuotate e calcolo le Feed + if ( ! ExtendConformalOffsAndSetFeed( pSfrPock, PockParams, vCrvOffs, vCrvLink)) + return false ; + // concateno Offset e Links + ICRVCOMPOPOVECTOR vCrvPaths ; + if ( ! ChainConformalOffsWithLinks( vCrvOffs, vCrvLink, vCrvPaths)) + return false ; + // estendo i percorsi per entrate/uscite dai lati aperti + if ( ! AddLeadInToCurveConformalPaths( pSfrOrig, pSfrChunk, PockParams, vCrvPaths)) + return false ; + // aggiungo i percorsi ricavati + for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) + vCrvCompoRes.emplace_back( Release( vCrvPaths[i])) ; + } + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, @@ -7023,7 +8017,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double if ( pSfr == nullptr || ! pSfr->IsValid() || dStep < 10 * EPS_SMALL || ( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN && - nType != POCKET_SPIRALOUT && nType != POCKET_CONFORMAL_ZIGZAG)) + nType != POCKET_SPIRALOUT && nType != POCKET_CONFORMAL_ZIGZAG && nType != POCKET_CONFORMAL_ONEWAY)) return false ; // pulizia vettore delle curve elementari @@ -7063,7 +8057,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double // ------------ gestione dei lati aperti ------------------- // modifico la superficie da svuotare estendendo i lati aperti bool bSkipPocket = false ; // se la superficie si svuota mediante curve singole di primo Offset dei chiusi - if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams, vCrvCompoRes, bSkipPocket)) + if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams, true, vCrvCompoRes, bSkipPocket)) return false ; // se le curve di primo offset che ho ottenuto, svuotano tutta la superficie, allora ho finito if ( bSkipPocket) { @@ -7096,7 +8090,8 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double return false ; break ; case POCKET_CONFORMAL_ZIGZAG : - if ( ! AddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes)) + case POCKET_CONFORMAL_ONEWAY : + if ( ! AddConformal( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) return false ; break ; } @@ -7422,4 +8417,4 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool } return true ; -} +} \ No newline at end of file