diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 616b585..61ec038 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -1826,20 +1826,76 @@ 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 + */ + // 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, bool bCalcSingleCrv, - 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 ( ! IsSfrAllHomogeneous( pSfr, PockParams.bAllClosed, PockParams.bAllOpen)) - return false ; // se lati tutti chiusi, allora non devo fare nulla if ( PockParams.bAllClosed) return true ; @@ -1853,38 +1909,11 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa 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 ; - - if ( bCalcSingleCrv) { - bool bIsAllRemoved = false ; - GetPocketCurvesByClosedEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; - if ( bIsAllRemoved) { - // se ho rimosso tutto, allora passo la chunk successivo - ++ nChunkOneCurve ; - 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))) ; @@ -1905,8 +1934,6 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa 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)) @@ -1915,8 +1942,9 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa } // 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 ; @@ -1945,7 +1973,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa // 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) { @@ -1957,10 +1985,10 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa 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) { /* @@ -1990,46 +2018,17 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa 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 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) ; - } - - // se ho rimosso tutti i Chunk con una singola curva, allora ho terminato la svuotatura - bSkipPocket = ( nChunk == nChunkOneCurve) ; - if ( bSkipPocket) - return true ; - - // restituisco la superficie aggiornata ricavata + // se la superficie finale estesa non è valida, errore if ( ! pSrfFinal->IsValid()) return false ; - // chiudo le isole che risultano ambigue + + + // 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à @@ -2051,694 +2050,13 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, bool bCa } } } + + // restituisco la superficie estesa pSfr->Clear() ; pSfr->CopyFrom( pSrfFinal) ; return ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) ; } -// *************************************************************************** -// ------------- SCELTA DEL PUNTO INIZIALE ----------------------------------- -// *************************************************************************** - -//---------------------------------------------------------------------------- -static bool -GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockParams, bool& bOutStart, - Point3d& ptStart, Vector3d& vtOut) -{ - // controllo dei parametri - if ( pCompo == nullptr || ! pCompo->IsValid()) - return false ; - - // verifico se tutti i lati sono aperti - bool bAllOpen = true ; - const ICurve* pMyCrv = pCompo->GetFirstCurve() ; - while ( pMyCrv != nullptr) { - if ( pMyCrv->GetTempProp() != TEMP_PROP_OPEN_EDGE) { - bAllOpen = false ; - break ; - } - pMyCrv = pCompo->GetNextCurve() ; - } - - // richiedo lunghezza superiore a diametro utensile più doppio offset radiale - double dRefLen = ( bAllOpen ? 0. : ( 2 * PockParams.dRad) + 2 * PockParams.dRadialOffset - EPS_SMALL) ; - double dMaxLen = dRefLen ; - // ciclo sulle singole curve - bool bFound = false ; - const ICurve* pPrevCrv = pCompo->GetLastCurve() ; - double dLenPrev = 0. ; - if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) - pPrevCrv->GetLength( dLenPrev) ; - const ICurve* pCrv = pCompo->GetFirstCurve() ; - while ( pCrv != nullptr) { - // analizzo la curva successiva - const ICurve* pNextCrv = pCompo->GetNextCurve() ; - bool bNextOk = ( pNextCrv != nullptr) ; - if ( ! bNextOk) - pNextCrv = pCompo->GetFirstCurve() ; - double dLenNext = 0. ; - if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) - pNextCrv->GetLength( dLenNext) ; - // verifico la curva corrente - if ( pCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { - // contributo dalle entità adiacenti ( se non tutte aperte) - double dLenAgg = 0. ; - if ( ! bAllOpen) { - if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { - Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ; - Vector3d vtStart ; pCrv->GetStartDir( vtStart) ; - dLenAgg += max( 0.4, vtPrevEnd * vtStart) * dLenPrev ; - } - if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { - Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ; - Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ; - dLenAgg += max( 0.4, vtEnd * vtNextStart) * dLenNext ; - } - } - // entità corrente - double dLen = 0 ; - if ( pCrv->GetLength( dLen)) { - const double LEN_TOL = 1 ; - // se di lunghezza praticamente uguale - if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) { - Point3d ptTest ; - pCrv->GetMidPoint( ptTest) ; - if ( ( PockParams.bAboveHead && ptTest.z > ptStart.z + 100 * EPS_SMALL) || - ( ! PockParams.bAboveHead && ptTest.z < ptStart.z - 100 * EPS_SMALL) || - ( abs( ptTest.z - ptStart.z) < 100 * EPS_SMALL && ptTest.y < ptStart.y - 100 * EPS_SMALL)) { - dMaxLen = max( dMaxLen, dLen + dLenAgg) ; - ptStart = ptTest ; - // versore ortogonale verso l'esterno - pCrv->GetMidDir( vtOut) ; - vtOut.Rotate( Z_AX, 0, -1) ; - } - } - // se più lunga ( o non già trovata) - else if ( dLen + dLenAgg > dMaxLen || ! bFound) { - dMaxLen = dLen + dLenAgg ; - if ( pCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart, &vtOut)) { - // versore ortogonale verso l'esterno - vtOut.Normalize() ; - vtOut.Rotate( Z_AX, 0, -1) ; - bFound = true ; - } - } - dLenPrev = dLen ; - } - } - else - dLenPrev = 0 ; - // vado alla successiva - pPrevCrv = pCrv ; - pCrv = ( bNextOk ? pNextCrv : nullptr) ; - } - - return bFound ; -} - -//---------------------------------------------------------------------------- -static bool -GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, - const ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut, - bool& bMidOut) -{ - // controllo dei parametri - if ( pCrvOrig == nullptr || ! pCrvOrig->IsValid() || - pCrvCompo == nullptr || ! pCrvCompo->IsValid()) - return false ; - bMidOut = false ; - - // cerco il lato aperto più lungo ( sufficientemente lungo) - double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; - for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { - // escludo le sottocurve chiuse - if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) - continue ; - // recupero la curva i-esima aperta dalla curva originale - const ICurve* pCrvOpen = pCrvOrig->GetCurve( i) ; - if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) - return false ; - // ricavo la lunghezza di tale curva - double dLen = 0. ; - pCrvOpen->GetLength( dLen) ; - // se lunghezza accettabile o maggiore della massima trovata - if ( dLen > dLenRef) { - Point3d ptSTmp ; - Vector3d vtMidOutTmp ; - // ricavo il punto medio e il vettore tangente ad esso associato - if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) { - // cerco la sottocurva più vicina a ptSTmp - int nFlag ; - double dMyPar ; - if ( DistPointCurve( ptSTmp, *pCrvCompo).GetParamAtMinDistPoint( 0, dMyPar, nFlag)) { - int nCrv = int( floor( dMyPar)) ; - // recupero tale sottocurva e controllo che anche essa sia OPEN - const ICurve* pMyCrv = pCrvCompo->GetCurve( nCrv) ; - if ( pMyCrv != nullptr && pMyCrv->IsValid() && pMyCrv->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - // recupero ptStart - pMyCrv->GetMidPoint( ptStart) ; - // versore d'uscita - vtMidOutTmp.Normalize() ; - vtMidOutTmp.Rotate( Z_AX, - ANG_RIGHT) ; - vtMidOut = vtMidOutTmp ; - // flag per possibile entrata da fuori - bMidOut = true ; - // aggiornamento della lunghezza di riferimento - dLenRef = dLen ; - } - } - } - } - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParams, - const ICurveComposite* pCrvCompo, const ICurveComposite* pCrvOrig, - Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) -{ - // controllo dei parametri - if ( ! ptRef.IsValid() || pCrvCompo == nullptr || ! pCrvCompo->IsValid() || - ! ptRef.IsValid()) - return false ; - bMidOut = false ; - - // lunghezza minima di riferimento per un lato aperto valido - double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; - - // cerco la curva OPEN a minima distanza da ptRef, sufficientemente lunga - int nStartCrv = -1 ; - double dMinDist = INFINITO ; - for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { - // considero solo le sottocurve OPEN - if ( pCrvCompo->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - // sufficientemente lunghe - double dLen ; - if ( pCrvCompo->GetCurve( i)->GetLength( dLen) && dLen > dLenRef) { - DistPointCurve DPC( ptRef, *pCrvCompo->GetCurve( i)) ; - double dCurrDist = INFINITO ; - // sufficiententemente vicine a ptRef - if ( DPC.GetSqDist( dCurrDist) && dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nStartCrv = i ; - } - } - } - } - - // se non ho trovato nulla, allora cerco un punto iniziale valido su una sottocurva OPEN - if ( nStartCrv == -1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { - return GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; - } - // se ho trovato la curva più vicina, cerco un punto iniziale valido - else { - const ICurve* pMyCrv = pCrvCompo->GetCurve( nStartCrv) ; - if ( pMyCrv != nullptr && pMyCrv->IsValid()) { - // ricavo ptStart e vettore tangente - if ( pMyCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart, &vtMidOut)) { - // versore ortogonale verso l'esterno - vtMidOut.Normalize() ; - vtMidOut.Rotate( Z_AX, 0, -1) ; - // flag per possibile entrata da fuori - bMidOut = true ; - } - } - } - - return true ; - -} - -//---------------------------------------------------------------------------- -static bool -GetPtStartOnHomogeousEdges( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, - int nType, const Point3d& ptRef, bool& bMidOut, Point3d& ptStart, - Vector3d& vtMidOut) -{ - // controllo dei parametri - if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) - return false ; - bMidOut = false ; - - // analizzo i sottotratti omogenei - ICRVCOMPOPOVECTOR vpCrvs ; - PtrOwner pCrvCompoClone( CloneCurveComposite( pCrvCompo)) ; - if ( IsNull( pCrvCompoClone) || ! pCrvCompoClone->IsValid()) - return false ; - GetHomogeneousParts( pCrvCompoClone, PockParams, vpCrvs) ; - - // se ho un solo tratto omogeneo e coerente al tipo scelto ... - if ( int( vpCrvs.size()) == 1 && vpCrvs[0]->GetTempProp( 0) == nType) { - // ... e non ho un punto di riferimento valido - if ( ! ptRef.IsValid()) { - // il punto iniziale è già definito - pCrvCompoClone->GetStartPoint( ptStart) ; - } - // ho un punto di riferimento valido - else { - // cerco il punto più vicino - DistPointCurve DistPtCrv( ptRef, *pCrvCompoClone) ; - int nFlag ; - if ( ! DistPtCrv.GetMinDistPoint( 0, ptStart, nFlag)) - return false ; - } - bMidOut = ( nType == TEMP_PROP_OPEN_EDGE) ; - return true ; - } - - // scorro i tratti omogenei e cerco il tratto del tipo definito più lungo - int nMaxInd = -1 ; - double dMaxLen = 0. ; - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - // considero solo i tratti aperti - if ( vpCrvs[i]->GetTempProp( 0) == nType) { - // calcolo la lunghezza del tratto aperto - double dLen ; - vpCrvs[i]->GetLength( dLen) ; - if ( dLen > dMaxLen) { - dMaxLen = dLen ; - nMaxInd = i ; - } - } - } - - // recupero il tratto del tipo definito più lungo - if ( nMaxInd != -1) { - // recupero il parametro alla sua metà - double dParIn ; - vpCrvs[nMaxInd]->GetParamAtLength( 0.5 * dMaxLen, dParIn) ; - // se tratto OPEN - if ( nType == TEMP_PROP_OPEN_EDGE) { - bMidOut = true ; - vpCrvs[nMaxInd]->GetPointD1D2( dParIn, ICurve::FROM_MINUS, ptStart, &vtMidOut) ; - vtMidOut.Normalize() ; - vtMidOut.Rotate( Z_AX, 0, -1) ; - } - // se tratto CLOSED - else - vpCrvs[nMaxInd]->GetPointD1D2( dParIn, ICurve::FROM_MINUS, ptStart) ; - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -GetPtStartOnGenericEdge( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, - Point3d& ptStart) -{ - // controllo dei parametri - if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) - return false ; - pCrvCompo->GetStartPoint( ptStart) ; - - // scorro tutte le curve - double dLenRef = 0. ; - bool bAllShort = true ; // flag per curve tutte piccole - for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { - // ricavo la curva i-esima dalla curva originale - const ICurve* pMyCrv = pCrvCompo->GetCurve( i) ; - if ( pMyCrv == nullptr || ! pMyCrv->IsValid()) - return false ; - // ricavo la lunghezza di tale curva - double dLen = 0. ; - pMyCrv->GetLength( dLen) ; - // se lunghezza accettabile o maggiore della massima trovata, ricavo ptStart - if ( dLen > dLenRef) { - if ( pMyCrv->GetMidPoint( ptStart)) { - dLenRef = dLen ; - bAllShort = false ; - } - } - } - - // se curve tutte piccole - if ( bAllShort) { - bool bMidOutFake ; - Vector3d vtMidOutFake ; - if ( ! GetPtStartOnHomogeousEdges( pCrvCompo, PockParams, TEMP_PROP_CLOSE_EDGE, P_INVALID, - bMidOutFake, ptStart, vtMidOutFake)) - return false ; - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -GetPtStartOnGenericEdgeByPtRef( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, - const Point3d& ptRef, Point3d& ptStart) -{ - // controllo dei parametri - if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0 || - ! ptRef.IsValid()) - return false ; - - // ordino le curve di pCrvCompo in base alla vicinanza da ptRef - // - vector> vCrvInfoDist ; vCrvInfoDist.resize( pCrvCompo->GetCurveCount()) ; - // scorro le curve di pCrvCompo - for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { - vCrvInfoDist[i].first = i ; - // calcolo la distanza tra la curva i-esima e ptRef - double dDist = INFINITO ; - DistPointCurve DistPtCrv( ptRef, *pCrvCompo->GetCurve( i)) ; - DistPtCrv.GetSqDist( dDist) ; - vCrvInfoDist[i].second = dDist ; - } - // ordino il vettore in base alla distanza - sort( vCrvInfoDist.begin(), vCrvInfoDist.end(), [] ( const pair& a, const pair& b) { - return a.second < b.second ; - }) ; - - // cerco un parametro iniziale valido per le sottocurve ordinate - double dLenRef = 2 * PockParams.dRad + 2 * PockParams.dRadialOffset ; - for ( int i = 0 ; i < int( vCrvInfoDist.size()) ; ++ i) { - // recupero la curva i-esima - const ICurve* pMyCrv = pCrvCompo->GetCurve( vCrvInfoDist[i].first) ; - if ( pMyCrv != nullptr && pMyCrv->IsValid()) { - // controllo che sia abbastanza lunga e aggiorno ptStart - double dLen = 0. ; - pMyCrv->GetLength( dLen) ; - if ( dLen > dLenRef) { - if ( pMyCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart)) - return true ; - } - } - } - - // alla peggio... - bool bMidOutFake ; - Vector3d vtMidOutFake ; - return GetPtStartOnHomogeousEdges( pCrvCompo, PockParams, TEMP_PROP_CLOSE_EDGE, ptRef, - bMidOutFake, ptStart, vtMidOutFake) ; -} - -//---------------------------------------------------------------------------- -static bool -AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParams& PockParams, - const ISurfFlatRegion* pSfrToWork, bool& bSomeOpen) -{ - // controllo dei parametri - if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0 || - pSfrToWork == nullptr || ! pSfrToWork->IsValid() || pSfrToWork->GetChunkCount() != 1) - return false ; - bSomeOpen = false ; // flag per presenza di lati aperti - int nInd = -1 ; // indice della prima curva che non è "raccordo" di Offset - - // scorro tutte le curve presenti in pCrv ( curva da cui devo entrare) - for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) { - // nProp0 -> #curva il cui Offset ha generato la curva i-esima di pCrv - int nProp0 = 0 ; pCrv->GetCurveTempProp( i, nProp0, 0) ; - // nProp1 -> #loop che contiene la curva espressa in nProp0 - int nProp1 = 0 ; pCrv->GetCurveTempProp( i, nProp1, 1) ; - - // se questa curva non è un "raccordo" di Offset - if ( nProp0 > 0) { - // aggiorno la proprietà della curva da cui devo entrare - int nTempProp = TEMP_PROP_CLOSE_EDGE ; - pSfrToWork->GetCurveTempProp( 0, nProp1, nProp0 - 1, nTempProp, 0) ; - pCrv->SetCurveTempProp( i, nTempProp, 0) ; - // se la curva è aperta, aggiorno il Flag - if ( nTempProp == TEMP_PROP_OPEN_EDGE && ! bSomeOpen) - bSomeOpen = true ; - // salvo l'indice della prima curva trovata che non è un "raccordo" di Offset - if ( nInd == -1) - nInd = i ; - } - // se questa curva è un "raccordo" di Offset - else { - pCrv->SetCurveTempProp( i, TEMP_PROP_SMOOTH, 0) ; - pCrv->SetCurveTempProp( i, TEMP_PROP_SMOOTH, 1) ; - } - } - - // cambio il punto iniziale all'inizio della prima curva che non deriva da un "raccordo" - Point3d ptStart ; - if ( nInd != -1) { - if ( ! pCrv->GetStartPoint( ptStart)) - return false ; - pCrv->ChangeStartPoint( nInd) ; // la prima curva non è un "raccordo" di Offset - } - - // scorro tutte le curve successive alla prima - for ( int i = 1 ; i < pCrv->GetCurveCount() ; ++ i) { - int nTmpProp0, nTmpProp1 ; - // se "raccordo" copio la tempProp precedente - if (( pCrv->GetCurveTempProp( i, nTmpProp0, 0) && nTmpProp0 == TEMP_PROP_SMOOTH) && - ( pCrv->GetCurveTempProp( i, nTmpProp1, 1) && nTmpProp1 == TEMP_PROP_SMOOTH)) - // copio la temp prop della curva precedente - pCrv->SetCurveTempProp( i, pCrv->GetCurve( i-1)->GetTempProp( 0), 0) ; - - } - - // lascio invariato il punto iniziale della curva originaria - if ( nInd != -1) { - double dUNewS ; - pCrv->GetParamAtPoint( ptStart, dUNewS) ; - pCrv->ChangeStartPoint( dUNewS) ; - } - - return true ; -} - -//---------------------------------------------------------------------------- -static bool -SetPtStartForPath( ICurveComposite* pCrvOffs, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, - const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut, - const ICurveComposite* pCrvOrig) -{ - /* - Come prima cosa ricavo i lati aperti equivalenti dal primo Offset; Facendo l'Offset di una curva - chiusa ho all'interno delle temp prop delle sottcurve due informazioni : - // nTmpProp0 -> #curva il cui Offset ha generato la curva i-esima attuale - // nTmpProp1 -> #loop che contiene la curva espressa in nTmpProp0 - - Quindi dal contorno con i lati aperti impostati, posso settare i lati aperti "equivalenti" - anche sulla curva di primo Offset. - NB. Il tool entra dalla curva di primo Offset, non dal bordo della regione da svuotare; quindi - l'entrata va calcolata sul primo Offset, non sulla curva di bordo della FlatRegion di Pocketing. - */ - - // controllo dei parametri - if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || - pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) - return false ; - - // assegno proprietà di OPEN/CLOSE alle sottocurve dell'offset corrente - bool bSomeOpen = false ; - if ( ! AssignOpenCloseTmpPropToFirstOffsCurve( pCrvOffs, PockParams, pSrfToWork, bSomeOpen)) - return false ; - - // punto valido per l'entrata ... - bMidOut = false ; - if ( bSomeOpen) { - // se esistono lati aperti... - if ( pCrvOrig != nullptr && pCrvOrig->IsValid()) { - // ... e non ho un punto di riferimento, lo cerco sulla curva originale - if ( ! ptEndPrec.IsValid()) { - if ( ! GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) - return false ; - } - // ... e ho un punto di riferimento - else { - if ( ! GetPtStartOnOpenEdgeByPtRef( ptEndPrec, PockParams, pCrvOffs, pCrvOrig, ptStart, vtMidOut, bMidOut)) - return false ; - } - } - // se punto non trovato precedentemente, tento con una sottocurva OPEN generica - if ( ! bMidOut) { - if ( ! GetParamOnOpenCurve( pCrvOffs, PockParams, bMidOut, ptStart, vtMidOut)) - return false ; - } - // se queste curve sono troppo corte, analizzo le parti uniformi - if ( ! bMidOut) { - if ( ! GetPtStartOnHomogeousEdges( pCrvOffs, PockParams, TEMP_PROP_OPEN_EDGE, ptEndPrec, - bMidOut, ptStart, vtMidOut)) - return false ; - } - } - // se sottocurve tutte CLOSED o un punto iniziale non valido, lo cerco su un lato generico - if ( ! bMidOut) { - if ( ! ptEndPrec.IsValid()) { - if ( ! GetPtStartOnGenericEdge( pCrvOffs, PockParams, ptStart)) - return false ; - } - else { - if ( ! GetPtStartOnGenericEdgeByPtRef( pCrvOffs, PockParams, ptEndPrec, ptStart)) - return false ; - } - } - - // imposto il punto iniziale scelto - double dPar = 0. ; - if ( ! pCrvOffs->GetParamAtPoint( ptStart, dPar) || ! pCrvOffs->ChangeStartPoint( dPar)) - pCrvOffs->ChangeStartPoint( .5) ; - return true ; -} - -//---------------------------------------------------------------------------- -static bool -SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, - const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, - bool& bMidOut, int& nIndex, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) -{ - // controllo dei parametri - for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) - if ( IsNull( vCrvOffsAct[i]) || ! vCrvOffsAct[i]->IsValid() || vCrvOffsAct[i]->GetCurveCount() == 0) - return false ; - if ( pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) - return false ; - nIndex = 0 ; - - // scorro le curve di primo Offset - // NB. in prima posizione ho il primo Offset del loop esterno, a seguire le isole - // NB. Se non riesco ad entrare in nessuna curva, allora tengo valida quella calcolata per il loop esterno - bool bMidOut_fist = false ; - Vector3d vtMidOut_first ; - Point3d ptStart_first ; - for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) { - // cambio il suo punto d'inizio dell'Offset attuale - if ( SetPtStartForPath( vCrvOffsAct[i], PockParams, pSrfToWork, ptEndPrec, ptStart, vtMidOut, - bMidOut, i < ( int( vCrvOrigChunkLoops.size())) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) - vCrvOffsAct[i]->GetStartPoint( ptStart) ; - else - return false ; - // se ho trovato un'entrata valida da un lato aperto, ho finito - if ( bMidOut) { - nIndex = i ; // salvo l'indice del vettore - return true ; - } - // se sono nel loop esterno e non ho trovato un'entrata da un lato aperto, salvo i risultati ottenuti - else if ( i == 0) { - bMidOut_fist = bMidOut ; - vtMidOut_first = vtMidOut ; - ptStart_first = ptStart ; - } - } - - // in questo caso non ho trovato un'entrata da un lato aperto in nessuna curva ( potrebbero essere tutte chiuse) - bMidOut = bMidOut_fist ; - vtMidOut = vtMidOut_first ; - ptStart = ptStart_first ; - return true ; - -} - -// *************************************************************************** -//---------------------------- CASI OTTIMIZZATI ------------------------------ -// *************************************************************************** - -//---------------------------------------------------------------------------- -static bool -GetOptCrvIndex( const ISurfFlatRegion* pSfrOrig, const ISurfFlatRegion* pSfrChunk, - const PocketParams& PockParams, int nReg, ICRVCOMPOPOVECTOR& vCrvOrig) -{ - - /* - NB. La superficie da lavorare è stata estesa presso i lati aperti; cerco il Chunk - di riferimento sulla superficie originale ed estraggo le sue curve ( in prima posizione - il loop esterno e a seguire le isole); queste curve verranno utilizzate per la scelta - dei casi ottimizzati ( trapezi, circonferenze, ecc ecc..) - */ - - // controllo dei parametri - if ( pSfrOrig == nullptr || ! pSfrOrig->IsValid() || - pSfrChunk == nullptr || ! pSfrChunk->IsValid()) - return false ; - - // se la superficie originale ha un solo Chunk, allora le curve originali sono già trovate - for ( int l = 0 ; l < pSfrOrig->GetLoopCount( 0) ; ++ l) - vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( 0, l))) ; - if ( pSfrOrig->GetChunkCount() == 1) - return true ; - - // vettore di indici dei chunk candidati - INTVECTOR vInds ; - - // scorro tutti i Chunk della superficie orginaria - for ( int c = 0 ; c < int( pSfrOrig->GetChunkCount()) ; ++ c) { - // la classificazione può essere fatta semplicemente guardando il Loop esterno - PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrOrig->GetLoop( c, 0))) ; - if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) - return false ; - // classifico il Chunk attuale con la curva in esame - CRVCVECTOR ccClass ; - if ( pSfrChunk->GetCurveClassification( *pCrvExtLoop, EPS_SMALL, ccClass)) { - // se il Chunk attuale è stato esteso presso presso i lati aperti mi aspetto che esso non sia più - // grande del chunk originale ( se non ci sono lati aperti, allora coincide ) - // se il ccClass non contiene parti classificate come esterne allora il Chunk di riferimento è il c-esimo - bool bIsThis = true ; - for ( int k = 0 ; k < int( ccClass.size()) && bIsThis ; ++ k) { - if ( ccClass[k].nClass == CRVC_OUT) - bIsThis = false ; - } - if ( bIsThis) - vInds.push_back( c) ; - } - } - // se ho un solo indice allora ho già identificato le curve originali - if ( int( vInds.size()) == 1) { - vCrvOrig.clear() ; - for ( int l = 0 ; l < pSfrOrig->GetLoopCount( vInds[0]) ; ++ l) - vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( vInds[0], l))) ; - return true ; - } - // altrimenti... - /* - NB. Come parametro alla funzione è stato passato "nReg"; Facendo il primo Offset del Chunk attuale - questo verrà diviso in n sottoregioni; devo considerare la nReg-esima - Situazione: Estendendo presso i lati aperti, due ( o più) chunk si sono uniti formandone uno unico - Quando effettuo il primo offset ( del diametro del materiale + offset radiale), questo Chunk si splitterà in n Chunk; - Uno ( o più) di questi nuovi chunk potrebbe corrispondere ad un caso ottimizzato. - Devo recuperare il Chunk della superficie originaria ( che non essendo estesa presso i lati aperti - ha la geomtria originale) - */ - - // effettuo un Offset del Chunk per simulare la creazione degli n Chunks - double dOffs = PockParams.dRad + PockParams.dRadialOffset ; - PtrOwner pSfrRefChunk( pSfrChunk->Clone()) ; - if ( IsNull( pSfrRefChunk) || - ! pSfrRefChunk->Offset( - dOffs, ICurve::OFF_FILLET)) - return false ; - - // clono il Chunk nReg-esimo se esiste - pSfrRefChunk.Set( pSfrRefChunk->CloneChunk( nReg)) ; - if ( IsNull( pSfrRefChunk)) - return true ; // bisogna passare al ( pSfrChunk + 1)-esimo se esiste - - // scorro tutti i Chunk della superficie orginaria e ripeto la classificazione - // NB. Questa volta posso fermarmi al primo Chunk classificato come non esterno - for ( int c = 0 ; c < int( pSfrOrig->GetChunkCount()) ; ++ c) { - // come prima recupero il Loop esterno - PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrOrig->GetLoop( c, 0))) ; - if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) - return false ; - // classificazione - CRVCVECTOR ccClass ; - if ( pSfrRefChunk->GetCurveClassification( *pCrvExtLoop, EPS_SMALL, ccClass)) { - bool bIsThis = true ; - for ( int k = 0 ; k < int( ccClass.size()) && bIsThis ; ++ k) { - if ( ccClass[k].nClass == CRVC_OUT) - bIsThis = false ; - } - if ( bIsThis) { - vCrvOrig.clear() ; - for ( int l = 0 ; l < pSfrOrig->GetLoopCount( c) ; ++ l) - vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( c, l))) ; - return true ; // esco - } - } - } - - return true ; // alla peggio non considero casi ottimizzati e svuoto normalmente... - -} - - //---------------------------------------------------------------------------- static bool OptimizedSpiralCirle( const ICurveComposite* pCrvCompo, const double dToll, double& dRad, @@ -3992,6 +3310,834 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double 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()) ; + + // recupero i tratti con proprietà uniformi + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvBorder, PockParam, vpCrvs) ; + if ( vpCrvs.size() > 1) { + // unisco il primo e l'ultimo se estremi compatibili + Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ; + Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ; + if ( AreSamePointApprox( ptS, ptE)) { + vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ; + vpCrvs.erase( vpCrvs.end() - 1) ; + } + } + if ( vpCrvs.empty()) + return false ; + + /* SPIRALE EUCLIDEA + - E' richiesto che la curva di bordo sia una circonferenza tutta OPEN o tutta CLOSED + */ + bool bOkSpiral = ( int( vpCrvs.size()) == 1) ; + if ( bOkSpiral) { + // controllo che sia una circonferenza + Point3d ptCen ; double dRad ; + if ( ! OptimizedSpiralCirle( 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 ( vpCrvs[0]->GetTempProp( 0) == 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 ( vpCrvs[0]->GetTempProp( 0) == 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) + return true ; + } + + 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 ; +} + +// *************************************************************************** +// ------------- SCELTA DEL PUNTO INIZIALE ----------------------------------- +// *************************************************************************** + +//---------------------------------------------------------------------------- +static bool +GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockParams, bool& bOutStart, + Point3d& ptStart, Vector3d& vtOut) +{ + // controllo dei parametri + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + + // verifico se tutti i lati sono aperti + bool bAllOpen = true ; + const ICurve* pMyCrv = pCompo->GetFirstCurve() ; + while ( pMyCrv != nullptr) { + if ( pMyCrv->GetTempProp() != TEMP_PROP_OPEN_EDGE) { + bAllOpen = false ; + break ; + } + pMyCrv = pCompo->GetNextCurve() ; + } + + // richiedo lunghezza superiore a diametro utensile più doppio offset radiale + double dRefLen = ( bAllOpen ? 0. : ( 2 * PockParams.dRad) + 2 * PockParams.dRadialOffset - EPS_SMALL) ; + double dMaxLen = dRefLen ; + // ciclo sulle singole curve + bool bFound = false ; + const ICurve* pPrevCrv = pCompo->GetLastCurve() ; + double dLenPrev = 0. ; + if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) + pPrevCrv->GetLength( dLenPrev) ; + const ICurve* pCrv = pCompo->GetFirstCurve() ; + while ( pCrv != nullptr) { + // analizzo la curva successiva + const ICurve* pNextCrv = pCompo->GetNextCurve() ; + bool bNextOk = ( pNextCrv != nullptr) ; + if ( ! bNextOk) + pNextCrv = pCompo->GetFirstCurve() ; + double dLenNext = 0. ; + if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) + pNextCrv->GetLength( dLenNext) ; + // verifico la curva corrente + if ( pCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { + // contributo dalle entità adiacenti ( se non tutte aperte) + double dLenAgg = 0. ; + if ( ! bAllOpen) { + if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { + Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ; + Vector3d vtStart ; pCrv->GetStartDir( vtStart) ; + dLenAgg += max( 0.4, vtPrevEnd * vtStart) * dLenPrev ; + } + if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) { + Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ; + Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ; + dLenAgg += max( 0.4, vtEnd * vtNextStart) * dLenNext ; + } + } + // entità corrente + double dLen = 0 ; + if ( pCrv->GetLength( dLen)) { + const double LEN_TOL = 1 ; + // se di lunghezza praticamente uguale + if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) { + Point3d ptTest ; + pCrv->GetMidPoint( ptTest) ; + if ( ( PockParams.bAboveHead && ptTest.z > ptStart.z + 100 * EPS_SMALL) || + ( ! PockParams.bAboveHead && ptTest.z < ptStart.z - 100 * EPS_SMALL) || + ( abs( ptTest.z - ptStart.z) < 100 * EPS_SMALL && ptTest.y < ptStart.y - 100 * EPS_SMALL)) { + dMaxLen = max( dMaxLen, dLen + dLenAgg) ; + ptStart = ptTest ; + // versore ortogonale verso l'esterno + pCrv->GetMidDir( vtOut) ; + vtOut.Rotate( Z_AX, 0, -1) ; + } + } + // se più lunga ( o non già trovata) + else if ( dLen + dLenAgg > dMaxLen || ! bFound) { + dMaxLen = dLen + dLenAgg ; + if ( pCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart, &vtOut)) { + // versore ortogonale verso l'esterno + vtOut.Normalize() ; + vtOut.Rotate( Z_AX, 0, -1) ; + bFound = true ; + } + } + dLenPrev = dLen ; + } + } + else + dLenPrev = 0 ; + // vado alla successiva + pPrevCrv = pCrv ; + pCrv = ( bNextOk ? pNextCrv : nullptr) ; + } + + return bFound ; +} + +//---------------------------------------------------------------------------- +static bool +GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, + const ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut, + bool& bMidOut) +{ + // controllo dei parametri + if ( pCrvOrig == nullptr || ! pCrvOrig->IsValid() || + pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + bMidOut = false ; + + // cerco il lato aperto più lungo ( sufficientemente lungo) + double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; + for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { + // escludo le sottocurve chiuse + if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) + continue ; + // recupero la curva i-esima aperta dalla curva originale + const ICurve* pCrvOpen = pCrvOrig->GetCurve( i) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + // ricavo la lunghezza di tale curva + double dLen = 0. ; + pCrvOpen->GetLength( dLen) ; + // se lunghezza accettabile o maggiore della massima trovata + if ( dLen > dLenRef) { + Point3d ptSTmp ; + Vector3d vtMidOutTmp ; + // ricavo il punto medio e il vettore tangente ad esso associato + if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) { + // cerco la sottocurva più vicina a ptSTmp + int nFlag ; + double dMyPar ; + if ( DistPointCurve( ptSTmp, *pCrvCompo).GetParamAtMinDistPoint( 0, dMyPar, nFlag)) { + int nCrv = int( floor( dMyPar)) ; + // recupero tale sottocurva e controllo che anche essa sia OPEN + const ICurve* pMyCrv = pCrvCompo->GetCurve( nCrv) ; + if ( pMyCrv != nullptr && pMyCrv->IsValid() && pMyCrv->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // recupero ptStart + pMyCrv->GetMidPoint( ptStart) ; + // versore d'uscita + vtMidOutTmp.Normalize() ; + vtMidOutTmp.Rotate( Z_AX, - ANG_RIGHT) ; + vtMidOut = vtMidOutTmp ; + // flag per possibile entrata da fuori + bMidOut = true ; + // aggiornamento della lunghezza di riferimento + dLenRef = dLen ; + } + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParams, + const ICurveComposite* pCrvCompo, const ICurveComposite* pCrvOrig, + Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) +{ + // controllo dei parametri + if ( ! ptRef.IsValid() || pCrvCompo == nullptr || ! pCrvCompo->IsValid() || + ! ptRef.IsValid()) + return false ; + bMidOut = false ; + + // lunghezza minima di riferimento per un lato aperto valido + double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; + + // cerco la curva OPEN a minima distanza da ptRef, sufficientemente lunga + int nStartCrv = -1 ; + double dMinDist = INFINITO ; + for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { + // considero solo le sottocurve OPEN + if ( pCrvCompo->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // sufficientemente lunghe + double dLen ; + if ( pCrvCompo->GetCurve( i)->GetLength( dLen) && dLen > dLenRef) { + DistPointCurve DPC( ptRef, *pCrvCompo->GetCurve( i)) ; + double dCurrDist = INFINITO ; + // sufficiententemente vicine a ptRef + if ( DPC.GetSqDist( dCurrDist) && dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nStartCrv = i ; + } + } + } + } + + // se non ho trovato nulla, allora cerco un punto iniziale valido su una sottocurva OPEN + if ( nStartCrv == -1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { + return GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; + } + // se ho trovato la curva più vicina, cerco un punto iniziale valido + else { + const ICurve* pMyCrv = pCrvCompo->GetCurve( nStartCrv) ; + if ( pMyCrv != nullptr && pMyCrv->IsValid()) { + // ricavo ptStart e vettore tangente + if ( pMyCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart, &vtMidOut)) { + // versore ortogonale verso l'esterno + vtMidOut.Normalize() ; + vtMidOut.Rotate( Z_AX, 0, -1) ; + // flag per possibile entrata da fuori + bMidOut = true ; + } + } + } + + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +GetPtStartOnHomogeousEdges( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, + int nType, const Point3d& ptRef, bool& bMidOut, Point3d& ptStart, + Vector3d& vtMidOut) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + bMidOut = false ; + + // analizzo i sottotratti omogenei + ICRVCOMPOPOVECTOR vpCrvs ; + PtrOwner pCrvCompoClone( CloneCurveComposite( pCrvCompo)) ; + if ( IsNull( pCrvCompoClone) || ! pCrvCompoClone->IsValid()) + return false ; + GetHomogeneousParts( pCrvCompoClone, PockParams, vpCrvs) ; + + // se ho un solo tratto omogeneo e coerente al tipo scelto ... + if ( int( vpCrvs.size()) == 1 && vpCrvs[0]->GetTempProp( 0) == nType) { + // ... e non ho un punto di riferimento valido + if ( ! ptRef.IsValid()) { + // il punto iniziale è già definito + pCrvCompoClone->GetStartPoint( ptStart) ; + } + // ho un punto di riferimento valido + else { + // cerco il punto più vicino + DistPointCurve DistPtCrv( ptRef, *pCrvCompoClone) ; + int nFlag ; + if ( ! DistPtCrv.GetMinDistPoint( 0, ptStart, nFlag)) + return false ; + } + bMidOut = ( nType == TEMP_PROP_OPEN_EDGE) ; + return true ; + } + + // scorro i tratti omogenei e cerco il tratto del tipo definito più lungo + int nMaxInd = -1 ; + double dMaxLen = 0. ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + // considero solo i tratti aperti + if ( vpCrvs[i]->GetTempProp( 0) == nType) { + // calcolo la lunghezza del tratto aperto + double dLen ; + vpCrvs[i]->GetLength( dLen) ; + if ( dLen > dMaxLen) { + dMaxLen = dLen ; + nMaxInd = i ; + } + } + } + + // recupero il tratto del tipo definito più lungo + if ( nMaxInd != -1) { + // recupero il parametro alla sua metà + double dParIn ; + vpCrvs[nMaxInd]->GetParamAtLength( 0.5 * dMaxLen, dParIn) ; + // se tratto OPEN + if ( nType == TEMP_PROP_OPEN_EDGE) { + bMidOut = true ; + vpCrvs[nMaxInd]->GetPointD1D2( dParIn, ICurve::FROM_MINUS, ptStart, &vtMidOut) ; + vtMidOut.Normalize() ; + vtMidOut.Rotate( Z_AX, 0, -1) ; + } + // se tratto CLOSED + else + vpCrvs[nMaxInd]->GetPointD1D2( dParIn, ICurve::FROM_MINUS, ptStart) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetPtStartOnGenericEdge( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, + Point3d& ptStart) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + pCrvCompo->GetStartPoint( ptStart) ; + + // scorro tutte le curve + double dLenRef = 0. ; + bool bAllShort = true ; // flag per curve tutte piccole + for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { + // ricavo la curva i-esima dalla curva originale + const ICurve* pMyCrv = pCrvCompo->GetCurve( i) ; + if ( pMyCrv == nullptr || ! pMyCrv->IsValid()) + return false ; + // ricavo la lunghezza di tale curva + double dLen = 0. ; + pMyCrv->GetLength( dLen) ; + // se lunghezza accettabile o maggiore della massima trovata, ricavo ptStart + if ( dLen > dLenRef) { + if ( pMyCrv->GetMidPoint( ptStart)) { + dLenRef = dLen ; + bAllShort = false ; + } + } + } + + // se curve tutte piccole + if ( bAllShort) { + bool bMidOutFake ; + Vector3d vtMidOutFake ; + if ( ! GetPtStartOnHomogeousEdges( pCrvCompo, PockParams, TEMP_PROP_CLOSE_EDGE, P_INVALID, + bMidOutFake, ptStart, vtMidOutFake)) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +GetPtStartOnGenericEdgeByPtRef( const ICurveComposite* pCrvCompo, const PocketParams& PockParams, + const Point3d& ptRef, Point3d& ptStart) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0 || + ! ptRef.IsValid()) + return false ; + + // ordino le curve di pCrvCompo in base alla vicinanza da ptRef + // + vector> vCrvInfoDist ; vCrvInfoDist.resize( pCrvCompo->GetCurveCount()) ; + // scorro le curve di pCrvCompo + for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { + vCrvInfoDist[i].first = i ; + // calcolo la distanza tra la curva i-esima e ptRef + double dDist = INFINITO ; + DistPointCurve DistPtCrv( ptRef, *pCrvCompo->GetCurve( i)) ; + DistPtCrv.GetSqDist( dDist) ; + vCrvInfoDist[i].second = dDist ; + } + // ordino il vettore in base alla distanza + sort( vCrvInfoDist.begin(), vCrvInfoDist.end(), [] ( const pair& a, const pair& b) { + return a.second < b.second ; + }) ; + + // cerco un parametro iniziale valido per le sottocurve ordinate + double dLenRef = 2 * PockParams.dRad + 2 * PockParams.dRadialOffset ; + for ( int i = 0 ; i < int( vCrvInfoDist.size()) ; ++ i) { + // recupero la curva i-esima + const ICurve* pMyCrv = pCrvCompo->GetCurve( vCrvInfoDist[i].first) ; + if ( pMyCrv != nullptr && pMyCrv->IsValid()) { + // controllo che sia abbastanza lunga e aggiorno ptStart + double dLen = 0. ; + pMyCrv->GetLength( dLen) ; + if ( dLen > dLenRef) { + if ( pMyCrv->GetPointD1D2( .5, ICurve::FROM_MINUS, ptStart)) + return true ; + } + } + } + + // alla peggio... + bool bMidOutFake ; + Vector3d vtMidOutFake ; + return GetPtStartOnHomogeousEdges( pCrvCompo, PockParams, TEMP_PROP_CLOSE_EDGE, ptRef, + bMidOutFake, ptStart, vtMidOutFake) ; +} + +//---------------------------------------------------------------------------- +static bool +AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParams& PockParams, + const ISurfFlatRegion* pSfrToWork, bool& bSomeOpen) +{ + // controllo dei parametri + if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0 || + pSfrToWork == nullptr || ! pSfrToWork->IsValid() || pSfrToWork->GetChunkCount() != 1) + return false ; + bSomeOpen = false ; // flag per presenza di lati aperti + int nInd = -1 ; // indice della prima curva che non è "raccordo" di Offset + + // scorro tutte le curve presenti in pCrv ( curva da cui devo entrare) + for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) { + // nProp0 -> #curva il cui Offset ha generato la curva i-esima di pCrv + int nProp0 = 0 ; pCrv->GetCurveTempProp( i, nProp0, 0) ; + // nProp1 -> #loop che contiene la curva espressa in nProp0 + int nProp1 = 0 ; pCrv->GetCurveTempProp( i, nProp1, 1) ; + + // se questa curva non è un "raccordo" di Offset + if ( nProp0 > 0) { + // aggiorno la proprietà della curva da cui devo entrare + int nTempProp = TEMP_PROP_CLOSE_EDGE ; + pSfrToWork->GetCurveTempProp( 0, nProp1, nProp0 - 1, nTempProp, 0) ; + pCrv->SetCurveTempProp( i, nTempProp, 0) ; + // se la curva è aperta, aggiorno il Flag + if ( nTempProp == TEMP_PROP_OPEN_EDGE && ! bSomeOpen) + bSomeOpen = true ; + // salvo l'indice della prima curva trovata che non è un "raccordo" di Offset + if ( nInd == -1) + nInd = i ; + } + // se questa curva è un "raccordo" di Offset + else { + pCrv->SetCurveTempProp( i, TEMP_PROP_SMOOTH, 0) ; + pCrv->SetCurveTempProp( i, TEMP_PROP_SMOOTH, 1) ; + } + } + + // cambio il punto iniziale all'inizio della prima curva che non deriva da un "raccordo" + Point3d ptStart ; + if ( nInd != -1) { + if ( ! pCrv->GetStartPoint( ptStart)) + return false ; + pCrv->ChangeStartPoint( nInd) ; // la prima curva non è un "raccordo" di Offset + } + + // scorro tutte le curve successive alla prima + for ( int i = 1 ; i < pCrv->GetCurveCount() ; ++ i) { + int nTmpProp0, nTmpProp1 ; + // se "raccordo" copio la tempProp precedente + if (( pCrv->GetCurveTempProp( i, nTmpProp0, 0) && nTmpProp0 == TEMP_PROP_SMOOTH) && + ( pCrv->GetCurveTempProp( i, nTmpProp1, 1) && nTmpProp1 == TEMP_PROP_SMOOTH)) + // copio la temp prop della curva precedente + pCrv->SetCurveTempProp( i, pCrv->GetCurve( i-1)->GetTempProp( 0), 0) ; + + } + + // lascio invariato il punto iniziale della curva originaria + if ( nInd != -1) { + double dUNewS ; + pCrv->GetParamAtPoint( ptStart, dUNewS) ; + pCrv->ChangeStartPoint( dUNewS) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +SetPtStartForPath( ICurveComposite* pCrvOffs, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, + const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut, + const ICurveComposite* pCrvOrig) +{ + /* + Come prima cosa ricavo i lati aperti equivalenti dal primo Offset; Facendo l'Offset di una curva + chiusa ho all'interno delle temp prop delle sottcurve due informazioni : + // nTmpProp0 -> #curva il cui Offset ha generato la curva i-esima attuale + // nTmpProp1 -> #loop che contiene la curva espressa in nTmpProp0 + + Quindi dal contorno con i lati aperti impostati, posso settare i lati aperti "equivalenti" + anche sulla curva di primo Offset. + NB. Il tool entra dalla curva di primo Offset, non dal bordo della regione da svuotare; quindi + l'entrata va calcolata sul primo Offset, non sulla curva di bordo della FlatRegion di Pocketing. + */ + + // controllo dei parametri + if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || + pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) + return false ; + + // assegno proprietà di OPEN/CLOSE alle sottocurve dell'offset corrente + bool bSomeOpen = false ; + if ( ! AssignOpenCloseTmpPropToFirstOffsCurve( pCrvOffs, PockParams, pSrfToWork, bSomeOpen)) + return false ; + + // punto valido per l'entrata ... + bMidOut = false ; + if ( bSomeOpen) { + // se esistono lati aperti... + if ( pCrvOrig != nullptr && pCrvOrig->IsValid()) { + // ... e non ho un punto di riferimento, lo cerco sulla curva originale + if ( ! ptEndPrec.IsValid()) { + if ( ! GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) + return false ; + } + // ... e ho un punto di riferimento + else { + if ( ! GetPtStartOnOpenEdgeByPtRef( ptEndPrec, PockParams, pCrvOffs, pCrvOrig, ptStart, vtMidOut, bMidOut)) + return false ; + } + } + // se punto non trovato precedentemente, tento con una sottocurva OPEN generica + if ( ! bMidOut) { + if ( ! GetParamOnOpenCurve( pCrvOffs, PockParams, bMidOut, ptStart, vtMidOut)) + return false ; + } + // se queste curve sono troppo corte, analizzo le parti uniformi + if ( ! bMidOut) { + if ( ! GetPtStartOnHomogeousEdges( pCrvOffs, PockParams, TEMP_PROP_OPEN_EDGE, ptEndPrec, + bMidOut, ptStart, vtMidOut)) + return false ; + } + } + // se sottocurve tutte CLOSED o un punto iniziale non valido, lo cerco su un lato generico + if ( ! bMidOut) { + if ( ! ptEndPrec.IsValid()) { + if ( ! GetPtStartOnGenericEdge( pCrvOffs, PockParams, ptStart)) + return false ; + } + else { + if ( ! GetPtStartOnGenericEdgeByPtRef( pCrvOffs, PockParams, ptEndPrec, ptStart)) + return false ; + } + } + + // imposto il punto iniziale scelto + double dPar = 0. ; + if ( ! pCrvOffs->GetParamAtPoint( ptStart, dPar) || ! pCrvOffs->ChangeStartPoint( dPar)) + pCrvOffs->ChangeStartPoint( .5) ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, + const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, + bool& bMidOut, int& nIndex, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) +{ + // controllo dei parametri + for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) + if ( IsNull( vCrvOffsAct[i]) || ! vCrvOffsAct[i]->IsValid() || vCrvOffsAct[i]->GetCurveCount() == 0) + return false ; + if ( pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) + return false ; + nIndex = 0 ; + + // scorro le curve di primo Offset + // NB. in prima posizione ho il primo Offset del loop esterno, a seguire le isole + // NB. Se non riesco ad entrare in nessuna curva, allora tengo valida quella calcolata per il loop esterno + bool bMidOut_fist = false ; + Vector3d vtMidOut_first ; + Point3d ptStart_first ; + for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) { + // cambio il suo punto d'inizio dell'Offset attuale + if ( SetPtStartForPath( vCrvOffsAct[i], PockParams, pSrfToWork, ptEndPrec, ptStart, vtMidOut, + bMidOut, i < ( int( vCrvOrigChunkLoops.size())) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) + vCrvOffsAct[i]->GetStartPoint( ptStart) ; + else + return false ; + // se ho trovato un'entrata valida da un lato aperto, ho finito + if ( bMidOut) { + nIndex = i ; // salvo l'indice del vettore + return true ; + } + // se sono nel loop esterno e non ho trovato un'entrata da un lato aperto, salvo i risultati ottenuti + else if ( i == 0) { + bMidOut_fist = bMidOut ; + vtMidOut_first = vtMidOut ; + ptStart_first = ptStart ; + } + } + + // in questo caso non ho trovato un'entrata da un lato aperto in nessuna curva ( potrebbero essere tutte chiuse) + bMidOut = bMidOut_fist ; + vtMidOut = vtMidOut_first ; + ptStart = ptStart_first ; + return true ; + +} + +// *************************************************************************** +//---------------------------- CASI OTTIMIZZATI ------------------------------ +// *************************************************************************** + +//---------------------------------------------------------------------------- +static bool +GetOptCrvIndex( const ISurfFlatRegion* pSfrOrig, const ISurfFlatRegion* pSfrChunk, + const PocketParams& PockParams, int nReg, ICRVCOMPOPOVECTOR& vCrvOrig) +{ + + /* + NB. La superficie da lavorare è stata estesa presso i lati aperti; cerco il Chunk + di riferimento sulla superficie originale ed estraggo le sue curve ( in prima posizione + il loop esterno e a seguire le isole); queste curve verranno utilizzate per la scelta + dei casi ottimizzati ( trapezi, circonferenze, ecc ecc..) + */ + + // controllo dei parametri + if ( pSfrOrig == nullptr || ! pSfrOrig->IsValid() || + pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + + // se la superficie originale ha un solo Chunk, allora le curve originali sono già trovate + for ( int l = 0 ; l < pSfrOrig->GetLoopCount( 0) ; ++ l) + vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( 0, l))) ; + if ( pSfrOrig->GetChunkCount() == 1) + return true ; + + // vettore di indici dei chunk candidati + INTVECTOR vInds ; + + // scorro tutti i Chunk della superficie orginaria + for ( int c = 0 ; c < int( pSfrOrig->GetChunkCount()) ; ++ c) { + // la classificazione può essere fatta semplicemente guardando il Loop esterno + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrOrig->GetLoop( c, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) + return false ; + // classifico il Chunk attuale con la curva in esame + CRVCVECTOR ccClass ; + if ( pSfrChunk->GetCurveClassification( *pCrvExtLoop, EPS_SMALL, ccClass)) { + // se il Chunk attuale è stato esteso presso presso i lati aperti mi aspetto che esso non sia più + // grande del chunk originale ( se non ci sono lati aperti, allora coincide ) + // se il ccClass non contiene parti classificate come esterne allora il Chunk di riferimento è il c-esimo + bool bIsThis = true ; + for ( int k = 0 ; k < int( ccClass.size()) && bIsThis ; ++ k) { + if ( ccClass[k].nClass == CRVC_OUT) + bIsThis = false ; + } + if ( bIsThis) + vInds.push_back( c) ; + } + } + // se ho un solo indice allora ho già identificato le curve originali + if ( int( vInds.size()) == 1) { + vCrvOrig.clear() ; + for ( int l = 0 ; l < pSfrOrig->GetLoopCount( vInds[0]) ; ++ l) + vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( vInds[0], l))) ; + return true ; + } + // altrimenti... + /* + NB. Come parametro alla funzione è stato passato "nReg"; Facendo il primo Offset del Chunk attuale + questo verrà diviso in n sottoregioni; devo considerare la nReg-esima + Situazione: Estendendo presso i lati aperti, due ( o più) chunk si sono uniti formandone uno unico + Quando effettuo il primo offset ( del diametro del materiale + offset radiale), questo Chunk si splitterà in n Chunk; + Uno ( o più) di questi nuovi chunk potrebbe corrispondere ad un caso ottimizzato. + Devo recuperare il Chunk della superficie originaria ( che non essendo estesa presso i lati aperti + ha la geomtria originale) + */ + + // effettuo un Offset del Chunk per simulare la creazione degli n Chunks + double dOffs = PockParams.dRad + PockParams.dRadialOffset ; + PtrOwner pSfrRefChunk( pSfrChunk->Clone()) ; + if ( IsNull( pSfrRefChunk) || + ! pSfrRefChunk->Offset( - dOffs, ICurve::OFF_FILLET)) + return false ; + + // clono il Chunk nReg-esimo se esiste + pSfrRefChunk.Set( pSfrRefChunk->CloneChunk( nReg)) ; + if ( IsNull( pSfrRefChunk)) + return true ; // bisogna passare al ( pSfrChunk + 1)-esimo se esiste + + // scorro tutti i Chunk della superficie orginaria e ripeto la classificazione + // NB. Questa volta posso fermarmi al primo Chunk classificato come non esterno + for ( int c = 0 ; c < int( pSfrOrig->GetChunkCount()) ; ++ c) { + // come prima recupero il Loop esterno + PtrOwner pCrvExtLoop( ConvertCurveToComposite( pSfrOrig->GetLoop( c, 0))) ; + if ( IsNull( pCrvExtLoop) || ! pCrvExtLoop->IsValid()) + return false ; + // classificazione + CRVCVECTOR ccClass ; + if ( pSfrRefChunk->GetCurveClassification( *pCrvExtLoop, EPS_SMALL, ccClass)) { + bool bIsThis = true ; + for ( int k = 0 ; k < int( ccClass.size()) && bIsThis ; ++ k) { + if ( ccClass[k].nClass == CRVC_OUT) + bIsThis = false ; + } + if ( bIsThis) { + vCrvOrig.clear() ; + for ( int l = 0 ; l < pSfrOrig->GetLoopCount( c) ; ++ l) + vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( c, l))) ; + return true ; // esco + } + } + } + + return true ; // alla peggio non considero casi ottimizzati e svuoto normalmente... + +} + //---------------------------------------------------------------------------- static bool ModifyCurveToSmoothed( ICurveComposite* pCrv, const PocketParams& PockParams, double dRightLen, double dLeftLen, bool bAsParam) @@ -5297,69 +5443,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 ; @@ -6652,11 +6735,9 @@ GetSfrByOpenEdgeExtension( const ISurfFlatRegion* pSfrOrig, PocketParams& PockPa PockParams.nOffsType = nOffsType ; // estensine presso i lati aperti - ICRVCOMPOPOVECTOR vCrvEmpty ; - bool bSkipPocket ; pSfrExtended->CopyFrom( pSfrOrig) ; if ( pSfrExtended == nullptr || ! pSfrExtended->IsValid() || - ! ModifySurfByOpenEdges( pSfrExtended, PockParams, false, vCrvEmpty, bSkipPocket)) + ! ModifySurfByOpenEdges( pSfrExtended, PockParams)) return false ; // riporto i parametri originari @@ -8043,7 +8124,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 ; @@ -8053,52 +8134,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, true, 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 ; + + // ------------ 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 ; + + // ------------ 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 ; + + // ------------ 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 : case POCKET_CONFORMAL_ONEWAY : - if ( ! AddConformal( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + 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 ; }