diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 6a4b1d3..13f3896 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -752,194 +752,6 @@ IsSfrAllClosed( const ISurfFlatRegion* pSfr, bool& bAllClose) return true ; } -//---------------------------------------------------------------------------- -static bool -GetCoeffLinArc( const ICurveArc* pArc, double dDiam, double& dSubArc) -{ - - // controllo parametri - if ( pArc == nullptr || ! pArc->IsValid()) - return false ; - - // recupero il punto medio - Point3d ptMid ; - if ( ! pArc->GetMidPoint( ptMid)) - return false ; - - // creo l'ombra del tool nel punto medio - PtrOwner pCrvTool( CreateCurveArc()) ; - pCrvTool->Set( ptMid, Z_AX, dDiam / 2) ; - if ( ! pCrvTool->IsValid()) - return false ; - - // effettuo la classificazione - IntersCurveCurve intCC( *pArc, *pCrvTool) ; - CRVCVECTOR ccClass ; - if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) && int( ccClass.size()) == 3 && - ccClass[1].nClass == CRVC_IN) { - // recupero i due punti di intersezione - Point3d ptS, ptE ; - pCrvTool->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ; - pCrvTool->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_PLUS, ptE) ; - // vettori uscenti dal centro dell'arco e diretti verso i punti di intersezione - Vector3d vtS = ptS - pArc->GetCenter() ; - Vector3d vtE = ptE - pArc->GetCenter() ; - // angolo tra i due vettori - double dTheta ; - vtS.GetAngle( vtE, dTheta) ; - dTheta = abs( dTheta) ; - // lunghezza del tratto di arco compreso - dSubArc = pArc->GetRadius() * DEGTORAD * dTheta ; - } - else - return false ; - - return true ; - -} - -//---------------------------------------------------------------------------- -static bool -GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCompo, - const ICRVCOMPOPOVECTOR& vOtherCrv, const PocketParams& PockParams, double& dPar) -{ - - // ==================== INFO ================================================================ - // pCrvCheck -> sottocurva di pCrvCompo su cui cercare il parametro ideale per ingresso - // vOtherCrv -> tutte le altre curve che non devono essere intersecate durante l'ingresso - // ( questo vettore è stato riempito con tutti loop della superificie da - // lavorare, i quali Offset non hanno generato alcuna curva di pCrvCheck ) - // ========================================================================================== - - // controllo dei parametri - if ( pCrvCheck == nullptr || ! pCrvCheck->IsValid() || - pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) - return false ; - - // clono le curve - PtrOwner pCrv( pCrvCheck->Clone()) ; - PtrOwner pCompo( pCrvCompo->Clone()) ; - if ( IsNull( pCrv) || IsNull( pCompo)) - return false ; - ICRVCOMPOPOVECTOR vCrvNoInters ; - for ( int i = 0 ; i < int( vOtherCrv.size()) ; ++ i) - vCrvNoInters.emplace_back( ConvertCurveToComposite( vOtherCrv[i]->Clone())) ; - - // ricavo l'estrusione della curva composita - Vector3d vtExtr ; - if ( ! pCompo->GetExtrusion( vtExtr)) - vtExtr = Z_AX ; - // ricavo il centroide o il punto iniziale della curva composita - Point3d ptCen ; - if ( ! pCompo->GetCentroid( ptCen)) - if ( ! pCompo->GetStartPoint( ptCen)) - return false ; - - // creo un frame locale per creare l'ombra del tool e intersecarla con la curva - Frame3d frLoc ; - frLoc.Set( ptCen, vtExtr) ; - - // porto le curve in questo sistema di riferimento - pCrv->ToLoc( frLoc) ; - pCompo->ToLoc( frLoc) ; - for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++i) - vCrvNoInters[i]->ToLoc( frLoc) ; - - // fisso il diametro del tool ( più grande per sicurezza ) - double dDiam = ( 2 * PockParams.dRad ) + 2 * PockParams.dRadialOffset ; - double dLen ; - if ( ! pCrv->GetLength( dLen)) - return false ; - double dSubArc = -1 ; - if ( pCrv->GetType() == CRV_ARC) - GetCoeffLinArc( GetCurveArc( pCrv), dDiam, dSubArc) ; - - double dDiv = dSubArc < 0 ? dDiam : dSubArc ; - double dMaxInt = floor( dLen / dDiv) ; - - int nDen = 2 ; // intervalli in cui suddivido la curva - dMaxInt = max( 2.0, dMaxInt) ; // così se entra una volta controllo sempre dParT = 0.5 - - while ( nDen < dMaxInt + EPS_SMALL) { // EPS_SMALL per comprendere l'uguaglianza - - for ( int i = 1 ; i < nDen ; ++i) { - - if ( int( i % nDen) == 0) - continue ; - - double dNum = 1.0 * i ; - double dParT = dNum / nDen ; - Point3d ptTest ; - Vector3d vtPerpIn ; - - if ( pCrv->GetPointD1D2( dParT, ICurve::FROM_PLUS, ptTest, &vtPerpIn)) { - - PtrOwner pCompoClone( pCompo->Clone()) ; - if ( IsNull( pCompoClone)) - return false ; - double dU ; - pCompoClone->GetParamAtPoint( ptTest, dU) ; - pCompoClone->ChangeStartPoint( dU) ; - - // se chiuso - if ( pCrv->GetTempProp() == 0) { - // se la curva è chiusa sposto il centro verso l'interno. - // Devo essere sicuro di essere su una curva di Offset interno, altrimenti potrebbe essere valido - // il punto trovato, però facendo poi il primo offeset tale punto potrebbe diventare un punto - // di convergenza tra più chunks... - vtPerpIn.Normalize() ; - vtPerpIn.Rotate( Z_AX, 0, 1) ; // cos( pi/2) = 0, sin( pi/2) = 1 - vtPerpIn *= (( PockParams.dRad + PockParams.dRadialOffset - 50 * EPS_SMALL)) ; - ptTest = ptTest + vtPerpIn ; - - // creo una circonferenza ( ombra del tool ) centrata su ptTest - PtrOwner pCrvToolShape( CreateCurveArc()) ; - pCrvToolShape->Set( ptTest, Z_AX, 0.5 * dDiam) ; - if ( ! pCrvToolShape->IsValid()) - return false ; - - // interseco la curva composita con l'ombra del tool - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCompoClone, *pCrvToolShape) ; - - if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { - // se ho solo due intersezioni, controllo di non intersecare isole ( In-Out-In) - if ( int( ccClass.size() == 3)) { - bool bOk = true ; - for ( int j = 0 ; j < ( int)vCrvNoInters.size() && bOk ; ++ j) { - - IntersCurveCurve intCCI( *vCrvNoInters[j], *pCrvToolShape) ; - if ( intCCI.GetCurveClassification( 0, EPS_SMALL, ccClass)) { - - if (( int)ccClass.size() > 1) - bOk = false ; - } - else - return false ; - } - if ( bOk) { - dPar = dParT ; - return true ; - } - } - } - else - return false ; - } - // se aperto - else { - dPar = dParT ; - return true ; - } - } - } - - ++nDen ; - } - - return false ; -} - //---------------------------------------------------------------------------- static bool ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams, @@ -975,176 +787,77 @@ ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketPa Vector3d vtRotOut = vtFirstOut ; double dMinDist = PockParams.dRad + PockParams.dRadialOffset ; for ( int i = 0 ; i < 4 ; ++ i) { - // calcolo il punto di caduta dell'utensile - Point3d ptFall = pt + vtRotOut * ( PockParams.dRad + PockParams.dOpenMinSafe) ; - // controllo che sia sufficientemente distante dalla superficie limite - bool bInside = true ; - bool bOkOut = true ; - if ( PockParams.SfrLimit.IsValid()) - bOkOut = ( IsPointInsideSurfFr( ptFall, &PockParams.SfrLimit, dMinDist, bInside) && ! bInside) ; - if ( bOkOut) - bOkOut = ( IsPointInsideSurfFr( ptFall, pSfr, dMinDist, bInside) && ! bInside) ; - if ( bOkOut) { - // aggiungo al ritorno l'uscita - pCompo->AddLine( ptFall, bEndOrStart) ; - pCompo->SetCurveTempProp( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0), TEMP_PROP_OUT_START, 0) ; - pCompo->SetCurveTempParam( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0), - ( bEndOrStart ? GetMaxFeed( PockParams) : GetMinFeed( PockParams)), 0) ; - bOkExtended = true ; - return true ; + // evito il 180deg + if ( i != 2) { + // calcolo il punto di caduta dell'utensile + Point3d ptFall = pt + vtRotOut * ( PockParams.dRad + PockParams.dOpenMinSafe) ; + // controllo che sia sufficientemente distante dalla superficie limite + bool bInside = true ; + bool bOkOut = true ; + if ( PockParams.SfrLimit.IsValid()) + bOkOut = ( IsPointInsideSurfFr( ptFall, &PockParams.SfrLimit, dMinDist, bInside) && ! bInside) ; + if ( bOkOut) + bOkOut = ( IsPointInsideSurfFr( ptFall, pSfr, dMinDist, bInside) && ! bInside) ; + if ( bOkOut) { + // aggiungo al ritorno l'uscita + pCompo->AddLine( ptFall, bEndOrStart) ; + pCompo->SetCurveTempProp( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0), TEMP_PROP_OUT_START, 0) ; + pCompo->SetCurveTempParam( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0), + ( bEndOrStart ? GetMaxFeed( PockParams) : GetMinFeed( PockParams)), 0) ; + bOkExtended = true ; + return true ; + } } vtRotOut.Rotate( Z_AX, - ANG_RIGHT) ; } + return true ; } //---------------------------------------------------------------------------- static bool -AdjustContourStart( ICurveComposite* pCompo, const PocketParams& PockParams, const ICRVCOMPOPOVECTOR& vCrvIsl, - bool bOrder, Point3d ptRef) +AdjustContourStart( ICurveComposite* pCompo, const PocketParams& PockParams) { - // se cerco semplicemente il tratto lineare chiuso più lungo ... - if ( ! bOrder) { - // la priorità è essagnata ai tratti lineari chiusi - int i = 0 ; // <--- indice della curva corrente - int nMax = - 1 ; - double dLenMax = 0 ; - const ICurve* pCrv = pCompo->GetFirstCurve() ; + // controllo dei parametri + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + + // cerco il tratto lineare chiuso più lungo ... + int i = 0 ; // <--- indice della curva corrente + int nMax = - 1 ; + double dLenMax = 0 ; + const ICurve* pCrv = pCompo->GetFirstCurve() ; + while ( pCrv != nullptr) { + double dLen ; + if ( pCrv->GetType() == CRV_LINE && pCrv->GetTempProp() == TEMP_PROP_CLOSE_EDGE && + pCrv->GetLength( dLen) && dLen > dLenMax) { + dLenMax = dLen ; + nMax = i ; + } + ++ i ; + pCrv = pCompo->GetNextCurve() ; + } + // se non trovato o troppo corto, cerco il tratto chiuso più lungo in generale ( non lineare) + if ( nMax < 0 || dLenMax < 2. * PockParams.dRad + 2 * PockParams.dRadialOffset) { + i = 0 ; + pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { double dLen ; - if ( pCrv->GetType() == CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { + if ( pCrv->GetType() != CRV_LINE && pCrv->GetTempProp() == TEMP_PROP_CLOSE_EDGE && + pCrv->GetLength( dLen) && dLen > dLenMax) { dLenMax = dLen ; nMax = i ; } ++ i ; pCrv = pCompo->GetNextCurve() ; } - // se non trovato o troppo corto, cerco il tratto chiuso più lungo in generale - if ( nMax < 0 || dLenMax < 2 * ( 2 * PockParams.dRad)) { - i = 0 ; - pCrv = pCompo->GetFirstCurve() ; - while ( pCrv != nullptr) { - double dLen ; - if ( pCrv->GetType() != CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { - dLenMax = dLen ; - nMax = i ; - } - ++ i ; - pCrv = pCompo->GetNextCurve() ; - } - } - // controllo che il tratto chiuso più lungo trovato sia sufficientemente lungo - if ( dLenMax < 10 * EPS_SMALL) { - // se troppo piccolo allora lo imposto aperto - pCompo->SetCurveTempProp( nMax, 0, 1) ; - // spezzo la curva nel primo tratto aperto sufficientemente lungo - for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { - double dLen ; pCompo->GetCurve( u)->GetLength( dLen) ; - if ( dLen > 10 * EPS_SMALL) { - nMax = u ; - continue ; - } - } - } - - // se non trovato, imposto il punto iniziale a mentà del primo tratto - if ( nMax == -1) { - pCompo->ChangeStartPoint( 0.5) ; - return true ; - } - pCompo->ChangeStartPoint( nMax + 0.5) ; } - // se invece sto cercando di entrare da un lato chiuso per una svuotatura, allora riordino i lati - // chiusi a seconda della lunghezza, e a partire dal più lungo cerco un parametro su tale curva che mi consenta - // un'entrata sufficientemente distante da isole e da altre curve della curva stessa su cui cerco l'entrata ... - else { - - // se ho un punto di riferimento, allora come prima cosa controllo il lato chiuso più vicino - if ( ptRef.IsValid()) { - double dMinDist = INFINITO ; - int nIndCrvMinDist = - 1 ; - for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { - DistPointCurve DPC( ptRef, *pCompo->GetCurve( u)) ; - double dCurrDist = INFINITO ; - if ( DPC.GetDist( dCurrDist) && dCurrDist < dMinDist) { - nIndCrvMinDist = u ; - dMinDist = dCurrDist ; - } - } - // se avessi curve alla stessa distanza ( circa) non controllo le altre, mi accontento della - // prima curva trovata - if ( nIndCrvMinDist != -1) { - // controllo che il lato chiuso sia sufficientemente lungo - double dLen = 0. ; - pCompo->GetCurve( nIndCrvMinDist)->GetLength( dLen) ; - if ( dLen > 2 * PockParams.dRad + 2 * PockParams.dRadialOffset + 500 * EPS_SMALL) { - pCompo->ChangeStartPoint( nIndCrvMinDist + 0.5) ; - return true ; - } - } - } - - // creo un vettore di indici che definisce l'ordine delle curve chiuse in base alla lunghezza - INTVECTOR vInd ; vInd.reserve( pCompo->GetCurveCount()) ; - - // vettore di indici già utilizzati - INTVECTOR vIndUsed ; vIndUsed.reserve( pCompo->GetCurveCount()) ; - - double dMaxLen = -INFINITO ; - int nCurrInd = 0 ; - bool bStop = false ; - - for ( int c = 0 ; c < pCompo->GetCurveCount() && ! bStop ; ++ c) { - bStop = true ; - for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { - - int nProp_i ; - // se la curva i-esima non è già stata considerata ed è chiusa... - if ( find( vIndUsed.begin(), vIndUsed.end(), i) == vIndUsed.end() && - pCompo->GetCurveTempProp( i, nProp_i, 0) && nProp_i == 0) { - - // creo la curva i-esima - const ICurve* pCrv_i( pCompo->GetCurve( i)) ; - double dLen_i ; - - if ( pCrv_i->GetLength( dLen_i) && dLen_i > dMaxLen) { // se di lunghezza maggiore alla soglia... - dMaxLen = dLen_i ; - nCurrInd = i ; - bStop = false ; - } - } - } - vIndUsed.push_back( nCurrInd) ; - vInd.push_back( nCurrInd) ; - dMaxLen = -INFINITO ; - } - - if ( vInd.empty()) { - // se questa condizione fosse vera allora non sono riuscito ad entrare da nessun lato aperto in precedenza e non - // ho nemmeno un lato chiuso disponibile per entrare... ( forzo l'entrata a metà del primo lato) - pCompo->ChangeStartPoint( 0.5) ; - return true ; - } - - // ora che ho riempito il vettore di indici lo scorro e cerco di entrare in questi lati chiusi secondo l'ordine - bool bOk = false ; - for ( int i = 0 ; i < int( vInd.size()) && !bOk ; ++ i) { - const ICurve* pCrv( pCompo->GetCurve( vInd[i])) ; - double dPar ; - if ( GetParamForPtStartOnEdge( pCrv, pCompo, vCrvIsl, PockParams, dPar)) { - pCompo->ChangeStartPoint( vInd[i] + dPar) ; - bOk = true ; - } - } - - if ( ! bOk) { - // se non riesco ad entrare da nessun lato chiuso, considerando che in precedenza ho già provato ad - // entrare da tutti i lati aperti... - pCompo->ChangeStartPoint( vInd[0] + 0.5) ; - return true ; - } + // se non trovato, imposto il punto iniziale a mentà del primo tratto + if ( nMax == -1) { + pCompo->ChangeStartPoint( 0.5) ; + return true ; } - + pCompo->ChangeStartPoint( nMax + 0.5) ; return true ; } @@ -1159,8 +872,7 @@ GetHomogeneousParts( ICurveComposite* pCrvCompo, const PocketParams& PockParams, return true ; // la curva ha sia tratti aperti che tratti chiusi, quindi sposto l'inizio a metà del tratto più lungo ( se richiesto)... - ICRVCOMPOPOVECTOR vCrvNULL ; - AdjustContourStart( pCrvCompo, PockParams, vCrvNULL, false, P_INVALID) ; + AdjustContourStart( pCrvCompo, PockParams) ; // estraggo parti con proprietà uniforme in un vettore ( vpCrvs) int nCurrTempProp ; @@ -1188,7 +900,6 @@ GetHomogeneousParts( ICurveComposite* pCrvCompo, const PocketParams& PockParams, return false ; pCrv->SetTempProp( nCurrTempProp) ; vpCrvs.emplace_back( Release( pCrv)) ; - return true ; } @@ -1713,6 +1424,48 @@ ChainCompoCurves( ICRVCOMPOPOVECTOR& vCrvCompo) return true ; } +//---------------------------------------------------------------------------- +static bool +ChangePtStartForSinglePocketCurve( ICurveComposite* pCrvCompo, const PocketParams& PockParams, + const Point3d& ptRef) +{ + // controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // se la curva è aperta + if ( ! pCrvCompo->IsClosed()) { + // se non ho un punto di riferimento, allora non faccio nulla + if ( ! ptRef.IsValid()) + return true ; + // se ho un punto di riferimento controllo quale estremo è più vicino + Point3d ptStart ; pCrvCompo->GetStartPoint( ptStart) ; + Point3d ptEnd ; pCrvCompo->GetEndPoint( ptEnd) ; + if ( SqDist( ptRef, ptEnd) < SqDist( ptRef, ptStart)) + pCrvCompo->Invert() ; + } + // se la curva è chiusa + else { + // se non ho un punto di riferimento, scelgo il tratto più lungo + if ( ! ptRef.IsValid()) { + ResetCurveTempProps( pCrvCompo) ; + AdjustContourStart( pCrvCompo, PockParams) ; + } + // se ho un punto di riferimento + else { + // cerco il punto più vicino + DistPointCurve DistPtCrv( ptRef, *pCrvCompo) ; + double dPar = 0. ; + int nFlag ; + if ( ! DistPtCrv.GetParamAtMinDistPoint( 0, dPar, nFlag)) + return false ; + pCrvCompo->ChangeStartPoint( dPar) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- static bool AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams) @@ -1722,13 +1475,17 @@ AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, if ( vCrvCompo.empty()) return true ; - // controllo validità delle curve + // per ogni curva composita... for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) { + // controllo validità della curva if ( IsNull( vCrvCompo[i]) || ! vCrvCompo[i]->IsValid()) return false ; + // cambio il punto iniziale della curva + if ( ! ChangePtStartForSinglePocketCurve( vCrvCompo[i], PockParams, PockParams.ptStart)) + return false ; } - // se superficie tutta chiusa, allora non estendo nulla + // se superficie tutta chiusa, allora ho finito if ( PockParams.bAllClosed) return true ; @@ -1740,32 +1497,15 @@ AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, */ // scorro ogni singola curva composita + const int MAX_ITER = 4 ; for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) { - - // se la curva è chiusa modifico il punto iniziale nel tratto più lungo - // ne creo una copia resettando le proprietà temporane - if ( vCrvCompo[i]->IsClosed()) { - PtrOwner pCompo( CloneCurveComposite( vCrvCompo[i])) ; - if ( IsNull( pCompo) || ! pCompo->IsValid()) - return false ; - ResetCurveTempProps( pCompo) ; - ICRVCOMPOPOVECTOR vCrvEmpty ; - AdjustContourStart( pCompo, PockParams, vCrvEmpty, false, P_INVALID) ; - Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; - double dUS = 0. ; - vCrvCompo[i]->GetParamAtPoint( ptStart, dUS) ; - vCrvCompo[i]->ChangeStartPoint( dUS) ; - } - - + // controllo se la curva è chiusa o aperta + bool bIsClosed = vCrvCompo[i]->IsClosed() ; // calcolo il numero massimo di punti in cui testare l'entrata da fuori - int nMaxIter = ( vCrvCompo[i]->IsClosed() ? 4 : 1) ; + int nMaxIter = ( bIsClosed ? MAX_ITER : 1) ; double dLen = EPS_SMALL ; - if ( nMaxIter == 4) + if ( nMaxIter == MAX_ITER) vCrvCompo[i]->GetLength( dLen) ; - // se richiesta inversione della curva, allora inverto - if ( PockParams.bInvert) - vCrvCompo[i]->Invert() ; // scorro il numero di punti su cui tentare l'entrata da fuori for ( int j = 0 ; j < nMaxIter ; ++ j) { if ( j > 0) { @@ -1773,14 +1513,14 @@ AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, vCrvCompo[i]->GetParamAtLength( dLen / nMaxIter, dParAtLen) ; vCrvCompo[i]->ChangeStartPoint( dParAtLen) ; } - // ricavo vettore tangente iniziale e cerco di estendere - Vector3d vtStart ; - vCrvCompo[i]->GetStartDir( vtStart) ; + // ricavo vettore tangente iniziale e provo ad estendere + Vector3d vtStart ; vCrvCompo[i]->GetStartDir( vtStart) ; vtStart.Invert() ; bool bIsStartExtended = false ; if ( ! ExtendPath( vCrvCompo[i], pSfr, PockParams, vtStart, false, bIsStartExtended)) return false ; - if ( ! vCrvCompo[i]->IsClosed()) { + // se aperta, controllo la fine + if ( ! bIsClosed) { // ricavo vettore tangente finale e provo ad estendere Vector3d vtEnd ; vCrvCompo[i]->GetEndDir( vtEnd) ; bool bIsEndExtended = false ; @@ -1863,8 +1603,9 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara // NB. Queste curve sono orientate in maniera corretta ICRVCOMPOPOVECTOR vCrvCompoRes_tmp ; // salvo il vettore di curve offsettate del raggio utensile for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - if ( vpCrvs[i]->GetTempProp( 0) == 0) { // se tratto chiuso... - OffsetCurve OffsCrv ; // con offset verso l'interno + // 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)) { @@ -1906,26 +1647,28 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara // se proprità non uniformi -> tutta chiusa ( isole non uniformi non sono definite) if ( bIsMixed) { for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) - pCrvIsl->SetTempProp( u, 0) ; + pCrvIsl->SetTempProp( u, TEMP_PROP_CLOSE_EDGE) ; nCurrTmpProp = 0 ; // aggiorno il Flag } // 2) e 3) - bValidIslands = ( ( nCurrTmpProp == 0 && bExtAllOpen) || - ( nCurrTmpProp == 1 && bExtAllClose)) ; + bValidIslands = ( ( nCurrTmpProp == TEMP_PROP_CLOSE_EDGE && bExtAllOpen) || + ( nCurrTmpProp == TEMP_PROP_OPEN_EDGE && bExtAllClose)) ; } if ( ! bValidIslands) return true ; // nel caso 2) devo inserire le curve - // creo una regione formata solo dalla isole - PtrOwner pSrfIslands( CreateSurfFlatRegion()) ; - if ( IsNull( pSrfIslands)) - return false ; - for ( int i = 1 ; i < pSfrChunk->GetLoopCount( 0) ; ++ i) - pSrfIslands->AddExtLoop( pSfrChunk->GetLoop( 0, i)) ; - pSrfIslands->Offset( PockParams.dRad + PockParams.dRadialOffset, ICurve::OFF_FILLET) ; - for ( int c = 0 ; c < pSrfIslands->GetChunkCount() ; ++ c) - for ( int l = 0 ; l < pSrfIslands->GetLoopCount( l) ; ++ l) - vCrvCompoRes_tmp.emplace_back( ConvertCurveToComposite( pSrfIslands->GetLoop( c, l))) ; + if ( bExtAllOpen) { + // creo una regione formata solo dalla isole + PtrOwner pSrfIslands( CreateSurfFlatRegion()) ; + if ( IsNull( pSrfIslands)) + return false ; + for ( int i = 1 ; i < pSfrChunk->GetLoopCount( 0) ; ++ i) + pSrfIslands->AddExtLoop( pSfrChunk->GetLoop( 0, i)) ; + pSrfIslands->Offset( PockParams.dRad + PockParams.dRadialOffset, ICurve::OFF_FILLET) ; + for ( int nC = 0 ; nC < pSrfIslands->GetChunkCount() ; ++ nC) + for ( int nL = 0 ; nL < pSrfIslands->GetLoopCount( nL) ; ++ nL) + vCrvCompoRes_tmp.emplace_back( ConvertCurveToComposite( pSrfIslands->GetLoop( nC, nL))) ; + } } // se non ho ottenuto curve, allora ho finito @@ -1970,6 +1713,9 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara // salvo come primo tempParam l'offset massimo della regione ( servirà per la Feed) for ( int i = 0 ; i < int( vCrvCompoRes_tmp.size()) ; ++ i) { vCrvCompoRes_tmp[i]->SetTempParam( dMaxOffs, 0) ; + // se richiesta inversione della curva, allora inverto se chiusa + if ( PockParams.bInvert) + vCrvCompoRes_tmp[i]->Invert() ; vCrvCompoRes.emplace_back( Release( vCrvCompoRes_tmp[i])) ; // aggiungo la curva al vettore } @@ -2151,7 +1897,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP // potrei doverle riconcatenare if ( ! ChainCompoCurves( vCrvCompoRes)) return false ; - // estendo le curve, calcolando anche le Feeds + // estendo le curve, definendo ptStart e calcolando le Feeds if ( ! AdvanceExtendCurves( vCrvCompoRes, pSfr, PockParams)) return false ; // imposto le Feed per tali curve se richiesto @@ -2160,7 +1906,6 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP 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 @@ -2189,42 +1934,35 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP // *************************************************************************** // ------------- SCELTA DEL PUNTO INIZIALE ----------------------------------- // *************************************************************************** -//---------------------------------------------------------------------------- //---------------------------------------------------------------------------- static bool -GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOtherCrv, - const PocketParams& PockParams, Point3d& ptMid, Vector3d& vtMidOrt) +GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockParams, bool& bOutStart, + Point3d& ptStart, Vector3d& vtOut) { - // recupero il vettore estrusione - Vector3d vtExtr = Z_AX ; - pCompo->GetExtrusion( vtExtr) ; + // 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() != 1) { + if ( pMyCrv->GetTempProp() != TEMP_PROP_OPEN_EDGE) { bAllOpen = false ; break ; } pMyCrv = pCompo->GetNextCurve() ; } - // salvo il punto iniziale e la direzione d'uscita del primo lato aperto valido che trovo - // NB. Il primo valido non significa il migliore, potrebbe infatti essere il lato aperto più lungo - // ma essere all'interno del grezzo... cerco di dare priorità ai lati sul grezzo - // flag per la presenza di un primo lato aperto valido per entrare - bool bFirstOpenValid = false ; - Point3d ptFirstOpenValid = P_INVALID ; - Vector3d vtFirstOpenValid = V_INVALID ; // richiedo lunghezza superiore a diametro utensile più doppio offset radiale - double dRefLen = ( bAllOpen ? 0 : ( 2 * PockParams.dRad) + 2 * PockParams.dRadialOffset - EPS_SMALL) ; + double dRefLen = ( bAllOpen ? 0. : ( 2 * PockParams.dRad) + 2 * PockParams.dRadialOffset - EPS_SMALL) ; double dMaxLen = dRefLen ; // ciclo sulle singole curve bool bFound = false ; const ICurve* pPrevCrv = pCompo->GetLastCurve() ; - double dLenPrev = 0 ; - if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) + double dLenPrev = 0. ; + if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) pPrevCrv->GetLength( dLenPrev) ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { @@ -2233,20 +1971,20 @@ GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOth bool bNextOk = ( pNextCrv != nullptr) ; if ( ! bNextOk) pNextCrv = pCompo->GetFirstCurve() ; - double dLenNext = 0 ; - if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) + double dLenNext = 0. ; + if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == TEMP_PROP_OPEN_EDGE) pNextCrv->GetLength( dLenNext) ; // verifico la curva corrente - if ( pCrv->GetTempProp() == 1) { - // contributo dalle entità adiacenti (se non tutte aperte) - double dLenAgg = 0 ; + 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() == 1) { + 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() == 1) { + 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 ; @@ -2256,41 +1994,28 @@ GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOth double dLen = 0 ; if ( pCrv->GetLength( dLen)) { const double LEN_TOL = 1 ; - // se di lunghezza praticamente uguale + // se di lunghezza praticamente uguale if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) { Point3d ptTest ; pCrv->GetMidPoint( ptTest) ; - if ( ( PockParams.bAboveHead && ptTest.z > ptMid.z + 100 * EPS_SMALL) || - ( ! PockParams.bAboveHead && ptTest.z < ptMid.z - 100 * EPS_SMALL) || - ( abs( ptTest.z - ptMid.z) < 100 * EPS_SMALL && ptTest.y < ptMid.y - 100 * EPS_SMALL)) { + 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) ; - ptMid = ptTest ; - // vettore ortogonale verso l'esterno (ruotato -90deg attorno a estrusione) - pCrv->GetMidDir( vtMidOrt) ; - vtMidOrt.Rotate( vtExtr, 0, -1) ; + 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) { + else if ( dLen + dLenAgg > dMaxLen || ! bFound) { dMaxLen = dLen + dLenAgg ; - double dParIn ; - // cerco il parametro di tale curva (0 < dParIn < 1) migliore per l'entrata - if ( GetParamForPtStartOnEdge( pCrv, pCompo, vOtherCrv, PockParams, dParIn)) { - pCrv->GetPointD1D2( dParIn, ICurve::FROM_PLUS, ptMid) ; - PtrOwner pCompoClone( pCompo->Clone()) ; - if ( IsNull( pCompoClone)) - return false ; - double dU ; - pCompoClone->GetParamAtPoint( ptMid, dU) ; - pCompoClone->ChangeStartPoint( dU) ; - pCompoClone->GetStartDir( vtMidOrt) ; - vtMidOrt.Rotate( vtExtr, 0, -1) ; - // salvo l'indice di questo lato aperto se si tratta del primo valido - if ( ! bFirstOpenValid) { - bFirstOpenValid = true ; - ptFirstOpenValid = ptMid ; - vtFirstOpenValid = vtMidOrt ; - } + 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 ; @@ -2303,306 +2028,438 @@ GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOth pCrv = ( bNextOk ? pNextCrv : nullptr) ; } - // se non ho trovato un lato aperto valido fuori dal grezzo, ma ho trovato un lato aperto - // generico accettabile - if ( ! bFound && bFirstOpenValid) { - ptMid = ptFirstOpenValid ; - vtMidOrt = vtFirstOpenValid ; - bFound = true ; - } - return bFound ; } //---------------------------------------------------------------------------- static bool -SetSpecialPtStartForOpenEdges( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, - ICurveComposite* pCrvCompo, Point3d& ptStart, - Vector3d& vtMidOut, bool& bMidOut) +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 - double dLenRef = ( 2 * PockParams.dRad) - 50 * EPS_SMALL ; // almeno di questa lunghezza - for ( int u = 0 ; u < pCrvOrig->GetCurveCount() ; ++ u) { - if ( pCrvOrig->GetCurve( u)->GetTempProp( 0) == 0) - continue ; // escludo le chiuse - // ricavo la curva u-esima aperta - const ICurve* pCrvOpen = pCrvOrig->GetCurve( u) ; + // 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) ; - if ( dLen > dLenRef) { // se lunghezza accettabile o maggiore della massima trovata + // se lunghezza accettabile o maggiore della massima trovata + if ( dLen > dLenRef) { Point3d ptSTmp ; Vector3d vtMidOutTmp ; - // ricavo il punto medio e il versore tangente associato + // 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 ; - if ( DistPointCurve( ptSTmp, *pCrvCompo).GetMinDistPoint( EPS_SMALL, ptStart, nFlag)) { - // controllo se il punto iniziale sta effettivaente su un lato aperto della curva attuale - // di primo Offset - double dU_check ; - if ( pCrvCompo->GetParamAtPoint( ptStart, dU_check)) { - // se il punto trovato è a cavallo tra due curve... - if ( abs( dU_check - floor( dU_check)) < EPS_PARAM || - abs( dU_check - ceil( dU_check)) < EPS_PARAM) { - const ICurve* pCrvA = pCrvCompo->GetCurve( int( floor( dU_check))) ; - if ( pCrvA == nullptr) - return false ; - const ICurve* pCrvB = pCrvCompo->GetCurve( int( ceil( dU_check))) ; - if ( pCrvB == nullptr) - return false ; - if ( pCrvA->GetTempProp( 0) == 0 || pCrvB->GetTempProp( 0) == 1) - continue ; // se una delle due è chiusa, salto tale punto - } - // se invece tocca una sola curva, controllo che sia aperta - else { - const ICurve* pCrvA = pCrvCompo->GetCurve( int( floor( dU_check))) ; - if ( pCrvA == nullptr) - return false ; - if ( pCrvA->GetTempProp( 0) == 0) - continue ; // se chiusa, salto tale punto - } + 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 ; } - vtMidOutTmp.Normalize() ; - vtMidOutTmp.Rotate( Z_AX, - 90) ; - vtMidOut = vtMidOutTmp ; - bMidOut = true ; } } } } - return bMidOut ; -} - -//---------------------------------------------------------------------------- -static bool -AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParams& PockParams, - ICRVCOMPOPOVECTOR& vCrvLoops, INTVECTOR& vIndex, bool& bSomeOpen) -{ - // controllo dei parametri - if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) - return false ; - for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) - if ( IsNull( vCrvLoops[i]) || ! vCrvLoops[i]->IsValid() || vCrvLoops[i]->GetCurveCount() == 0) - 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 ; pCrv->GetCurveTempProp( i, nProp0, 0) ; - // nProp1 -> #loop che contiene la curva espressa in nProp0 - int nProp1 ; pCrv->GetCurveTempProp( i, nProp1, 1) ; - - if ( nProp0 > 0) { // se questa curva non è un "raccordo" di Offset - // controllo per maggiore sicurezza che effettivamente nProp1 sia un indice valido per il vettore dei Loops e - // che nProp0 non sia maggiore del numero di curve del loop nProp1-esimo del vettore dei Loops della pSrfToWork - if ( nProp1 >= 0 && nProp1 < int( vCrvLoops.size()) && nProp0 < vCrvLoops[nProp1]->GetCurveCount()) { - // aggiorno il vettore di indici ... - if ( find( vIndex.begin(), vIndex.end(), nProp1) == vIndex.end()) - vIndex.push_back( nProp1) ; - // aggiorno la proprietà della curva da cui devo entrare - int nTempProp ; vCrvLoops[nProp1]->GetCurveTempProp( nProp0 - 1, nTempProp, 0) ; - pCrv->SetCurveTempProp( i, nTempProp, 0) ; - // se la curva è aperta, aggiorno il Flag - if ( nTempProp == 1 && ! bSomeOpen) - bSomeOpen = true ; - // salvo l'indice della prima curva trovata che non è un "raccordo" di Offset - if ( nInd == -1) - nInd = i ; - } - else - pCrv->SetCurveTempProp( i, 0, 0) ; - } - else { - pCrv->SetCurveTempProp( i, -2, 0) ; - pCrv->SetCurveTempProp( i, -2, 1) ; - } - } - - // scorro tutte le curve incerte ( che derivano da raccordi ) - if ( nInd != -1) - pCrv->ChangeStartPoint( nInd) ; // la prima curva non è un "raccordo" di Offset - - for ( int i = 1 ; i < pCrv->GetCurveCount() ; ++ i) { - double dLen = 0. ; - if ( pCrv->GetCurve( i)->GetLength( dLen) && dLen < 0.025 * ( 2 * PockParams.dRad)) - pCrv->SetCurveTempProp( i, 0, 0) ; - else { - int nTmpProp0, nTmpProp1 ; - if (( pCrv->GetCurveTempProp( i, nTmpProp0, 0) && nTmpProp0 == -2) && - ( pCrv->GetCurveTempProp( i, nTmpProp1, 1) && nTmpProp1 == -2)) { - // copio la temp prop della curva precedente - pCrv->SetCurveTempProp( i, pCrv->GetCurve( i-1)->GetTempProp(), 0) ; - // se troppo corta, allora chiusa - if ( pCrv->GetCurve( i)->GetLength( dLen) && dLen < 0.01 * ( 2 * PockParams.dRad)) - pCrv->SetCurveTempProp( i, 0, 0) ; - } - } - } return true ; } //---------------------------------------------------------------------------- static bool -SetPtStartForPath( ICurveComposite* pCrvOffsAct, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, - const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut, - int nOffs, const ICurveComposite* pCrvOrig) +GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParams, + const ICurveComposite* pCrvCompo, const ICurveComposite* pCrvOrig, + Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) { - // ============================= INFO ============================================================== - // pCrvOffsAct -> Curva di Offset su cui cercare ptStart, vtMidOut, bMidOpen - // pSrfToWork -> Superificie originaria da lavorare - // ( questa superificie ha i flag di lati aperti/chiusi settati nei loops) - // ================================================================================================= + // controllo dei parametri + if ( ! 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) +{ /* - 1) Come prima cosa ricavo i lati aperti equivalenti dal primo Offset ; Facendo l'Offset di una curva + 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 mio contorno con i lati aperti impostati, posso settare i lati aperti "equivalenti" + 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. - - 2) Verifico l'esistenza di lati aperti : - - Se esistono lati aperti -> cerco il lato più sensato su cui entrare - - 2.1) Guardo la curva originale ( senza estensione degli aperti) che delimita la regione di - svuotatura e cerco i lati aperti presenti in essa ; se mi posiziono a metà del lato aperto - e cerco il punto più vicino sulla curva di primo offset. Se quest'ultima è anch'essa aperta - e di lunghezza adeguata, l'entrata è valida - - 2.2) ( se 2.1 non accettabile ) Scorro tutte le curve di lato aperto sulla curva di primo - Offset e per ogni curva di lunghezza accettabile controllo la precedente e la successiva. - Ad ogni curva aperta viene assegnato uno "score", in base alla sua Lenght, alle Lenghts - delle curve adiacenti ( se aperte ) e ai loro angoli di adiacenza. - Se la curva aperta corrente ha uno "score" sufficiente, viene scelta come curva per l'entrata - - 2.3) ( se 2.2 non accettabile ) Considero le curve come tutte chiuse ( vedi sotto ) - - Se non esistono dei lati aperti -> entro presso il lato chiuso più lungo - - 2.4) */ // controllo dei parametri - if ( pCrvOffsAct == nullptr || ! pCrvOffsAct->IsValid() || pCrvOffsAct->GetCurveCount() == 0 || + if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) return false ; - // clono le curva su cui devo entrare - PtrOwner pCrv( pCrvOffsAct->Clone()) ; - if ( IsNull( pCrv)) + // assegno proprietà di OPEN/CLOSE alle sottocurve dell'offset corrente + bool bSomeOpen = false ; + if ( ! AssignOpenCloseTmpPropToFirstOffsCurve( pCrvOffs, PockParams, pSrfToWork, bSomeOpen)) return false ; - // 1) ********************************************************************* - - bool bSomeOpen = false ; // flag per presenza di lati aperti - // creo un vettore di Loops della superificie, ordinati - ICRVCOMPOPOVECTOR vCrvLoops ; - for ( int l = 0 ; l < pSrfToWork->GetLoopCount( 0) ; ++ l) - vCrvLoops.emplace_back( ConvertCurveToComposite( pSrfToWork->GetLoop( 0, l))) ; - // creo un vettore di indici. Questi indici si riferiscono alle posizioni di vCrvLoops i quali offset - // hanno generato delle curve sulla pCrv ( curva da cui devo entrare ) - INTVECTOR vIndex ; - if ( ! AssignOpenCloseTmpPropToFirstOffsCurve( pCrv, PockParams, vCrvLoops, vIndex, bSomeOpen)) - return false ; - - // ********************************************************************* - - // se ho dei lati aperti... - double dLenMax = EPS_SMALL ; - int nCrvForMax = 0 ; - if ( bSomeOpen) { - // ... e sono al primo Step, cerco la curva Aperta più lunga ( scelgo la prima che trovo) ... - if ( ! ptEndPrec.IsValid()) { - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - int nTmpProp = 0 ; - double dLenAct = EPS_SMALL ; - if ( pCrv->GetCurveTempProp( u, nTmpProp, 0) && nTmpProp == 1 && - pCrv->GetCurve( u)->GetLength( dLenAct) && dLenAct > dLenMax) { - dLenMax = dLenAct ; - nCrvForMax = u ; - } - } - // il punto iniziale della curva sarà il punto iniziale della sottocurva trovata - pCrv->ChangeStartPoint( nCrvForMax) ; - } - // ... se invece non sono al primo Step, cerco la prima curva aperta più vicina al punto finale - else { - int nIndClosesOpenCrv = -1 ; - double dMinDist = INFINITO ; - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - if ( pCrv->GetCurve( u)->GetTempProp( 0) == 1) { - DistPointCurve DPC( ptEndPrec, *pCrv->GetCurve( u)) ; - double dCurrDist = INFINITO ; - if ( DPC.GetDist( dCurrDist) && dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nIndClosesOpenCrv = u ; - } - } - } - // il punto iniziale della curva sarà il punto iniziale della sottocurva trovata - pCrv->ChangeStartPoint( nIndClosesOpenCrv) ; - } - } - - // creo un vettore con tutti i Loops della pSwfToWork per i quali, mediante l'Offset, non hanno - // generato alcuna curva presente nella pCrv ( quella da cui devo entrare) - ICRVCOMPOPOVECTOR vOtherCrv ; - for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { - bool bOk = true ; - for ( int j = 0 ; j < int( vIndex.size()) && bOk ; ++ j) { - if ( i == vIndex[j]) - bOk = false ; - } - if ( bOk) - vOtherCrv.emplace_back( vCrvLoops[i]->Clone()) ; - } - - // cerchiamo un punto valido per l'entrata ... + // punto valido per l'entrata ... bMidOut = false ; - if ( bSomeOpen) { // se ho dei lati aperti, cerco un parametro ideale per entrare - /* ( 2.1 ) */ - bool bOK = false ; - if ( nOffs == 1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { - // in questo caso le curve a fagiolo dei lati aperti a sinistra e a destra potrebbero - // intersecarsi tra loro -> risulta difficile calcolare il versore direzione d'uscita - bOK = SetSpecialPtStartForOpenEdges( pCrvOrig, PockParams, pCrv, ptStart, vtMidOut, bMidOut) ; + 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 ; } - if ( ! bOK) /* ( 2.2 ) */ - bMidOut = GetParamOnOpenSide( pCrv, vOtherCrv, PockParams, ptStart, vtMidOut) ; } - if ( bMidOut) { // se ho trovato e valido, allora imposto il punto inziale trovato - const double LEN_OUT = 5 ; - double dPar ; int nFlag ; - bMidOut = ( DistPointCurve( ptStart + LEN_OUT * vtMidOut, *pCrv).GetParamAtMinDistPoint( 0, dPar, nFlag) - && pCrv->ChangeStartPoint( dPar)) ; + // 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 ; + } } - /* ( 2.3 | 2.4 ) */ - if ( ! bMidOut) // alla peggio, ordino i lati lunghi per lunghezza e cerco un'entrata valida - AdjustContourStart( pCrv, PockParams, vOtherCrv, true, ptEndPrec) ; - - // ora che ho deciso quale sia il punto iniziale, lo imposto effettivamente sulla curva di Offset passata alla funzione - pCrv->GetStartPoint( ptStart) ; - pCrvOffsAct->Clear() ; - pCrvOffsAct->CopyFrom( pCrv) ; - - return true ; + // 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, int nOffs, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) + bool& bMidOut, int& nIndex, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) { // controllo dei parametri for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) @@ -2621,7 +2478,7 @@ SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& P 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, nOffs, ( int( vCrvOrigChunkLoops.size()) < i) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) + bMidOut, i < ( int( vCrvOrigChunkLoops.size())) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) vCrvOffsAct[i]->GetStartPoint( ptStart) ; else return false ; @@ -2837,17 +2694,14 @@ OptimizedSpiralCirle( const ICurveComposite* pCrvCompo, const double dToll, doub //---------------------------------------------------------------------------- static bool CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad, - const PocketParams& PockParams, ICurveComposite* pMCrv, ICurveComposite* pRCrv) + const PocketParams& PockParams, ICurveComposite* pMCrv) { - /* calcola il percorso di a spirale assieme al percorso di ritorno */ - // raggio della circonferenza esterna if ( dOutRad < 10 * EPS_SMALL) return false ; // imposto versore estrusione sulle curve composite pMCrv->SetExtrusion( vtN) ; - pRCrv->SetExtrusion( vtN) ; // creo e inserisco la circonferenza esterna PtrOwner pArc( CreateCurveArc()) ; @@ -2893,20 +2747,6 @@ CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, dou // assegno la Feed AssignFeedSpiralOpt( 0, PockParams, pMCrv) ; - - // calcolo l'eventuale percorso di ritorno - Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; - Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; - Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ; - if ( ! AreSamePointApprox( ptStart, ptEnd)) { - PtrOwner pArc2( CreateCurveArc()) ; - if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) - return false ; - pRCrv->AddCurve( Release( pArc2)) ; - // inverto e eventualmente sistemo archi - pRCrv->Invert() ; - } - return true ; } @@ -3837,7 +3677,8 @@ AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* p //---------------------------------------------------- static bool CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double dPocketSize, int nBase, - int nSecondBase, const PocketParams& PockParams, ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap) + int nSecondBase, const PocketParams& PockParams, ICurveComposite* pMCrv, + bool& bOptimizedTrap) { // parametri double dDiam = 2 * PockParams.dRad ; @@ -5062,6 +4903,8 @@ 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) { @@ -5175,7 +5018,6 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // aggiorno il collegamento vLinks[i+1].Set( pCrvLink) ; - } } @@ -5822,12 +5664,11 @@ AddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, //---------------------------------------------------------------------------- static bool CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int& nReg, Point3d& ptStart, - ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops, ICurveComposite* pMCrv, ICurveComposite* pRCrv, - bool& bOptimizedTrap, bool& bMidOut, Vector3d& vtMidOut) + ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops, ICurveComposite* pMCrv, bool& bOptimizedTrap, + bool& bMidOut, Vector3d& vtMidOut) { - // inizializzo i risultati + // inizializzo il percorso come vuoto pMCrv->Clear() ; - pRCrv->Clear() ; // Offset corrente ( il primo è definito dal raggio utensile) double dOffs = PockParams.dRad + PockParams.dRadialOffset ; @@ -5856,7 +5697,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int if ( bIsCircle && dRad - dOffs > 10 * EPS_SMALL) { double dIntRad = 0 ; if ( nReg == 0) { - bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, PockParams, pMCrv, pRCrv) ; + bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, PockParams, pMCrv) ; if ( bOk) { pMCrv->GetStartPoint( ptStart) ; for ( int u = 0 ; u < pCrvBorder->GetCurveCount() ; ++ u) { @@ -5888,7 +5729,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int if ( pCrvTrap->IsValid()) { pCrvTrap->SetExtrusion( Z_AX) ; if ( nReg == 0) { - CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParams, pMCrv, pRCrv, bOptimizedTrap) ; + CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParams, pMCrv, bOptimizedTrap) ; if ( bOptimizedTrap) { nReg = 1 ; return true ; @@ -5906,7 +5747,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset - PtrOwner pSrfAct( pSrfToWork->Clone()) ; // regione attuale + PtrOwner pSrfAct( CloneSurfFlatRegion( pSrfToWork)) ; // regione attuale if ( IsNull( pSrfAct) || pSrfAct->GetChunkCount() == 0) return false ; @@ -5994,21 +5835,21 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int return true ; // cambio il punto iniziale della prima Curva di Offset - Point3d ptRef = PockParams.ptEnd ; + Point3d ptRef = PockParams.ptStart ; Point3d ptNewStart ; // Se ho come lavorazione uno SpiralIn posso poter entrare dalle isole aperte... int nIndexSwap = 0 ; // indice del vettore di curve per identificare la curva su cui entrare if ( PockParams.nType == POCKET_SPIRALIN) { if ( SetAdvancedPtStartForPath( vOffsFirstCurve, PockParams, pSrfToWork, ptRef, ptStart, - vtMidOut, bMidOut, nIndexSwap, int( vOffs.size()), vCrvOrigChunkLoops)) + vtMidOut, bMidOut, nIndexSwap, vCrvOrigChunkLoops)) vOffsFirstCurve[nIndexSwap]->GetStartPoint( ptNewStart) ; else return false ; } else { if ( SetPtStartForPath( vOffs[0], PockParams, pSrfToWork, ptRef, ptStart, vtMidOut, bMidOut, - int( vOffs.size()), vCrvOrigChunkLoops[0])) + vCrvOrigChunkLoops[0])) vOffs[0]->GetStartPoint( ptNewStart) ; else return false ; @@ -6564,15 +6405,31 @@ CalcZigZag( const ISurfFlatRegion* pSrfZigZag, const PocketParams& PockParams, I //---------------------------------------------------------------------------- static bool -AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, - const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) +AddSpiralIn( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, + PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { - // ciclo sui chunk della superficie da svuotare - for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { + // ricavo il numero di Chunk da svuotare + if ( pSrfPock == nullptr) + return false ; + int nChunk = pSrfPock->GetChunkCount() ; - // copio il chunk c-esimo - PtrOwner pSrfChunk( pSrfPock->CloneChunk( c)) ; - if ( IsNull( pSrfChunk)) + // scorro i Chunk + for ( int nC = 0 ; nC < nChunk ; ++ nC) { + + // indice del Chunk da corrente da svuotare + int nChunkInd = 0 ; + if ( PockParams.ptStart.IsValid()) { + // se il punto di riferimento è valido, il Chunk è quello ad esso più vicino + DistPointSurfFr DistPtSfr( PockParams.ptStart, *pSrfPock) ; + int nMinLoop = 0 ; + double dMinPar = 0. ; + if ( ! DistPtSfr.GetParamAtMinDist( nChunkInd, nMinLoop, dMinPar)) + return false ; + } + + // Clono il Chunk attuale come regione FlatRegion + PtrOwner pSfrChunk( pSrfPock->CloneChunk( nChunkInd)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; const int MAX_REGS = 50 ; // massimo numero di regioni create dal primo offset @@ -6581,9 +6438,8 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // ciclo su tutte le regioni che posso ottenere col primo Offset del chunk c-esimo while ( nReg < MAX_REGS) { // calcolo la spirale dall'esterno all'interno e la curva che unisce inizio e fine - PtrOwner pMCrv( CreateCurveComposite()) ; // percorso di svuotatura - PtrOwner pRCrv( CreateCurveComposite()) ; // percorso di ritorno - if ( IsNull( pMCrv) || IsNull( pRCrv)) + PtrOwner pMCrv( CreateCurveComposite()) ; + if ( IsNull( pMCrv)) return false ; int nRegTot = nReg ; @@ -6592,13 +6448,13 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // cerco le curve originali del chunk cc-esimo ( per casi ottimizzati) ICRVCOMPOPOVECTOR vCrvOrigChunkLoops ; - if ( ! GetOptCrvIndex( pSfrOrig, pSrfChunk, PockParams, nReg, vCrvOrigChunkLoops)) + if ( ! GetOptCrvIndex( pSfrOrig, pSfrChunk, PockParams, nReg, vCrvOrigChunkLoops)) return false ; // calcolo il percorso di svuotatura bool bSomeOpen ; Vector3d vtMidOut ; - if ( ! CalcSpiral( pSrfChunk, PockParams, nRegTot, ptStart, vCrvOrigChunkLoops, pMCrv, pRCrv, bOptimizedTrap, + if ( ! CalcSpiral( pSfrChunk, PockParams, nRegTot, ptStart, vCrvOrigChunkLoops, pMCrv, bOptimizedTrap, bSomeOpen, vtMidOut)) return false ; @@ -6627,9 +6483,13 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; ++ nReg ; // incremento il numero di regione progressiva - + // aggiorno il punto di riferimento per il Chunk Successivo + vCrvCompoRes.back()->GetEndPoint( PockParams.ptStart) ; } + // rimuovo il Chunk dalla regione + pSrfPock->EraseChunk( nChunkInd) ; + } return true ; @@ -6637,15 +6497,31 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, //---------------------------------------------------------------------------- static bool -AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, - const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) +AddSpiralOut( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, + PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { + // ricavo il numero di Chunk da svuotare + if ( pSrfPock == nullptr) + return false ; + int nChunk = pSrfPock->GetChunkCount() ; + // ciclo sui chunk della superficie da svuotare - for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { - - // copio il chunk c-esimo - PtrOwner pSrfChunk( pSrfPock->CloneChunk( c)) ; - if ( IsNull( pSrfChunk)) + for ( int nC = 0 ; nC < nChunk ; ++ nC) { + + // indice del Chunk da corrente da svuotare + int nChunkInd = 0 ; + if ( PockParams.ptStart.IsValid()) { + // se il punto di riferimento è valido, il Chunk è quello ad esso più vicino + DistPointSurfFr DistPtSfr( PockParams.ptStart, *pSrfPock) ; + int nMinLoop = 0 ; + double dMinPar = 0. ; + if ( ! DistPtSfr.GetParamAtMinDist( nChunkInd, nMinLoop, dMinPar)) + return false ; + } + + // Clono il Chunk attuale come regione FlatRegion + PtrOwner pSfrChunk( pSrfPock->CloneChunk( nChunkInd)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; const int MAX_REGS = 50 ; // massimo numero di regioni create dal primo offset @@ -6656,8 +6532,7 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // calcolo la spirale dall'interno all'esterno PtrOwner pMCrv( CreateCurveComposite()) ; - PtrOwner pRCrv( CreateCurveComposite()) ; - if ( IsNull( pMCrv) || IsNull( pRCrv)) + if ( IsNull( pMCrv)) return false ; int nRegTot = nReg ; @@ -6666,13 +6541,13 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // cerco la curva originale del chunk cc-esimo ( per casi ottimizzati) ICRVCOMPOPOVECTOR vCrvOrig ; - if ( ! GetOptCrvIndex( pSfrOrig, pSrfChunk, PockParams, nReg, vCrvOrig)) + if ( ! GetOptCrvIndex( pSfrOrig, pSfrChunk, PockParams, nReg, vCrvOrig)) return false ; // calcolo il percorso di svuotatura bool bSomeOpen ; Vector3d vtMidOut ; - if ( ! CalcSpiral( pSrfChunk, PockParams, nRegTot, ptStart, vCrvOrig, pMCrv, pRCrv, bOptimizedTrap, + if ( ! CalcSpiral( pSfrChunk, PockParams, nRegTot, ptStart, vCrvOrig, pMCrv, bOptimizedTrap, bSomeOpen, vtMidOut)) return false ; @@ -6680,7 +6555,6 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo - if ( bOptimizedTrap) { // se caso a trapezio Vector3d vtRef ; pMCrv->GetStartDir( vtRef) ; @@ -6695,14 +6569,19 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, pMCrv->SetTempProp( TEMP_PROP_OPT_TRAPEZOID, 0) ; } - // inverto i percorsi, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato) + // inverto il percorso, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato) pMCrv->Invert() ; - pRCrv->Invert() ; // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; + // incremento il numero di regione progressiva ++ nReg ; + // aggiorno il punto di riferimento per il Chunk Successivo + vCrvCompoRes.back()->GetEndPoint( PockParams.ptStart) ; } + + // rimuovo il Chunk dalla regione + pSrfPock->EraseChunk( nChunkInd) ; } return true ; @@ -6870,23 +6749,38 @@ GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegio //---------------------------------------------------------------------------- static bool -AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, +AddZigZag( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { + // ricavo il numero di Chunk da svuotare + if ( pSrfPock == nullptr) + return false ; + int nChunk = pSrfPock->GetChunkCount() ; + // offset della regione per curva ZigZag double dOffs = PockParams.dRad + PockParams.dRadialOffset ; if ( PockParams.bAllowZigZagOneWayBorders) dOffs += PockParams.dOffsExtra ; // ciclo su tutti i chunks della superficie originale - for ( int nC = 0 ; nC < pSrfPock->GetChunkCount() ; ++ nC) { + for ( int nC = 0 ; nC < nChunk ; ++ nC) { - // creo la regione per il percorso a ZigZag ( mediante primo Offset) portandola - // nel sistema di riferimento creato - PtrOwner pSrfZigZag( pSrfPock->CloneChunk( nC)) ; + // indice del Chunk da corrente da svuotare + int nChunkInd = 0 ; + if ( PockParams.ptStart.IsValid()) { + // se il punto di riferimento è valido, il Chunk è quello ad esso più vicino + DistPointSurfFr DistPtSfr( PockParams.ptStart, *pSrfPock) ; + int nMinLoop = 0 ; + double dMinPar = 0. ; + if ( ! DistPtSfr.GetParamAtMinDist( nChunkInd, nMinLoop, dMinPar)) + return false ; + } + + // creo la regione per il percorso a ZigZag ( mediante primo Offset) + PtrOwner pSrfZigZag( pSrfPock->CloneChunk( nChunkInd)) ; if ( ! pSrfZigZag->Offset( - dOffs, ICurve::OFF_FILLET)) return false ; - // vettore con i percorsi a ZigZag relativi al Chunk nC-esimo + // vettore con i percorsi a ZigZag relativi al Chunk attuale ICRVCOMPOPOVECTOR vpCrvs ; // ciclo sui Chunk ottenuti dal primo offset @@ -6900,10 +6794,10 @@ AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con if ( ! CalcZigZag( pSrfZigZagChunk, PockParams, vpCrvs, false)) return false ; - // controllo esistenza di lati aperti per il Chunk nC-esimo + // controllo esistenza di lati aperti per il Chunk attuale bool bIsChunkClosed = true ; if ( ! PockParams.bAllClosed) { - if ( ! IsChunkAllClosed( pSrfPock, nC, bIsChunkClosed)) + if ( ! IsChunkAllClosed( pSrfPock, nChunkInd, bIsChunkClosed)) return false ; // se il Chunk originale aveva lati aperti, estendo il percorso a ZigZag for ( int nU = 0 ; nU < int( vpCrvs.size()) ; ++ nU) { @@ -6929,11 +6823,15 @@ AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con // se richiesto, aggiungo le curve chiuse di Bordo if ( PockParams.bAllowZigZagOneWayBorders) { // recupero il Chunk nC-esimo - PtrOwner pSfrChunk( pSrfPock->CloneChunk( nC)) ; + PtrOwner pSfrChunk( pSrfPock->CloneChunk( nChunkInd)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid() || ! GetZigZagOneWayBorderCrvs( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) return false ; } + + // rimuovo il Chunk dalla regione + pSrfPock->EraseChunk( nChunkInd) ; + } return true ; @@ -7011,7 +6909,7 @@ OptimizeChunkOneWay( const ISurfFlatRegion* pSfrOrig, ISURFFRPOVECTOR& vSrfIdeal //---------------------------------------------------------------------------- static bool -AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, +AddOneWay( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) { // offset della regione per segmenti a ZigZag @@ -7119,7 +7017,7 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, - const ISurfFlatRegion* pSfrLimit, ICRVCOMPOPOVECTOR& vCrvCompoRes) + const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, ICRVCOMPOPOVECTOR& vCrvCompoRes) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || @@ -7142,6 +7040,8 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.bInvert = bInvert ; myParams.bAvoidOpt = bAvoidOpt ; myParams.bAllowZigZagOneWayBorders = bAllowZigZagOneWayBorders ; + if ( ptEndPrec.IsValid()) + myParams.ptStart = ptEndPrec ; if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) myParams.SfrLimit.CopyFrom( pSfrLimit) ; Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ; @@ -7156,6 +7056,9 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double // porto la superficie limite ( se valida) in tale sistema if ( myParams.SfrLimit.IsValid()) myParams.SfrLimit.ToLoc( myParams.frLocXY) ; + // 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