diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 966bf33..c36d618 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -25,13 +25,14 @@ #include "/EgtDev/Include/EGkFilletChamfer.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkDistPointSurfFr.h" #include "/EgtDev/Include/EGkCurveLocal.h" #include "/EgtDev/Include/EGkMedialAxis.h" #include "/EgtDev/Include/EGkLinePntTgCurve.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkIntervals.h" -#include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EgtNumUtils.h" #include using namespace std ; @@ -50,7 +51,7 @@ struct PocketParams { double dRadialOffset = 0. ; // offset radiale double dRadialOffset_prec = -1. ; // offset radiale precedente double dOpenEdgeRad = 0. ; // massimo raggio per estensione lati aperti - double dOpenMinSafe = 2. ; // estensione minima di sicurezza + double dOpenMinSafe = 5. ; // estensione minima di sicurezza double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag bool bOptOffsets = true ; // flag per evitare Offset non necessari in SpiralIn/Out @@ -59,18 +60,21 @@ struct PocketParams { bool bSmooth = false ; // curve smussate bool bInvert = false ; // inversione dei percorsi bool bAvoidOpt = false ; // flag per evitare casi ottimizzati + bool bAllowZigZagOneWayBorders = false ; // flag per abilitare le curve di bordo per ZigZag/OneWay Point3d ptStart = P_INVALID ; // punto d'inizio Point3d ptEnd = P_INVALID ; // punto di fine SurfFlatRegion SfrLimit ; // superficie limite per estensione lati aperti bool bCalcFeed = true ; // flag per calcolo della Feed double dFeed = 1000 ; // feed di riferimento per frazione double dToolFeed = 1000 ; // feed del tool + // ------------------------------------------------------- + bool bAllClosed = true ; // flag per indicare se tutti i bordi sono chiusi + double dOffsExtra = 2. ; // Offset aggiuntivo per percosi a ZigZag/OneWay se richieste le curve di bordo + Frame3d frLocXY ; // frame per conti nel piano XY + int nOffsType = ICurve::OFF_FILLET ; // tipologia di Offset per estensione degli aperti } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket -static int TMP_PROP_SINGLE_CURVE = 3 ; // percorso singola curva aperta ( seguendo i chiusi) -static int TMP_PROP_CRV_OPEN_SIDE = 2 ; // segmento per entrata da fuori -static int TMP_PROP_OPT_TRAPEZOID = 4 ; // caso ottimizzato Trapezio //--------------------------------------------------------------------------- @@ -372,10 +376,10 @@ CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nSt //---------------------------------------------------------------------------- static bool AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig, - const PocketParams& PockParams) + const PocketParams& PockParams, bool bAllowOverWrite) { // se non rischiesto il calcolo della Feed, lascio quella standard - if ( ! PockParams.bCalcFeed) + if ( ! PockParams.bCalcFeed && bAllowOverWrite) return AssignMaxFeed( pCrv, PockParams) ; // controllo se qualche curva passa sopra ad un lato aperto... @@ -515,7 +519,7 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs // se non ho una superificie svuotata, allora esco ( con Feed Minima) if ( pSrfRemoved_offs == nullptr || ! pSrfRemoved_offs->IsValid() || pSrfRemoved_offs->GetChunkCount() == 0) { // controllo eventuali sovrapposizioni con lati aperti - AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams, true) ; return true ; } @@ -666,7 +670,7 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs } // controllo eventuali sovrapposizioni con lati aperti - AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams, true) ; return true ; } @@ -723,35 +727,126 @@ AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveC //---------------------------------------------------------------------------- static bool -IsPointInsideSfr( const ISurfFlatRegion* pSfr, const Point3d& pt, bool& bIsInside) +AssignFeedConformalZigZag( ICurveComposite* pCompoPath, const ICurveComposite* pCrvLoop, + const PocketParams& PockParams, ISurfFlatRegion* pSfrToRemove) { // controllo dei parametri - if ( pSfr == nullptr || ! pSfr->IsValid() || ! pt.IsValid()) + if ( pCompoPath == nullptr || ! pCompoPath->IsValid()) return false ; - bIsInside = false ; - // ciclo sui chunk della FlatRegion - for ( int i = 0 ; i < pSfr->GetChunkCount() ; i ++) { - // verifico se è contenuto nel loop esterno - PtrOwner pCrv( pSfr->GetLoop( i, 0)) ; - PolyLine PL ; - pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_STD, PL) ; - if ( IsPointInsidePolyLine( pt, PL, EPS_SMALL)) { - bool bInsideHole = false ; - // verifico se è contenuto in un loop interno - for ( int j = 1 ; j < pSfr->GetLoopCount( i) ; j ++) { - PtrOwner pCrv( pSfr->GetLoop( i, j)) ; - pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_STD, PL) ; - PL.Invert() ; - if ( IsPointInsidePolyLine( pt, PL, EPS_SMALL)) - bInsideHole = true ; - } - // se è contenuto nel loop esterno ma non è contenuto in nessuno dei loop interni allora il punto è interno - if ( ! bInsideHole) { - bIsInside = true ; - return true ; - } + // controllo se il Flag per assegnare la Feed è attivo + if ( ! PockParams.bCalcFeed) + AssignMaxFeed( pCompoPath, PockParams) ; + else + AssignMinFeed( pCompoPath, PockParams) ; + + // creo la superficie di classificazione ( creata mediante raggio utensile e SideStep) + // creo la curva da restituire con le Feed Assegnate + PtrOwner pSfrRemoved( CreateSurfFlatRegion()) ; + PtrOwner pCompoPathWithFeed( CreateCurveComposite()) ; + if ( IsNull( pSfrRemoved) || IsNull( pCompoPathWithFeed)) + return false ; + ICRVCOMPOPOVECTOR vCrvEmpty ; + + // scorro tutte le curve del percorso + for ( int i = 0 ; i < pCompoPath->GetCurveCount() ; ++ i) { + // recupero la singola curva come composita + PtrOwner pSingleCompo( ConvertCurveToComposite( pCompoPath->GetCurve( i)->Clone())) ; + if ( IsNull( pSingleCompo) || ! pSingleCompo->IsValid()) + return false ; + + // calcolo la Feed per tale curva + AssignFeedSpiral( pSingleCompo, pSfrRemoved, false, vCrvEmpty, pCrvLoop, PockParams, 2 * PockParams.dRad / 3) ; + + // aggiorno la regione svuotata dal Tool + PtrOwner pSfrSingleCompo( GetSurfFlatRegionFromFatCurve( pSingleCompo->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; + if ( ! IsNull( pSfrSingleCompo) || ! pSfrSingleCompo->IsValid()) { + if ( ! pSfrRemoved->IsValid()) + pSfrRemoved->CopyFrom( pSfrSingleCompo) ; + else + pSfrRemoved->Add( *pSfrSingleCompo) ; } + + if ( ! pCompoPathWithFeed->AddCurve( Release( pSingleCompo))) + return false ; + } + + // definisco la regione da svuotare + PtrOwner pMyLoop( CloneCurveComposite( pCrvLoop)) ; + pSfrToRemove->Clear() ; + + if ( ! pSfrToRemove->AddExtLoop( Release( pMyLoop)) || + ! pSfrToRemove->Offset( - PockParams.dRad - PockParams.dRadialOffset, ICurve::OFF_FILLET) || + ! pSfrToRemove->Subtract( *pSfrRemoved)) + pSfrToRemove->Clear() ; // alla peggio non rimuovo le Uncleared Regions... + + // restituisco la curva se valida + if ( pCompoPathWithFeed->IsValid()) + pCompoPath->CopyFrom( pCompoPathWithFeed) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +ResetCurveTempProps( ICurveComposite* pCrvCompo) +{ + // controllo parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // scorro le curve + for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() ; ++ nU) { + pCrvCompo->SetCurveTempProp( nU, 0, 0) ; + pCrvCompo->SetCurveTempProp( nU, 0, 1) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +IsChunkAllClosed( const ISurfFlatRegion* pSfr, int nChunk, bool& bAllClose) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid() || nChunk < 0 || nChunk > pSfr->GetChunkCount()) + return false ; + bAllClose = true ; + + // scorro tutti i loop del Chunk + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nChunk) ; ++ nL) { + // recupero il loop + PtrOwner pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nChunk, nL))) ; + if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) + return false ; + // scorro le curve semplici + int nCurrProp = TEMP_PROP_INVALID ; + for ( int nU = 0 ; nU < pCrvLoop->GetCurveCount() ; ++ nU) { + bAllClose = ( pCrvLoop->GetCurveTempProp( nU, nCurrProp, 0) && + nCurrProp == TEMP_PROP_CLOSE_EDGE) ; + if ( ! bAllClose) + return true ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +IsSfrAllClosed( const ISurfFlatRegion* pSfr, bool& bAllClose) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + bAllClose = true ; + + // ciclo sui Chunk della regione + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { + if ( ! IsChunkAllClosed( pSfr, nC, bAllClose)) + return false ; + if ( ! bAllClose) + return true ; } return true ; @@ -856,10 +951,9 @@ GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCo if ( ! pCrv->GetLength( dLen)) return false ; double dSubArc = -1 ; - if ( pCrv->GetType() == CRV_ARC) { - if ( ! GetCoeffLinArc( GetCurveArc( pCrv), dDiam, dSubArc)) - return false ; - } + if ( pCrv->GetType() == CRV_ARC) + GetCoeffLinArc( GetCurveArc( pCrv), dDiam, dSubArc) ; + double dDiv = dSubArc < 0 ? dDiam : dSubArc ; double dMaxInt = floor( dLen / dDiv) ; @@ -946,116 +1040,61 @@ GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCo return false ; } -//---------------------------------------------------- -static bool -ComputeTrapezoidSpiralLeadInLeadOut( ICurveComposite* pCompo, const Vector3d& vtMainDir, bool bLeadIn, - const PocketParams& PockParams, bool& bIsOutsideRaw) -{ - // inizializzazione come interno al grezzo - bIsOutsideRaw = false ; - Point3d ptP ; - Vector3d vtDir ; - if ( bLeadIn) { - pCompo->GetStartPoint( ptP) ; - pCompo->GetStartDir( vtDir) ; - } - else { - pCompo->GetEndPoint( ptP) ; - pCompo->GetEndDir( vtDir) ; - } - - // recupero estrusione della curva - Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; - - // recupero info sui lati aperti - int nPropOpen = pCompo->GetTempProp( 0) ; - bool bEdgeOpen = (( nPropOpen & ( bLeadIn ? 8 : 2)) > 0) ; - bool bBase0Open = (( nPropOpen & 1) > 0) ; - bool bBase1Open = (( nPropOpen & 4) > 0) ; - - // recupero info per capire se sto considerando un lato aggiuntivo per pulire angoli - int nIdCrv = ( bLeadIn ? 0 : pCompo->GetCurveCount() - 1) ; - int nExtraEdge ; - pCompo->GetCurveTempProp( nIdCrv, nExtraEdge) ; - - // tento con allungamento se lato inclinato è aperto oppure se sto considerando un lato aggiuntivo per pulire angoli - if ( bEdgeOpen || nExtraEdge == 1) { - - Vector3d vtDirP = ( bLeadIn ? -vtDir : vtDir) ; - Point3d ptNewStart = ptP + vtDirP * ( PockParams.dRad + PockParams.dOpenMinSafe) ; - pCompo->AddLine( ptNewStart, ! bLeadIn) ; - pCompo->SetCurveTempProp( bLeadIn ? 0 : pCompo->GetCurveCount() - 1, 2) ; - bIsOutsideRaw = true ; - } - // tento con attacco ruotato di 90° se non sto considerando un tratto aggiuntivo per pulire angoli - else if (( bBase0Open || bBase1Open) && ! bIsOutsideRaw && nExtraEdge == 0) { - - Vector3d vtDirO = bBase0Open ? vtDir : - vtDir ; - vtDirO.Rotate( vtExtr, ( PockParams.bInvert ? -90 : 90)) ; - - // se vicino al bordo del grezzo - Point3d ptNewStart = ptP + vtDirO * ( PockParams.dRad + PockParams.dOpenMinSafe) ; - pCompo->AddLine( ptNewStart, ! bLeadIn) ; - pCompo->SetCurveTempProp( bLeadIn ? 0 : pCompo->GetCurveCount() - 1, 2) ; - bIsOutsideRaw = true ; - } - - return true ; -} - -//---------------------------------------------------- -static bool -AdjustTrapezoidSpiralForLeadInLeadOut( ICurveComposite* pCompo, const PocketParams& PockParams) -{ - // recupero la direzione principale della svuotatura - Vector3d vtMainDir ; - for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) { - int nProp ; - if ( pCompo->GetCurveTempProp( i, nProp) && nProp == 0) { - // se non è lato aggiuntivo per la pulitura angoli recupero la sua direzione - pCompo->GetCurve( i)->GetStartDir( vtMainDir) ; - break ; - } - } - - // start point - bool bStartOutside = false ; - ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, true, PockParams, bStartOutside) ; - // end point - bool bEndOutside = false ; - ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, false, PockParams, bEndOutside) ; - - // eventuale inversione della curva per partire sempre dall'esterno del grezzo - if ( bEndOutside && ! bStartOutside) - pCompo->Invert() ; - - return true ; -} - //---------------------------------------------------------------------------- static bool -ExtendPathOnOpenEdge( ICurveComposite* pCrvPath, const PocketParams& PockParams, const Vector3d& vtN, - Vector3d& vtMidOut, bool bEndOrStart) +ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams, + Vector3d& vtFirstOut, bool bEndOrStart, bool& bOkExtended) { + /* + Estensione della curva pCompo con un segmento lineare. + bEndOrStart: definisce se la curva va estesa all'inizio o alla fine + vtFirstOut: prima direzione su cui tentare l'entrata, se questa non andasse bene + ruoto progressivamente di 90° + La curva viene estesa di un tratto lineare in direzione vtRotOut per una lunghezza + pari a Rad + OffsR + OpenMinSafe. + */ + // controllo dei parametri - if ( pCrvPath == nullptr || ! pCrvPath->IsValid()) + if ( pCompo == nullptr || ! pCompo->IsValid() || + pSfr == nullptr || ! pSfr->IsValid()) return false ; - // recupero il punto iniziale della curva - Point3d ptMidOpen ; + bOkExtended = false ; + + // recupero il punto iniziale/finale della curva + Point3d pt ; if ( bEndOrStart) { - if ( ! pCrvPath->GetEndPoint( ptMidOpen)) + if ( ! pCompo->GetEndPoint( pt)) return false ; } else { - if ( ! pCrvPath->GetStartPoint( ptMidOpen)) + if ( ! pCompo->GetStartPoint( pt)) return false ; } - // calcolo il punto fuori - Point3d ptOut = ptMidOpen + vtMidOut * ( PockParams.dRad + PockParams.dOpenMinSafe) ; - // aggiungo al ritorno l'uscita - pCrvPath->AddLine( ptOut, bEndOrStart) ; - pCrvPath->SetCurveTempProp( ( bEndOrStart ? pCrvPath->GetCurveCount() - 1 : 0), TMP_PROP_CRV_OPEN_SIDE, 0) ; // nProp 2 per le curve LeadIn/Out - pCrvPath->SetCurveTempParam( ( bEndOrStart ? pCrvPath->GetCurveCount() - 1 : 0), GetMinFeed( PockParams) , 0) ; // Feed minima + + // ruoto il versore di uscita cercando un'entrata valida + 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 ; + } + vtRotOut.Rotate( Z_AX, - ANG_RIGHT) ; + } return true ; } @@ -1255,8 +1294,9 @@ GetHomogeneousParts( ICurveComposite* pCrvCompo, const PocketParams& PockParams, //--------------------------------------------------------------------------- static bool -CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, const Vector3d& vtTanE_, - const double dRad, ISurfFlatRegion* pSfrInc) +CreateSurfFrIncidence( const ICurveComposite* pCrv, const PocketParams& PockParams, + const Vector3d& vtTanS_, const Vector3d& vtTanE_, const double dRad, + ISurfFlatRegion* pSfrInc) { // controllo dei parametri if ( pCrv == nullptr || ! pCrv->IsValid()) @@ -1276,7 +1316,7 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, con OffsetCurve OffsCrv ; PtrOwner pOffsExt( CreateCurveComposite()) ; if ( IsNull( pOffsExt) || - ! OffsCrv.Make( pCrv, dRad, ICurve::OFF_FILLET) || + ! OffsCrv.Make( pCrv, dRad, PockParams.nOffsType) || ! pOffsExt.Set( OffsCrv.GetLongerCurve()) || IsNull( pOffsExt)) return false ; @@ -1285,7 +1325,7 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, con PtrOwner pOffsInt( CreateCurveComposite()) ; if ( IsNull( pOffsInt)) return false ; - if ( OffsCrv.Make( pCrv, - dRad, ICurve::OFF_FILLET)) { + if ( OffsCrv.Make( pCrv, - dRad, PockParams.nOffsType)) { PtrOwner pMyCrv( OffsCrv.GetLongerCurve()) ; if ( ! IsNull( pMyCrv) && pMyCrv->IsValid()) pOffsInt.Set( pMyCrv) ; @@ -1360,7 +1400,7 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI // definisco la regione di incidenza PtrOwner pSfrInc( CreateSurfFlatRegion()) ; if ( IsNull( pSfrInc) || - ! CreateSurfFrIncidence( pCrvBorder, vtTanS, vtTanE, dRad + 75 * EPS_SMALL, pSfrInc)) + ! CreateSurfFrIncidence( pCrvBorder, PockParams, vtTanS, vtTanE, dRad + 75 * EPS_SMALL, pSfrInc)) return false ; // creo un vettore con tutte le curve che potrebbero cadere, in parte, nella regione di incidenza @@ -1400,13 +1440,15 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI continue ; // 4) effettuo l'Offset della curva di metà dDiamJ OffsetCurve OffsCrv ; - if ( ! OffsCrv.Make( vpCrvs[cl], - dDiamJ * 0.5 - 20 * EPS_SMALL, ICurve::OFF_FILLET)) + if ( ! OffsCrv.Make( vpCrvs[cl], - dDiamJ * 0.5 - 20 * EPS_SMALL, PockParams.nOffsType)) return false ; // 5) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; while ( ! IsNull( pOffLongestCrv)) { // 6) creo la regione di incidenza di tale curva ( "Curva a fagiolo") - PtrOwner pSfrBean( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrv), dDiamJ * 0.5, false, false)) ; + bool bSquareEnds = ( PockParams.nOffsType == ICurve::OFF_CHAMFER) ; + bool bSquareMids = ( PockParams.nOffsType == ICurve::OFF_CHAMFER) ; + PtrOwner pSfrBean( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrv), dDiamJ * 0.5, bSquareEnds, bSquareMids)) ; if ( IsNull( pSfrBean) || ! pSfrBean->IsValid()) return false ; // inverto se necessario @@ -1605,6 +1647,14 @@ AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvI double dRad = dOutEdge + dOffR ; if ( abs( PockParams.dOpenEdgeRad) > 0 && PockParams.dOpenEdgeRad < dRad) dRad = PockParams.dOpenEdgeRad ; + // se lavorazione ZigZag/OneWay con richiesta di curve di Bordo, gli aperti vanno leggermente allargati + if ( PockParams.bAllowZigZagOneWayBorders && + ( PockParams.nType == POCKET_ZIGZAG || PockParams.nType == POCKET_ONEWAY)) + dRad += PockParams.dOffsExtra ; + // se lavorazione a ZigZag con smusso, esco di Step/2 per pulire gli aperti + if ( PockParams.nType == POCKET_ZIGZAG && PockParams.bSmooth) + dRad += max( PockParams.dSideStep / 2, PockParams.dRad / 8) ; + // ricavo i tratti omogenei ICRVCOMPOPOVECTOR vpCrvs ; @@ -1739,103 +1789,85 @@ ChainCompoCurves( ICRVCOMPOPOVECTOR& vCrvCompo) //---------------------------------------------------------------------------- static bool -AdjustOpenCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const PocketParams& PockParams) +AdvanceExtendCurves( ICRVCOMPOPOVECTOR& vCrvCompo, const ISurfFlatRegion* pSfr, const PocketParams& PockParams) { - /* - sistemazione punto di inizio, segmento per LeadIn, e Feed - ( Se la curva è chiusa, allora si può cambiare il punto d'inizio) - */ + + // se non ho curve, allora non faccio nulla + if ( vCrvCompo.empty()) + return true ; // controllo validità delle curve for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) if ( IsNull( vCrvCompo[i]) || ! vCrvCompo[i]->IsValid()) return false ; - // recupero la superficie limite ( se esiste ed è valida) - PtrOwner pSfrLimit( CreateSurfFlatRegion()) ; - if ( IsNull( pSfrLimit)) - return false ; - if ( PockParams.SfrLimit.IsValid()) { // se esiste, allora classifico - // recupero la superficie limite - pSfrLimit.Set( PockParams.SfrLimit.Clone()) ; - if ( IsNull( pSfrLimit) || ! pSfrLimit->IsValid()) - return false ; - // effettuo un Offset della regione, tutto ciò che dista più del raggio utensile non la rovina - pSfrLimit->Offset( PockParams.dRad - 250 * EPS_SMALL, ICurve::OFF_FILLET) ; // c'è un offset radiale, quindi tengo tolleranza alta - } + /* + L'estensione della curva permettendo un'entrata da fuori è valida se il + nuovo punto di Inizio ( ptFall) : + - E' al di fuori della superficie Limite ( di almeno Rad + OffsR) + - E' al di fuori della superifice di svuotatura ( di almeno dRad + OffsR) + */ - // per ogni curva signola, aggiungo l'entrata da fuori se ammissibile + // scorro ogni singola curva composita 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) ; + } + + + // calcolo il numero massimo di punti in cui testare l'entrata da fuori int nMaxIter = ( vCrvCompo[i]->IsClosed() ? 4 : 1) ; double dLen = EPS_SMALL ; if ( nMaxIter == 4) 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) - vCrvCompo[i]->ChangeStartPoint( dLen / nMaxIter) ; - - // ricavo punto di inizio e vettore tangente - Point3d ptStart ; vCrvCompo[i]->GetStartPoint( ptStart) ; - Vector3d vtStart ; vCrvCompo[i]->GetStartDir( vtStart) ; - // recupero il punto di caduta dell'utensile - Point3d ptFall = ptStart - vtStart * ( 2 * PockParams.dRad + PockParams.dOpenMinSafe) ; - // controllo che il tool non sia interno alla regione limite - bool bAllowLeadIn = ( ! pSfrLimit->IsValid()) ; - if ( ! bAllowLeadIn) { - // calcolo l'ombra del tool centrata in ptFall - PtrOwner pCrvToolShape( CreateCurveArc()) ; - if ( IsNull( pCrvToolShape) || ! pCrvToolShape->Set( ptFall, Z_AX, PockParams.dRad - 100 * EPS_SMALL)) + if ( j > 0) { + double dParAtLen = EPS_SMALL ; + vCrvCompo[i]->GetParamAtLength( dLen / nMaxIter, dParAtLen) ; + vCrvCompo[i]->ChangeStartPoint( dParAtLen) ; + } + // ricavo vettore tangente iniziale e cerco di 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()) { + // ricavo vettore tangente finale e provo ad estendere + Vector3d vtEnd ; vCrvCompo[i]->GetEndDir( vtEnd) ; + bool bIsEndExtended = false ; + if ( ! ExtendPath( vCrvCompo[i], pSfr, PockParams, vtEnd, true, bIsEndExtended)) return false ; - CRVCVECTOR ccClass ; - bAllowLeadIn = ( pSfrLimit->GetCurveClassification( *pCrvToolShape, EPS_SMALL, ccClass) && - int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; - // se esiste intersezione con la limite Offsettata, provo a ruotare di 90° il tratto lineare - if ( ! bAllowLeadIn) { - vtStart.Rotate( Z_AX, PockParams.bInvert ? - ANG_RIGHT : ANG_RIGHT) ; - ptFall = ptStart + vtStart * ( 2 * PockParams.dRad + PockParams.dOpenMinSafe) ; - if ( ! pCrvToolShape->Set( ptFall, Z_AX, PockParams.dRad - 100 * EPS_SMALL)) - return false ; - ccClass.clear() ; - bAllowLeadIn = ( pSfrLimit->GetCurveClassification( *pCrvToolShape, EPS_SMALL, ccClass) && - int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; - } - } - if ( bAllowLeadIn) { // se ammessa entrata da fuori - vCrvCompo[i]->AddLine( ptFall, false) ; - vCrvCompo[i]->SetCurveTempProp( 0, TMP_PROP_CRV_OPEN_SIDE, 0) ; // nProp 2 per le curve LeadIn/Out - vCrvCompo[i]->SetCurveTempParam( 0, GetMinFeed( PockParams) , 0) ; // Feed massima - break ; // interrompo a prescindere l'iterazione per i punti iniziali + if ( bIsEndExtended) + break ; } + if ( bIsStartExtended) + break ; } } - // imposto le Feed per tali curve - for ( int i = 0 ; i < int( vCrvCompo.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 = vCrvCompo[i]->GetTempParam( 0) ; - // calcolo la Feed proporzionale a tale Offset - double dFeed ; - GetFeedForParam( 2 * dMaxOffs, PockParams, dFeed) ; - AssignCustomFeed( vCrvCompo[i], PockParams, dFeed) ; - // imposto il flag di curva singola - vCrvCompo[i]->SetTempProp( TMP_PROP_SINGLE_CURVE, 0) ; //nProp per curva singola - } - return true ; } //---------------------------------------------------------------------------- static bool -GetPocketCurvesByCloseEdges( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParams, +GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, bool& bAllRemoved) { // controllo parametri @@ -1919,7 +1951,6 @@ GetPocketCurvesByCloseEdges( const ISurfFlatRegion* pSfrChunk, const PocketParam 1) La curva esterna e mista e non ho isole ( ho già il percorso) 2) La curva esterna è tutta aperta e le isole sono tutte chiuse 3) La curva esterna è tutta chiusa e ho una sola isola aperta ( ho già il percorso) - */ // 1) @@ -2017,7 +2048,7 @@ GetPocketCurvesByCloseEdges( const ISurfFlatRegion* pSfrChunk, const PocketParam //---------------------------------------------------------------------------- static bool -ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, +ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes, bool& bSkipPocket) { // controllo parametri : @@ -2025,6 +2056,13 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, IC return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati bSkipPocket = false ; + // controllo se esistono dei lati aperti + if ( ! IsSfrAllClosed( pSfr, PockParams.bAllClosed)) + return false ; + // se lati tutti chiusi, allora non devo fare nulla + if ( PockParams.bAllClosed) + return true ; + // NB. Tutti i Loop che presentano dei lati aperti possono essere estesi ; sia per loop esterni che per isole... // I lati aperti vanno estesi seguendo lo geometria dei lati chiusi adiacenti e tenendo conto delle isole chiuse // vicine ad essi @@ -2034,133 +2072,146 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, IC if ( IsNull( pSrfFinal)) return false ; - int nChunkOneCurve = 0 ; // numero di chunk rimovibili mediante una sola curva di Offset - int nChunk = pSfr->GetChunkCount() ; // numero complessivo di Chunk da svuotare + // 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 c = 0 ; c < nChunk ; ++ c) { + for ( int nC = 0 ; nC < nChunk ; ++ nC) { - // 0) controllo se seguendo i chiusi posso svuotare l'interno chunk + // controllo se seguendo i chiusi posso svuotare l'interno chunk /* - nel caso in cui il chunk c-esimo può essere svuotata da una o più curve che seguono + 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( c)) ; + PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; bool bIsAllRemoved = false ; - GetPocketCurvesByCloseEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; - if ( bIsAllRemoved) { // se ho rimosso tutto, allora passo la chunk successivo - ++ nChunkOneCurve ; // aumento il contatore - continue ; // ignoro il chunk c-esimo + GetPocketCurvesByClosedEdges( pSfrChunk, PockParams, vCrvCompoRes, bIsAllRemoved) ; + if ( bIsAllRemoved) { + // se ho rimosso tutto, allora passo la chunk successivo + ++ nChunkOneCurve ; + continue ; } + // controllo se la lavorazione ammatte estensione da aperti + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) + continue ; // vettore delle isole che userò ( le isole aperte piccole sono trascurate) ICRVCOMPOPOVECTOR vCrvToTIsland ; - // Flag per sapere se c'è stata almeno una modifica in un loop + // flag per sapere se c'è stata almeno una modifica in un loop del Chunk nC-esimo bool bIsChunkModified = false ; - // 1) ricavo il Loop esterno - PtrOwner pCrvEL( ConvertCurveToComposite( pSfr->GetLoop( c, 0))) ; + // ricavo il Loop esterno ( External Loop) + PtrOwner pCrvEL( ConvertCurveToComposite( pSfr->GetLoop( nC, 0))) ; if ( IsNull( pCrvEL) || ! pCrvEL->IsValid()) return false ; - // 2) creo un vettore di curve con le isole del Chunk + // creo un vettore di curve con le isole del Chunk ( Internal Loops) ICRVCOMPOPOVECTOR vCrvIsl ; - for ( int l = 1 ; l < pSfr->GetLoopCount( c) ; ++ l) { - PtrOwner pCrvIL( ConvertCurveToComposite( pSfr->GetLoop( c, l))) ; + for ( int nL = 1 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { + PtrOwner pCrvIL( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCrvIL) || ! pCrvIL->IsValid()) return false ; vCrvIsl.emplace_back( Release( pCrvIL)) ; } - // 3) se la curva esterna presenta dei lati aperti -> devo modificarla + // se la curva esterna presenta dei lati aperti -> devo modificarla bool bSomeOpen = false ; - int nProp0 = -1 ; + int nProp0 = TEMP_PROP_INVALID ; for ( int u = 0 ; u < pCrvEL->GetCurveCount() && ! bSomeOpen ; ++ u) - if ( pCrvEL->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) - bSomeOpen = true ; - if ( bSomeOpen) { // se trovo dei lati aperti - // 3.1) sistemo la superificie + 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)) return false ; - bIsChunkModified = true ; // la curva è stata modificata + bIsChunkModified = true ; } - // 4) Controllo i bordi delle isole ottenute - // NB. L'isola può essere tutta aperta o tutta chiusa ( se non uniforme, passo a tutta chiusa ) + // controllo i bordi delle isole ottenute + // NB. L'isola può essere tutta aperta o tutta chiusa ( se non uniforme, passo a tutta chiusa) // La definizione di isola con proprietà non uniformi non è definita... - for ( int i = 0 ; i < int( vCrvIsl.size()) ; ++ i) { + for ( int nI = 0 ; nI < int( vCrvIsl.size()) ; ++ nI) { // controllo uniformità - int nCurrTmpProp = -1 ; - int nPrecTmpProp = -1 ; + int nCurrTmpProp = TEMP_PROP_INVALID ; + int nPrecTmpProp = TEMP_PROP_INVALID ; bool bIsMixed = false ; - PtrOwner pCrvIsl( vCrvIsl[i]->Clone()) ; + PtrOwner pCrvIsl( CloneCurveComposite( vCrvIsl[nI])) ; if ( IsNull( pCrvIsl) || ! pCrvIsl->IsValid()) return false ; - for ( int u = 0 ; u < pCrvIsl->GetCurveCount() && ! bIsMixed ; ++ u) { - pCrvIsl->GetCurveTempProp( u, nCurrTmpProp, 0) ; - bIsMixed = ( u != 0 && nCurrTmpProp != nPrecTmpProp) ; + for ( int nU = 0 ; nU < pCrvIsl->GetCurveCount() && ! bIsMixed ; ++ nU) { + pCrvIsl->GetCurveTempProp( nU, nCurrTmpProp, 0) ; + bIsMixed = ( nU != 0 && nCurrTmpProp != nPrecTmpProp) ; nPrecTmpProp = nCurrTmpProp ; } // se proprità non uniformi -> tutta chiusa if ( bIsMixed) { - for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) - pCrvIsl->SetTempProp( u, 0) ; - nCurrTmpProp = 0 ; // aggiorno il Flag - bIsChunkModified = true ; // la curva è stata modificata + for ( int nU = 0 ; nU < pCrvIsl->GetCurveCount() ; ++ nU) + pCrvIsl->SetTempProp( nU, TEMP_PROP_CLOSE_EDGE) ; + nCurrTmpProp = TEMP_PROP_CLOSE_EDGE ; + bIsChunkModified = true ; } // se curva tutta aperta, controllo se l'isola può essere trascurata - if ( nCurrTmpProp == 1) { + if ( nCurrTmpProp == TEMP_PROP_OPEN_EDGE) { // calcolo il massimo Offset double dMaxOffs ; CalcCurveLimitOffset( *pCrvIsl, dMaxOffs) ; + // se l'isola è trascurabile passo alla successiva if ( dMaxOffs < 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) continue ; - // altrimenti, estendo l'isola aperta ( considero il loop esterno come "isola" per l'estensione) - ICRVCOMPOPOVECTOR vCrvExtLoop ; vCrvExtLoop.emplace_back( pCrvEL->Clone()) ; - if ( ! AdjustContourWithOpenEdges( pCrvIsl, vCrvExtLoop, PockParams)) + // altrimenti, estendo l'isola aperta + ICRVCOMPOPOVECTOR vCrvOther ; + vCrvOther.emplace_back( pCrvEL->Clone()) ; + for ( int nII = 0 ; nII < int( vCrvIsl.size()) ; ++ nII) { + if ( nII != nI) + vCrvOther.emplace_back( vCrvIsl[nII]->Clone()) ; + } + if ( ! AdjustContourWithOpenEdges( pCrvIsl, vCrvOther, PockParams)) return false ; bIsChunkModified = true ; } - vCrvToTIsland.emplace_back( pCrvIsl->Clone()) ; // entra nelle curve della regione da svuotare + // conservo l'isola ( estesa o meno) + vCrvToTIsland.emplace_back( pCrvIsl->Clone()) ; } - // 6) Se c'è stata almeno una modifica di lato aperto al chunk (c-esimo), devo ricreare il Chunk - // nuovi loop ricavati ( Chunk dopo Chunk creo la superficie finale) + // 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) { - - SurfFlatRegionByContours SfrBC ; // per sicurezza analizzo ancora i Loop + /* + l'estensione degli aperti, può unire il loop esterno con il loop delle sue isole. + Creo una nuova regione dai nuovi contorni ottenuti + */ + SurfFlatRegionByContours SfrBC ; + // loop Esterno pCrvEL->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; - SfrBC.AddCurve( Release( pCrvEL)) ; // <--- Loop esterno - for ( int i = 0 ; i < int( vCrvToTIsland.size()) ; ++ i) { - vCrvToTIsland[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; - SfrBC.AddCurve( Release( vCrvToTIsland[i])) ; // <--- isole "valide" + SfrBC.AddCurve( Release( pCrvEL)) ; + // isole non trascurate + for ( int nI = 0 ; nI < int( vCrvToTIsland.size()) ; ++ nI) { + vCrvToTIsland[nI]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + SfrBC.AddCurve( Release( vCrvToTIsland[nI])) ; } - - // ricavo il nuovo Chunk + // ricavo il nuovo Chunk nC-esimo esteso presso i lati aperti PtrOwner pNewChunk( SfrBC.GetSurf()) ; if ( IsNull( pNewChunk) || ! pNewChunk->IsValid()) return false ; - - // aggiungo il Chunk alla superficie finale + // aggiungo il Chunk nC-esimo alla superficie finale if ( pSrfFinal->GetChunkCount() == 0) pSrfFinal.Set( pNewChunk) ; - else - if ( ! pSrfFinal->Add( *pNewChunk)) - return false ; + else if ( ! pSrfFinal->Add( *pNewChunk)) + return false ; } - // se il Chunk c-esimo non è mai stato modificato... + // se il Chunk c-esimo non è mai stato modificato else { // aggiungo il Chunk alla superficie finale if ( pSrfFinal->GetChunkCount() == 0) - pSrfFinal.Set( pSfr->CloneChunk( c)) ; - else { - PtrOwner pSfrToAdd( pSfr->CloneChunk( c)) ; - if ( IsNull( pSfrToAdd) || ! pSrfFinal->Add( *pSfrToAdd)) - return false ; - } + pSrfFinal.Set( pSfrChunk) ; + else if ( ! pSrfFinal->Add( *pSfrChunk)) + return false ; } } @@ -2169,23 +2220,39 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, IC // potrei doverle riconcatenare if ( ! ChainCompoCurves( vCrvCompoRes)) return false ; - // determino ora il punto di inizio, il tratto per il LeadIn e la Feed delle curve singole - if ( ! AdjustOpenCurves( vCrvCompoRes, PockParams)) + // estendo le curve, calcolando anche 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 + */ - // se ho rimosso tutti i Chunk con una singola curva... + // 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 - if ( ! pSrfFinal->IsValid()) - return false ; - pSfr->Clear() ; - pSfr->CopyFrom( pSrfFinal) ; - - return ( pSrfFinal->IsValid() && pSrfFinal->GetChunkCount() > 0) ; - + if ( PockParams.nType != POCKET_CONFORMAL_ZIGZAG) { + if ( ! pSrfFinal->IsValid()) + return false ; + pSfr->Clear() ; + pSfr->CopyFrom( pSrfFinal) ; + } + return ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) ; } // *************************************************************************** @@ -2196,7 +2263,7 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, const PocketParams& PockParams, IC //---------------------------------------------------------------------------- static bool GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOtherCrv, - const Frame3d& frPocket, const PocketParams& PockParams, Point3d& ptMid, Vector3d& vtMidOrt) + const PocketParams& PockParams, Point3d& ptMid, Vector3d& vtMidOrt) { // recupero il vettore estrusione Vector3d vtExtr = Z_AX ; @@ -2293,14 +2360,6 @@ GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOth ptFirstOpenValid = ptMid ; vtFirstOpenValid = vtMidOrt ; } - // controllo se questa quantità è effettivamente fuori dal grezzo - // ( privilegio i lati aperti che sono effettivamente sul bordo del grezzo) - // punto iniziale nel sistema di riferimento globale - Point3d ptStart ; pCompoClone->GetStartPoint( ptStart) ; - ptStart.ToGlob( frPocket) ; - // vettore d'uscita nel sistema di riferimento globale - Vector3d vtMidOut = vtMidOrt ; - vtMidOut.ToGlob( frPocket) ; } } dLenPrev = dLen ; @@ -2326,13 +2385,12 @@ GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOth //---------------------------------------------------------------------------- static bool -SetSpecialPtStartForOpenEdges( const ICurveComposite* pCrvOrig, const Frame3d& frPocket, - const PocketParams& PockParams, ICurveComposite* pCrvCompo, Point3d& ptStart, +SetSpecialPtStartForOpenEdges( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, + ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) { // controllo dei parametri if ( pCrvOrig == nullptr || ! pCrvOrig->IsValid() || - ! frPocket.IsValid() || pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; @@ -2466,8 +2524,8 @@ AssignOpenCloseTmpPropToFirstOffsCurve( ICurveComposite* pCrv, const PocketParam //---------------------------------------------------------------------------- static bool SetPtStartForPath( ICurveComposite* pCrvOffsAct, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, - const Point3d& ptEndPrec, const Frame3d& frPocket, Point3d& ptStart, - Vector3d& vtMidOut, bool& bMidOut, int nOffs, const ICurveComposite* pCrvOrig) + const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut, + int nOffs, const ICurveComposite* pCrvOrig) { // ============================= INFO ============================================================== // pCrvOffsAct -> Curva di Offset su cui cercare ptStart, vtMidOut, bMidOpen @@ -2585,10 +2643,10 @@ SetPtStartForPath( ICurveComposite* pCrvOffsAct, const PocketParams& PockParams, if ( nOffs == 1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { // in questo caso le curve a fagiolo dei lati aperti a sinistra e a destra potrebbero // intersecarsi tra loro -> risulta difficile calcolare il versore direzione d'uscita - bOK = SetSpecialPtStartForOpenEdges( pCrvOrig, frPocket, PockParams, pCrv, ptStart, vtMidOut, bMidOut) ; + bOK = SetSpecialPtStartForOpenEdges( pCrvOrig, PockParams, pCrv, ptStart, vtMidOut, bMidOut) ; } if ( ! bOK) /* ( 2.2 ) */ - bMidOut = GetParamOnOpenSide( pCrv, vOtherCrv, frPocket, PockParams, ptStart, vtMidOut) ; + 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 ; @@ -2612,9 +2670,8 @@ SetPtStartForPath( ICurveComposite* pCrvOffsAct, const PocketParams& PockParams, //---------------------------------------------------------------------------- static bool SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& PockParams, const ISurfFlatRegion* pSrfToWork, - const Point3d& ptEndPrec, const Frame3d& frPocket, Point3d& ptStart, - Vector3d& vtMidOut, bool& bMidOut, int& nIndex, int nOffs, - ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) + const Point3d& ptEndPrec, Point3d& ptStart, Vector3d& vtMidOut, + bool& bMidOut, int& nIndex, int nOffs, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops) { // controllo dei parametri for ( int i = 0 ; i < int( vCrvOffsAct.size()) ; ++ i) @@ -2632,9 +2689,8 @@ SetAdvancedPtStartForPath( ICRVCOMPOPOVECTOR& vCrvOffsAct, const PocketParams& P 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, frPocket, ptStart, - vtMidOut, bMidOut, nOffs, - ( int( vCrvOrigChunkLoops.size()) < i) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) + if ( SetPtStartForPath( vCrvOffsAct[i], PockParams, pSrfToWork, ptEndPrec, ptStart, vtMidOut, + bMidOut, nOffs, ( int( vCrvOrigChunkLoops.size()) < i) ? Get( vCrvOrigChunkLoops[i]) : nullptr)) vCrvOffsAct[i]->GetStartPoint( ptStart) ; else return false ; @@ -2683,7 +2739,7 @@ GetOptCrvIndex( const ISurfFlatRegion* pSfrOrig, const ISurfFlatRegion* pSfrChun // 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))) ; // sono inizializzate... + vCrvOrig.emplace_back( ConvertCurveToComposite( pSfrOrig->GetLoop( 0, l))) ; if ( pSfrOrig->GetChunkCount() == 1) return true ; @@ -3134,7 +3190,12 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr // se la curva è già un trapezio, non sempre devo adattarla... Point3d pt ; Vector3d vtDir, vtB2, vtOtherDir ; if ( pCrvCompo->IsATrapezoid( 100 * EPS_SMALL, pt, vtDir, vtOtherDir, vtB2)) { - pCrvTrap->AddCurve( pCrvCompo->Clone()) ; + // data la tolleranza, creo la curva a trapezio dai 4 punti + pCrvTrap->AddPoint( pt) ; + pCrvTrap->AddLine( pt + vtDir) ; + pCrvTrap->AddLine( pt + vtOtherDir + vtB2) ; + pCrvTrap->AddLine( pt + vtOtherDir) ; + pCrvTrap->Close() ; // se parallelogramma scelgo come base i lati lunghi Vector3d vtL2( - vtDir + vtOtherDir + vtB2) ; if ( AreSameOrOppositeVectorApprox( vtOtherDir, vtL2)) { @@ -3144,13 +3205,6 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr vtDir.Normalize() ; Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ; dPocketSize = vtOrtho.Len() ; - // eventuale approssimazione della curva con polyline per ottenere la stessa curva calcolata in ICurveComposite::IsATrapezoid - if ( pCrvCompo->GetCurveCount() > 4) { - PolyLine PL ; - if ( ! pCrvCompo->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) - return false ; - pCrvTrap->FromPolyLine( PL) ; - } if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap)) return false ; bool bBaseOpen = false ; @@ -5970,8 +6024,8 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con //---------------------------------------------------------------------------- static bool -CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, const int nOffsCount, - const int nIter, const Vector3d& vtN, const PocketParams& PockParams, bool& bInsert) +CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, + const int nIter, const PocketParams& PockParams, bool& bInsert) { // controllo dei parametri @@ -5984,73 +6038,552 @@ CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, c return true ; if ( nIter != 0) { // controllo se sono almeno al secondo offset... - - // per ogni curva controllo se il controOffset + 5 * EPS_SMALL genera una regione ... - OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad - if ( OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) { - // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive - if ( OffsCrv.GetCurveCount() == 0) { - bInsert = false ; - return true ; - } - } - else - return true ; - - // controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis - if ( ! PockParams.bOptOffsetsAdv || OffsCrv.GetCurveCount() > 1) - return true ; - - PtrOwner pCrvOffLonger( OffsCrv.GetLongerCurve()) ; - if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid()) - return true ; - - // Immagine del tool con centro nel centroide della zona da svuotare - Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ; - PtrOwner pCrvTool( CreateCurveArc()) ; - if( IsNull( pCrvTool)) + // per ogni curva controllo se il suo Offset massimo non genera alcuna regione + double dMaxOffs ; + if ( ! CalcCurveLimitOffset( *pCrvOffs, dMaxOffs)) return false ; - pCrvTool->SetXY( ptC, PockParams.dRad - 5 * EPS_SMALL) ; - - CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ; - intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ; - if ( int(ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) { - // centroide + // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive + if ( dMaxOffs < PockParams.dRad - dOffs + 5 * EPS_SMALL) { bInsert = false ; return true ; } + } + else + return true ; - // recupero la PolyLine per altezza e lunghezza del Box2D ( rettangolo) - PolyLine pl ; - if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl)) - return true ; - Vector3d vtX ; - double dLen = 0 ; double dHeight = 0 ; - if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight)) - return true ; + // se non richiesto percorso avanzato + if ( ! PockParams.bOptOffsetsAdv) + return true ; - // frame locale, recupero DimX e DimY - Frame3d frLoc ; frLoc.Set( ptC, vtN, vtX) ; - if ( ! frLoc.IsValid()) - return true ; - BBox3d bBox ; - frLoc.Invert() ; - pCrvOffLonger->GetBBox( frLoc, bBox) ; - double dDimX = bBox.GetDimX() ; - double dDimY = bBox.GetDimY() ; + OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad + if ( ! OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) + return false ; - // se dimensioni accettabili, inserisco - if ( dDimX < 2 * PockParams.dRad - 100 * EPS_SMALL || - dDimY < 2 * 2 * PockParams.dRad - 100 * EPS_SMALL) { - bInsert = false ; - return true ; - } + // controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis + if ( OffsCrv.GetCurveCount() > 1) + return true ; + + PtrOwner pCrvOffLonger( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid()) + return true ; + + // Immagine del tool con centro nel centroide della zona da svuotare + Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ; + PtrOwner pCrvTool( CreateCurveArc()) ; + if( IsNull( pCrvTool)) + return false ; + pCrvTool->SetXY( ptC, PockParams.dRad - 5 * EPS_SMALL) ; + + CRVCVECTOR ccClass ; + IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ; + intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ; + if ( int(ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) { + // centroide + bInsert = false ; + return true ; + } + + // recupero la PolyLine per altezza e lunghezza del Box2D ( rettangolo) + PolyLine pl ; + if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl)) + return true ; + Vector3d vtX ; + double dLen = 0 ; double dHeight = 0 ; + if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight)) + return true ; + + // frame locale, recupero DimX e DimY + Frame3d frLoc ; frLoc.Set( ptC, Z_AX, vtX) ; + if ( ! frLoc.IsValid()) + return true ; + BBox3d bBox ; + frLoc.Invert() ; + pCrvOffLonger->GetBBox( frLoc, bBox) ; + double dDimX = bBox.GetDimX() ; + double dDimY = bBox.GetDimY() ; + + // se dimensioni accettabili, inserisco + if ( dDimX < 2 * PockParams.dRad - 100 * EPS_SMALL || + dDimY < 2 * 2 * PockParams.dRad - 100 * EPS_SMALL) { + bInsert = false ; + return true ; } return true ; } +//---------------------------------------------------------------------------- +static bool +ExtendGuideByIteration( ICurveComposite* pCompoTempGuide, const ICurveComposite* pCompoPerimeter, + bool bInverted) +{ + // controllo dei parametri + if ( pCompoTempGuide == nullptr || ! pCompoTempGuide->IsValid() || + pCompoPerimeter == nullptr || ! pCompoPerimeter->IsValid()) + return false ; + + const double EXTENSION_VAL = 1000. ; + + // ricavo il punto finale della guida + Point3d ptEndGuide ; pCompoTempGuide->GetEndPoint( ptEndGuide) ; + // direzione finale della guida + Vector3d vtEndGuide ; pCompoTempGuide->GetEndDir( vtEndGuide) ; + // creo un segmento diretto come il chiuso + PtrOwner pSeg( CreateCurveLine()) ; + if ( IsNull( pSeg) || + ! pSeg->Set( ptEndGuide, ptEndGuide + EXTENSION_VAL * vtEndGuide)) + return false ; + // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta + IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; + // se l'unica intersezione è il punto iniziale del segmento, allora non estendo la guida + // ( vale anche nel caso di intersezione con Overlap) + if ( ICC.GetIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) + return true ; + } + } + // passo alla PolyLine del perimetro + PolyLine PL ; + pCompoPerimeter->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, PL) ; + // cerco il punto più esterno rispetto alla direzione del chiuso + Point3d ptPoly ; + PL.GetFirstPoint( ptPoly) ; + while ( PL.GetNextPoint( ptPoly)) { + if ( ! pSeg->Set( ptEndGuide, ptEndGuide + ( ptPoly - ptEndGuide) * EXTENSION_VAL)) + return false ; + // calcolo l'intersezione tra questo segmento e la curva di perimetro aperta + IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ; + // se una intersezione, allora di Overlap con punto iniziale e finale definito + if ( ICC.GetIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + if ( aInfo.bOverlap) { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide) && + AreSamePointApprox( aInfo.IciB[1].ptI, ptPoly)) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + else { + if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide)) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + } + } + // se più di una intersezione, allora il perimetro deve essere tutto Interno al segmento + // ( Out nel caso in cui ho le curve invertite) + IntCrvCrvInfo aInfo ; + bool bOk = true ; + for ( int i = 0 ; i < ICC.GetIntersCount() && bOk ; ++ i) { + bOk = ( ICC.GetIntCrvCrvInfo( i, aInfo)) ; + bOk = ( aInfo.bOverlap || + ( aInfo.IciB[0].nPrevTy != ( ! bInverted ? CRVC_OUT : CRVC_IN) && + aInfo.IciB[0].nNextTy != ( ! bInverted ? CRVC_OUT : CRVC_IN))) ; + } + if ( bOk) + return ( pCompoTempGuide->AddLine( ptPoly)) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const PocketParams& PockParams, + bool& bOk, ICRVCOMPOPOVECTOR& vpCrvs) +{ + // controllo dei parametri + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + bOk = false ; + vpCrvs.clear() ; + + // clono la curva composita ( cambierà il suo punto iniziale) + PtrOwner pCompoCL( CloneCurveComposite( pCompo)) ; + if ( IsNull( pCompoCL) || ! pCompoCL->IsValid()) + return false ; + + // recupero i tratti con proprietà uniformi + GetHomogeneousParts( pCompoCL, PockParams, 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) ; + } + } + + // controlloo che la curva abbia esattamente due tratti omogenei + bOk = ( int( vpCrvs.size()) == 2) ; + if ( ! bOk) + vpCrvs.clear() ; + return true ; + +} + +//---------------------------------------------------------------------------- +static bool +CalcCrvGuideConformalZigZag( const ISurfFlatRegion* pSfrChunk, PocketParams& PockParams, ICurveComposite* pCompoGuide, + ICurveComposite* pCompoClass) +{ + // controllo dei parametri + if ( pCompoGuide == nullptr || pCompoClass == nullptr || + pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return false ; + pCompoGuide->Clear() ; + pCompoClass->Clear() ; + + // la superficie deve avere un Chunk e non avere isole + if ( pSfrChunk->GetChunkCount() > 1 || pSfrChunk->GetLoopCount( 0) > 1) + return true ; + + // ricavo la curva di bordo ( la curva che definisce il perimetro) + PtrOwner pCompoPerimeter( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; + if ( IsNull( pCompoPerimeter) || ! pCompoPerimeter->IsValid()) + return false ; + // controllo che sia formata da esattamente due tratti omogenei + bool b2HP = false ; + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs)) + return false ; + if ( ! b2HP) + return true ; + + // allargo curva di Bordo secondo le specifiche di una lavorazione a SpiralIn + double dRad = PockParams.dRad ; + int nOffsType = PockParams.nOffsType ; + PockParams.dRad = max( dRad / 8, PockParams.dSideStep / 2) ; + PockParams.nOffsType = ICurve::OFF_CHAMFER ; + ICRVCOMPOPOVECTOR vCrvEmpty ; + if ( ! AdjustContourWithOpenEdges( pCompoPerimeter, vCrvEmpty, PockParams)) + return false ; + PockParams.dRad = dRad ; + PockParams.nOffsType = nOffsType ; + + // reucupero ora i due tratti uniformi ( della curva allargata) + if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs) || + ! b2HP) + return false ; + + // la guida inizialmente è data dal tratto chiuso + // il perimetro coincide con il tratto aperto + PtrOwner pCompoTempGuide( Release( vpCrvs[0])) ; + if ( IsNull( pCompoTempGuide) || ! pCompoTempGuide->IsValid()) + return false ; + + // estendo la curva nel suo tratto finale ed iniziale + for ( int i = 0 ; i < 2 ; ++ i) { + if ( ! ExtendGuideByIteration( pCompoTempGuide, vpCrvs[1], ( i == 1))) + return false ; + // se la guida diventa diventa chiusa, allora esco + if ( ! pCompoTempGuide->IsValid() || pCompoTempGuide->IsClosed()) + return true ; + pCompoTempGuide->Invert() ; + vpCrvs[1]->Invert() ; + } + + // tratto iniziale + Vector3d vtStart ; pCompoTempGuide->GetStartDir( vtStart) ; + Point3d ptStart ; pCompoTempGuide->GetStartPoint( ptStart) ; + PtrOwner pLineStart( CreateCurveLine()) ; + if ( IsNull( pLineStart) || ! pLineStart->Set( ptStart - 1000. * vtStart, ptStart)) + return false ; + // tratto finale ( potrebbe intersecare il tratto iniziale) + Vector3d vtEnd ; pCompoTempGuide->GetEndDir( vtEnd) ; + Point3d ptEnd ; pCompoTempGuide->GetEndPoint( ptEnd) ; + PtrOwner pLineEnd( CreateCurveLine()) ; + if ( IsNull( pLineEnd) || ! pLineEnd->Set( ptEnd, ptEnd + 1000. * vtEnd)) + return false ; + IntersCurveCurve ICC( *pLineStart, *pLineEnd) ; + if ( ICC.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) { + pLineStart->TrimStartAtParam( aInfo.IciA[0].dU) ; + pLineEnd->TrimEndAtParam( aInfo.IciB[0].dU) ; + } + } + // le due estensioni vanno tagliate presso i bordi dei lati aperti estesi + IntersCurveCurve ICCLS( *pLineStart, *vpCrvs[1]) ; + if ( ICCLS.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + for ( int i = 0 ; i < ICCLS.GetCrossIntersCount() ; ++ i) { + if ( ICCLS.GetIntCrvCrvInfo( i, aInfo)) { + if ( ! AreSamePointApprox( aInfo.IciA[ aInfo.bOverlap ? 1 : 0].ptI, ptStart)) + pLineStart->ModifyStart( aInfo.IciA[aInfo.bOverlap ? 1 : 0].ptI) ; + } + } + } + IntersCurveCurve ICCLE( *pLineEnd, *vpCrvs[1]) ; + if ( ICCLE.GetIntersCount() > 0) { + IntCrvCrvInfo aInfo ; + for ( int i = 0 ; i < ICCLE.GetCrossIntersCount() ; ++ i) { + if ( ICCLE.GetIntCrvCrvInfo( 0, aInfo)) { + if ( ! AreSamePointApprox( aInfo.IciA[0].ptI, ptEnd)) + pLineEnd->ModifyEnd( aInfo.IciA[0].ptI) ; + } + } + } + pCompoTempGuide->AddCurve( Release( pLineStart), false) ; + pCompoTempGuide->AddCurve( Release( pLineEnd), true) ; + + // recupero la curva guida + pCompoGuide->CopyFrom( pCompoTempGuide) ; + + // recupero la curva di classificazione ( abballendola) + PolyLine PL ; + pCompoPerimeter->ApproxWithLines( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ; + PL.RemoveAlignedPoints( 500 * EPS_SMALL) ; + pCompoPerimeter->Clear() ; + pCompoPerimeter->FromPolyLine( PL) ; + pCompoPerimeter->RemoveSmallDefects( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, true) ; + pCompoPerimeter->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; + pCompoClass->CopyFrom( pCompoPerimeter) ; + ResetCurveTempProps( pCompoClass) ; + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddAddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvCompoRes) +{ + /* + Calcolo ottimizzato di svuotatura mediante Offset progressivi di una guida, raccordati + rispetto al bordo della superficie di Pocketing mediante logica ZigZag + */ + + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + vCrvCompoRes.clear() ; + + // ciclo sui chunk della regione + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { + // recupero il Chunk nC-esimo + PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + + // recupero il massimo Offset del Chunk nC-esimo + double dMaxOffs ; + pSfrChunk->GetMaxOffset( dMaxOffs) ; + // se inferiore del Tool ( ho già svuotato tale Chunk in precedenza) + if ( dMaxOffs < PockParams.dRad + 200 * EPS_SMALL) + continue ; + + // ricavo la guida ideale e la curva su cui tagliare gli Offset a partire dal Chunk nC-esimo + PtrOwner pCrvGuideExt( CreateCurveComposite()) ; + PtrOwner pCrvClass( CreateCurveComposite()) ; + if ( IsNull( pCrvGuideExt) || IsNull( pCrvClass) || + ! CalcCrvGuideConformalZigZag( pSfr, PockParams, pCrvGuideExt, pCrvClass)) + return false ; + // se non è stata trovata una guida ideale, allora passo al Chunk successivo + if ( ! pCrvGuideExt->IsValid() || pCrvGuideExt->GetCurveCount() == 0 || + ! pCrvClass->IsValid() || pCrvClass->GetCurveCount() == 0) { + return true ; + } + + // memorizzo le curve di Offset tagliate a seconda dalla geometria del perimetro + ICRVCOMPOPOVECTOR vCompoInternalOffs ; + const int MAX_ITER = 100 ; + double dOffs = PockParams.dRad + PockParams.dRadialOffset ; + for ( int i = 0 ; i < MAX_ITER ; ++ i) { + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCrvGuideExt, - dOffs, ICurve::OFF_FILLET)) + return false ; + // se invece ne ottengo più di una, controllo se è necessaria + if ( OffsCrv.GetCurveCount() > 1) { + // recupero le curve extra ( tutte tranne la più lunga) + for ( int j = 0 ; j < OffsCrv.GetCurveCount() - 1 ; ++ j) { + // recupero la curva più corta + PtrOwner pCrvShorter( ConvertCurveToComposite( OffsCrv.GetShorterCurve())) ; + if ( ! IsNull( pCrvShorter) && pCrvShorter->IsValid()) { + // controllo se è davvero necessaria per non lasciare materiale + bool bSkip = false ; + if ( pCrvShorter->IsClosed()) { + CheckIfOffsetIsNecessary( pCrvShorter, ( i == 0 ? dOffs : PockParams.dSideStep), + i, PockParams, bSkip) ; + if ( bSkip) + return true ; + } + } + } + } + // se non ottengo nessuna curva, allora ho finito + PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid()) + break ; + // se ottengo una curva chiusa, lavorazione non ammessa + if ( pCrvOffs->IsClosed()) + return true ; + // la inverto se numero di Offset progressivo dispari + if ( ( ! IsEven( i) && ! PockParams.bInvert) || + ( IsEven( i) && PockParams.bInvert)) + pCrvOffs->Invert() ; + // classifico la curva rispetto al perimetro, devo tenere solo le parti interne + CRVCVECTOR ccClass ; + IntersCurveCurve ICC( *pCrvOffs, *pCrvClass) ; + if ( ! ICC.GetCurveClassification( 0, EPS_SMALL, ccClass)) + return true ; + // se curva tutta esterna ho finito + if ( int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) + break ; + // scorro tutte le classificazioni ottenute + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + // tengo quelle strettamente interne + if ( ccClass[j].nClass == CRVC_IN) { + // recupero la porzione di Offset + PtrOwner pCrvOffs_Int( pCrvOffs->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; + if ( ! IsNull( pCrvOffs_Int) && pCrvOffs_Int->IsValid()) { + // salvo come prima proprietà temporanea, il numero di Offset progressivo + pCrvOffs_Int->SetTempProp( i, 0) ; + // salvo la curva + vCompoInternalOffs.emplace_back( ConvertCurveToComposite( Release( pCrvOffs_Int))) ; + } + } + } + dOffs += PockParams.dSideStep ; + } + // se non ho ottenuto Offset, passo al Chunk successivo + if ( vCompoInternalOffs.empty()) + return true ; + + /* + Creo la curva di Svuotatura come unione di due curve : + - La curva che non deve essere smussata ( curve di primo Offset e raccordi) + - La Curva che necessita di smusso ( le altre) + NB. Nel caso non sia richiesto lo smusso, allora la seconda curva non viene smussata, ma la + logica rimane la stessa. + */ + + PtrOwner pCompoNoSmooth( CreateCurveComposite()) ; + PtrOwner pCompoSmooth( CreateCurveComposite()) ; + if ( IsNull( pCompoNoSmooth) || IsNull( pCompoSmooth)) + return false ; + + // scorro i tratti di Offset interni e aggiungo i raccordi sul bordo esterno + // raccordo il tratto di Offset interno corrente al successivo + const double TOL_JOINT = 25. * EPS_SMALL ; + double dHalfLenPerimeter ; + pCrvClass->GetLength( dHalfLenPerimeter) ; + dHalfLenPerimeter /= 2. ; + for ( int i = 0 ; i < int( vCompoInternalOffs.size()) - 1 ; ++ i) { + // recupero il parametro iniziale del raccordo sulla curva di perimetro + Point3d ptS ; vCompoInternalOffs[i]->GetEndPoint( ptS) ; + double dUS ; pCrvClass->GetParamAtPoint( ptS, dUS) ; + // recupero il parametro finale del raccordo sulla curva di perimetro + Point3d ptE ; vCompoInternalOffs[i+1]->GetStartPoint( ptE) ; + double dUE ; pCrvClass->GetParamAtPoint( ptE, dUE) ; + // aggiungo il tratto di Offset interno corrente alla curva di svuotatura + if ( vCompoInternalOffs[i]->GetTempProp() == 0) { + // se deriva dal primo Offset + if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT)) + return false ; + } + else { + // se deriva da Offset successivi + if ( ! pCompoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT)) + return false ; + } + // recupero il tratto di curva di interesse + PtrOwner pCrvJoint( pCrvClass->CopyParamRange( dUS, dUE)) ; + if ( ! IsNull( pCrvJoint) && pCrvJoint->IsValid()) { + double dLen ; + pCrvJoint->GetLength( dLen) ; + if ( dLen > dHalfLenPerimeter) { + pCrvJoint.Set( pCrvClass->CopyParamRange( dUE, dUS)) ; + pCrvJoint->Invert() ; + } + // aggiungo il tratto di percorso + if ( vCompoInternalOffs[i+1]->GetTempProp() == 0) { + // se l'offset successivo deriva ancora dal primo + if ( ! pCompoNoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT)) + return false ; + } + else { + // se l'Offset successivo non deriva dal primo Offset + if ( ! pCompoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT)) + return false ; + } + } + } + // aggiungo l'ultimo tratto di Offset + if ( vCompoInternalOffs.back()->GetTempProp() == 0) { + if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs.back()), true, TOL_JOINT)) + return false ; + } + else { + if ( ! pCompoSmooth->AddCurve( vCompoInternalOffs.back()->Clone(), true, TOL_JOINT)) + return false ; + } + // porto l'ultima curva del percorso NoSmooth nel percorso Smooth per avere un raccordo anche + // sul tratto di giunzione tra esse + if ( pCompoSmooth->IsValid() && pCompoNoSmooth->IsValid()) { + PtrOwner pCrv( pCompoNoSmooth->GetLastCurve()->Clone()) ; + if ( IsNull( pCrv) || ! pCrv->IsValid() || + ! pCompoSmooth->AddCurve( Release( pCrv), false, TOL_JOINT)) + return false ; + delete( pCompoNoSmooth->RemoveFirstOrLastCurve( true)) ; + } + + // smusso dove necessario + ModifyCurveToSmoothed( pCompoSmooth, PockParams, PockParams.dRad / 8, PockParams.dRad / 8, false) ; + // creo il percorso di svuotatura + PtrOwner pCompoTempPath( CreateCurveComposite()) ; + if ( IsNull( pCompoTempPath)) + return false ; + if ( pCompoNoSmooth->IsValid() && pCompoNoSmooth->GetCurveCount() > 0) { + if ( ! pCompoTempPath.Set( pCompoNoSmooth)) + return false ; + } + if ( pCompoSmooth->IsValid()) { + if ( ! pCompoTempPath->AddCurve( Release( pCompoSmooth), true, TOL_JOINT)) + return false ; + } + // se la curva finale di Pocketing è valida, allora la resituisco + if ( pCompoTempPath->IsValid()) { + // inverto l'ordine delle curve di Offset ( in modo da partire sempre ad eseguire il percorso + // più lontano dal dai lati chiusi) + pCompoTempPath->Invert() ; + // controllo eventuali parti non svuotate... + // calcolo la Feed del percorso trovato + PtrOwner pSfrToRemove( CreateSurfFlatRegion()) ; + ICRVCOMPOPOVECTOR vOffs ; vOffs.emplace_back( CloneCurveComposite( pCompoTempPath)) ; + ICRVCOMPOPOVECTOR vOffsClosedCrv ; + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCrvClass, - PockParams.dRad - PockParams.dRadialOffset + 15 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + PtrOwner pCrvFirstOffs( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; + if ( IsNull( pCrvFirstOffs) || ! pCrvFirstOffs->IsValid()) + return false ; + vOffsClosedCrv.emplace_back( Release( pCrvFirstOffs)) ; + ICURVEPOVECTOR vCompoEmpty ; + if ( IsNull( pSfrToRemove) || + ! AssignFeedConformalZigZag( pCompoTempPath, pCrvClass, PockParams, pSfrToRemove) || + ! RemoveExtraParts( pSfrToRemove, vOffs, vOffsClosedCrv, vOffsClosedCrv, vCompoEmpty, PockParams)) + return false ; + if ( ! vOffs.empty() && ! IsNull( vOffs[0]) && vOffs[0]->IsValid()) + pCompoTempPath.Set( vOffs[0]) ; + // aggiugno il tratto iniziale e finale per entrate da fuori + Vector3d vtStart ; pCompoTempPath->GetStartDir( vtStart) ; + vtStart.Invert() ; + bool bExt = false ; + if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtStart, false, bExt)) + return false ; + Vector3d vtEnd ; pCompoTempPath->GetEndDir( vtEnd) ; + if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtEnd, true, bExt)) + return false ; + // sostituisco la curva + if ( pCompoTempPath->IsValid()) + vCrvCompoRes.emplace_back( Release( pCompoTempPath)) ; + } + } + + return true ; +} //---------------------------------------------------------------------------- static bool @@ -6070,18 +6603,11 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int if ( IsNull( pSrfToWork) || pSrfToWork->GetChunkCount() == 0) return false; - // porto il Chunk c-esimo nel sistema di riferimento locale - Vector3d vtExtr = pSrfToWork->GetNormVersor() ; - Point3d ptCen ; pSrfToWork->GetCentroid( ptCen) ; - Frame3d frPocket ; frPocket.Set( ptCen, vtExtr) ; - - - // CONTROLLO PER CASI OTTIMIZZATI + // ---------------------------------- 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()) @@ -6099,6 +6625,14 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, PockParams, pMCrv, pRCrv) ; 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 ; } @@ -6108,7 +6642,6 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int else return true ; } - // -------------------------- caso trapezoide --------------------------------------- PtrOwner pCrvTrap( CreateCurveComposite()) ; if ( IsNull( pCrvTrap)) @@ -6116,17 +6649,13 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int Frame3d frTrap ; double dPocketSize ; int nBase, nSecondBase ; - vCrvOrigChunkLoops[0]->ToLoc( frPocket) ; if ( ! GetTrapezoidFromShape( vCrvOrigChunkLoops[0], pCrvTrap, frTrap, PockParams, dPocketSize, nBase, nSecondBase)) return false ; - vCrvOrigChunkLoops[0]->ToGlob( frPocket) ; if ( pCrvTrap->IsValid()) { - pCrvTrap->SetExtrusion( vtExtr) ; + pCrvTrap->SetExtrusion( Z_AX) ; if ( nReg == 0) { CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParams, pMCrv, pRCrv, bOptimizedTrap) ; if ( bOptimizedTrap) { - pMCrv->ToGlob( frPocket) ; - pRCrv->ToGlob( frPocket) ; nReg = 1 ; return true ; } @@ -6137,9 +6666,6 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int } - // porto la superficie nel frame corrente - pSrfToWork->ToLoc( frPocket) ; - // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; @@ -6193,7 +6719,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int pCrvCompoBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; - if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, int( vOffs.size()), nIter, vtExtr, PockParams, bInsert)) + if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, nIter, PockParams, bInsert)) return false ; if ( bInsert) vOffs.emplace_back( Release( pCrvCompoBorder)) ; @@ -6234,29 +6760,25 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int return true ; // cambio il punto iniziale della prima Curva di Offset - Point3d ptRef = PockParams.ptEnd ; ptRef.ToLoc( frPocket) ; + Point3d ptRef = PockParams.ptEnd ; Point3d ptNewStart ; - if ( ! IsNull( vCrvOrigChunkLoops[0])) - vCrvOrigChunkLoops[0]->ToLoc( frPocket) ; // 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, frPocket, - ptStart, vtMidOut, bMidOut, nIndexSwap, int( vOffs.size()), vCrvOrigChunkLoops)) + if ( SetAdvancedPtStartForPath( vOffsFirstCurve, PockParams, pSrfToWork, ptRef, ptStart, + vtMidOut, bMidOut, nIndexSwap, int( vOffs.size()), vCrvOrigChunkLoops)) vOffsFirstCurve[nIndexSwap]->GetStartPoint( ptNewStart) ; else return false ; } else { - if ( SetPtStartForPath( vOffs[0], PockParams, pSrfToWork, ptRef, frPocket, ptStart, vtMidOut, bMidOut, + if ( SetPtStartForPath( vOffs[0], PockParams, pSrfToWork, ptRef, ptStart, vtMidOut, bMidOut, int( vOffs.size()), vCrvOrigChunkLoops[0])) vOffs[0]->GetStartPoint( ptNewStart) ; else return false ; } - if ( ! IsNull( vCrvOrigChunkLoops[0])) - vCrvOrigChunkLoops[0]->ToGlob( frPocket) ; // se richiesta inversione for ( int i = 0 ; i < int( vOffs.size()) && PockParams.bInvert ; ++ i) @@ -6286,8 +6808,6 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int return false ; // controllo eventuali parti non svuotate... - if ( ! IsNull( vCrvOrigChunkLoops[0])) - vCrvOrigChunkLoops[0]->ToLoc( frPocket) ; PtrOwner pSrfToCut( CreateSurfFlatRegion()) ; if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, vCrvOrigChunkLoops[0], PockParams, pSrfToCut)) { // Modifico i percorsi @@ -6321,15 +6841,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int } // setto estrusione - pMCrv->SetExtrusion( vtExtr) ; - - // riporto tutto nel sistema di riferimento originale - pMCrv->ToGlob( frPocket) ; - ptStart.ToGlob( frPocket) ; - vtMidOut.ToGlob( frPocket) ; - if ( ! IsNull( vCrvOrigChunkLoops[0])) - vCrvOrigChunkLoops[0]->ToGlob( frPocket) ; - + pMCrv->SetExtrusion( Z_AX) ; return true ; } @@ -6856,15 +7368,23 @@ AddSpiralIn( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo - if ( bOptimizedTrap) { // se caso a trapezio - AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, PockParams) ; - AssignFeedSpiralOpt( 1, PockParams, pMCrv) ; - pMCrv->SetTempProp( TMP_PROP_OPT_TRAPEZOID, 0) ; - } - else if ( bSomeOpen) { // se presenza di lati aperti - if ( ! ExtendPathOnOpenEdge( pMCrv, PockParams, pSrfChunk->GetNormVersor(), vtMidOut, false)) + bool bIsExtended = false ; + // se caso a trapezio + if ( bOptimizedTrap) { + Vector3d vtRef ; + pMCrv->GetStartDir( vtRef) ; + vtRef.Invert() ; + if ( ! ExtendPath( pMCrv, pSrfPock, PockParams, vtRef, false, bIsExtended)) return false ; + pMCrv->GetEndDir( vtRef) ; + if ( ! ExtendPath( pMCrv, pSrfPock, PockParams, vtRef, true, bIsExtended)) + return false ; + AssignFeedSpiralOpt( 1, PockParams, pMCrv) ; + pMCrv->SetTempProp( TEMP_PROP_OPT_TRAPEZOID, 0) ; } + // se esistenza di lati aperti validi + else if ( bSomeOpen) + ExtendPath( pMCrv, pSfrOrig, PockParams, vtMidOut, false, bIsExtended) ; // inserisco le curve nel vettore vCrvCompoRes.emplace_back( Release( pMCrv)) ; @@ -6922,10 +7442,19 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo + if ( bOptimizedTrap) { // se caso a trapezio - AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, PockParams) ; + Vector3d vtRef ; + pMCrv->GetStartDir( vtRef) ; + vtRef.Invert() ; + bool bIsExtended = false ; + if ( ! ExtendPath( pMCrv, pSrfPock, PockParams, vtRef, false, bIsExtended)) + return false ; + pMCrv->GetEndDir( vtRef) ; + if ( ! ExtendPath( pMCrv, pSrfPock, PockParams, vtRef, true, bIsExtended)) + return false ; AssignFeedSpiralOpt( 1, PockParams, pMCrv) ; - pMCrv->SetTempProp( TMP_PROP_OPT_TRAPEZOID, 0) ; + pMCrv->SetTempProp( TEMP_PROP_OPT_TRAPEZOID, 0) ; } // inverto i percorsi, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato) @@ -6943,71 +7472,214 @@ AddSpiralOut( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, //---------------------------------------------------------------------------- static bool -AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) +GetZigZagOneWayBorderCrvs( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, + const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvRes) { - // Offset della regione per curva ZigZag + /* + Restituisce le curve di Primo Offset dei lati chiusi per i percorsi a ZigZag e OneWay. + Vengono calcolate le Feed ed eventuali entrate da fuori per i percorsi ricavati + */ + + // controllo validità della regione + if ( pSfrPock == nullptr || ! pSfrPock->IsValid()) + return false ; + + // recupero la superficie limite e calcolo Offset + PtrOwner pSfrLimit( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrLimit)) + return false ; + if ( PockParams.SfrLimit.IsValid()) { + pSfrLimit.Set( PockParams.SfrLimit.Clone()) ; + if ( IsNull( pSfrLimit) || ! pSfrLimit->IsValid()) + return false ; + pSfrLimit->Offset( PockParams.dRad + PockParams.dRadialOffset - 50 * EPS_SMALL, ICurve::OFF_FILLET) ; + } + + // vettore delle curve chiuse Offsettate + ICRVCOMPOPOVECTOR vClosedOffs ; + + // scorro i Chunk e i Loop della regione + for ( int nC = 0 ; nC < pSfrPock->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfrPock->GetLoopCount( nC) ; ++ nL) { + // loop come curva composita + PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrPock->GetLoop( nC, nL))) ; + if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) + return false ; + // recupero i tratti con proprietà uniformi + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvLoop, PockParams, 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) ; + } + } + // le isole aperte vanno percorse + bool bOpenIsland = ( nL > 0 && int( vpCrvs.size()) == 1 && + vpCrvs[0]->GetTempProp() == TEMP_PROP_OPEN_EDGE) ; + // scorro tutti i tratti omogenei + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + // se tratto chiuso o isola aperta + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE || bOpenIsland) { + // Offset per le curve + OffsetCurve OffsCrv ; + double dOffs = - PockParams.dRad - PockParams.dRadialOffset ; + // se isola aperta, allora l'offset è verso il suo interno + if ( bOpenIsland) + dOffs *= -1 ; + if ( OffsCrv.Make( vpCrvs[i], dOffs, ICurve::OFF_FILLET)) { + PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; + while ( ! IsNull( pOffLongestCrv)) { + // recupero solo i tratti di curva al di fuori della superficie limite + if ( pSfrLimit->IsValid()) { + CRVCVECTOR ccClass ; + if ( pSfrLimit->GetCurveClassification( *pOffLongestCrv, EPS_SMALL, ccClass)) { + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + if ( ccClass[j].nClass == CRVC_OUT) { + // recupero il tratto di curva + PtrOwner pCrv( pOffLongestCrv->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; + if ( ! IsNull( pCrv) && pCrv->IsValid()) + vClosedOffs.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; + } + } + } + } + else + vClosedOffs.emplace_back( ConvertCurveToComposite( Release( pOffLongestCrv))) ; + + // passo alla successiva + pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; + } + } + } + } + } + } + // se non ho percorsi ho finito + if ( vClosedOffs.empty()) + return true ; + + // le curve che ricavo devono essere sempre conenute nella regione che sto svuotando + /* + Se siamo in presenza di isole chiuse molto vicine a lati chiusi non posso estendere il bordo + dell'isola chiusa a piacere, devo limitarlo alla regione di svuotatura + */ + PtrOwner pSfrBucket( CloneSurfFlatRegion( pSfrPock)) ; + if ( IsNull( pSfrBucket) || ! pSfrBucket->IsValid() || + ! pSfrBucket->Offset( - PockParams.dRad - PockParams.dRadialOffset + 50 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + ICRVCOMPOPOVECTOR vClosedOffs1 ; + // scorro le curve di Offset chiuse ricavate + for ( int i = 0 ; i < int( vClosedOffs.size()) ; ++ i) { + CRVCVECTOR ccClass ; + if ( pSfrBucket->GetCurveClassification( *vClosedOffs[i], EPS_SMALL, ccClass)) { + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + if ( ccClass[j].nClass == CRVC_IN) { + // recupero il tratto di curva + PtrOwner pCrv( vClosedOffs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; + if ( ! IsNull( pCrv) && pCrv->IsValid()) + vClosedOffs1.emplace_back( ConvertCurveToComposite( Release( pCrv))) ; + } + } + } + } + if ( vClosedOffs1.empty()) + return true ; + swap( vClosedOffs, vClosedOffs1) ; + + // concateno eventuali percorsi + if ( ! ChainCompoCurves( vClosedOffs)) + return false ; + // determino ora il punto di inizio, il tratto per il LeadIn + if ( ! AdvanceExtendCurves( vClosedOffs, pSfrOrig, PockParams)) + return false ; + + // Calcolo ora le Feed e restituisco le curve ottenute + for ( int i = 0 ; i < int( vClosedOffs.size()) ; ++ i) { + // se ZigZag -> ho percorso i tratti a ZigZag, quindi posso andare a Feed massima + if ( PockParams.nType == POCKET_ZIGZAG) + AssignMaxFeed( vClosedOffs[i], PockParams) ; + // se OneWay -> prima percorro queste curva, quindi la Feed è minima + if ( PockParams.nType == POCKET_ONEWAY) + AssignMinFeed( vClosedOffs[i], PockParams) ; + // assegno la proprità alla curva composita + vClosedOffs[i]->SetTempProp( TEMP_PROP_BORDER_CURVE, 0) ; + // restituisco le curve ottenute + vCrvRes.emplace_back( Release( vClosedOffs[i])) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvCompoRes) +{ + // 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 c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { + for ( int nC = 0 ; nC < pSrfPock->GetChunkCount() ; ++ nC) { - // copio il chunk c-esimo - PtrOwner pSrfChunk( pSrfPock->CloneChunk( c)) ; - if ( IsNull( pSrfChunk)) - return false ; - - // determino il riferimento in base alla svuotatura ( per poter orientare il frame per m_dSideAngle) - Frame3d frPocket ; - Point3d ptCen ; pSrfChunk->GetCentroid( ptCen) ; - frPocket.Set( ptCen, pSrfChunk->GetNormVersor()) ; - frPocket.Rotate( ptCen, pSrfChunk->GetNormVersor(), PockParams.dAngle) ; - - // porto la superficie nel nuovo sistema di riferimento - pSrfChunk->ToLoc( frPocket) ; - - // creo la regione per il percorso a ZigZag - PtrOwner pSrfZigZag( pSrfChunk->Clone()) ; + // creo la regione per il percorso a ZigZag ( mediante primo Offset) portandola + // nel sistema di riferimento creato + PtrOwner pSrfZigZag( pSrfPock->CloneChunk( nC)) ; if ( ! pSrfZigZag->Offset( - dOffs, ICurve::OFF_FILLET)) return false ; - - // vettore con i percorsi a ZigZag + // vettore con i percorsi a ZigZag relativi al Chunk nC-esimo ICRVCOMPOPOVECTOR vpCrvs ; - // ciclo sui Chunk ottenuti... - for ( int cfz = 0 ; cfz < pSrfZigZag->GetChunkCount() ; ++ cfz) { - // considero un chunk per volta... - PtrOwner pSrfZigZagChunk( pSrfZigZag->CloneChunk( cfz)) ; - if ( IsNull( pSrfZigZagChunk)) + // ciclo sui Chunk ottenuti dal primo offset + for ( int nC1 = 0 ; nC1 < pSrfZigZag->GetChunkCount() ; ++ nC1) { + // recupero il Chunk attuale + PtrOwner pSrfZigZagChunk( pSrfZigZag->CloneChunk( nC1)) ; + if ( IsNull( pSrfZigZagChunk) || ! pSrfZigZagChunk->IsValid()) return false ; + // calcolo i percorsi di ZigZag if ( ! CalcZigZag( pSrfZigZagChunk, PockParams, vpCrvs, false)) return false ; - // aggiorno il vettore delle curve risultati - for ( int u = 0 ; u < int( vpCrvs.size()) ; ++ u) { - // riportando prima in Globale - vpCrvs[u]->ToGlob( frPocket) ; - - // controllo se il punto iniziale e finale sono esterni alla superficie originale - Point3d ptStart ; vpCrvs[u]->GetStartPoint( ptStart) ; - bool bIsInside = false ; - if ( IsPointInsideSfr( pSfrOrig, ptStart, bIsInside) && ! bIsInside) { - Vector3d vtMidOut ; vpCrvs[u]->GetStartDir( vtMidOut) ; - vtMidOut.Invert() ; - ExtendPathOnOpenEdge( vpCrvs[u], PockParams, pSrfChunk->GetNormVersor(), vtMidOut, false) ; + // controllo esistenza di lati aperti per il Chunk nC-esimo + bool bIsChunkClosed = true ; + if ( ! PockParams.bAllClosed) { + if ( ! IsChunkAllClosed( pSrfPock, nC, bIsChunkClosed)) + return false ; + // se il Chunk originale aveva lati aperti, estendo il percorso a ZigZag + for ( int nU = 0 ; nU < int( vpCrvs.size()) ; ++ nU) { + Vector3d vtRef ; vpCrvs[nU]->GetStartDir( vtRef) ; + vtRef.Invert() ; + bool bIsExtended = false ; + if ( ! ExtendPath( vpCrvs[nU], pSfrOrig, PockParams, vtRef, false,bIsExtended)) + return false ; + vpCrvs[nU]->GetEndDir( vtRef) ; + if ( ! ExtendPath( vpCrvs[nU], pSfrOrig, PockParams, vtRef, true, bIsExtended)) + return false ; } - Point3d ptEnd ; vpCrvs[u]->GetEndPoint( ptEnd) ; - if ( IsPointInsideSfr( pSfrOrig, ptEnd, bIsInside) && ! bIsInside) { - Vector3d vtMidOut ; vpCrvs[u]->GetEndDir( vtMidOut) ; - ExtendPathOnOpenEdge( vpCrvs[u], PockParams, pSrfChunk->GetNormVersor(), vtMidOut, true) ; - } - - // inserisco le curve nel vettore risultante - vCrvCompoRes.emplace_back( Release( vpCrvs[u])) ; } + + // inserisco le curve nel vettore risultante + for ( int nU = 0 ; nU < int( vpCrvs.size()) ; ++ nU) + vCrvCompoRes.emplace_back( Release( vpCrvs[nU])) ; + // libero il vettore di curve ZigZag per il chunk successivo vpCrvs.clear() ; } + + // se richiesto, aggiungo le curve chiuse di Bordo + if ( PockParams.bAllowZigZagOneWayBorders) { + // recupero il Chunk nC-esimo + PtrOwner pSfrChunk( pSrfPock->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid() || + ! GetZigZagOneWayBorderCrvs( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) + return false ; + } } return true ; @@ -7015,73 +7687,69 @@ AddZigZag( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con //---------------------------------------------------------------------------- static bool -OptimizeChunkOneWay( ISurfFlatRegion* pSrfOrig, ISURFFRPOVECTOR& vSrfIdeal) +OptimizeChunkOneWay( const ISurfFlatRegion* pSfrOrig, ISURFFRPOVECTOR& vSrfIdeal) { // controllo parametri - if ( pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0) + if ( pSfrOrig == nullptr || pSfrOrig->GetChunkCount() == 0) return false ; vSrfIdeal.clear() ; - // clono la superficie passata alla funzione - PtrOwner pSrfToPock( pSrfOrig->Clone()) ; - if ( IsNull( pSrfToPock) || pSrfToPock->GetChunkCount() == 0) - return false ; + /* + classifico i chunks in modo da creare delle regioni ideali; una regione ideale è formata + da un chunk principale con tutti gli altri contenuti in esso ( in questo modo ottimizzo i + percorsi per i bordi) + */ - // classifico i chunks in modo da creare delle regioni ideali; una regione ideale è formata da un chunk principale - // con tutti gli altri contenuti in esso ( in questo modo ottimizzo i percorsi per i bordi) - - INTVECTOR vChunksAvailable( pSrfToPock->GetChunkCount(), 1) ; - - for ( int c = 0 ; c < pSrfToPock->GetChunkCount() ; ++ c) { + INTVECTOR vChunksAvailable( pSfrOrig->GetChunkCount(), 1) ; + for ( int nC = 0 ; nC < pSfrOrig->GetChunkCount() ; ++ nC) { PtrOwner pSrfIdeal( CreateSurfFlatRegion()) ; if ( IsNull( pSrfIdeal)) - return false ; - if ( vChunksAvailable[c] == 1) { // se Chunk valido... + return false ; + // se Chunk valido... + if ( vChunksAvailable[nC] == 1) { // prendo la curva esterna - PtrOwner pCrvExt( pSrfToPock->GetLoop( c, 0)) ; + PtrOwner pCrvExt( pSfrOrig->GetLoop( nC, 0)) ; if ( IsNull( pCrvExt)) return false ; - // inserisco il chunk c-esimo ( curva per curva, così non perdo le temp prop) - pSrfIdeal->AddExtLoop( pCrvExt->Clone()) ; // ... inizio a creare la regione ideale da esso - for ( int l = 1 ; l < pSrfToPock->GetLoopCount( c) ; ++ l) - pSrfIdeal->AddIntLoop( pSrfToPock->GetLoop( c, l)) ; - // il chunk c-esimo non è più disponibile... - vChunksAvailable[c] = -1 ; + // inserisco il chunk nC-esimo ( curva per curva, così non perdo le temp prop) + pSrfIdeal->AddExtLoop( pCrvExt->Clone()) ; + for ( int nL = 1 ; nL < pSfrOrig->GetLoopCount( nC) ; ++ nL) + pSrfIdeal->AddIntLoop( pSfrOrig->GetLoop( nC, nL)) ; + // il chunk nC-esimo non è più disponibile... + vChunksAvailable[nC] = -1 ; // scorro tutti gli altri chunk i-esimi ancora disponibili for ( int i = 0 ; i < int( vChunksAvailable.size()) ; ++ i) { if ( vChunksAvailable[i] == 1) { // prendo la curva esterna del chunk i-esimo disponibile - PtrOwner pCrvExtC( pSrfToPock->GetLoop( i, 0)) ; + PtrOwner pCrvExtC( pSfrOrig->GetLoop( i, 0)) ; if ( IsNull( pCrvExtC)) return false ; - // classifico i bordi esterni ( se il bordo del chunk c-esimo contiene o è contenuto nel loop + // classifico i bordi esterni ( se il bordo del chunk nC-esimo contiene o è contenuto nel loop // esterno del chunk i-esimo -> sono chunks appartenenti alla stessa superficie ideale) IntersCurveCurve intCC( *pCrvExtC, *pCrvExt) ; CRVCVECTOR ccClass, ccClass1 ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; intCC.GetCurveClassification( 1, EPS_SMALL, ccClass1) ; - if (( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) || - ( ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN)) { + if (( int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_IN) || + ( int( ccClass1.size()) == 1 && ccClass1[0].nClass == CRVC_IN)) { // inserisco il chunk i-esimo ( curva per curva, così non perdo le temp prop) - pSrfIdeal->AddExtLoop( pSrfToPock->GetLoop( i, 0)) ; - for ( int l = 1 ; l < pSrfToPock->GetLoopCount( i) ; ++ l) - pSrfIdeal->AddIntLoop( pSrfToPock->GetLoop( i, l)) ; + pSrfIdeal->AddExtLoop( pSfrOrig->GetLoop( i, 0)) ; + for ( int nL = 1 ; nL < pSfrOrig->GetLoopCount( i) ; ++ nL) + pSrfIdeal->AddIntLoop( pSfrOrig->GetLoop( i, nL)) ; vChunksAvailable[i] = -1 ; // chunk j-esimo non più disponibile // NB: Se il chunk i-esimo contiene la pSrfIdeal ( quindi chunk i-esimo unito ad eventuali altri chunk // j-esimi precedenti -> prendo come bordo esterno di riferimento il suo e ricontrollo dall'inizio i // chunk disponibili - if (( int)ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN) { - pCrvExt.Set( pCrvExtC->Clone()) ; + if ( int( ccClass1.size()) == 1 && ccClass1[0].nClass == CRVC_IN) { + pCrvExt.Set( pCrvExtC) ; i = 0 ; } } } } } - if ( pSrfIdeal->GetChunkCount() > 0) vSrfIdeal.emplace_back( Release( pSrfIdeal)) ; - } return ( ! vSrfIdeal.empty()) ; @@ -7089,51 +7757,35 @@ OptimizeChunkOneWay( ISurfFlatRegion* pSrfOrig, ISURFFRPOVECTOR& vSrfIdeal) //---------------------------------------------------------------------------- static bool -AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvCompoRes) +AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, + ICRVCOMPOPOVECTOR& vCrvCompoRes) { + // offset della regione per segmenti a ZigZag double dOffs = PockParams.dRad + PockParams.dRadialOffset ; double dExtra = 0. ; + if ( PockParams.bAllowZigZagOneWayBorders) + dExtra = PockParams.dOffsExtra ; - // copio la regione da svuotare - PtrOwner pSrfToPock( pSrfPock->Clone()) ; - if ( IsNull( pSrfToPock)) + // vettore delle regioni ideali + ISURFFRPOVECTOR vSrfFlat ; + if ( ! OptimizeChunkOneWay( pSrfPock, vSrfFlat)) return false ; - - // creo le regioni ideali -------------------------------------------- - // creo un frame di riferimento della svuotatura - Frame3d frLoc ; - Point3d ptC ; pSrfToPock->GetCentroid( ptC) ; - Vector3d vtN = pSrfToPock->GetNormVersor() ; - frLoc.Set( ptC, vtN) ; - pSrfToPock->ToLoc( frLoc) ; - - ISURFFRPOVECTOR vSrfFlat ; // vettore delle regioni ideali - if ( ! OptimizeChunkOneWay( pSrfToPock, vSrfFlat)) - return false ; - - // riporto le superfici ideali nel sistema di riferimento globale ( Ogni chunk verrà poi messo nel suo frame) - for ( int i = 0 ; i < int( vSrfFlat.size()) ; ++ i) - vSrfFlat[i]->ToGlob( frLoc) ; - // ------------------------------------------------------------------ // scorro le regioni ideali for ( int nIs = 0 ; nIs < int( vSrfFlat.size()) ; ++ nIs) { - // copio la superficie ideale - PtrOwner pSrfIdeal( vSrfFlat[nIs]->Clone()) ; - if ( IsNull( pSrfIdeal)) + // copio la superficie ideale ed effettuo il primo Offset + PtrOwner pSrfIdeal( CloneSurfFlatRegion( vSrfFlat[nIs])) ; + if ( IsNull( pSrfIdeal) || ! pSrfIdeal->Offset( - dOffs, ICurve::OFF_FILLET)) return false ; - // effettuo Offset interno - if ( ! pSrfIdeal->Offset( - dOffs, ICurve::OFF_FILLET)) - return false ; + // se sono richieste le curve di Bordo, le aggiungo + if ( PockParams.bAllowZigZagOneWayBorders) { + if ( ! GetZigZagOneWayBorderCrvs( vSrfFlat[nIs], pSfrOrig, PockParams, vCrvCompoRes)) + return false ; + } - // creo un frame coerente con i parametri - Frame3d frPocket ; - Point3d ptCen ; pSrfIdeal->GetCentroid( ptCen) ; - frPocket.Set( ptCen, pSrfIdeal->GetNormVersor()) ; - frPocket.Rotate ( ptCen, pSrfIdeal->GetNormVersor(), PockParams.dAngle) ; - pSrfIdeal->ToLoc( frPocket) ; + // recupero il Box della superficie attuale da svuotare BBox3d b3Pocket ; pSrfIdeal->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; @@ -7143,7 +7795,7 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; -- nYStep ; - // vettore dei segmenti al di sotto della linea corrente + // vettore dei segmenti al di sotto della linea corrente ( per le Feed) ICURVEPOVECTOR vLineUnder ; ICURVEPOVECTOR vCrvNull ; ICRVCOMPOPOVECTOR vCrvCompoNull ; @@ -7162,7 +7814,7 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con if ( PockParams.bInvert) pLine->Invert() ; - // linea come composita per Feed ( la dovrò spezzare) + // linea come composita per Feed ( la dovrò spezzare in tratti uniformi di Feed) PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; @@ -7196,7 +7848,6 @@ AddOneWay( const ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, con pCrvSegCompo->AddCurve( Release( pCrvSeg)) ; // calcolo la Feed AssignFeedZigZagOneWay( pCrvSegCompo, false, vCrvNull, vLineUnder, vCrvCompoNull, PockParams) ; - pCrvSegCompo->ToGlob( frPocket) ; vCrvCompoRes.emplace_back( Release( pCrvSegCompo)) ; } } @@ -7212,13 +7863,15 @@ 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, ISurfFlatRegion* pSfrLimit, ICRVCOMPOPOVECTOR& vCrvCompoRes) +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) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || dStep < 10 * EPS_SMALL || - ( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN && nType != POCKET_SPIRALOUT)) + ( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN && + nType != POCKET_SPIRALOUT && nType != POCKET_CONFORMAL_ZIGZAG)) return false ; // pulizia vettore delle curve elementari @@ -7234,49 +7887,68 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.dSideStep = dStep ; myParams.bInvert = bInvert ; myParams.bAvoidOpt = bAvoidOpt ; + myParams.bAllowZigZagOneWayBorders = bAllowZigZagOneWayBorders ; if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) myParams.SfrLimit.CopyFrom( pSfrLimit) ; - - // ------------ gestione dei lati aperti ------------------- - // creo un sistema di riferimento locale Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ; - Vector3d vtN = pSfr->GetNormVersor() ; - Frame3d frLoc ; - if ( ! frLoc.Set( ptCenter, vtN)) + if ( ! myParams.frLocXY.Set( ptCenter, pSfr->GetNormVersor()) || + ! myParams.frLocXY.Rotate( ptCenter, pSfr->GetNormVersor() , myParams.dAngle)) return false ; + // porto la superficie da svuotare in tale sistema PtrOwner pSfrAdj( pSfr->Clone()) ; - if ( IsNull( pSfrAdj) || ! pSfrAdj->ToLoc( frLoc)) + if ( IsNull( pSfrAdj) || ! pSfrAdj->ToLoc( myParams.frLocXY)) return false ; // porto la superficie limite ( se valida) in tale sistema if ( myParams.SfrLimit.IsValid()) - myParams.SfrLimit.ToLoc( frLoc) ; + myParams.SfrLimit.ToLoc( myParams.frLocXY) ; + + // ------------ gestione dei lati aperti ------------------- // modifico la superficie da svuotare estendendo i lati aperti bool bSkipPocket = false ; // se la superficie si svuota mediante curve singole di primo Offset dei chiusi if ( ! ModifySurfByOpenEdges( pSfrAdj, myParams, vCrvCompoRes, bSkipPocket)) return false ; - // se ottengo delle curve si svuotatura di primo Offset, le riporto in globale - for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) - vCrvCompoRes[i]->ToGlob( frLoc) ; - if ( bSkipPocket) // se tali curva rimuovono tutta la regione, allora non faccio nulla + // 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 ; - // riporto tutto nel frame originale - pSfrAdj->ToGlob( frLoc) ; - if ( myParams.SfrLimit.IsValid()) - myParams.SfrLimit.ToGlob( frLoc) ; + } + // 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 ------------------- switch ( nType) { case POCKET_ZIGZAG : - return AddZigZag( pSfrAdj, pSfr, myParams, vCrvCompoRes) ; + if ( ! AddZigZag( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + return false ; + break ; case POCKET_ONEWAY : - return AddOneWay( pSfrAdj, pSfr, myParams, vCrvCompoRes) ; + if ( ! AddOneWay( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + return false ; + break ; case POCKET_SPIRALIN : - return AddSpiralIn( pSfrAdj, pSfr, myParams, vCrvCompoRes) ; + if ( ! AddSpiralIn( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + return false ; + break ; case POCKET_SPIRALOUT : - return AddSpiralOut( pSfrAdj, pSfr, myParams, vCrvCompoRes) ; + if ( ! AddSpiralOut( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes)) + return false ; + break ; + case POCKET_CONFORMAL_ZIGZAG : + if ( ! AddAddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes)) + return false ; + break ; } - return false ; + + // riporto tutte le curve ottenute in globale + for ( int i = 0 ; i < int( vCrvCompoRes.size()) ; ++ i) + vCrvCompoRes[i]->ToGlob( myParams.frLocXY) ; + + return true ; } //---------------------------------------------------------------------------- diff --git a/DistPointSurfFr.cpp b/DistPointSurfFr.cpp new file mode 100644 index 0000000..ca318ed --- /dev/null +++ b/DistPointSurfFr.cpp @@ -0,0 +1,156 @@ +//---------------------------------------------------------------------------- +// EgalTech 2018-2020 +//---------------------------------------------------------------------------- +// File : DistPointSurfTm.cpp Data : 19.12.20 Versione : 2.2l3 +// Contenuto : Implementazione della classe distanza Punto da Trimesh. +// +// +// +// Modifiche : 07.12.18 LM Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#include "stdafx.h" +#include "SurfFlatRegion.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkDistPointSurfFr.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +DistPointSurfFr::DistPointSurfFr( const Point3d& ptP, const ISurfFlatRegion& frSurf) + : m_dDist( -1) +{ + // FlatRegion non valida + if ( &frSurf == nullptr || ! frSurf.IsValid()) + return ; + // Calcolo la distanza + Calculate( ptP, frSurf) ; +} + +//---------------------------------------------------------------------------- +void +DistPointSurfFr::Calculate( const Point3d& ptP, const ISurfFlatRegion& frSurf) +{ + // Inizializzo distanza non calcolata + m_dDist = -1 ; + + // Converto regione in classe base + const SurfFlatRegion* pSfr = GetBasicSurfFlatRegion( &frSurf) ; + if ( pSfr == nullptr) + return ; + + // ciclo sulle parti della regione + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; nC ++) { + // ciclo sui loop della parte di regione + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; nL ++) { + PtrOwner pLoop( pSfr->GetLoop( nC, nL)) ; + if ( IsNull( pLoop)) { + m_dDist = -1 ; + return ; + } + DistPointCurve DPL( ptP, *pLoop) ; + double dDist ; + if ( DPL.GetDist( dDist) && ( m_dDist < -EPS_SMALL || dDist < m_dDist)) { + m_dDist = dDist ; + int nFlag ; + m_nMinChunk = nC ; + m_nMinLoop = nL ; + DPL.GetParamAtMinDistPoint( 0, m_dMinPar, nFlag) ; + DPL.GetMinDistPoint( 0, m_ptMinDistPoint, nFlag) ; + DPL.GetSideAtMinDistPoint( 0, pSfr->GetNormVersor(), m_nSide) ; + } + } + } + // se trovata, aggiorno minima distanza sul piano + if ( m_dDist > - EPS_SMALL) { + Point3d ptOn = ptP - ( ptP - pSfr->GetPlanePoint()) * pSfr->GetNormVersor() * pSfr->GetNormVersor() ; + m_dDistOnPlane = min( Dist( ptOn, m_ptMinDistPoint), m_dDist) ; + } +} + +//---------------------------------------------------------------------------- +bool +DistPointSurfFr::GetDist( double& dDist) const +{ + if ( m_dDist < 0) + return false ; + dDist = m_dDist ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointSurfFr::GetDistOnRegionPlane( double& dDist) const +{ + if ( m_dDist < 0) + return false ; + dDist = m_dDistOnPlane ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointSurfFr::GetPointAtMinDist( Point3d& ptMinDist) const +{ + if ( m_dDist < 0) + return false ; + ptMinDist = m_ptMinDistPoint ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointSurfFr::GetParamAtMinDist( int& nMinChunk, int& nMinLoop, double& dMinPar) const +{ + if ( m_dDist < 0) + return false ; + nMinChunk = m_nMinChunk ; + nMinLoop = m_nMinLoop ; + dMinPar = m_dMinPar ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +DistPointSurfFr::GetSideAtMinDist( int& nSide) const +{ + if ( m_dDist < 0) + return false ; + nSide = m_nSide ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +IsPointInsideSurfFr( const Point3d& ptP, const ISurfFlatRegion* pSfr, double dMinDist, bool& bInside, int& nChunk) +{ + // default non include + bInside = false ; + nChunk = -1 ; + // verifica regione + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + // verifico se la proiezione del punto sul piano della regione sta nel suo box + Point3d ptOn = ptP - ( ptP - pSfr->GetPlanePoint()) * pSfr->GetNormVersor() * pSfr->GetNormVersor() ; + BBox3d b3Box ; + pSfr->GetLocalBBox( b3Box) ; + b3Box.Expand( dMinDist) ; + if ( ! b3Box.Encloses( ptOn)) + return true ; + // determino dove sta il punto + DistPointSurfFr DPR( ptP, *pSfr) ; + double dDist ; int nMinCh, nMinL; double dMinPar ; int nSide ; + if ( DPR.GetDistOnRegionPlane( dDist) && DPR.GetParamAtMinDist( nMinCh, nMinL, dMinPar) && DPR.GetSideAtMinDist( nSide)) { + if ( abs( dMinDist) < EPS_SMALL) + bInside = ( nSide != PRS_OUT) ; + else if ( dMinDist < 0) + bInside = ( nSide == PRS_IN && dDist > abs( dMinDist) - EPS_SMALL) ; + else + bInside = ( nSide != PRS_OUT || dDist < dMinDist + EPS_SMALL) ; + if ( bInside) + nChunk = nMinCh ; + } + return true ; +} diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 11258ea..60be838 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 2a61ee7..825a635 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -310,6 +310,7 @@ copy $(TargetPath) \EgtProg\Dll64 + false false diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 7b4369b..0eff6b3 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -546,6 +546,9 @@ File di origine\GeoCreate + + File di origine\GeoDist + diff --git a/PolyLine.cpp b/PolyLine.cpp index 4678ce9..9557017 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -1608,7 +1608,7 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV // distanza del punto dal segmento della polilinea DistPointLine PointLineDistCalc( vPnt1[i].first, vPnt2[j-1].first, vPnt2[j].first) ; double dPlDist ; - if ( PointLineDistCalc.GetDist( dPlDist) && dPlDist < dDist) { + if ( PointLineDistCalc.GetDist( dPlDist) && dPlDist < dDist - EPS_SMALL) { dDist = dPlDist ; PointLineDistCalc.GetParamAtMinDistPoint( dMinDistPar) ; dMinDistPar += j - 1 ; @@ -1639,8 +1639,7 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV // distanza del punto dal segmento della polilinea DistPointLine PointLineDistCalc( vPnt2[j].first, vPnt1[i-1].first, vPnt1[i].first) ; double dPlDist ; - PointLineDistCalc.GetDist( dPlDist) ; - if ( dPlDist < dDist) { + if ( PointLineDistCalc.GetDist( dPlDist) && dPlDist < dDist - EPS_SMALL) { dDist = dPlDist ; PointLineDistCalc.GetParamAtMinDistPoint( dMinDistPar) ; dMinDistPar += i - 1 ; diff --git a/SurfFlatRegion.cpp b/SurfFlatRegion.cpp index 41b74cb..4c60547 100644 --- a/SurfFlatRegion.cpp +++ b/SurfFlatRegion.cpp @@ -922,9 +922,6 @@ SurfFlatRegion::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) bool SurfFlatRegion::GetArea( double& dArea) const { - // controllo parametro di ritorno - if ( &dArea == nullptr) - return false ; // inizio con area nulla dArea = 0 ; // la regione deve essere validata @@ -947,9 +944,6 @@ SurfFlatRegion::GetArea( double& dArea) const bool SurfFlatRegion::GetGrossArea( double& dArea) const { - // controllo parametro di ritorno - if ( &dArea == nullptr) - return false ; // inizio con area nulla dArea = 0 ; // la regione deve essere validata @@ -973,9 +967,6 @@ SurfFlatRegion::GetGrossArea( double& dArea) const bool SurfFlatRegion::GetCentroid( Point3d& ptCen) const { - // controllo parametro di ritorno - if ( &ptCen == nullptr) - return false ; // la regione deve essere validata if ( m_nStatus != OK || m_vpLoop.empty()) return false ; @@ -1001,13 +992,20 @@ SurfFlatRegion::GetCentroid( Point3d& ptCen) const return true ; } +//---------------------------------------------------------------------------- +int +SurfFlatRegion::GetChunkCount( void) const +{ + // la regione deve essere validata + if ( m_nStatus != OK) + return 0 ; + return int( m_vExtInd.size()) ; +} + //---------------------------------------------------------------------------- bool SurfFlatRegion::GetChunkCentroid( int nChunk, Point3d& ptCen) const { - // controllo parametro di ritorno - if ( &ptCen == nullptr) - return false ; // la regione deve essere validata if ( m_nStatus != OK || m_vpLoop.empty()) return false ; @@ -1021,13 +1019,53 @@ SurfFlatRegion::GetChunkCentroid( int nChunk, Point3d& ptCen) const } //---------------------------------------------------------------------------- -int -SurfFlatRegion::GetChunkCount( void) const +bool +SurfFlatRegion::GetChunkArea( int nChunk, double& dArea) const { + // default, area nulla + dArea = 0 ; // la regione deve essere validata - if ( m_nStatus != OK) - return 0 ; - return int( m_vExtInd.size()) ; + if ( m_nStatus != OK || m_vpLoop.empty()) + return false ; + // il chunk deve esistere + if ( nChunk < 0 || nChunk >= GetChunkCount()) + return false ; + // calcolo l'area + bool bOk = true ; + for ( int nL = 0 ; nL < GetLoopCount( nChunk) ; ++ nL) { + const ICurve* pLoop = GetMyLoop( nChunk, nL) ; + double dLoopArea ; + if ( pLoop != nullptr && pLoop->GetAreaXY( dLoopArea)) + dArea += dLoopArea ; + else + bOk = false ; + } + return bOk ; +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::GetChunkPerimeter( int nChunk, double& dLen) const +{ + // default, perimetro nullo + dLen = 0 ; + // la regione deve essere validata + if ( m_nStatus != OK || m_vpLoop.empty()) + return false ; + // il chunk deve esistere + if ( nChunk < 0 || nChunk >= GetChunkCount()) + return false ; + // calcolo il perimetro + bool bOk = true ; + for ( int nL = 0 ; nL < GetLoopCount( nChunk) ; ++ nL) { + const ICurve* pLoop = GetMyLoop( nChunk, nL) ; + double dLoopLen ; + if ( pLoop != nullptr && pLoop->GetLength( dLoopLen)) + dLen += dLoopLen ; + else + bOk = false ; + } + return bOk ; } //---------------------------------------------------------------------------- @@ -1236,6 +1274,56 @@ SurfFlatRegion::CloneChunk( int nChunk) const return Release( pSfr) ; } +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::EraseChunk(int nChunk) +{ + // la regione deve essere validata + if ( m_nStatus != OK || m_vpLoop.empty()) + return false ; + // il chunk deve esistere + if ( nChunk < 0 || nChunk >= GetChunkCount()) + return false ; + // se un solo chunk, resetto la regione + if ( GetChunkCount() == 1) { + Clear() ; + return true ; + } + // se ultimo chunk + if ( nChunk == m_vExtInd.size() - 1) { + // elimino i loop + for ( int i = m_vExtInd[nChunk] ; i < int( m_vpLoop.size()) ; ++ i) { + delete m_vpLoop[i] ; + m_vpLoop[i] = nullptr ; + } + m_vpLoop.erase( m_vpLoop.begin() + m_vExtInd[nChunk], m_vpLoop.end()) ; + // elimino indice di loop esterno + m_vExtInd.pop_back() ; + } + // altrimenti + else { + // numero di loop da eliminare + int nLoopCnt = m_vExtInd[nChunk+1] - m_vExtInd[nChunk] ; + // elimino i loop + for ( int i = m_vExtInd[nChunk] ; i < m_vExtInd[nChunk+1] ; ++ i) { + delete m_vpLoop[i] ; + m_vpLoop[i] = nullptr ; + } + m_vpLoop.erase( m_vpLoop.begin() + m_vExtInd[nChunk], m_vpLoop.begin() + m_vExtInd[nChunk+1]) ; + // elimino indice di loop esterno + m_vExtInd.erase( m_vExtInd.begin() + nChunk) ; + // aggiorno indice inizio chunk successivi + for ( int i = nChunk ; i < int( m_vExtInd.size()) ; ++i) + m_vExtInd[i] -= nLoopCnt ; + } + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + ResetAuxSurf() ; + // imposto ricalcolo Voronoi + ResetVoronoiObject() ; + return true ; +} + //---------------------------------------------------------------------------- bool SurfFlatRegion::MyGetCurveClassification( const ICurve& Crv, double dLenMin, CRVCVECTOR& ccClass) const @@ -1560,6 +1648,31 @@ SurfFlatRegion::GetCurveTempProp( int nChunk, int nLoop, int nCrv, int& nProp, i return GetBasicCurveComposite( pLoop)->GetCurveTempProp( nCrv, nProp, nPropInd) ; } +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::ResetAllCurveTempProps( void) +{ + for ( int nC = 0 ; nC < GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < GetLoopCount( nC) ; ++ nL) { + ICurve* pLoop = GetMyLoop( nC, nL) ; + if ( pLoop != nullptr) { + if ( pLoop->GetType() != CRV_COMPO) { + pLoop->SetTempProp( 0, 0) ; + pLoop->SetTempProp( 0, 1) ; + } + else { + CurveComposite* pCompoLoop = GetBasicCurveComposite( pLoop) ; + for ( int nI = 0 ; nI < pCompoLoop->GetCurveCount() ; ++ nI) { + pCompoLoop->SetCurveTempProp( nI, 0, 0) ; + pCompoLoop->SetCurveTempProp( nI, 0, 1) ; + } + } + } + } + } + return true ; +} + //---------------------------------------------------------------------------- bool SurfFlatRegion::SetCurveTempParam( int nChunk, int nLoop, int nCrv, double dParam, int nParamInd) @@ -1591,3 +1704,28 @@ SurfFlatRegion::GetCurveTempParam( int nChunk, int nLoop, int nCrv, double& dPar } return GetBasicCurveComposite( pLoop)->GetCurveTempParam( nCrv, dParam, nParamInd) ; } + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::ResetAllCurveTempParams( void) +{ + for ( int nC = 0 ; nC < GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < GetLoopCount( nC) ; ++ nL) { + ICurve* pLoop = GetMyLoop( nC, nL) ; + if ( pLoop != nullptr) { + if ( pLoop->GetType() != CRV_COMPO) { + pLoop->SetTempParam( 0, 0) ; + pLoop->SetTempParam( 0, 1) ; + } + else { + CurveComposite* pCompoLoop = GetBasicCurveComposite( pLoop) ; + for ( int nI = 0 ; nI < pCompoLoop->GetCurveCount() ; ++ nI) { + pCompoLoop->SetCurveTempParam( nI, 0, 0) ; + pCompoLoop->SetCurveTempParam( nI, 0, 1) ; + } + } + } + } + } + return true ; +} diff --git a/SurfFlatRegion.h b/SurfFlatRegion.h index d257fce..be42bea 100644 --- a/SurfFlatRegion.h +++ b/SurfFlatRegion.h @@ -94,24 +94,29 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW { return m_frF.Orig() ; } const Vector3d& GetNormVersor( void) const override { return m_frF.VersZ() ; } + bool CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound = 3) const override ; + void ResetVoronoiObject( void) const override ; + bool GetMaxOffset( double& dOffs) const override ; + bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) const override ; + const SurfTriMesh* GetAuxSurf( void) const override ; + bool GetCurveClassification( const ICurve& Crv, double dLenMin, CRVCVECTOR& ccClass) const override ; int GetChunkCount( void) const override ; + SurfFlatRegion* CloneChunk( int nChunk) const override ; + bool EraseChunk(int nChunk) override ; + bool GetChunkCentroid( int nChunk, Point3d& ptCen) const override ; + bool GetChunkArea( int nChunk, double& dArea) const override ; + bool GetChunkPerimeter( int nChunk, double& dLen) const override ; + int GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& Other, int nOthChunk) const override ; // compare only outsides + bool GetChunkMaxOffset( int nChunk, double& dOffs) const override ; int GetLoopCount( int nChunk) const override ; ICurve* GetLoop( int nChunk, int nLoop) const override ; // nChunk 0-based, nLoop 0-based (1°esterno, successivi interni) bool ApproxLoopWithLines( int nChunk, int nLoop, double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ; - const SurfTriMesh* GetAuxSurf( void) const override ; - SurfFlatRegion* CloneChunk( int nChunk) const override ; - bool GetChunkCentroid( int nChunk, Point3d& ptCen) const override ; - bool GetCurveClassification( const ICurve& Crv, double dLenMin, CRVCVECTOR& ccClass) const override ; - int GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& Other, int nOthChunk) const override ; // compare only outsides - bool CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound = 3) const override ; - bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) const override ; - bool GetChunkMaxOffset( int nChunk, double& dOffs) const override ; - bool GetMaxOffset( double& dOffs) const override ; - void ResetVoronoiObject( void) const override ; bool SetCurveTempProp( int nChunk, int nLoop, int nCrv, int nProp, int nPropInd = 0) override ; bool GetCurveTempProp( int nChunk, int nLoop, int nCrv, int& nProp, int nPropInd = 0) const override ; + bool ResetAllCurveTempProps( void) override ; bool SetCurveTempParam( int nChunk, int nLoop, int nCrv, double dParam, int nParamInd = 0) override ; bool GetCurveTempParam( int nChunk, int nLoop, int nCrv, double& dParam, int nParamInd = 0) const override ; + bool ResetAllCurveTempParams( void) override ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/Tree.cpp b/Tree.cpp index 3d4f2e9..da1abbf 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -2571,6 +2571,13 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, IntersCurveCurve iccRetry( clTrimExtended, *pCC) ; icc = iccRetry ; } + if ( icc.GetCrossOrOverlapIntersCount() < 1) { + CurveLine clTrimExtended = clTrim ; + clTrimExtended.ExtendEndByLen( 5 * EPS_SMALL) ; + clTrimExtended.ExtendStartByLen( 5 * EPS_SMALL) ; + IntersCurveCurve iccRetry( clTrimExtended, *pCC) ; + icc = iccRetry ; + } IntCrvCrvInfo iccInfo ; if ( icc.GetOverlaps()) { for ( int i = 0 ; i < icc.GetIntersCount() ; ++i) {