diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 13f3896..8db84a6 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, @@ -1602,21 +1706,17 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara // scorro i chiusi e sottraggo la regione da loro creata mediante l'utensile // NB. Queste curve sono orientate in maniera corretta ICRVCOMPOPOVECTOR vCrvCompoRes_tmp ; // salvo il vettore di curve offsettate del raggio utensile + Voronoi myVRONI ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { // se tratto chiuso - if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { - OffsetCurve OffsCrv ; // con offset verso l'interno ( è il loop esterno) - if ( OffsCrv.Make( vpCrvs[i], - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET)) { - PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; - while ( ! IsNull( pOffLongestCrv)) { - // salvo la curva corrente - vCrvCompoRes_tmp.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; - // passo alla successiva - pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; - } - } - } + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) + myVRONI.AddCurve( vpCrvs[i]) ; } + // offset delle parti chiuse + ICURVEPOVECTOR vCrvVroniOffs ; + myVRONI.CalcOffset( vCrvVroniOffs, - PockParams.dRad - PockParams.dRadialOffset + EPS_SMALL, ICurve::OFF_FILLET) ; + for ( int i = 0 ; i < int( vCrvVroniOffs.size()) ; ++ i) + vCrvCompoRes_tmp.emplace_back( ConvertCurveToComposite( Release( vCrvVroniOffs[i]))) ; /* Casi gestiti : @@ -1722,20 +1822,94 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara return true ; } +//---------------------------------------------------------------------------- +static bool +GetSinglePocketingCurves( ISurfFlatRegion* pSfr, const PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvSingleCurves) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + vCrvSingleCurves.clear() ; + + // tengo una copia della superficie ( serve per l'estensione dei percorsi fuori dal grezzo) + PtrOwner pSfr_clone( CloneSurfFlatRegion( pSfr)) ; + if ( IsNull( pSfr_clone) || ! pSfr_clone->IsValid()) + return false ; + + // scorro i Chunk della superficie + int nChunks = pSfr->GetChunkCount() ; + int nCurrChunk = 0 ; + for ( int i = 0 ; i < nChunks ; ++ i) { + // recupero il Chunk corrente + PtrOwner pSfrChunk( pSfr->CloneChunk( nCurrChunk)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + // se il Chunk corrente si svuota con curva singola, allora lo rimuovo dalla superficie + bool bRemoved = false ; + GetPocketCurvesByClosedEdges( pSfrChunk, PockParams, vCrvSingleCurves, bRemoved) ; + if ( bRemoved) + pSfr->EraseChunk( nCurrChunk) ; + else + ++ nCurrChunk ; + } + + // 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 + if ( ! ChainCompoCurves( vCrvSingleCurves)) + return false ; + // estendo le curve, definendo ptStart e calcolando le Feeds + if ( ! AdvanceExtendCurves( vCrvSingleCurves, pSfr_clone, PockParams)) + return false ; + // imposto le Feed per tali curve se richiesto + for ( int i = 0 ; i < int( vCrvSingleCurves.size()) ; ++ i) { + /* + Idea : Feed proporzionale al minimo Offset per annullare la regione + -> Massimo parametro sui bisettori di VORONOI + se le curve risultano aperte, cambio il loro punto iniziale a seconda dell'estensione fatta + */ + if ( vCrvSingleCurves[i]->IsValid() && vCrvSingleCurves[i]->GetCurveCount() != 0 && + ! vCrvSingleCurves[i]->IsClosed()) { + int nTempProp_firstCrv = vCrvSingleCurves[i]->GetFirstCurve()->GetTempProp( 0) ; + int nTempProp_lastCrv = vCrvSingleCurves[i]->GetLastCurve()->GetTempProp( 0) ; + // se estremi entrambi estesi + if ( nTempProp_firstCrv == TEMP_PROP_OUT_START && nTempProp_lastCrv == TEMP_PROP_OUT_START) { + if ( PockParams.ptStart.IsValid()) { + Point3d ptStart ; vCrvSingleCurves[i]->GetStartPoint( ptStart) ; + double dSqDist_first = SqDist( PockParams.ptStart, ptStart) ; + Point3d ptEnd ; vCrvSingleCurves[i]->GetEndPoint( ptEnd) ; + double dSqDist_last = SqDist( PockParams.ptStart, ptEnd) ; + if ( dSqDist_last < dSqDist_first) + vCrvSingleCurves[i]->Invert() ; + } + } + // se invece l'estensione è alla fine + else if ( nTempProp_lastCrv == TEMP_PROP_OUT_START) + vCrvSingleCurves[i]->Invert() ; + } + // recupero il MaxOffset per la curva + double dMaxOffs = vCrvSingleCurves[i]->GetTempParam( 0) ; + // calcolo la Feed proporzionale a tale Offset + double dFeed ; + GetFeedForParam( 2 * dMaxOffs, PockParams, dFeed) ; + AssignCustomFeed( vCrvSingleCurves[i], PockParams, dFeed) ; + // imposto il flag di curva singola + vCrvSingleCurves[i]->SetTempProp( TEMP_PROP_SINGLE_CURVE, 0) ; + } + + return true ; +} + //---------------------------------------------------------------------------- static bool -ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, - bool& bSkipPocket) +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 - bSkipPocket = false ; - // controllo se esistono dei lati aperti - if ( ! IsSfrAllClosed( pSfr, PockParams.bAllClosed)) - return false ; // se lati tutti chiusi, allora non devo fare nulla if ( PockParams.bAllClosed) return true ; @@ -1749,38 +1923,11 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP if ( IsNull( pSrfFinal)) return false ; - // numero di chunk rimovibili mediante una sola curva di Offset seguente il tratto chiuso - int nChunkOneCurve = 0 ; - // numero complessivo di Chunk da svuotare - int nChunk = pSfr->GetChunkCount() ; - // per ogni Chunck della superificie ottenuta... - for ( int nC = 0 ; nC < nChunk ; ++ nC) { + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { - // controllo se seguendo i chiusi posso svuotare l'interno chunk - /* - nel caso in cui il chunk c-esimo può essere svuotato da una o più curve che seguono - il/i tratto/i chiuso/i, queste vengono salvate direttamente nei percorsi di svuotatura. - Il chuck c-esimo verrà poi ignorato ( quindi nessuna estensione presso gli aperti) - */ - 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 ; - } - // 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 ; - // flag per sapere se c'è stata almeno una modifica in un loop del Chunk nC-esimo - bool bIsChunkModified = false ; + // flag per indicare se il Chunk è stato modificato mediante estensione degli aperti + bool bIsChunkModified = true ; // ricavo il Loop esterno ( External Loop) PtrOwner pCrvEL( ConvertCurveToComposite( pSfr->GetLoop( nC, 0))) ; @@ -1801,8 +1948,6 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP int nProp0 = TEMP_PROP_INVALID ; for ( int u = 0 ; u < pCrvEL->GetCurveCount() && ! bSomeOpen ; ++ u) bSomeOpen = ( pCrvEL->GetCurveTempProp( u, nProp0, 0) && nProp0 == TEMP_PROP_OPEN_EDGE) ; - - // se trovo dei lati aperti if ( bSomeOpen) { // allorargo il Loop esterno presso i lati aperti if ( ! AdjustContourWithOpenEdges( pCrvEL, vCrvIsl, PockParams)) @@ -1811,8 +1956,9 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP } // 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... + // NB. L'isola può essere tutta aperta o tutta chiusa ( se non uniforme, la forzo chiusa) + // [ La definizione di isola con proprietà non uniformi non è definita ] + ICRVCOMPOPOVECTOR vCrvToTIsland ; // isole che considero valide for ( int nI = 0 ; nI < int( vCrvIsl.size()) ; ++ nI) { // controllo uniformità int nCurrTmpProp = TEMP_PROP_INVALID ; @@ -1841,7 +1987,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP // se l'isola è trascurabile passo alla successiva if ( dMaxOffs < 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) continue ; - // altrimenti, estendo l'isola aperta + // altrimenti la restringo ICRVCOMPOPOVECTOR vCrvOther ; vCrvOther.emplace_back( pCrvEL->Clone()) ; for ( int nII = 0 ; nII < int( vCrvIsl.size()) ; ++ nII) { @@ -1853,10 +1999,10 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP bIsChunkModified = true ; } // conservo l'isola ( estesa o meno) - vCrvToTIsland.emplace_back( pCrvIsl->Clone()) ; + vCrvToTIsland.emplace_back( pCrvIsl->Clone()) ; // <-- valida } - // se c'è stata almeno una modifica di lato aperto al Chunk (nC-esimo), devo ricreare il Chunk + // se c'è stata almeno una modifica di lato aperto al Chunk ( nC-esimo), devo ricreare il Chunk // con i nuovi loop ricavati ( Chunk dopo Chunk creo la superficie finale) if ( bIsChunkModified) { /* @@ -1886,49 +2032,1451 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP else { // aggiungo il Chunk alla superficie finale if ( pSrfFinal->GetChunkCount() == 0) - pSrfFinal.Set( pSfrChunk) ; - else if ( ! pSrfFinal->Add( *pSfrChunk)) + pSrfFinal.Set( pSfr->CloneChunk( nC)) ; + else if ( ! pSrfFinal->Add( *pSfr->CloneChunk( nC))) return false ; } } + // se la superficie finale estesa non è valida, errore + if ( ! pSrfFinal->IsValid()) + return false ; - // 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 - if ( ! ChainCompoCurves( vCrvCompoRes)) - return false ; - // estendo le curve, definendo ptStart e calcolando le Feeds - if ( ! AdvanceExtendCurves( vCrvCompoRes, pSfr, PockParams)) - return false ; - // imposto le Feed per tali curve se richiesto - for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) { - /* - Idea : Feed proporzionale al minimo Offset per annullare la regione - -> Massimo parametro sui bisettori di VORONOI - */ - // recupero il MaxOffset per la curva - double dMaxOffs = vCrvCompoRes[i]->GetTempParam( 0) ; - // calcolo la Feed proporzionale a tale Offset - double dFeed ; - GetFeedForParam( 2 * dMaxOffs, PockParams, dFeed) ; - AssignCustomFeed( vCrvCompoRes[i], PockParams, dFeed) ; - // imposto il flag di curva singola - vCrvCompoRes[i]->SetTempProp( TEMP_PROP_SINGLE_CURVE, 0) ; + + // chiudo le isole che risultano ambigue ( quindi non omgenee) + 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) ; + } + } } - // se ho rimosso tutti i Chunk con una singola curva, allora ho terminato la svuotatura - bSkipPocket = ( nChunk == nChunkOneCurve) ; - if ( bSkipPocket) + // restituisco la superficie estesa + pSfr->Clear() ; + pSfr->CopyFrom( pSrfFinal) ; + return ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) ; +} + +//---------------------------------------------------------------------------- +static bool +OptimizedSpiralCircle( 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 ; - // restituisco la superficie aggiornata ricavata - if ( PockParams.nType != POCKET_CONFORMAL_ZIGZAG) { - if ( ! pSrfFinal->IsValid()) - return false ; - pSfr->Clear() ; - pSfr->CopyFrom( pSrfFinal) ; + // 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( pCrvCompo->Clone()) ; + 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 } - return ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) ; + + // 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, + const PocketParams& PockParams, ICurveComposite* pMCrv) +{ + // raggio della circonferenza esterna + if ( dOutRad < 10 * EPS_SMALL) + return false ; + + // imposto versore estrusione sulle curve composite + pMCrv->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 ; + + // assegno la Feed + AssignFeedSpiralOpt( 0, PockParams, pMCrv) ; + 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( pCrvCompo->Clone()) ; + 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 || ! pCrvCompo->IsValid() || + nBase < 0 || nBase >= pCrvCompo->GetCurveCount() || + nSecondBase < 0 || nSecondBase >= pCrvCompo->GetCurveCount()) + 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) == TEMP_PROP_OPEN_EDGE) { + int nCrvRight_ref = ( nType == 0 ? 0 : 1) ; + pCrvTrap->GetCurve( nCrvRight_ref)->GetStartPoint( ptEB0) ; + pCrvTrap->GetCurve( nCrvRight_ref)->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) == TEMP_PROP_OPEN_EDGE) { + int nCrvLeft_ref = ( nType == 0 ? 2 : 3) ; + pCrvTrap->GetCurve( nCrvLeft_ref)->GetStartPoint( ptEB1) ; + pCrvTrap->GetCurve( nCrvLeft_ref)->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, TEMP_PROP_OPEN_EDGE, 0) ; // aperta + } + nSecondBase = pCrvTrap->GetCurveCount() ; + pCrvTrap->AddLine( ptEB1) ; + if ( bCopyLeft) + pCrvTrap->AddCurve( Release( pCrvTest1)) ; + else { + pCrvTrap->Close() ; + pCrvTrap->SetCurveTempProp( pCrvTrap->GetCurveCount() - 1, TEMP_PROP_OPEN_EDGE, 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, const 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)) { + // data la tolleranza, creo la curva a trapezio dai 4 punti + pCrvTrap->AddPoint( pt) ; + pCrvTrap->AddLine( pt + vtDir) ; + pCrvTrap->AddLine( pt + vtOtherDir + vtB2) ; + pCrvTrap->AddLine( pt + vtOtherDir) ; + pCrvTrap->Close() ; + // 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() ; + if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap)) + return false ; + // assegno le tempProp della curva trapezio + for ( int nU = 0 ; nU < 4 ; ++ nU) { + Vector3d vtCrvDir ; pCrvTrap->GetCurve( nU)->GetStartDir( vtCrvDir) ; + for ( int nI = 0 ; nI < pCrvCompo->GetCurveCount() ; ++ nI) { + Vector3d vtCurrCrvDir ; pCrvTrap->GetCurve( nI)->GetStartDir( vtCurrCrvDir) ; + if ( AreSameVectorEpsilon( vtCrvDir, vtCurrCrvDir, 150 * EPS_SMALL)) { + pCrvTrap->SetCurveTempProp( nU, pCrvCompo->GetCurve( nI)->GetTempProp( 0), 0) ; + break ; + } + } + } + bool 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 ; + } + } + } + } + } + if ( ! bOK) { + pCrvTrap->Clear() ; + nBase = -1 ; + nSecondBase = -1 ; + return true ; + } + } + + // 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, const 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, + const 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 +AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket, + const 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, const PocketParams& PockParams, ICurveComposite* pMCrv, + 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 +GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParam, + ICurveComposite* pCrvRes) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + pCrvRes->Clear() ; + + // ricavo la curva di bordo del chunk corrente + PtrOwner pCrvBorder( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) + return false ; + pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + pCrvBorder->SetExtrusion( pSfrChunk->GetNormVersor()) ; + + /* SPIRALE EUCLIDEA + - E' richiesto che la curva di bordo sia una circonferenza tutta OPEN o tutta CLOSED + */ + bool bOkSpiral = true ; + int nTempPropRef = pCrvBorder->GetCurve( 0)->GetTempProp( 0) ; + for ( int nU = 1 ; nU < pCrvBorder->GetCurveCount() && bOkSpiral ; ++ nU) + bOkSpiral = ( pCrvBorder->GetCurve( nU)->GetTempProp( 0) == nTempPropRef) ; + if ( bOkSpiral) { + // controllo che sia una circonferenza + Point3d ptCen ; double dRad ; + if ( ! OptimizedSpiralCircle( pCrvBorder, 50 * EPS_SMALL, dRad, ptCen, bOkSpiral)) + return false ; + // se è una circonferenza + if ( bOkSpiral) { + double dOffs = PockParam.dRad + PockParam.dRadialOffset ; + // se curva tutta Open, allora ingrandisco il raggio + if ( nTempPropRef == TEMP_PROP_OPEN_EDGE) + dRad += 1.05 * PockParam.dRad + PockParam.dRadialOffset ; + // se curva chiusa, controllo che il raggio sia compatibile con il primo Offset + else + bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; + if ( bOkSpiral) { + double dIntRad = 0 ; + bool bOkSpiral = CalcCircleSpiral( ptCen, pSfrChunk->GetNormVersor(), dRad - dOffs, dIntRad, PockParam, pCrvRes) ; + if ( bOkSpiral && pCrvRes->IsValid() && pCrvRes->GetCurveCount() > 0) { + // se curva di bordo OPEN, imposto i parametri per LeadIn + if ( nTempPropRef == TEMP_PROP_OPEN_EDGE) { + Vector3d vtMidOut ; + pCrvRes->GetStartDir( vtMidOut) ; + vtMidOut.Rotate( pSfrChunk->GetNormVersor(), PockParam.bInvert ? ANG_RIGHT : - ANG_RIGHT) ; + bool bIsExtended ; + ExtendPath( pCrvRes, pSfrChunk, PockParam, vtMidOut, false, bIsExtended) ; + } + return true ; + } + } + } + } + + /* TRAPEZI + - E' richiesto che una dimensione del box della curva sia compatibile con il primo Offset, il + quale sarebbe una singola curva aperta + */ + PtrOwner pCrvTrap( CreateCurveComposite()) ; + if ( IsNull( pCrvTrap)) + return false ; + Frame3d frTrap ; + double dPocketSize ; + int nBase, nSecondBase ; + bool bOkTrap = ( GetTrapezoidFromShape( pCrvBorder, pCrvTrap, frTrap, PockParam, dPocketSize, nBase, nSecondBase)) ; + if ( bOkTrap && pCrvTrap->IsValid()) { + pCrvTrap->SetExtrusion( Z_AX) ; + CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParam, pCrvRes, bOkTrap) ; + if ( bOkTrap) { + // calcolo eventuali uscite e ingressi + if ( pCrvRes->GetTempProp( 0) > 0) { + Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ; + vtRef.Invert() ; + bool bIsStartExtended = false ; + if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, bIsStartExtended)) + return false ; + pCrvRes->GetEndDir( vtRef) ; + bool bIsEndExtended = false ; + if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, true, bIsEndExtended)) + return false ; + if ( bIsEndExtended && ! bIsStartExtended) + pCrvRes->Invert() ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetPocketingOptimizedCurves( ISurfFlatRegion* pSfr, const PocketParams& PockParam, + ICRVCOMPOPOVECTOR& vCrvOptCurves) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + vCrvOptCurves.clear() ; + + // se non sono richiesti i casi ottimizzati esco + if ( PockParam.bAvoidOpt) + return true ; + + // scorro i Chunk della superficie + int nChunks = pSfr->GetChunkCount() ; + int nCurrChunk = 0 ; + for ( int i = 0 ; i < nChunks ; ++ i) { + + // recupero il Chunk corrente + PtrOwner pSfrChunk( pSfr->CloneChunk( nCurrChunk)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + + // se il Chunk ha isole, non ho casi ottimizzati + if ( pSfrChunk->GetLoopCount( 0) > 1) { + ++ nCurrChunk ; + continue ; + } + + // ricavo le curve ottimizzate a seconda della lavorazione richiesta + if ( PockParam.nType == POCKET_SPIRALIN || PockParam.nType == POCKET_SPIRALOUT) { + // curva da resituire + PtrOwner pCrvOptSpiral( CreateCurveComposite()) ; + if ( IsNull( pCrvOptSpiral) || + ! GetSpiralOptimizedCurves( pSfrChunk, PockParam, pCrvOptSpiral)) + return false ; + // se ho ricavato una curva ottimizzata + if ( ! IsNull( pCrvOptSpiral) && pCrvOptSpiral->IsValid() && pCrvOptSpiral->GetCurveCount() > 0) { + vCrvOptCurves.emplace_back( Release( pCrvOptSpiral)) ; + pSfr->EraseChunk( nCurrChunk) ; + } + else + ++ nCurrChunk ; + } + // else if ( PockParam.nType == POCKET_ZIGZAG) + // ; + // else if ( PockParam.nType == POCKET_ONEWAY) + // ; + // else if ( PockParam.nType == POCKET_CONFORMAL_ONEWAY || PockParam.nType == POCKET_CONFORMAL_ZIGZAG) + // ; + } + + return true ; } // *************************************************************************** @@ -2613,1260 +4161,6 @@ GetOptCrvIndex( const ISurfFlatRegion* pSfrOrig, const ISurfFlatRegion* pSfrChun } - -//---------------------------------------------------------------------------- -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( pCrvCompo->Clone()) ; - 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, - const PocketParams& PockParams, ICurveComposite* pMCrv) -{ - // raggio della circonferenza esterna - if ( dOutRad < 10 * EPS_SMALL) - return false ; - - // imposto versore estrusione sulle curve composite - pMCrv->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 ; - - // assegno la Feed - AssignFeedSpiralOpt( 0, PockParams, pMCrv) ; - 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( pCrvCompo->Clone()) ; - 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( pCrvCompo->Clone()) ; - PtrOwner pCrvTest1( pCrvCompo->Clone()) ; - 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, const 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)) { - // data la tolleranza, creo la curva a trapezio dai 4 punti - pCrvTrap->AddPoint( pt) ; - pCrvTrap->AddLine( pt + vtDir) ; - pCrvTrap->AddLine( pt + vtOtherDir + vtB2) ; - pCrvTrap->AddLine( pt + vtOtherDir) ; - pCrvTrap->Close() ; - // 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() ; - 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, const 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, - const 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 -AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket, - const 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, const PocketParams& PockParams, ICurveComposite* pMCrv, - 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, const PocketParams& PockParams, double dRightLen, double dLeftLen, bool bAsParam) @@ -4170,9 +4464,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 +4828,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 +4870,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 +4908,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 +4921,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 +5203,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 +5413,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 +5441,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 ; } @@ -5678,69 +5466,6 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int if ( IsNull( pSrfToWork) || pSrfToWork->GetChunkCount() == 0) return false; - // ---------------------------------- Casi ottimizzati ---------------------------------- - bool bHasIsland = ( pSrfPock->GetLoopCount( 0) > 1) ; - // se non ho isole e curva valida allora controllo casi ottimizzati - if ( ! PockParams.bAvoidOpt && ! bHasIsland && - ( ! vCrvOrigChunkLoops.empty()) && ! IsNull( vCrvOrigChunkLoops[0])) { - // --------------------------- 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 && dRad - dOffs > 10 * EPS_SMALL) { - double dIntRad = 0 ; - if ( nReg == 0) { - bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, PockParams, pMCrv) ; - if ( bOk) { - pMCrv->GetStartPoint( ptStart) ; - for ( int u = 0 ; u < pCrvBorder->GetCurveCount() ; ++ u) { - if ( pCrvBorder->GetCurve( u)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - bMidOut = true ; - pMCrv->GetStartDir( vtMidOut) ; - vtMidOut.Rotate( pSrfPock->GetNormVersor(), PockParams.bInvert ? ANG_RIGHT : - ANG_RIGHT) ; - break ; - } - } - 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 ; - if ( ! GetTrapezoidFromShape( vCrvOrigChunkLoops[0], pCrvTrap, frTrap, PockParams, dPocketSize, nBase, nSecondBase)) - return false ; - if ( pCrvTrap->IsValid()) { - pCrvTrap->SetExtrusion( Z_AX) ; - if ( nReg == 0) { - CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParams, pMCrv, bOptimizedTrap) ; - if ( bOptimizedTrap) { - nReg = 1 ; - return true ; - } - } - else - return true ; - } - - } - // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; @@ -6714,7 +6439,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 +6522,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) { @@ -7000,6 +6727,17 @@ AddOneWay( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketPar pCrvSegCompo->AddCurve( Release( pCrvSeg)) ; // calcolo la Feed AssignFeedZigZagOneWay( pCrvSegCompo, false, vCrvNull, vLineUnder, vCrvCompoNull, PockParams) ; + // estendo presso lati aperti se richiesto + if ( ! PockParams.bAllClosed) { + Vector3d vtRef ; pCrvSegCompo->GetStartDir( vtRef) ; + vtRef.Invert() ; + bool bIsExtended = false ; + if ( ! ExtendPath( pCrvSegCompo, pSfrOrig, PockParams, vtRef, false,bIsExtended)) + return false ; + pCrvSegCompo->GetEndDir( vtRef) ; + if ( ! ExtendPath( pCrvSegCompo, pSfrOrig, PockParams, vtRef, true, bIsExtended)) + return false ; + } vCrvCompoRes.emplace_back( Release( pCrvSegCompo)) ; } } @@ -7013,6 +6751,1491 @@ 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 + pSfrExtended->CopyFrom( pSfrOrig) ; + if ( pSfrExtended == nullptr || ! pSfrExtended->IsValid() || + ! ModifySurfByOpenEdges( pSfrExtended, PockParams)) + 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 bFirstOffs0, bool bFirstOffs1, double dSmoothPar, double dTol) +{ + + // controllo dei parametri + if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || + pCrvOffs1 == nullptr || ! pCrvOffs1->IsValid() || + pCrvLink == nullptr || ! pCrvLink->IsValid()) + return false ; + // curva precedente e successiva + PtrOwner pCrvBef ; + if ( bFirstOffs0 && pCrvOffs0->IsClosed()) + pCrvBef.Set( pCrvOffs0->GetFirstCurve()->Clone()) ; + else + pCrvBef.Set( 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 + if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { + pCrvOffs0->AddCurve( pCrvLink->GetFirstCurve()->Clone()) ; + pCrvLink->RemoveFirstOrLastCurve( false) ; + } + else { + Point3d ptS ; pCrvLink->GetStartPoint( ptS) ; + double dUE ; pCrvOffs0->GetParamAtPoint( ptS, dUE, dTol) ; + pCrvOffs0->TrimEndAtParam( dUE) ; + } + // modifico Offset1 per raccordarlo al nuovo Link + Point3d ptE ; pCrvLink->GetEndPoint( ptE) ; + double dUS ; pCrvOffs1->GetParamAtPoint( ptE, dUS, dTol) ; + if ( bFirstOffs1 && 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, false, false, 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 +CalcConformalOffsAndLinks( 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 ------------ + if ( PockParams.nType == POCKET_CONFORMAL_ONEWAY) + vCrvLink.resize( vCrvOffs.size()) ; + else { + // 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 +OrderConformalPaths( ICRVCOMPOPOVECTOR& vCrvPaths, const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pSfrOrig, + PocketParams& PockParams) +{ + // controllo dei parametri + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid() || + pSfrOrig == nullptr || ! pSfrOrig->IsValid()) + return false ; + if ( int( vCrvPaths.size()) < 2) + return true ; + + // superficie di controllo per parti isolate + PtrOwner pSfrToRemove( CloneSurfFlatRegion( pSfrChunk)) ; + if ( IsNull( pSfrToRemove) || ! pSfrToRemove->IsValid() || + ! pSfrToRemove->Intersect( *pSfrOrig)) + return false ; + + // creo le regioni piane di svuotatura dei percorsi + ISURFFRPOVECTOR vSfrRemoved ; vSfrRemoved.resize( vCrvPaths.size()) ; + for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { + // creo la regione di svuotatura di tale percorso + vSfrRemoved[i].Set( GetSurfFlatRegionFromFatCurve( CloneCurveComposite( vCrvPaths[i]), PockParams.dRad, false, false)) ; + if ( IsNull( vSfrRemoved[i]) || ! vSfrRemoved[i]->IsValid()) + return false ; + } + + // scorro i percorsi ricavati + INTVECTOR vInds ; vInds.resize( vCrvPaths.size(), -1) ; + int nChunkRef = pSfrToRemove->GetChunkCount() ; + for ( int i = 0 ; i < int( vInds.size()) ; ++ i) { + int j = 0 ; + INTVECTOR vTempInds ; + for ( ; j < int( vCrvPaths.size()) ; ++ j) { + // se indice già presente + if ( find( vInds.begin(), vInds.end(), j) != vInds.end()) + continue ; + // se sottraendo questa regione a quella originale ottengo più isole, allora non è il percorso ideale + PtrOwner pSfrRemain( CloneSurfFlatRegion( pSfrToRemove)) ; + if ( IsNull( pSfrRemain) || ! pSfrRemain->IsValid()) + continue ; + pSfrRemain->Subtract( *vSfrRemoved[j]) ; + // se aumento il numero di Chunk, allora non è il percorso ideale + if ( pSfrRemain->GetChunkCount() > nChunkRef) + continue ; + vTempInds.push_back( j) ; + } + if ( vTempInds.empty()) { + // se non ho trovato curva candidate, prendo l'indice disponibile più basso + for ( int k = 0 ; k < int( vInds.size()) ; ++ k) { + if ( find( vInds.begin(), vInds.end(), k) != vInds.end()) + continue ; + vInds[i] = k ; + break ; + } + } + else if ( int( vTempInds.size()) == 1) { + // se la candidata è singola, allora è lei + vInds[i] = vTempInds[0] ; + if ( PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + if ( vCrvPaths[vInds[i]]->IsClosed() && i > 0) { + Point3d ptS ; vCrvPaths[vInds[i-1]]->GetStartPoint( ptS) ; + DistPointCurve DistCalculator( ptS, *vCrvPaths[vInds[i]]) ; + int nFlag ; double dUS ; + DistCalculator.GetParamAtMinDistPoint( 0, dUS, nFlag) ; + vCrvPaths[vInds[i]]->ChangeStartPoint( dUS) ; + } + } + } + else { + // se lavorazione conformal ZigZag + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { + // se ne ho trovate di più, allora euristicamente prendo la più corta + double dMinLen = INFINITO ; + for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { + // privilegio le aperte + if ( vCrvPaths[vTempInds[k]]->IsClosed()) + continue ; + double dLen ; vCrvPaths[vTempInds[k]]->GetLength( dLen) ; + if ( dLen < dMinLen) { + dMinLen = dLen ; + vInds[i] = vTempInds[k] ; + } + } + // cerco solo tra le chiuse se non ho aperte + if ( dMinLen > INFINITO - 1) { + for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { + if ( vCrvPaths[vTempInds[k]]->IsClosed()) { + double dLen ; vCrvPaths[vTempInds[k]]->GetLength( dLen) ; + if ( dLen < dMinLen) { + dMinLen = dLen ; + vInds[i] = vTempInds[k] ; + } + } + } + } + } + // se lavorazione conformal OneWay + else { + // se ne ho trovate di più, cerco euristicamente la più vicina al punto iniziale della curva + // se prima in assoluto, allora prendo la più corta + if ( i == 0) { + double dMinLen = INFINITO ; + for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { + double dLen ; vCrvPaths[vTempInds[k]]->GetLength( dLen) ; + if ( dLen < dMinLen) { + dMinLen = dLen ; + vInds[i] = vTempInds[k] ; + } + } + } + // altrimenti + else { + double dSqMinDist = INFINITO ; + Point3d ptS ; vCrvPaths[vInds[i-1]]->GetStartPoint( ptS) ; + Point3d ptTmpS ; + for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { + if ( vCrvPaths[vTempInds[k]]->IsClosed()) + continue ; + vCrvPaths[vTempInds[k]]->GetStartPoint( ptTmpS) ; + double dMyDist = SqDist( ptS, ptTmpS) ; + if ( dMyDist < dSqMinDist) { + dSqMinDist = dMyDist ; + vInds[i] = vTempInds[k] ; + } + } + if ( dSqMinDist > INFINITO - 1) { + for ( int k = 0 ; k < int( vTempInds.size()) ; ++ k) { + if ( vCrvPaths[vTempInds[k]]->IsClosed()) { + DistPointCurve DistCalculator( ptS, *vCrvPaths[vTempInds[k]]) ; + double dMySqDist ; + DistCalculator.GetSqDist( dMySqDist) ; + if ( dMySqDist < dSqMinDist) { + dSqMinDist = dMySqDist ; + vInds[i] = vTempInds[k] ; + double dUS ; + int nFlag ; + DistCalculator.GetParamAtMinDistPoint( 0, dUS, nFlag) ; + vCrvPaths[vTempInds[k]]->ChangeStartPoint( dUS) ; + } + } + } + } + } + } + } + // aggiorno la regione da svuotare e il numero di Chunk che si sono formati + pSfrToRemove->Subtract( *vSfrRemoved[vInds[i]]) ; + nChunkRef = pSfrToRemove->GetChunkCount() ; + } + + // riordino i percorsi trovati + ICRVCOMPOPOVECTOR vCrvOrderedPaths ; vCrvOrderedPaths.resize( vCrvPaths.size()) ; + for ( int i = 0 ; i < int( vInds.size()) ; ++ i) + vCrvOrderedPaths[i].Set( vCrvPaths[vInds[i]]) ; + swap( vCrvOrderedPaths, vCrvPaths) ; + + 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)) + return false ; + if ( ! pSfrClass->IsValid()) + return true ; // non posso svuotare nulla + + // 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()) { + if ( ! AddSpiralIn( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) + return false ; + } + else { + // definisco vettore degli Offset e dei Link + ICRVCOMPOPOVECTOR vCrvOffs ; + ICURVEPOVECTOR vCrvLink ; + // ordino le curve di Offset e raccordo + if ( ! CalcConformalOffsAndLinks( vvCrvOffs, pSfrChunk, pSfrClassChunk, PockParams, vCrvOffs, vCrvLink)) + return false ; + // 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 ; + // ordino i percorsi trovati + if ( ! OrderConformalPaths( vCrvPaths, pSfrChunk, pSfrOrig, PockParams)) + 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 +8246,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 @@ -7049,7 +8272,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double ! myParams.frLocXY.Rotate( ptCenter, pSfr->GetNormVersor() , myParams.dAngle)) return false ; - // porto la superficie da svuotare in tale sistema + // porto la superficie da svuotare nel sistema di riferimento lungo Z_AX PtrOwner pSfrAdj( pSfr->Clone()) ; if ( IsNull( pSfrAdj) || ! pSfrAdj->ToLoc( myParams.frLocXY)) return false ; @@ -7059,51 +8282,74 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double // porto il punto iniziale di riferimento ( se valido) in tale sistema if ( myParams.ptStart.IsValid()) myParams.ptStart.ToLoc( myParams.frLocXY) ; - - // ------------ 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)) + // controllo se esistono supercicie tutta chiusa o tutta aperta + if ( ! IsSfrAllHomogeneous( pSfr, myParams.bAllClosed, myParams.bAllOpen)) return false ; - // se le curve di primo offset che ho ottenuto, svuotano tutta la superficie, allora ho finito - if ( bSkipPocket) { - // riporto le curve in Globale - for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) - vCrvCompoRes[i]->ToGlob( myParams.frLocXY) ; - return true ; + + // ------------ casi ottimizzati ------------------------------------------ + ICRVCOMPOPOVECTOR vCrvOptCurves ; + if ( ! GetPocketingOptimizedCurves( pSfrAdj, myParams, vCrvOptCurves)) + return false ; + for ( int i = 0 ; i < int( vCrvOptCurves.size()) ; ++ i) { + vCrvOptCurves[i]->ToGlob( myParams.frLocXY) ; + vCrvCompoRes.emplace_back( Release( vCrvOptCurves[i])) ; } + // se ho svuotato tutta la superficie, allora ho finito + if ( IsNull( pSfrAdj) || ! pSfrAdj->IsValid() || pSfrAdj->GetChunkCount() == 0) + return true ; + + // ------------ recupero le singole curve di svuotatura ------------------- + ICRVCOMPOPOVECTOR vCrvSingleCurves ; + if ( ! GetSinglePocketingCurves( pSfrAdj, myParams, vCrvSingleCurves)) + return false ; + for ( int i = 0 ; i < int( vCrvSingleCurves.size()) ; ++ i) { + vCrvSingleCurves[i]->ToGlob( myParams.frLocXY) ; + vCrvCompoRes.emplace_back( Release( vCrvSingleCurves[i])) ; + } + // se ho svuotato tutta la superficie, allora ho finito + if ( IsNull( pSfrAdj) || ! pSfrAdj->IsValid() || pSfrAdj->GetChunkCount() == 0) + return true ; + + // ------------ estensione lati aperti ------------------------------------ + if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams)) + return false ; + // porto una copia della superficie originale nel frame creato PtrOwner pSfr_Loc( CloneSurfFlatRegion( pSfr)) ; if ( IsNull( pSfr_Loc) || ! pSfr_Loc->IsValid() || ! pSfr_Loc->ToLoc( myParams.frLocXY)) return false ; // ------------ calcolo delle curve elementari della superficie ------------------- + ICRVCOMPOPOVECTOR vCrvCompoPock ; switch ( nType) { case POCKET_ZIGZAG : - if ( ! AddZigZag( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + if ( ! AddZigZag( pSfrAdj, pSfr_Loc, myParams, vCrvCompoPock)) return false ; break ; case POCKET_ONEWAY : - if ( ! AddOneWay( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + if ( ! AddOneWay( pSfrAdj, pSfr_Loc, myParams, vCrvCompoPock)) return false ; break ; case POCKET_SPIRALIN : - if ( ! AddSpiralIn( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + if ( ! AddSpiralIn( pSfrAdj, pSfr_Loc, myParams, vCrvCompoPock)) return false ; break ; case POCKET_SPIRALOUT : - if ( ! AddSpiralOut( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + if ( ! AddSpiralOut( pSfrAdj, pSfr_Loc, myParams, vCrvCompoPock)) return false ; break ; case POCKET_CONFORMAL_ZIGZAG : - if ( ! AddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes)) + case POCKET_CONFORMAL_ONEWAY : + if ( ! AddConformal( pSfrAdj, pSfr_Loc, myParams, vCrvCompoPock)) return false ; break ; } // riporto tutte le curve ottenute in globale - for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) - vCrvCompoRes[i]->ToGlob( myParams.frLocXY) ; + for ( int i = 0 ; i < int( vCrvCompoPock.size()) ; ++ i) { + vCrvCompoPock[i]->ToGlob( myParams.frLocXY) ; + vCrvCompoRes.emplace_back( Release( vCrvCompoPock[i])) ; + } return true ; } @@ -7422,4 +8668,4 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool } return true ; -} +} \ No newline at end of file diff --git a/CurveAux.cpp b/CurveAux.cpp index 6d0043c..7af77f4 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -1940,6 +1940,22 @@ CalcCurveVoronoiDiagram( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, int nBound) return pVoronoiObj->CalcVoronoiDiagram( vCrvs, nBound) ; } +//---------------------------------------------------------------------------- +bool +CalcCurvesVoronoiDiagram( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nBound) +{ + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vCrvC.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vCrvC[i])) + return false ; + } + + return pVoronoiObj->CalcVoronoiDiagram( vCrvs, nBound) ; +} + //---------------------------------------------------------------------------- bool CalcCurveMedialAxis( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, int nSide) @@ -1951,6 +1967,22 @@ CalcCurveMedialAxis( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, int nSide) return pVoronoiObj->CalcMedialAxis( vCrvs, nSide) ; } +//---------------------------------------------------------------------------- +bool +CalcCurvesMedialAxis( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nSide) +{ + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vCrvC.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vCrvC[i])) + return false ; + } + + return pVoronoiObj->CalcMedialAxis( vCrvs, nSide) ; +} + //---------------------------------------------------------------------------- bool CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 8ddb891..87e3278 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 6797ba8..2d4db16 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1987,7 +1987,7 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& Point3d pt3DEnd ; pCrv0->GetEndPoint( pt3DEnd) ; bool bThroughEdge = false ; BOOLVECTOR vbThroughEdge ; - if ( ! UnprojectPoint(pt3D, pt2D, pt3DEnd, &bThroughEdge, pPlCut)) + if ( ! UnprojectPoint( pt3D, pt2D, pt3DEnd, &bThroughEdge, pPlCut)) return false ; vbThroughEdge.push_back( bThroughEdge) ; @@ -2034,7 +2034,7 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& return false ; // se il precedente era passato attraverso l'edge ed era un edge di polo allora devo sistemare le coordinate - if( bPrevIsPole){ + if ( bPrevIsPole) { // se il punto precedente era di polo allora devo correggere le sue coordinate 2D if ( bHorizontalPole) pt2DPrev.x = pt2D.x ; @@ -2045,12 +2045,12 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& vtDir.Normalize() ; // se mi accorgo che sto per tracciare un taglio lungo un bordo posso semplicemente evitarlo double dDelta = 10 * EPS_SMALL ; - if ( (1 - abs(vtDir.x) < SQ_EPS_SMALL && (pt2D.y < dDelta || m_nSpanV * SBZ_TREG_COEFF - pt2D.y < dDelta)) || // parallelo agli edge 0 e 2 e su uno di questi - (1 - abs(vtDir.y) < SQ_EPS_SMALL && (pt2D.x < dDelta || m_nSpanU * SBZ_TREG_COEFF - pt2D.x < dDelta))) { // parallello agli edge 1 e 3 e su uno di questi + if ( ( 1 - abs( vtDir.x) < SQ_EPS_SMALL && ( pt2D.y < dDelta || m_nSpanV * SBZ_TREG_COEFF - pt2D.y < dDelta)) || // parallelo agli edge 0 e 2 e su uno di questi + ( 1 - abs( vtDir.y) < SQ_EPS_SMALL && ( pt2D.x < dDelta || m_nSpanU * SBZ_TREG_COEFF - pt2D.x < dDelta))) { // parallello agli edge 1 e 3 e su uno di questi ++ nRejected ; continue ; } - if ( bThroughEdge && vbThroughEdge.back()) { + if ( bThroughEdge && vbThroughEdge.back()) { double dParamH, dParamL ; dParamH = m_nSpanV * SBZ_TREG_COEFF ; dParamL = m_nSpanU * SBZ_TREG_COEFF ; @@ -2058,8 +2058,8 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& // ( i punti per periodicità hanno coordinate diverse anche se dovrebbero averle uguali, quindi il segmento attraversa tutto lo spazio parametrico, anche se in realtà è lungo il bordo di chiusura) // potrei star tracciando un taglio sul bordo di chiusura // controllo se sto tracciando una linea che unisce due lati di chiusura, allora in realtà sdtarei tracciando un taglio sull'edge e quindi posso non tracciarlo - if ( (abs( vtDir.x) > abs( vtDir.y) && Dist( pt2D, pt2DPrev) > dParamL * 0.5) || - (abs( vtDir.y) > abs( vtDir.x) && Dist( pt2D, pt2DPrev) > dParamH * 0.5)) { + if ( ( abs( vtDir.x) > abs( vtDir.y) && Dist( pt2D, pt2DPrev) > dParamL * 0.5) || + ( abs( vtDir.y) > abs( vtDir.x) && Dist( pt2D, pt2DPrev) > dParamH * 0.5)) { ++ nRejected ; continue ; } @@ -2073,12 +2073,14 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& Point3d ptNear ; pCrv0->GetStartPoint( ptNear) ; INTVECTOR vId ; bool bAdded = true ; - while( chainC.GetChainFromNear( pt3D, false, vId)) { + while ( chainC.GetChainFromNear( pt3D, false, vId)) { PtrOwner pCC2D ( CreateCurveComposite()) ; + if ( IsNull( pCC2D)) + return false ; for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // creo un segmento di retta - ICurveLine* pLine( CreateCurveLine()) ; - if ( pLine == nullptr) + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine)) return false ; // recupero gli estremi (non vanno mai invertiti per opzione di concatenamento) int nInd = abs( vId[i]) - 1 ; @@ -2086,12 +2088,12 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& Point3d ptEnd = vBPnt[nInd].second ; // provo ad accodarlo alla composita bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && - pLine->Set( ptStart, ptEnd)) ; - bAdded = bAdded && pCC2D->AddCurve( pLine, true, dToler) ; + pLine->Set( ptStart, ptEnd)) ; + bAdded = bAdded && pCC2D->AddCurve( Release( pLine), true, dToler) ; ptNear = ( bAdded ? ptEnd : ptStart) ; } if ( pCC2D->IsValid()) - vpCC.emplace_back( Release(pCC2D)) ; + vpCC.emplace_back( Release( pCC2D)) ; } return true ; } @@ -2100,31 +2102,31 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& bool SurfBezier::AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler, const Plane3d* pPlCut) const { - // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro e sposto il punto finale nel punto di fine della curva che sto ignorando + // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro e sposto il punto finale nel punto di fine della curva che sto ignorando double dCrvLen ; if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) return true ; - // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene + // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene Point3d ptStart, ptEnd ; if ( pCrvCompo->GetStartPoint( ptStart) && - pCrvCompo->GetEndPoint( ptEnd) && - AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && - ! AreSamePointApprox( ptStart, ptEnd)) { - // porto il punto finale a coincidere esattamente con l'inizio + pCrvCompo->GetEndPoint( ptEnd) && + AreSamePointEpsilon( ptStart, ptEnd, 5 * dToler) && + ! AreSamePointApprox( ptStart, ptEnd)) { + // porto il punto finale a coincidere esattamente con l'inizio pCrvCompo->ModifyEnd( ptStart) ; } - // unisco segmenti allineati + // unisco segmenti allineati pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; - // porto la curva nello spazio parametrico + // porto la curva nello spazio parametrico ICRVCOMPOPVECTOR vCC ; if ( ! UnprojectCurveFromStm( pCrvCompo, vCC, pPlCut)) return false ; for ( int i = 0 ; i < int( vCC.size()); ++i) { - // le curve aperte le tengo da parte per giuntarle alla fine col bordo + // le curve aperte le tengo da parte per giuntarle alla fine col bordo if ( ! vCC[i]->IsClosed() ) vpCCOpen.emplace_back( vCC[i]) ; - // le curve chiuse le metto tutte insieme subito + // le curve chiuse le metto tutte insieme subito else vpCCClosed.emplace_back( vCC[i]) ; } diff --git a/SurfFlatRegion.cpp b/SurfFlatRegion.cpp index 844e0cc..503198b 100644 --- a/SurfFlatRegion.cpp +++ b/SurfFlatRegion.cpp @@ -1166,6 +1166,19 @@ SurfFlatRegion::GetLoop( int nChunk, int nLoop) const return pCrv ; } +//---------------------------------------------------------------------------- +int +SurfFlatRegion::GetLoopCurveCount( int nChunk, int nLoop) const +{ + // recupero il loop nel riferimento intrinseco + const ICurve* pMyCrv = GetMyLoop( nChunk, nLoop) ; + if ( pMyCrv == nullptr) + return 0 ; + // restituisco il numero di curve di cui è composto + const ICurveComposite* pMyCompo = GetCurveComposite( pMyCrv) ; + return ( pMyCompo == nullptr ? 1 : pMyCompo->GetCurveCount()) ; +} + //---------------------------------------------------------------------------- bool SurfFlatRegion::ApproxLoopWithLines( int nChunk, int nLoop, double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const diff --git a/SurfFlatRegion.h b/SurfFlatRegion.h index be42bea..70b865e 100644 --- a/SurfFlatRegion.h +++ b/SurfFlatRegion.h @@ -109,6 +109,7 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW int GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& Other, int nOthChunk) const override ; // compare only outsides bool GetChunkMaxOffset( int nChunk, double& dOffs) const override ; int GetLoopCount( int nChunk) const override ; + int GetLoopCurveCount( int nChunk, int nLoop) const override ; ICurve* GetLoop( int nChunk, int nLoop) const override ; // nChunk 0-based, nLoop 0-based (1°esterno, successivi interni) bool ApproxLoopWithLines( int nChunk, int nLoop, double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ; bool SetCurveTempProp( int nChunk, int nLoop, int nCrv, int nProp, int nPropInd = 0) override ; diff --git a/Voronoi.cpp b/Voronoi.cpp index 87cd79d..2f01458 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -734,14 +734,13 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( j == 0) pCrvOffs->AddPoint( ptS) ; - // se estremi coincidenti passo alla curva successiva ( da vroni non possono arrivare circonferenze) - if ( AreSamePointApprox( ptS, ptE)) - continue ; - bool bOk = false ; if ( nType == t_site::SEG) bOk = pCrvOffs->AddLine( ptE) ; - else { + else { + // se estremi coincidenti passo alla curva successiva ( da vroni non possono arrivare circonferenze) + if ( AreSamePointApprox( ptS, ptE)) + continue ; PtrOwner pArc( CreateBasicCurveArc()) ; pArc->Set2PRS( ptS, ptE, Dist( ptC, ptS), nType == CCW) ; bOk = pCrvOffs->AddCurve( Release( pArc)) ;