From 4a0bd638fae5188d3bb75f584df3602610ed078d Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 8 Jan 2026 19:19:08 +0100 Subject: [PATCH] EgtGeomKernel : - in CalcPocketing migliorata la gestione dei punti iniziali dei percorsi nel caso dei Trapezi o di punti di riferimento generici. --- CalcPocketing.cpp | 190 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 143 insertions(+), 47 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 25fe4ff..dc23fc0 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -2699,7 +2699,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr double dLen0, dLen2 ; pCrvTrap->GetCurve( 0)->GetLength( dLen0) ; pCrvTrap->GetCurve( 2)->GetLength( dLen2) ; - if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) + if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) pCrvTrap->Clear() ; } @@ -2980,38 +2980,38 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr // se non ho trovato delle basi, allora cerco in maniera generale un trapezoide ( se esiste) if ( nBase == -1) { bool bOK = false ; - for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && !bOK ; ++ u) { + for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nU) { // cerco un lato chiuso ( esiste per forza) - if ( pCrvCompo->GetCurve( u)->GetTempProp( 0) == 0) { + if ( pCrvCompo->GetCurve( nU)->GetTempProp( 0) == 0) { // controllo se il lato corrente può essere una base int nType = -1 ; - if ( ! GetBoxCrvOptTrap( u, pCrvCompo, dDiam, nType, pCrvTrap)) + if ( ! GetBoxCrvOptTrap( nU, pCrvCompo, dDiam, nType, pCrvTrap)) return false ; // se è una base valida if ( nType != -1) { // ricavo la dimensione di svuotatura pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; // ricavo la sua direzione iniziale - Vector3d vtBaseDir ; pCrvCompo->GetCurve( u)->GetStartDir( vtBaseDir) ; + Vector3d vtBaseDir ; pCrvCompo->GetCurve( nU)->GetStartDir( vtBaseDir) ; // ricavo il suo punto iniziale - Point3d ptBaseStart ; pCrvCompo->GetCurve( u)->GetStartPoint( ptBaseStart) ; + Point3d ptBaseStart ; pCrvCompo->GetCurve( nU)->GetStartPoint( ptBaseStart) ; // ricavo il suo punto finale - Point3d ptBaseEnd ; pCrvCompo->GetCurve( u)->GetEndPoint( ptBaseEnd) ; + Point3d ptBaseEnd ; pCrvCompo->GetCurve( nU)->GetEndPoint( ptBaseEnd) ; // cerco il lato chiuso lineare parallelo ad esso e distante circa dPocketSize - for ( int uu = 0 ; uu < pCrvCompo->GetCurveCount() && !bOK ; ++ uu) { - if ( uu == u || - pCrvCompo->GetCurve( uu)->GetType() != CRV_LINE || - pCrvCompo->GetCurve( uu)->GetTempProp() != 0) + for ( int nOtherU = 0 ; nOtherU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nOtherU) { + if ( nOtherU == nU || + pCrvCompo->GetCurve( nOtherU)->GetType() != CRV_LINE || + pCrvCompo->GetCurve( nOtherU)->GetTempProp() != 0) continue ; - Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( uu)->GetStartDir( vtSecondBaseDir) ; + Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( nOtherU)->GetStartDir( vtSecondBaseDir) ; if ( ! AreOppositeVectorEpsilon( vtBaseDir, vtSecondBaseDir, 5 * EPS_SMALL)) continue ; - Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( uu)->GetStartPoint( ptSecondBaseStart) ; + Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( nOtherU)->GetStartPoint( ptSecondBaseStart) ; double dDist = 0. ; - DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( uu), false) ; + DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( nOtherU), false) ; if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) { - nBase = u ; - nSecondBase = uu ; + nBase = nU ; + nSecondBase = nOtherU ; if ( ! PreparareTrapezoidTwoBases( pCrvCompo, dDiam, nType, nBase, nSecondBase, bOK, pCrvTrap)) return false ; } @@ -3049,7 +3049,8 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr //---------------------------------------------------- static bool SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed, - const ICurveComposite* pCrvPocket, const PocketParams& PockParams) + const ICurveComposite* pCrvPocket, const PocketParams& PockParams, + const Point3d& ptRef) { // parametri double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; @@ -3059,10 +3060,18 @@ SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenC // calcolo gli offset dei lati obliqui PtrOwner pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ; pLineS->SimpleOffset( - dRad) ; - pLineS->Invert() ; PtrOwner pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ; pLineE->SimpleOffset( - dRad) ; - pLineE->Invert() ; + + // verifico orientamento delle curve in base al punto di riferimento ( se valido) + double dSqDistS = 0., dSqDistE = 0. ; + if ( ! ptRef.IsValid() || + ( ( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 3 : 0)).GetSqDist( dSqDistS)) && + ( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 1 : 2)).GetSqDist( dSqDistE)) && + dSqDistS < dSqDistE)) { + pLineS->Invert() ; + pLineE->Invert() ; + } Point3d ptS, ptE ; pLineS->GetEndPoint( ptS) ; @@ -3133,10 +3142,10 @@ CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSe double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; double dRad = 0.5 * dDiam + dOffsR ; - + // recupero la curva di interesse int nCrvId = ( bStart ? nSecondBase : nBase) + 1 ; - int nProp = - 1 ; + int nProp = -1 ; if ( ! pCrvPocket->GetCurveTempProp( nCrvId, nProp)) return false ; // se Open @@ -3416,6 +3425,9 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double // passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli // (possibilmente aperto) e centro nel punto iniziale del lato pCrvPocket->ToLoc( frTrap) ; + Point3d ptRef = P_INVALID ; + if ( PockParams.ptStart.IsValid()) + ptRef = GetToLoc( PockParams.ptStart, frTrap) ; // calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso) double dLen0, dLen1, dLen2, dLen3, dMaxLarg = 0. ; @@ -3434,14 +3446,17 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double BBox3d b3Dim ; pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ; dMaxLarg = ( vnProp[0] != 0 ? b3Dim.GetDimY() : dPocketSize) ; } - // calcolo percorso di svuotatura // se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale - if (( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) && - ((( vnProp[0] != 0 && vnProp[2] != 0) && ( vnProp[3] == 0 && vnProp[1] == 0) && ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) || - (( vnProp[1] != 0 && vnProp[3] != 0) && ( vnProp[0] == 0 && vnProp[2] == 0) && ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) { - if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, vnProp[0] == 0, pCrvPocket, PockParams)) { + if ( ( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) && + ( ( ( vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE) && + ( vnProp[3] == TEMP_PROP_CLOSE_EDGE && vnProp[1] == TEMP_PROP_CLOSE_EDGE) && + ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) || + ( ( vnProp[1] != TEMP_PROP_CLOSE_EDGE && vnProp[3] != TEMP_PROP_CLOSE_EDGE) && + ( vnProp[0] == TEMP_PROP_CLOSE_EDGE && vnProp[2] == TEMP_PROP_CLOSE_EDGE) && + ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) { + if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, ( vnProp[0] == TEMP_PROP_CLOSE_EDGE), pCrvPocket, PockParams, ptRef)) { pMCrv->Clear() ; return false ; } @@ -3451,7 +3466,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double double dYCoord ; // se base principale chiusa if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) - dYCoord = 0.5 * dDiam + dOffsR ; + dYCoord = 0.5 * dDiam + dOffsR ; // se base principale aperta e secondaria chiusa else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ; @@ -3462,15 +3477,32 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double // determino le quote coordinate in X inziale e finale double dXCoordStart = -INFINITO ; double dXCoordEnd = INFINITO ; - if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, - dPocketSize, PockParams) || dXCoordStart < - INFINITO + 1) + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, dPocketSize, PockParams) || + dXCoordStart < - INFINITO + 1) return false ; - if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, - dPocketSize, PockParams) || dXCoordEnd > INFINITO - 1) + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, dPocketSize, PockParams) || + dXCoordEnd > INFINITO - 1) return false ; if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL) return false ; + // determino se devo invertire la curva dato il punto di riferimento + bool bInvertByRef = false ; + if ( ptRef.IsValid()) { + PtrOwner pCrvRight( pCrvPocket->CopyParamRange( nBase + 1, nSecondBase)) ; + PtrOwner pCrvLeft( pCrvPocket->CopyParamRange( nSecondBase + 1, nBase)) ; + if ( IsNull( pCrvRight) || IsNull( pCrvLeft) || + ! pCrvRight->IsValid() || ! pCrvLeft->IsValid()) + return false ; + double dSqDistBase = INFINITO, dSqDistSecondBase = INFINITO, dSqDistLeft = INFINITO, dSqDistRight = INFINITO ; + DistPointCurve( ptRef, *pCrvPocket->GetCurve( nBase)).GetSqDist( dSqDistBase) ; + DistPointCurve( ptRef, *pCrvPocket->GetCurve( nSecondBase)).GetSqDist( dSqDistSecondBase) ; + DistPointCurve( ptRef, *pCrvRight).GetSqDist( dSqDistRight) ; + DistPointCurve( ptRef, *pCrvLeft).GetSqDist( dSqDistLeft) ; + bInvertByRef = ( dSqDistSecondBase < min( {dSqDistBase, dSqDistLeft, dSqDistRight}) || + dSqDistRight < min( {dSqDistBase, dSqDistSecondBase, dSqDistLeft})) ; + } + // determino gli estremi del segmento di svuotatura Point3d ptStart( dXCoordStart, dYCoord) ; Point3d ptEnd( dXCoordEnd, dYCoord) ; @@ -3490,7 +3522,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double if ( ! pLine1->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset) || ! pLine3->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset)) return false ; - Point3d ptS, ptE ; if ( vtDir3 * X_AX > EPS_SMALL) { pLine1->GetStartPoint( ptS) ; @@ -3500,7 +3531,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pLine1->GetEndPoint( ptE) ; pLine3->GetEndPoint( ptS) ; } - if ( vnProp[0] != TEMP_PROP_CLOSE_EDGE) { pMCrv->AddPoint( ptS) ; if ( vnProp[2] != TEMP_PROP_CLOSE_EDGE) @@ -3516,34 +3546,37 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pMCrv->AddLine( ptStart) ; pMCrv->Invert() ; } - pMCrv->SetCurveTempProp( 0, TEMP_PROP_OPEN_EDGE) ; + // verifico se invertirla nel caso di un punto di riferimento + if ( bInvertByRef && + vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE) + pMCrv->Invert() ; } } // se estremi del segmento differenti, allora il percorso è definito else { + // creo la linea if ( ! pMCrv->AddPoint( ptStart)) return true ; if ( ! pMCrv->AddLine( ptEnd)) return true ; - // aggiustamenti al percorso per rimuovere materiale residuo negli angoli if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE || pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - Frame3d frOpen ; bool bSwitch = false ; - // Base principale chiusa e base Secondaria aperta - if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { + // Base Principale chiusa e Base Secondaria aperta o inversione per punto di riferimento + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE || + bInvertByRef) { pCrvPocket->ChangeStartPoint( nSecondBase) ; // oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto) Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ; - Point3d ptORIG ; + Point3d ptOpen ; if ( vtDir.y > 0) - pCrvPocket->GetCurve( nBase)->GetEndPoint( ptORIG) ; + pCrvPocket->GetFirstCurve()->GetEndPoint( ptOpen) ; else - pCrvPocket->GetCurve( nBase)->GetStartPoint( ptORIG) ; - frOpen.Set( ptORIG, Z_AX, -X_AX) ; + pCrvPocket->GetFirstCurve()->GetStartPoint( ptOpen) ; + frOpen.Set( ptOpen, Z_AX, -X_AX) ; if ( ! frOpen.IsValid()) return false ; pCrvPocket->ToLoc( frOpen) ; @@ -3551,7 +3584,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pMCrv->Invert() ; bSwitch = true ; } - + // la Base principale è sempre aperta if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, true)) { pMCrv->Clear() ; @@ -3848,7 +3881,7 @@ GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockPara //---------------------------------------------------------------------------- static bool -GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, +GetPtStartOnOpenEdgeByOrigCurve( const Point3d& ptRef, const ICurveComposite* pCrvOrig, const PocketParams& PockParams, const ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) { @@ -3858,8 +3891,71 @@ GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketPa return false ; bMidOut = false ; - // cerco il lato aperto più lungo ( sufficientemente lungo) double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; + + // se ho un punto di riferimento, cerco il lato aperto sull'originale più vicino ad essa ( sufficientemente lungo) + if ( ptRef.IsValid()) { + double dSqMinDist = INFINITO ; + int nIndCrv = -1 ; + for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { + // escludo le sottocurve chiuse + if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) + continue ; + // recupero la curva i-esima aperta dalla curva originale + const ICurve* pCrvOpen = pCrvOrig->GetCurve( i) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + // ricavo la lunghezza di tale curva + double dLen = 0. ; + pCrvOpen->GetLength( dLen) ; + // se lunghezza accettabile o maggiore della massima trovata + if ( dLen > dLenRef - 10. * EPS_SMALL) { + // verifico la distanza con il punto di riferimento + double dCurrSqDist = 0. ; + if ( DistPointCurve( ptRef, *pCrvOpen).GetSqDist( dCurrSqDist) && dCurrSqDist < dSqMinDist) { + dSqMinDist = dCurrSqDist ; + nIndCrv = i ; + } + } + } + // se ho un indice di curva valido, allora ricavo i valori + if ( nIndCrv != -1) { + // recupero la curva + const ICurve* pCrvOpen = pCrvOrig->GetCurve( nIndCrv) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + Point3d ptSTmp ; + Vector3d vtMidOutTmp ; + // ricavo il punto medio e il vettore tangente ad esso associato + if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) { + // versore d'uscita + vtMidOutTmp.Normalize() ; + vtMidOutTmp.Rotate( Z_AX, 0, -1) ; + ptSTmp += vtMidOutTmp * max( PockParams.dRad - PockParams.dSideStep, 0.) ; + // cerco la sottocurva più vicina a ptSTmp + int nFlag ; + double dMyPar ; + if ( DistPointCurve( ptSTmp, *pCrvCompo).GetParamAtMinDistPoint( 0, dMyPar, nFlag)) { + int nCrv = int( floor( dMyPar)) ; + // recupero tale sottocurva e controllo che anche essa sia OPEN + const ICurve* pMyCrv = pCrvCompo->GetCurve( nCrv) ; + if ( pMyCrv != nullptr && pMyCrv->IsValid() && pMyCrv->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // recupero ptStart + pMyCrv->GetMidPoint( ptStart) ; + // assegno direzione fuori + vtMidOut = vtMidOutTmp ; + // flag per possibile entrata da fuori + bMidOut = true ; + } + } + } + // esco + return true ; + } + } + + // se non ho un punto di riferimento valido, o avendolo non si riesce ad entrare dal lato aperto più vicino + // cerco il lato aperto più lungo ( sufficientemente lungo) for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { // escludo le sottocurve chiuse if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) @@ -3943,7 +4039,7 @@ GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParam // se non ho trovato nulla, allora cerco un punto iniziale valido su una sottocurva OPEN if ( nStartCrv == -1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { - return GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; + return GetPtStartOnOpenEdgeByOrigCurve( ptRef, pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; } // se ho trovato la curva più vicina, cerco un punto iniziale valido else { @@ -4232,7 +4328,7 @@ SetPtStartForPath( ICurveComposite* pCrvOffs, const PocketParams& PockParams, co if ( pCrvOrig != nullptr && pCrvOrig->IsValid()) { // ... e non ho un punto di riferimento, lo cerco sulla curva originale if ( ! ptEndPrec.IsValid()) { - if ( ! GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) + if ( ! GetPtStartOnOpenEdgeByOrigCurve( P_INVALID, pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) return false ; } // ... e ho un punto di riferimento