From 21afe8165ced7fe6dea0ece9df6060437dc50362 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 20 May 2025 17:28:05 +0200 Subject: [PATCH 01/24] EgtGeomKernel : - In CalcPocketing aggiunto controllo su Feed per lati aperti - In CalcPocketing inizio stesura funzioni per Biarchi. --- CalcPocketing.cpp | 325 +++++++++++++++++++++++++++++----------------- 1 file changed, 203 insertions(+), 122 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 4af806b..14ff319 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -76,6 +76,7 @@ struct PocketParams { double dOpenEdgeRad = 0. ; // raggio effettivo di estensione degli aperti } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket +static double BIARC_MAX_LEN = 200. ; // massima lunghezza oltre la quale il biarco viene smussato typedef vector VICRVCOMPOPOVECTOR ; //--------------------------------------------------------------------------- @@ -389,29 +390,52 @@ CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nSt //---------------------------------------------------------------------------- static bool -AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig, +AssignFeedForOpenEdge( ICurveComposite* pCrv, const ISurfFlatRegion* pSfrOpenEdges, const PocketParams& PockParams) { + // NB. *pSfrOpenEdges deve essere una regione che all'esterno contiene i lati considerati aperti + // Solo ai tratti esterni vengono assegnate le Feed + // se non rischiesto il calcolo della Feed, lascio quella standard if ( ! PockParams.bCalcFeed) return AssignMaxFeed( pCrv, PockParams) ; - // controllo se qualche curva passa sopra ad un lato aperto... - if ( pCrvOF_orig != nullptr) { - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - const ICurve* pCrv_u = pCrv->GetCurve( u) ; - if ( pCrv_u == nullptr) - return false ; - int nStat = -1 ; - if ( CheckSimpleOverlap( pCrv_u, pCrvOF_orig, nStat, 1500 * EPS_SMALL) && nStat == 1) { - double dFeed = GetMinFeed( PockParams) ; - GetFeedForParam( PockParams.dOpenEdgeRad, PockParams, dFeed) ; - pCrv->SetCurveTempParam( u, dFeed, 0) ; + // se non ho una regione di classificazione, non faccio nulla + if ( pSfrOpenEdges == nullptr || ! pSfrOpenEdges->IsValid()) + return true ; + + // classifico la curva in base alla regione + CRVCVECTOR ccClass ; + if ( pSfrOpenEdges->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) { + PtrOwner pNewCrv( CreateCurveComposite()) ; + if ( IsNull( pNewCrv)) + return false ; + for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { + // recupero il tratto di curva corrente + PtrOwner pCrvRange( ConvertCurveToComposite( pCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; + if ( ! IsNull( pCrvRange) && pCrvRange->IsValid()) { + // se il tratto non è interno, calcolo la sua Feed + if ( ccClass[i].nClass != CRVC_IN) { + double dFeed = GetMinFeed( PockParams) ; + GetFeedForParam( 2. * PockParams.dRad - PockParams.dOpenEdgeRad, PockParams, dFeed) ; + AssignCustomFeed( pCrvRange, PockParams, dFeed) ; + } + // aggiungo il tratto alla sottocurva + if ( ! pNewCrv->AddCurve( Release( pCrvRange))) + return false ; } } + // assegno la curva calcolata + pNewCrv->SetTempProp( pCrv->GetTempProp( 0), 0) ; + pNewCrv->SetTempProp( pCrv->GetTempProp( 1), 1) ; + pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; + pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; + double dThick ; pCrv->GetThickness( dThick) ; + pNewCrv->SetThickness( dThick) ; + Vector3d vtExtr ; pCrv->GetExtrusion( vtExtr) ; + pNewCrv->SetExtrusion( vtExtr) ; + pCrv->CopyFrom( pNewCrv) ; } - else - AssignMaxFeed( pCrv, PockParams) ; return true ; } @@ -516,7 +540,7 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, //---------------------------------------------------------------------------- static bool AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, bool bIsLink, - bool bFirstOffs, const ICurveComposite* pCrv_orig, const PocketParams& PockParams, + bool bFirstOffs, const ISurfFlatRegion* pSfrOpenEdges, const PocketParams& PockParams, double dToll) { // controllo la validità della curva @@ -537,7 +561,7 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo // se non ho una superificie svuotata, allora esco ( con Feed Minima) if ( pSrfRemoved == nullptr || ! pSrfRemoved->IsValid() || pSrfRemoved->GetChunkCount() == 0) { // controllo eventuali sovrapposizioni con lati aperti - return AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; + return AssignFeedForOpenEdge( pCrv, pSfrOpenEdges, PockParams) ; } // parametro di Offset per regione svuotata ( restringo la superficie in maniera appropriata) @@ -567,9 +591,8 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo if ( IsNull( pCrv_sez)) continue ; // curva troppo piccola, passo alla successiva // controllo se interno o fuori alla regione ( regolando quindi la Feed) - double dCurrFeed = GetMinFeed( PockParams) ; - if ( ccClass[i].nClass == CRVC_IN) // se interna alla regione rimossa... - dCurrFeed = GetMaxFeed( PockParams) ; + double dCurrFeed = ( ccClass[i].nClass == CRVC_IN ? GetMaxFeed( PockParams) : + GetMinFeed( PockParams)) ; // assegno tale Feed ad ogni sottocurva ricavata dal tratto di classificazione for ( int u = 0 ; u < pCrv_sez->GetCurveCount() ; ++ u) pCrv_sez->SetCurveTempParam( u, dCurrFeed, 0) ; @@ -581,13 +604,14 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo pCrv->Clear() ; pCrv->AddCurve( Release( pCrv_new)) ; + // cerco di uniformare i tratti ricavati if ( ! bIsLink) { // ---------------- NEL CASO DI OFFSET ---------------- // creo un intervallo con tutte le Feed Minime Intervals IntMinFeed ; - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - double dParam ; pCrv->GetCurveTempParam( u, dParam, 0) ; - if ( abs( dParam - GetMinFeed( PockParams)) < 5 * EPS_SMALL) - IntMinFeed.Add( u, u + 1) ; + for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU) { + double dFeed ; pCrv->GetCurveTempParam( nU, dFeed, 0) ; + if ( abs( dFeed - GetMinFeed( PockParams)) < 5 * EPS_SMALL) + IntMinFeed.Add( nU, nU + 1) ; } double dParS = EPS_SMALL ; double dParE = EPS_SMALL ; // a questo intervallo tolgo tutti i sottotratti di lunghezza inferiore alla tolleranza richiesta @@ -600,13 +624,13 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo IntMinFeed_noSmall.Add( dParS, dParE) ; bFound = IntMinFeed.GetNext( dParS, dParE) ; } - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { - if ( ! IntMinFeed_noSmall.IsInside( u + 0.5)) - pCrv->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ; + for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU) { + if ( ! IntMinFeed_noSmall.IsInside( nU + 0.5)) + pCrv->SetCurveTempParam( nU, GetMaxFeed( PockParams), 0) ; } } else { // ---------------- NEL CASO DI LINK ---------------- - // le curve con lunghezza < dToll vanno modificate + // le curve con lunghezza inferiore alla tolleranza vanno modificate for ( int j = 0 ; j < pCrv->GetCurveCount() ; ++ j) { double dLen = EPS_SMALL ; pCrv->GetCurve( j)->GetLength( dLen) ; @@ -646,8 +670,7 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo } if ( bFirstOffs) - AssignFeedForOpenEdge( pCrv, pCrv_orig, PockParams) ; - + AssignFeedForOpenEdge( pCrv, pSfrOpenEdges, PockParams) ; return true ; } @@ -4664,7 +4687,7 @@ ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) // controllo dei parametri if ( pBiArcLink == nullptr) return false ; - if ( dToll > 0.99 || dToll < 0.01) + if ( dToll > 1. - 10. * EPS_SMALL || dToll < 10. * EPS_SMALL) return false ; pNewBiArc->Clear() ; @@ -4673,8 +4696,8 @@ ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) pBiArcLink->GetDomain( dUS, dUE) ; // prendo i due archi della curva BiArco - PtrOwner pArc1( pBiArcLink->CopyParamRange( dUS, ( dUS + dUE) / 2)) ; - PtrOwner pArc2( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2, dUE)) ; + PtrOwner pArc1( pBiArcLink->CopyParamRange( dUS, ( dUS + dUE) / 2.)) ; + PtrOwner pArc2( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2., dUE)) ; if ( IsNull( pArc1) || ! pArc1->IsValid() || IsNull( pArc2) || ! pArc2->IsValid()) return false ; @@ -4710,13 +4733,57 @@ ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) return true ; } +//------------------------------------------------------------------------------ +static bool +CalcSpecialSmoothBiArc( const ICurveComposite* pCrvBiArc, const ICRVCOMPOPOVECTOR& vOffIslands, + const PocketParams& PockParams, ICurveComposite* pCrvLink) +{ + // controllo della curva + if ( pCrvBiArc == nullptr || ! pCrvBiArc->IsValid() || + pCrvLink == nullptr) + return false ; + pCrvLink->Clear() ; + // controllo che la lunghezza sia sufficiente + double dLen ; pCrvBiArc->GetLength( dLen) ; + if ( dLen < 2 * PockParams.dRad + 50 * EPS_SMALL) + return false ; + // costruisco il tratto lineare + double dULineS, dULineE ; + Point3d ptLineS, ptLineE ; + if ( ! pCrvBiArc->GetParamAtLength( PockParams.dRad, dULineS) || + ! pCrvBiArc->GetPointD1D2( dULineS, ICurve::FROM_MINUS, ptLineS) || + ! pCrvBiArc->GetParamAtLength( dLen - PockParams.dRad, dULineE) || + ! pCrvBiArc->GetPointD1D2( dULineE, ICurve::FROM_MINUS, ptLineE)) + return false ; + // costruisco il collegamento lineare + PtrOwner pLine( CreateCurveComposite()) ; + if ( IsNull( pLine) || + ! CalcBoundedLink( ptLineS, ptLineE, vOffIslands, pLine)) + return false ; + // creo i due raccordi + PtrOwner pCrvStartJoint( pCrvBiArc->CopyParamRange( 0., dULineS)) ; + PtrOwner pCrvEndJoint( pCrvBiArc->CopyParamRange( dULineE, pCrvBiArc->GetCurveCount())) ; + if ( IsNull( pCrvStartJoint) || IsNull( pCrvEndJoint) || + ! pCrvStartJoint->IsValid() || ! pCrvEndJoint->IsValid()) + return false ; + // definisco il BiArco speciale + if ( ! pCrvLink->AddCurve( Release( pCrvStartJoint)) || + ! pCrvLink->AddCurve( Release( pLine)) || + ! pCrvLink->AddCurve( Release( pCrvEndJoint))) + return false ; + // smusso + ModifyCurveToSmoothed( pCrvLink, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; + return true ; +} + //------------------------------------------------------------------------------ static bool CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vOffIslands, - const PocketParams& PockParams, ICurveComposite* pCrvLink) + const PocketParams& PockParams, ICurveComposite* pCrvLink, bool& bSpecial) { // se senza smusso, ritorno tratto lineare + bSpecial = false ; if ( ! PockParams.bSmooth) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; @@ -4739,10 +4806,10 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const if ( IsNull( pBiArcLink)) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; - // se BiArco troppo grande allora lo modifico - double dLenBiArc ; - pBiArcLink->GetLength( dLenBiArc) ; - if ( dLenBiArc > 200) { + // se BiArco troppo grande allora lo modifico (ne tengo una copia per eventuale gestione speciale) + PtrOwner pCrvBiArc_clone( ConvertCurveToComposite( pBiArcLink->Clone())) ; + double dLenBiArc ; pBiArcLink->GetLength( dLenBiArc) ; + if ( dLenBiArc > BIARC_MAX_LEN) { PtrOwner pCrvNewBiArcS( CreateBasicCurveComposite()) ; ModifyBiArc( pBiArcLink, 0.2, pCrvNewBiArcS) ; pBiArcLink.Set( pCrvNewBiArcS) ; @@ -4856,42 +4923,37 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM pCrvLink->Clear() ; // curva finale da restituire - PtrOwner ptCrvFinal( CreateBasicCurveComposite()) ; - if ( IsNull( ptCrvFinal)) + PtrOwner pCrvFinal( CreateBasicCurveComposite()) ; + if ( IsNull( pCrvFinal)) return false ; - // Prendo i punti, i vettori tangenti e i parametri di essi per le curve - Point3d ptSS, ptSE, ptES, ptEE ; - Vector3d vS, vE ; - double dUSS, dUSE, dUES, dUEE, dLenS, dLenE ; - dUSS = 0 ; dUSE = 0 ; - pCrvS->GetEndPoint( ptSE) ; - pCrvS->GetStartPoint( ptSS) ; - pCrvE->GetStartPoint( ptES) ; - pCrvE->GetEndPoint( ptEE) ; - pCrvS->GetEndDir( vS) ; - pCrvE->GetStartDir( vE) ; - pCrvS->GetDomain( dUSS, dUSE) ; - pCrvE->GetDomain( dUES, dUEE) ; - pCrvS->GetLength( dLenS) ; - pCrvE->GetLength( dLenE) ; + // recupero gli estremi delle due curve ( S = Start, E = End) + Point3d ptSS ; pCrvS->GetStartPoint( ptSS) ; + Point3d ptSE ; pCrvS->GetEndPoint( ptSE) ; + Point3d ptES ; pCrvE->GetStartPoint( ptES) ; + Point3d ptEE ; pCrvE->GetEndPoint( ptEE) ; + // recupero i versori per il BiArco + Vector3d vS ; pCrvS->GetEndDir( vS) ; + Vector3d vE ; pCrvE->GetStartDir( vE) ; + // recupero i domini delle curve + double dUSS, dUSE ; pCrvS->GetDomain( dUSS, dUSE) ; + double dUES, dUEE ; pCrvE->GetDomain( dUES, dUEE) ; + // recupero le lunghezze delle curve + double dLenS ; pCrvS->GetLength( dLenS) ; + double dLenE ; pCrvE->GetLength( dLenE) ; - // se ho una curva di primo Offset allora non devo accorciarla ... ( si per bordi esterni che per isole) + // se ho una curva di primo Offset allora non devo accorciarla ( sia per bordi esterni che per isole) for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) { if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE)) - dLenPercS = 0 ; + dLenPercS = 0. ; if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) - dLenPercE = 0 ; + dLenPercE = 0. ; } double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : PockParams.dRad) ; dLenE = 0 ; - /* - calcolo il biArco tra il punto iniziale e finale dei due offset consecutivi - se richiesto lo smusso -> accorcio entrambi i tratti di Offset e, riuscendo, si sotituisce - il biArco calcolato prima con quest'ultimo - */ + // recupero il numero massimo di iterazioni per il calcolo del BiArco int nMaxIter = 2 ; if ( ! PockParams.bSmooth) nMaxIter = 1 ; @@ -4901,46 +4963,45 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM while ( nIter < nMaxIter) { // calcolo il biArco - PtrOwner ptBiArc( CreateBasicCurveComposite()) ; - if ( ! CalcBoundedSmoothedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, PockParams, ptBiArc) || - ptBiArc->GetCurveCount() == 0) + bool bSpecial = false ; + PtrOwner pCrvBiArc( CreateBasicCurveComposite()) ; + if ( IsNull( pCrvBiArc) || + ! CalcBoundedSmoothedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, PockParams, pCrvBiArc, bSpecial) || + pCrvBiArc->GetCurveCount() == 0) return false ; + pCrvFinal->Clear() ; + pCrvFinal.Set( pCrvBiArc->Clone()) ; - ptCrvFinal->Clear() ; - ptCrvFinal.Set( ptBiArc->Clone()) ; - - if ( dLenPercE == 0 && dLenPercS == 0 ) + // se non devo cercarne altri, allora tengo quest'ultimo + if ( dLenPercE == 0 && dLenPercS == 0 || bSpecial) break ; - - // se ho trovato un BiArco valido, allora accorcio le due curve di Offset - dLenS -= dLStepS ; + // altrimentik, calcolo un nuovo BiArco, estendendo i suoi estremi + #if 0 // nel caso volessi estendere anche prima del punto finale + dLenS -= dLStepS ; + #endif dLenE += dLStepE ; // ricalcolo il punto iniziale e finale pCrvS->GetParamAtLength( dLenS, dUSE) ; - pCrvS->GetPointD1D2( dUSE, ICurve::FROM_MINUS, ptSE) ; + if ( ! pCrvS->GetPointD1D2( dUSE, ICurve::FROM_MINUS, ptSE, &vS)) + return false ; + vS.Normalize() ; pCrvE->GetParamAtLength( dLenE, dUES) ; - pCrvE->GetPointD1D2( dUES, ICurve::FROM_PLUS, ptES) ; - - // ricalcolo il vettore tangente iniziale e finale - PtrOwner pCrvS_clone( CloneCurveComposite( pCrvS)) ; - PtrOwner pCrvE_clone( CloneCurveComposite( pCrvE)) ; - pCrvS_clone->ChangeStartPoint( dUSE) ; - pCrvE_clone->ChangeStartPoint( dUES) ; - pCrvS_clone->GetStartDir( vS) ; - pCrvE_clone->GetStartDir( vE) ; + if ( ! pCrvE->GetPointD1D2( dUES, ICurve::FROM_PLUS, ptES, &vE)) + return false ; + vE.Normalize() ; ++ nIter ; } - pCrvLink->AddCurve( Release( ptCrvFinal)) ; // ultimo arco valido trovato + pCrvLink->AddCurve( Release( pCrvFinal)) ; // ultimo arco valido trovato return true ; } //---------------------------------------------------------- static bool GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, - const ICurveComposite* pCrv_orig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) + const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) { // controllo dei parametri @@ -4948,7 +5009,10 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& return false ; pSrfToCut->Clear() ; - // 1) creo la regione esterna + // creo la regione esterna ( definita dalle curve di primo Offset) + // NB. Questa regione è diversa dalla pSfrOrig : + // - i tratti chiusi sono Offsettati di R + OffsR() + // - i tratti aperti sono stati estesi all'esterno PtrOwner pSrfExtern( CreateSurfFlatRegion()) ; if ( IsNull( pSrfExtern)) return false ; @@ -4964,8 +5028,20 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } } - // ---- le seguenti regioni sono distinte per calcolar emeglio la Feed ---- - // Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links + // 2) creo la regione che all'esterno contiene i lati aperti + // NB. Prendendo la superficie originale ( con lati Open/Close impostati), se effettuo un + // Offset interno dell'estensione degli aperti, tutto ciò che è all'esterno di tale regione è classificato + // come lato aperto + PtrOwner pSfrForOpenEdges( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrForOpenEdges)) + return false ; + if ( pSfrOrig != nullptr && pSfrOrig->IsValid()) { + if ( ! pSfrForOpenEdges.Set( CloneSurfFlatRegion( pSfrOrig)) || + ! pSfrForOpenEdges->Offset( 1000 * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + } + + // definisco la regione rimossa dall'utensile PtrOwner pSfrTool( CreateSurfFlatRegion()) ; if ( IsNull( pSfrTool)) return false ; @@ -4983,11 +5059,15 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& // Feed bool bFirstOffs = false ; - Point3d ptStart ; vOffs[i]->GetStartPoint( ptStart) ; - for ( int j = 0 ; j < int( vFirstOffs.size()) && ! bFirstOffs ; ++ j) - bFirstOffs = vFirstOffs[j]->IsPointOn( ptStart, 100 * EPS_SMALL) ; + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) + bFirstOffs = true ; + else { + Point3d ptStart ; vOffs[i]->GetStartPoint( ptStart) ; + for ( int j = 0 ; j < int( vFirstOffs.size()) && ! bFirstOffs ; ++ j) + bFirstOffs = vFirstOffs[j]->IsPointOn( ptStart, 100 * EPS_SMALL) ; + } // calcolo gli intervalli di Feed per la curva di Offset - if ( ! AssignFeedSpiral( vOffs[i], pSfrTool, false, bFirstOffs, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) + if ( ! AssignFeedSpiral( vOffs[i], pSfrTool, false, bFirstOffs, pSfrForOpenEdges, PockParams, 2 * PockParams.dRad / 3)) return false ; // aggiorno la superificie svuotata PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( vOffs[i]->Clone() , PockParams.dRad + 5 * EPS_SMALL, false, false)) ; @@ -5013,7 +5093,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& PtrOwner pCrvLink( ConvertCurveToComposite( vLinks[nLink_Ind]->Clone())) ; // calcolo gli intervalli di Feed per la curva di Link if ( IsNull( pCrvLink) || ! pCrvLink->IsValid() || - ! AssignFeedSpiral( pCrvLink, pSfrTool, true, false, pCrv_orig, PockParams, 2 * PockParams.dRad / 3)) + ! AssignFeedSpiral( pCrvLink, pSfrTool, true, false, pSfrForOpenEdges, PockParams, 2 * PockParams.dRad / 3)) return false ; // aggiorno la regione svuotata PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( pCrvLink->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; @@ -5235,9 +5315,10 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs } // recupero le due direzioni per i Biarchi bool bSameDir = AreSameVectorEpsilon( vt1, vt2, 2 * EPS_SMALL) ; + bool bSpecial = false ; // se parallele, allora trasformo in una circonferenza if ( bSameDir) { - if ( ! CalcBoundedSmoothedLink( ptMain, V_INVALID, ptCentroid, V_INVALID, 0., vOffsFirstCurve, PockParams, pCrvCurl)) + if ( ! CalcBoundedSmoothedLink( ptMain, V_INVALID, ptCentroid, V_INVALID, 0., vOffsFirstCurve, PockParams, pCrvCurl, bSpecial)) continue ; Vector3d vtStartCheck ; pCrvCurl->GetStartDir( vtStartCheck) ; if ( AreOppositeVectorApprox( vtStartCheck, vt1)) @@ -5256,8 +5337,8 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs PtrOwner pCrvBiArc1( CreateCurveComposite()) ; PtrOwner pCrvBiArc2( CreateCurveComposite()) ; if ( IsNull( pCrvBiArc1) || IsNull( pCrvBiArc2) || - ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vtDir, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc1) || - ! CalcBoundedSmoothedLink( ptCentroid, vtDir, ptMain, vt2, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc2)) + ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vtDir, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc1, bSpecial) || + ! CalcBoundedSmoothedLink( ptCentroid, vtDir, ptMain, vt2, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc2, bSpecial)) continue ; // aggiorno la curva a ricciolo @@ -5282,6 +5363,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs // se la curva a ricciolo non svuota il Chunk nC-esimo -> percorro il bordo di tale Chunk if ( pSfrChunk->IsValid() || pSfrChunk->GetChunkCount() > 0) { + // so che il punto più vicino alla curva è ptCloser // ricavo dunque il punto più vicino sul bordo del Chunk nC-esimo PtrOwner pCompoChunkBorder( ConvertCurveToComposite( pSfrUncleared->GetLoop( nC, 0))) ; @@ -5297,10 +5379,15 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs double dUS = 0. ; pCompoChunkBorder->GetParamAtPoint( ptCloserOnChunk, dUS) ; pCompoChunkBorder->ChangeStartPoint( dUS) ; + /* Creo due curve composite rappresentanti un piccolo tratto tangente sulla curva di Offset attuale; questi servono per la partenza e l'arrivo dei biArchi */ + if ( bSameDir) { + pt1 = ptMain ; + pt2 = ptMain ; + } PtrOwner pCompoHelpS( CreateCurveComposite()) ; if ( IsNull( pCompoHelpS) || ! pCompoHelpS->AddPoint( pt1 - vt1 / 4) || ! vt1.Normalize() || ! pCompoHelpS->AddLine( pt1)) @@ -5309,6 +5396,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs if ( IsNull( pCompoHelpE) || ! pCompoHelpE->AddPoint( pt2) || ! vt2.Normalize() || ! pCompoHelpE->AddLine( pt2 + vt2 / 4)) continue ; + /* creo il Biarco iniziale ( nel caso non si riuscisse diventa un segmento lineare) @@ -5330,6 +5418,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs // accorgio il bordo dell'Offset in raccordo al BiArco iniziale if ( dMyU > EPS_SMALL) pCompoChunkBorder->TrimStartAtParam( dMyU) ; + /* creo il Biarco finale ( nel caso non si riuscisse diventa un segmento lineare) @@ -5347,6 +5436,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs if ( ! pCrvBiArc2->GetStartPoint( ptMyPoint) || ! pCompoChunkBorder->GetParamAtPoint( ptMyPoint, dMyU)) continue ; + // la curva a ricciolo ora diventa l'unione di pCrvBiArc1 - pCompoChunkBorder - pCrvBiArc2 pCrvCurl->Clear() ; // smusso la curva di bordo del Chunk ( è aperta) @@ -5372,12 +5462,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs continue ; // aggiungo il tratto finale di Offset pCrvTest->AddCurve( ConvertCurveToBasicComposite( pMyOffs->CopyParamRange( dURef2, pMyOffs->GetCurveCount()))) ; - // nel caso di direzioni parallele manca uno smusso - //if ( bSameDir) { - // double dSmoothPar = PockParams.dRad / 8. ; - // ModifyCurveToSmoothed( pCrvTest, PockParams, dSmoothPar, dSmoothPar, false) ; - //} - // provo a controllare che i punti inzili e finali coincidano, in caso aggiorno il nuovo Offset + // provo a controllare che i punti inziali e finali coincidano, in caso aggiorno il nuovo Offset Point3d ptStart_Old ; vOffs[nInd]->GetStartPoint( ptStart_Old) ; Point3d ptEnd_Old ; vOffs[nInd]->GetEndPoint( ptEnd_Old) ; Point3d ptStart_New ; pCrvTest->GetStartPoint( ptStart_New) ; @@ -5405,16 +5490,13 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { - // ricavo il punto inziale della curva corrente Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; - int nNextInd = -1 ; // indice della curva successiva double dMinDist = INFINITO ; // distanza tra questa curva e la successiva Point3d ptStartNext ; // punto iniziale della curva successiva - // tra le curve successive cerco la curva interna e più vicina ad essa for ( int j = i + 1 ; j < int( vOffs.size()) ; ++ j) { IntersCurveCurve IntCC( *vOffs[i], *vOffs[j]) ; @@ -5457,7 +5539,6 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scambio la curva i+1 esima con la j-esima ( se non sono già in ordine) if ( nNextInd != i + 1) swap( vOffs[nNextInd], vOffs[i+1]) ; - // cambio il suo punto iniziale nel punto più vicino tovato double dUS ; if ( ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUS, EPS_SMALL)) @@ -5476,31 +5557,30 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con if ( IsNull( pCrvLink)) return false ; // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset - if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, - ( i == 0 ? 0. : 10 * EPS_SMALL), 10 * EPS_SMALL, pCrvLink) || + double dLenPercS = ( i == 0 ? 0. : 10 * EPS_SMALL) ; + double dLenPercE = 10 * EPS_SMALL ; + if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, dLenPercS, dLenPercE, pCrvLink) || ! pCrvLink->IsValid()) { - // se non sono riuscito, cerco una strada più semplice - // ripristino le curve + // se non sono riuscito, cerco una strada più semplice ripristinando le curve pCrvLink->Clear() ; vOffs[i].Set( pCrv_i) ; // chiuso vOffs[i+1].Set( pCrv_ii) ; // chiuso - // recupero i vettori tangente iniziali ( le curve sono chiuse ) + // recupero i vettori tangenti iniziali ( le curve sono chiuse ) Vector3d vtS, vtE ; if ( ! vOffs[i]->GetStartDir( vtS) || ! vOffs[i+1]->GetStartDir( vtE)) return false ; // creo il bi-arco tra esse - if ( CalcBoundedSmoothedLink( ptS, vtS, ptStartNext, vtE, 0.5, vOffsFirstCurve, PockParams, pCrvLink)) + bool bSpecial = false ; + if ( CalcBoundedSmoothedLink( ptS, vtS, ptStartNext, vtE, 0.5, vOffsFirstCurve, PockParams, pCrvLink, bSpecial)) vLinks[i + 1].Set( pCrvLink) ; // aggiorno il collegamento else return false ; - continue ; // passo alla curva i+1 esima successiva } // per sicurezza aggiorno i nuovi punti e i nuovi parametri double dUNewS, dUNewE ; - if ( ! pCrvLink->GetStartPoint( ptS) || - ! pCrvLink->GetEndPoint( ptStartNext) || + if ( ! pCrvLink->GetEndPoint( ptStartNext) || ! vOffs[i]->GetParamAtPoint( ptS, dUNewS) || ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUNewE)) return false ; @@ -5650,7 +5730,7 @@ IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const Po //---------------------------------------------------------------------------- static bool -CalcSpiral( const ISurfFlatRegion* pSfrPock, const PocketParams& PockParams, int& nReg, Point3d& ptStart, +CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, int& nReg, Point3d& ptStart, ICRVCOMPOPOVECTOR& vCrvOrigChunkLoops, ICurveComposite* pMCrv, bool& bMidOut, Vector3d& vtMidOut) { // inizializzo il percorso come vuoto @@ -5814,7 +5894,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const PocketParams& PockParams, int // controllo eventuali parti non svuotate ( e setto la Feed degli Offset e dei Link)... PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; - if ( GetUnclearedRegionAndSetFeed( vOffsFirstCurve, vOffs, vLinks, vCrvOrigChunkLoops[0], PockParams, pSfrUncleared)) { + if ( GetUnclearedRegionAndSetFeed( vOffsFirstCurve, vOffs, vLinks, pSfrOrig, PockParams, pSfrUncleared)) { // modifico i percorsi if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) return false ; @@ -6379,7 +6459,7 @@ AddSpiralIn( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // calcolo il percorso di svuotatura bool bSomeOpen ; Vector3d vtMidOut ; - if ( ! CalcSpiral( pSfrChunk, PockParams, nRegTot, ptStart, vCrvOrigChunkLoops, pMCrv, bSomeOpen, vtMidOut)) + if ( ! CalcSpiral( pSfrChunk, pSfrOrig, PockParams, nRegTot, ptStart, vCrvOrigChunkLoops, pMCrv, bSomeOpen, vtMidOut)) return false ; // se terminate le regioni, esco @@ -6456,7 +6536,7 @@ AddSpiralOut( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, // calcolo il percorso di svuotatura bool bSomeOpen ; Vector3d vtMidOut ; - if ( ! CalcSpiral( pSfrChunk, PockParams, nRegTot, ptStart, vCrvOrig, pMCrv, bSomeOpen, vtMidOut)) + if ( ! CalcSpiral( pSfrChunk, pSfrOrig, PockParams, nRegTot, ptStart, vCrvOrig, pMCrv, bSomeOpen, vtMidOut)) return false ; // se terminate le regioni, esco @@ -7093,7 +7173,8 @@ GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, Pocket ! pCrvOffs0->GetStartPoint( ptS) || ! pCrvOffs1->GetStartPoint( ptE)) return false ; // creo il bi-arco tra esse - if ( ! CalcBoundedSmoothedLink( ptS, vtS, ptE, vtE, 0.5, vCrvChunk, PockParams, pCrvLink) || + bool bSpecial = false ; + if ( ! CalcBoundedSmoothedLink( ptS, vtS, ptE, vtE, 0.5, vCrvChunk, PockParams, pCrvLink, bSpecial) || ! pCrvLink->IsValid()) return false ; } @@ -7621,7 +7702,7 @@ CalcConformalOffsAndLinks( VICRVCOMPOPOVECTOR& vvCrvOffs, const ISurfFlatRegion* //---------------------------------------------------------------------------- static bool -ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const PocketParams& PockParams, +ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ICRVCOMPOPOVECTOR& vCrvOffs, ICURVEPOVECTOR& vCrvLinks) { // controllo dei parametri @@ -7641,7 +7722,7 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const PocketPara PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; if ( IsNull( pSfrUncleared)) return false ; - if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, nullptr, PockParams, pSfrUncleared)) { + if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, pSfrOrig, PockParams, pSfrUncleared)) { // estendo i percorsi di Offset se richiesto if ( ! RemoveExtraParts( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) return false ; @@ -8490,7 +8571,7 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, // flag per controllo bool bOk = true ; // estendo i percorsi per eventuali regioni non svuotate e calcolo le Feed - bOk = bOk && ExtendConformalOffsAndSetFeed( pSfrPock, PockParams, vCrvOffs, vCrvLink) ; + bOk = bOk && ExtendConformalOffsAndSetFeed( pSfrPock, pSfrOrig, PockParams, vCrvOffs, vCrvLink) ; // concateno Offset e Links ICRVCOMPOPOVECTOR vCrvPaths ; bOk = bOk && ChainConformalOffsWithLinks( vCrvOffs, vCrvLink, vCrvPaths) ; From 0e663c02c4abfe937dd0e45993076aac18b80886 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Wed, 21 May 2025 09:34:18 +0200 Subject: [PATCH 02/24] EgtGeomKernel : - piccola miglioria suggeritra da compilatore 64bit. --- CalcPocketing.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 14ff319..994f7ea 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -4946,7 +4946,7 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) { if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE)) dLenPercS = 0. ; - if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) + if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) dLenPercE = 0. ; } double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; @@ -4973,9 +4973,9 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM pCrvFinal.Set( pCrvBiArc->Clone()) ; // se non devo cercarne altri, allora tengo quest'ultimo - if ( dLenPercE == 0 && dLenPercS == 0 || bSpecial) + if ( ( dLenPercE == 0 && dLenPercS == 0) || bSpecial) break ; - // altrimentik, calcolo un nuovo BiArco, estendendo i suoi estremi + // altrimenti, calcolo un nuovo BiArco, estendendo i suoi estremi #if 0 // nel caso volessi estendere anche prima del punto finale dLenS -= dLStepS ; #endif From 0a21a582becaf66333ff0e44cf34562a88c68d34 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 22 May 2025 10:32:36 +0200 Subject: [PATCH 03/24] EgtGeomKernel : - correzione scelta basi e tempProps per le curve a trapezio. --- CalcPocketing.cpp | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 994f7ea..3383a63 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -2429,6 +2429,8 @@ CalcTrapezoidSpiralLocalFrame( ICurveComposite* pCrvTrap, const Vector3d& vtDir, } if ( nBaseId != 0 && nBaseId != 1) return false ; + if ( pCrvTrap->GetCurve( nBaseId)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) + nBaseId += 2 ; // imposto come lato iniziale per la curva uno dei lati paralleli a vtDir pCrvTrap->ChangeStartPoint( nBaseId) ; @@ -2632,20 +2634,21 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr vtDir.Normalize() ; Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ; dPocketSize = vtOrtho.Len() ; - if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap)) - return false ; // assegno le tempProp della curva trapezio for ( int nU = 0 ; nU < 4 ; ++ nU) { Vector3d vtCrvDir ; pCrvTrap->GetCurve( nU)->GetStartDir( vtCrvDir) ; for ( int nI = 0 ; nI < pCrvCompo->GetCurveCount() ; ++ nI) { - Vector3d vtCurrCrvDir ; pCrvTrap->GetCurve( nI)->GetStartDir( vtCurrCrvDir) ; + Vector3d vtCurrCrvDir ; pCrvCompo->GetCurve( nI)->GetStartDir( vtCurrCrvDir) ; if ( AreSameVectorEpsilon( vtCrvDir, vtCurrCrvDir, 150 * EPS_SMALL)) { pCrvTrap->SetCurveTempProp( nU, pCrvCompo->GetCurve( nI)->GetTempProp( 0), 0) ; break ; } } } - bool bBaseOpen = ( pCrvTrap->GetCurve( 0)->GetTempProp( 0) == 1 || pCrvTrap->GetCurve( 2)->GetTempProp( 0) == 1) ; + if ( ! CalcTrapezoidSpiralLocalFrame( pCrvTrap, vtDir, frTrap)) + return false ; + bool bBaseOpen = ( pCrvTrap->GetCurve( 0)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE || + pCrvTrap->GetCurve( 2)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) ; // controllo dimensioni della svuotatura if ( ! ( bBaseOpen && dPocketSize < dDiam + EPS_SMALL) && abs( dPocketSize - dDiam) > EPS_SMALL) { @@ -2653,7 +2656,8 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr return true ; } // recupero flag aperto/chiuso dei lati - if ( pCrvTrap->GetCurve( 1)->GetTempProp( 0) == 0 && pCrvTrap->GetCurve( 3)->GetTempProp( 0) == 0) { + if ( pCrvTrap->GetCurve( 1)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE && + pCrvTrap->GetCurve( 3)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { double dLen0, dLen2 ; pCrvTrap->GetCurve( 0)->GetLength( dLen0) ; pCrvTrap->GetCurve( 2)->GetLength( dLen2) ; @@ -2705,7 +2709,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr frTrap.Set( ptNewOrig, Z_AX, vtDir) ; // imposto tutte le 4 curve come aperte for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) - pCrvTrap->SetCurveTempProp( u, 1, 0) ; + pCrvTrap->SetCurveTempProp( u, TEMP_PROP_OPEN_EDGE, 0) ; // imposto le basi nBase = 0 ; nSecondBase = 2 ; @@ -2719,7 +2723,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr if ( nType != -1) { // imposto tutte le curve come aperte tranne la prima ( estendo il solo lato chiuso come base del Box) for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) - pCrvTrap->SetCurveTempProp( u, u == 0 ? 0 : 1, 0) ; + pCrvTrap->SetCurveTempProp( u, u == 0 ? 0 : TEMP_PROP_OPEN_EDGE, 0) ; // memorizzo la dimensione di svuotatura pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; // imposto le basi @@ -2755,7 +2759,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) { // imposto tutte le curve di indice dispari aperte for ( int u = 0 ; u < pCrvTrap->GetCurveCount() ; ++ u) - pCrvTrap->SetCurveTempProp( u, u % 2 == 0 ? 0 : 1, 0) ; + pCrvTrap->SetCurveTempProp( u, u % 2 == 0 ? TEMP_PROP_CLOSE_EDGE : TEMP_PROP_OPEN_EDGE, 0) ; // imposto le basi nBase = 0 ; nSecondBase = 2 ; @@ -3377,7 +3381,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double double dLen0, dLen1, dLen2, dLen3, dMaxLarg = 0. ; pCrvPocket->GetCurve( nBase)->GetLength( dLen0) ; pCrvPocket->GetCurve( nSecondBase)->GetLength( dLen2) ; - bool bRealTrap = pCrvPocket->GetCurveCount() == 4 ; + bool bRealTrap = ( pCrvPocket->GetCurveCount() == 4) ; for ( int i = 0 ; i < 4 && bRealTrap ; ++ i) bRealTrap = pCrvPocket->GetCurve( i)->GetType() == CRV_LINE ; if ( bRealTrap) { @@ -3405,9 +3409,9 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double else { // trovo la quota Y per centro del Tool double dYCoord ; - if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 0) // se base principale chiusa + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) // se base principale chiusa dYCoord = 0.5 * dDiam + dOffsR ; - else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 0) // se base principale aperta e secondaria chiusa + else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) // se base principale aperta e secondaria chiusa dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ; else // se entrambi i lati paralleli sono aperti mi posiziono a metà della svuotatura dYCoord = 0.5 * dPocketSize ; @@ -3449,23 +3453,23 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pLine3->GetEndPoint( ptS) ; } - if ( vnProp[0] != 0) { + if ( vnProp[0] != TEMP_PROP_CLOSE_EDGE) { pMCrv->AddPoint( ptS) ; - if ( vnProp[2] != 0) + if ( vnProp[2] != TEMP_PROP_CLOSE_EDGE) pMCrv->AddLine( ptE) ; else pMCrv->AddLine( ptStart) ; } else { pMCrv->AddPoint( ptE) ; - if ( vnProp[0] != 0) + if ( vnProp[0] != TEMP_PROP_CLOSE_EDGE) pMCrv->AddLine( ptS) ; else pMCrv->AddLine( ptStart) ; pMCrv->Invert() ; } - pMCrv->SetCurveTempProp( 0, 1) ; + pMCrv->SetCurveTempProp( 0, TEMP_PROP_OPEN_EDGE) ; } } else { @@ -3475,13 +3479,13 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double return true ; // aggiustamenti al percorso per rimuovere materiale residuo negli angoli - if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == 1 || - pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == 1) { + 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) == 0) { + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { pCrvPocket->ChangeStartPoint( nSecondBase) ; // oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto) Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ; @@ -3499,12 +3503,12 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double bSwitch = true ; } - if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == 0 && + if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, true)) { pMCrv->Clear() ; return false ; } - if ( pCrvPocket->GetCurve( 1)->GetTempProp( 0) == 0 && + if ( pCrvPocket->GetCurve( 1)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, false)) { pMCrv->Clear() ; return false ; @@ -3525,7 +3529,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pMCrv->ToGlob( frTrap) ; - if ( ! PockParams.bInvert) { + if ( PockParams.bInvert) { pMCrv->Invert() ; // inverto le proprietà in modo che nProp3 sia sempre legata al punto iniziale e nProp1 a quello finale swap( vnProp[1], vnProp[3]) ; From 4a5639780bb547a57416e88a62038b51c5e840aa Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 22 May 2025 12:02:53 +0200 Subject: [PATCH 04/24] EgtGeomKernel : - In CalcPocketing aggiunto controllo di MaxOptSize anche sulle curve singole di lavorazione. --- CalcPocketing.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 3383a63..726cf59 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -1832,6 +1832,9 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara pSfrChunk->GetMaxOffset( dMaxOffs) ; if ( dMaxOffs > PockParams.dRad + 200 * EPS_SMALL) return true ; + // controllo che il MaxOptSize sia coerente + if ( 2 * dMaxOffs > PockParams.dMaxOptSize + 10 * EPS_SMALL) + return true ; /* NB. Si poteva calcolare la Fat curve del raggio utensile dell'Offset di tutti i chiusi e vedere @@ -1859,6 +1862,9 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara vpCrvs.erase( vpCrvs.end() - 1) ; } } + // CASO PARTICOLARE : Tunnel ( 2 tratti open e due tratto chiusi) -> non uso le curve singole + if ( int( vpCrvs.size() == 4)) + return true ; // controllo se il loop Esterno è uniforme ( quindi tutto chiuso o tutto aperto) bool bExtAllClose = false ; bool bExtAllOpen = false ; @@ -1870,7 +1876,7 @@ GetPocketCurvesByClosedEdges( const ISurfFlatRegion* pSfrChunk, const PocketPara } // NB. Se regione estena tutta chiusa o aperta e senza isole... allora non faccio nulla ( es caso trapezi) // Se tutta chiusa -> Chunk non svuotabile, il contro-offset del raggio utensile annulla la regione - // Se tutta aperta -> La regione è definita mediante Offset esterno del contorno aperto + // Se tutta aperta -> La regione è definita mediante Offset esterno del contorno aperto if ( ( bExtAllClose || bExtAllOpen) && ! bHasIslands) return true ; // Se il contorno esterno è misto -> non devo avere isole From 7edf4bced8df27028f2f70ed9e56632378a9ea2b Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 27 May 2025 08:28:56 +0200 Subject: [PATCH 05/24] EgtGeomKernel : - Aggiunto parametro alle funzioni per creare la FatCurve. --- CurveAux.cpp | 5 +++-- SfrCreate.cpp | 5 +++-- Voronoi.cpp | 19 ++++++++++--------- Voronoi.h | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 4bc1c70..a47fb8e 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -2043,13 +2043,14 @@ CalcCurvesMedialAxis( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nS //---------------------------------------------------------------------------- bool -CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids) +CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids, + bool bMergeOnlySameProps) { Voronoi* pVoronoiObj = GetCurveVoronoi( crvC) ; if ( pVoronoiObj == nullptr) return false ; - return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids) ; + return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps) ; } //---------------------------------------------------------------------------- diff --git a/SfrCreate.cpp b/SfrCreate.cpp index cc18437..4535e90 100644 --- a/SfrCreate.cpp +++ b/SfrCreate.cpp @@ -115,7 +115,8 @@ GetSurfFlatRegionDisk( double dRadius) //------------------------------------------------------------------------------- ISurfFlatRegion* -GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol) +GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol, + bool bMergeOnlySameProps) { // metodo di calcolo impostato da USE_VORONOI @@ -330,7 +331,7 @@ GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, b else { // calcolo la fat curve con Voronoi ICURVEPOVECTOR vFatCurves ; - if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids)) + if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps)) return nullptr ; // costruisco la superficie a partire dalle curve diff --git a/Voronoi.cpp b/Voronoi.cpp index 8321f49..4feb971 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -847,18 +847,19 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) //---------------------------------------------------------------------------- bool -Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids) +Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids, + bool bMergeOnlySameProps) { vCrvs.clear() ; if ( ! IsValid()) - return false ; - - // se offset nullo errore - if ( abs( dOffs) < EPS_SMALL) return false ; - ICRVCOMPOPLIST OffsList ; + // se offset nullo errore + if ( abs( dOffs) < EPS_SMALL) + return false ; + + ICRVCOMPOPLIST OffsList ; if ( ! CalcVroniOffset( OffsList, abs( dOffs))) return false ; @@ -873,7 +874,7 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo // identifico i raccordi da modificare if ( bClosed && bSquareMids) { // se curva è chiusa tutti i raccordi rispondono a bSquareMids - IdentifyFillets( pCrvOffs, dOffs) ; + IdentifyFillets( pCrvOffs, dOffs) ; } else if ( ! bClosed && ( bSquareMids || bSquareEnds)) { // se curva è aperta devo distinguere i raccordi interni da quelli relativi agli estremi e @@ -889,9 +890,9 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo } // unisco le parti allineate - pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ; + pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, bMergeOnlySameProps) ; // aggiungo al vettore finale - vCrvs.emplace_back( pCrvOffs) ; + vCrvs.emplace_back( pCrvOffs) ; } // sistemo i raccordi diff --git a/Voronoi.h b/Voronoi.h index 8f6e1fc..d0f033b 100644 --- a/Voronoi.h +++ b/Voronoi.h @@ -57,7 +57,7 @@ class Voronoi bool CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) ; bool CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) ; bool CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) ; - bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids) ; + bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps = true) ; bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) ; bool CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) ; From 0f14e8335ade36c1c421b47153a286864a9baf11 Mon Sep 17 00:00:00 2001 From: SaraP Date: Tue, 27 May 2025 12:05:04 +0200 Subject: [PATCH 06/24] EgtGeomKernel : - aggiornata funzione CalcZigZagInfill per modifiche a CalcZigZag. --- CalcPocketing.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 726cf59..44acad9 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -9105,6 +9105,9 @@ CalcZigZagInfill( const ISurfFlatRegion* pSfr, double dStep, bool bSmooth, bool PocketParams myParams ; myParams.bSmooth = false ; myParams.dRad = 0.5 * dStep ; + myParams.bCalcFeed = false ; + myParams.dSideStep = dStep ; + myParams.bInvert = false ; // vettore con i percorsi a ZigZag ICRVCOMPOPOVECTOR vpCrvs ; From 7894a8fdc846d31d95c5bcce52d4a04a365cf224 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 27 May 2025 14:27:20 +0200 Subject: [PATCH 07/24] EgtGeomKernel : - In CalcPocketing aggiunto riconoscimento per curve SpiralCirle. --- CalcPocketing.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 726cf59..02f7c53 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -2416,6 +2416,9 @@ CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, dou // assegno la Feed AssignFeedSpiralOpt( 0, PockParams, pMCrv) ; + + // assegno proprietà di riconoscimento + pMCrv->SetTempProp( TEMP_PROP_OPT_CIRCLE, 0) ; return true ; } From d88baa070f08234ecc57219e7cc66017e169c29e Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 27 May 2025 16:00:17 +0200 Subject: [PATCH 08/24] EgtGeomKernel 2.7e2 : - ricompilazione con cambio versione. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index f7add899b9b10d7ad0220d9eeef165c256c776fe..e014c00dc63a316a07a1b561484b40a85eb97592 100644 GIT binary patch delta 94 zcmdlNy)SyhFE&P_&A-_cnHh~HD{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-Vf-5U delta 94 zcmdlNy)SyhFE&QQ&A-_cnHdcyD{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-U|t&X From 161d3d9b172fd60a0be27db1b00dd552f743bcff Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 28 May 2025 17:22:49 +0200 Subject: [PATCH 09/24] EgtGeomKernel : - In CalcPocketing aggiunte correzioni e migliorie per raccordi tra offset, per calcolo e rimozione delle regioni non svuotate e scelta degli offset per i percorsi. --- CalcPocketing.cpp | 829 ++++++++++++++++++++++++---------------------- 1 file changed, 428 insertions(+), 401 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index d206308..2c2fd39 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -55,7 +55,6 @@ struct PocketParams { 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 - bool bOptOffsetsAdv = false ; // flag per evitare Offset coperti da curve di MedialAxis in SpiralIn/Out bool bAboveHead = true ; // flag per testa da sopra ( Z+) bool bSmooth = false ; // curve smussate bool bInvert = false ; // inversione dei percorsi @@ -76,7 +75,7 @@ struct PocketParams { double dOpenEdgeRad = 0. ; // raggio effettivo di estensione degli aperti } ; static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket -static double BIARC_MAX_LEN = 200. ; // massima lunghezza oltre la quale il biarco viene smussato +static double TOL_REMOVE_OFFSET = 2. ; // tolleranza per controllo materiale lasciato da un Offset typedef vector VICRVCOMPOPOVECTOR ; //--------------------------------------------------------------------------- @@ -4657,14 +4656,10 @@ CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPO for ( int j = 0 ; j < int( ccClass.size()) ; ++j ) { // se ho intersezione spezzo il segmento if ( ccClass[j].nClass == CRVC_OUT) { - Point3d ptS ; - pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; - double dOffS ; - vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ; - Point3d ptE ; - pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; - double dOffE ; - vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ; + Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; + double dOffS ; vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ; + Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; + double dOffE ; vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ; // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( vOffIslands[i]->CopyParamRange( dOffS, dOffE)) ; PtrOwner pCrvB( vOffIslands[i]->CopyParamRange( dOffE, dOffS)) ; @@ -4692,235 +4687,195 @@ CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICRVCOMPOPO return true ; } -//----------------------------------------------------------------------------- -static bool -ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) -{ - - // controllo dei parametri - if ( pBiArcLink == nullptr) - return false ; - if ( dToll > 1. - 10. * EPS_SMALL || dToll < 10. * EPS_SMALL) - return false ; - pNewBiArc->Clear() ; - - // dominio - double dUS, dUE ; - pBiArcLink->GetDomain( dUS, dUE) ; - - // prendo i due archi della curva BiArco - PtrOwner pArc1( pBiArcLink->CopyParamRange( dUS, ( dUS + dUE) / 2.)) ; - PtrOwner pArc2( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2., dUE)) ; - if ( IsNull( pArc1) || ! pArc1->IsValid() || IsNull( pArc2) || ! pArc2->IsValid()) - return false ; - - // primo pezzo - pArc1->GetDomain( dUS, dUE) ; - PtrOwner pArc1A( pArc1->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll)) ; // Arc1 - PtrOwner pArc1B( pArc1->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE)) ; // Arc2 - Point3d pt1A, pt1B ; - pArc1A->GetEndPoint( pt1A) ; - pArc1B->GetStartPoint( pt1B) ; - PtrOwner pLine1( CreateBasicCurveLine()) ; - pLine1->Set( pt1A, pt1B) ; - - // secondo pezzo - pArc2->GetDomain( dUS, dUE) ; - PtrOwner pArc2A( pArc2->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll)) ; // Arc1 - PtrOwner pArc2B( pArc2->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE)) ; // Arc2 - Point3d pt2A, pt2B ; - pArc2A->GetEndPoint( pt2A) ; - pArc2B->GetStartPoint( pt2B) ; - PtrOwner pLine2( CreateBasicCurveLine()) ; - pLine2->Set( pt2A, pt2B) ; - - // ricostruisco il nuovo link - if ( ! pNewBiArc->AddCurve( Release( pArc1A)) || - ! pNewBiArc->AddCurve( Release( pLine1)) || - ! pNewBiArc->AddCurve( Release( pArc1B)) || - ! pNewBiArc->AddCurve( Release( pArc2A)) || - ! pNewBiArc->AddCurve( Release( pLine2)) || - ! pNewBiArc->AddCurve( Release( pArc2B))) - return false ; - - return true ; -} - //------------------------------------------------------------------------------ static bool -CalcSpecialSmoothBiArc( const ICurveComposite* pCrvBiArc, const ICRVCOMPOPOVECTOR& vOffIslands, - const PocketParams& PockParams, ICurveComposite* pCrvLink) +CalcSpecialBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, + const Vector3d& vtEnd, const PocketParams& PockParams, + ICurveComposite* pCrvLink) { - // controllo della curva - if ( pCrvBiArc == nullptr || ! pCrvBiArc->IsValid() || - pCrvLink == nullptr) + // controllo dei parametri + if ( pCrvLink == nullptr) return false ; pCrvLink->Clear() ; - // controllo che la lunghezza sia sufficiente - double dLen ; pCrvBiArc->GetLength( dLen) ; - if ( dLen < 2 * PockParams.dRad + 50 * EPS_SMALL) + + // parametro di estensione in tangenza + double dLenExtension = PockParams.dRad / 2. ; + + // determino i punti della curva + PNTVECTOR vPnts = { ptStart, ptStart + ( dLenExtension * vtStart), + ptEnd - ( dLenExtension * vtEnd), ptEnd} ; + int nInd = 1 ; + static const double COS_TOL = cos( 130 * DEGTORAD) ; + // se primo angolo minore della tolleranza, aggiungo un punto + Vector3d vtPrev = vPnts[nInd] - vPnts[nInd-1] ; vtPrev.Normalize() ; + Vector3d vtNext = vPnts[nInd+1] - vPnts[nInd] ; vtNext.Normalize() ; + double dCos = vtPrev * vtNext ; + if ( dCos < COS_TOL) { + Point3d ptA = vPnts[nInd] + dLenExtension * GetRotate( vtStart, Z_AX, ANG_RIGHT) ; + Point3d ptB = vPnts[nInd] - dLenExtension * GetRotate( vtStart, Z_AX, ANG_RIGHT) ; + if ( SqDist( ptA, vPnts[nInd+1]) < SqDist( ptB, vPnts[nInd+1])) + vPnts.insert( vPnts.begin() + nInd + 1, ptA) ; + else + vPnts.insert( vPnts.begin() + nInd + 1, ptB) ; + ++ nInd ; + } + ++ nInd ; + // se secondo angolo maggiore della tolleranza, aggiungo un punto + vtPrev = vPnts[nInd] - vPnts[nInd-1] ; vtPrev.Normalize() ; + vtNext = vPnts[nInd+1] - vPnts[nInd] ; vtNext.Normalize() ; + dCos = vtPrev * vtNext ; + if ( dCos < COS_TOL) { + Point3d ptA = vPnts[nInd] + dLenExtension * GetRotate( - vtEnd, Z_AX, ANG_RIGHT) ; + Point3d ptB = vPnts[nInd] - dLenExtension * GetRotate( - vtEnd, Z_AX, ANG_RIGHT) ; + if ( SqDist( ptA, vPnts[nInd-1]) < SqDist( ptB, vPnts[nInd-1])) + vPnts.insert( vPnts.begin() + nInd + 1, ptA) ; + else + vPnts.insert( vPnts.begin() + nInd + 1, ptB) ; + } + + // definisco raccordo a ZigZag ( Lineare) + PtrOwner pZigZagLink( CreateCurveComposite()) ; + if ( IsNull( pZigZagLink)) return false ; - // costruisco il tratto lineare - double dULineS, dULineE ; - Point3d ptLineS, ptLineE ; - if ( ! pCrvBiArc->GetParamAtLength( PockParams.dRad, dULineS) || - ! pCrvBiArc->GetPointD1D2( dULineS, ICurve::FROM_MINUS, ptLineS) || - ! pCrvBiArc->GetParamAtLength( dLen - PockParams.dRad, dULineE) || - ! pCrvBiArc->GetPointD1D2( dULineE, ICurve::FROM_MINUS, ptLineE)) - return false ; - // costruisco il collegamento lineare - PtrOwner pLine( CreateCurveComposite()) ; - if ( IsNull( pLine) || - ! CalcBoundedLink( ptLineS, ptLineE, vOffIslands, pLine)) - return false ; - // creo i due raccordi - PtrOwner pCrvStartJoint( pCrvBiArc->CopyParamRange( 0., dULineS)) ; - PtrOwner pCrvEndJoint( pCrvBiArc->CopyParamRange( dULineE, pCrvBiArc->GetCurveCount())) ; - if ( IsNull( pCrvStartJoint) || IsNull( pCrvEndJoint) || - ! pCrvStartJoint->IsValid() || ! pCrvEndJoint->IsValid()) - return false ; - // definisco il BiArco speciale - if ( ! pCrvLink->AddCurve( Release( pCrvStartJoint)) || - ! pCrvLink->AddCurve( Release( pLine)) || - ! pCrvLink->AddCurve( Release( pCrvEndJoint))) - return false ; - // smusso - ModifyCurveToSmoothed( pCrvLink, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; - return true ; + bool bFirst = true ; + for ( const Point3d& ptNew : vPnts) { + if ( bFirst) { + bFirst = false ; + pZigZagLink->AddPoint( ptNew) ; + } + else + pZigZagLink->AddLine( ptNew) ; + } + + // Smusso il raccordo a ZigZag + ModifyCurveToSmoothed( pZigZagLink, PockParams, .4, .4, true) ; + pCrvLink->CopyFrom( pZigZagLink) ; + return ( pCrvLink != nullptr && pCrvLink->IsValid() && pCrvLink->GetCurveCount() > 0) ; } //------------------------------------------------------------------------------ static bool CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, - const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vOffIslands, + const Vector3d& vtEnd, double dParMeet, const ICRVCOMPOPOVECTOR& vCrvBorders, const PocketParams& PockParams, ICurveComposite* pCrvLink, bool& bSpecial) { + // controllo parametri + if ( pCrvLink == nullptr) + return false ; + pCrvLink->Clear() ; + // se senza smusso, ritorno tratto lineare bSpecial = false ; if ( ! PockParams.bSmooth) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; - // creo il BiArc che unisce i due punti - double dAngStart, dAngEnd ; - vtStart.GetAngleXY( X_AX, dAngStart) ; - vtEnd.GetAngleXY( X_AX, dAngEnd) ; - PtrOwner pBiArcLink ; - if ( dParMeet != 0) - pBiArcLink.Set( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet)) ; - else { - PtrOwner pCrvCir( CreateBasicCurveArc()) ; - if ( IsNull( pCrvCir)) - return false ; - pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, PockParams.bInvert ? 360 : - 360, 0, Z_AX) ; - pBiArcLink.Set( pCrvCir->Clone()) ; - pCrvLink->AddCurve( pBiArcLink->Clone()) ; - return true ; - } - if ( IsNull( pBiArcLink)) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; - - // se BiArco troppo grande allora lo modifico (ne tengo una copia per eventuale gestione speciale) - PtrOwner pCrvBiArc_clone( ConvertCurveToComposite( pBiArcLink->Clone())) ; - double dLenBiArc ; pBiArcLink->GetLength( dLenBiArc) ; - if ( dLenBiArc > BIARC_MAX_LEN) { - PtrOwner pCrvNewBiArcS( CreateBasicCurveComposite()) ; - ModifyBiArc( pBiArcLink, 0.2, pCrvNewBiArcS) ; - pBiArcLink.Set( pCrvNewBiArcS) ; - } - - // creo la nuova curva formata inizialmente dai tratti di archi - PtrOwner pCompo( GetCurveComposite( pBiArcLink->Clone())) ; - if ( IsNull( pCompo)) - return false ; - PtrOwner pCompoHelp( GetCurveComposite( pBiArcLink->Clone())) ; - if ( IsNull( pCompoHelp)) + // inizializzo la curva di Link da restituire + PtrOwner pMyCrvLink( CreateCurveComposite()) ; + if ( IsNull( pMyCrvLink)) return false ; - // scorro tutte le curve per controllare le intersezioni ... - for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) { + // controllo se la distanza lineare tra i due punti è maggiore della tolleranza... + static double dSqTol = 4 * PockParams.dRad * PockParams.dRad + PockParams.dSideStep * PockParams.dSideStep ; + if ( SqDist( ptStart, ptEnd) > dSqTol) + bSpecial = ( CalcSpecialBoundedSmoothedLink( ptStart, vtStart, ptEnd, vtEnd, PockParams, pMyCrvLink)) ; + if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) { + // ...in caso negativo creo il Biarco ( se parametro a zero, allora circonferenza) + double dAngStart ; vtStart.GetAngleXY( X_AX, dAngStart) ; + double dAngEnd ; vtEnd.GetAngleXY( X_AX, dAngEnd) ; + if ( dParMeet > EPS_ZERO) + pMyCrvLink.Set( ConvertCurveToComposite( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet))) ; + else { + PtrOwner pCrvCir( CreateBasicCurveArc()) ; + if ( IsNull( pCrvCir)) + return false ; + if ( pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, PockParams.bInvert ? 360 : -360, 0, Z_AX)) + pMyCrvLink.Set( ConvertCurveToComposite( Release( pCrvCir))) ; + } + } + if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + // se il BiArco creato è troppo piccolo, lo approssimo ad un tratto lineare + BBox3d bBox3 ; + if ( pMyCrvLink->GetLocalBBox( bBox3)) { + double dRadBB ; + if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + } + + // il link ottenuto non deve uscire dalle curve di bordo ( Loop esterno ed Isole) + // curva di test + PtrOwner pCompoTest( CloneCurveComposite( pMyCrvLink)) ; + if ( IsNull( pCompoTest) || ! pCompoTest->IsValid()) + return false ; + // curva ausiliaria + PtrOwner pCompoHelp( CloneCurveComposite( pMyCrvLink)) ; + if ( IsNull( pCompoHelp) || ! pCompoHelp->IsValid()) + return false ; + + // scorro tutte le curve le curve di bordo + for ( const ICurveComposite* pCrvBorder : vCrvBorders) { + // calcolo eventuali intersezioni CRVCVECTOR ccClass ; - IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ; + IntersCurveCurve intCC( *pCompoTest, *pCrvBorder) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; - if ( ! pCompoHelp->Clear()) - return false ; - // per ogni intersezione j con l'offset dell'isola i - for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + // pulisco la curva ausiliaria + pCompoHelp->Clear() ; + + // analizzo le intersezioni + for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { // se ho intersezione spezzo il segmento - if ( ccClass[j].nClass == CRVC_OUT && int( ccClass.size()) > 1) { - Point3d ptS ; - pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; - double dOffS ; - vOffIslands[i]->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ; - Point3d ptE ; - pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; - double dOffE ; - vOffIslands[i]->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ; + if ( ccClass[i].nClass == CRVC_OUT && int( ccClass.size()) > 1) { + // recupero eventuali punti di intersezioni e parametri + Point3d ptS ; pCompoTest->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_PLUS, ptS) ; + double dOffS ; pCrvBorder->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ; + Point3d ptE ; pCompoTest->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptE) ; + double dOffE ; pCrvBorder->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ; // recupero i due possibili percorsi e uso il più corto - PtrOwner pCrvA( vOffIslands[i]->CopyParamRange( dOffS, dOffE)) ; - PtrOwner pCrvB( vOffIslands[i]->CopyParamRange( dOffE, dOffS)) ; - + PtrOwner pCrvA( pCrvBorder->CopyParamRange( dOffS, dOffE)) ; + PtrOwner pCrvB( pCrvBorder->CopyParamRange( dOffE, dOffS)) ; if ( IsNull( pCrvA) || IsNull( pCrvB)) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; - + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; - - if ( j != 0) { + // definisco il nuovo bordo mediante la curva ausiliaria + if ( i != 0) { if ( dLenA < dLenB) { if ( ! pCompoHelp->AddCurve( Release( pCrvA))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } // se non interseco else { - if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) - return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; + if ( ! pCompoHelp->AddCurve( pCompoTest->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; } } - - pCompo->Clear() ; - if ( ! pCompo->AddCurve( pCompoHelp->Clone())) - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) + // la curva di test diventa la curva ausiliaria + pCompoTest->Clear() ; + if ( ! pCompoTest->AddCurve( pCompoHelp->Clone())) + if ( ! CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink)) return false ; } + // La curva necessita di un ulteriore smusso, in quanto tagliata su un bordo + ModifyCurveToSmoothed( pCompoTest, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; - // controllo le dimensioni del BiArco - BBox3d bBox3 ; - if ( pCompo->GetLocalBBox( bBox3)) { - double dRadBB ; - // se troppo piccolo, lo approssimo con un segmento - if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) { - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) - return false ; - return true ; - } - // se troppo grande, lo approssimo con un segmento - if ( bBox3.GetRadius( dRadBB) && dRadBB > 3 * PockParams.dRad) { - if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) - return false ; - return true ; - } - } - - PtrOwner pCrvCompo_noSmooth( pCompo->Clone()) ; - if ( ! ModifyCurveToSmoothed( pCompo, PockParams, 0.05, 0.05, true) || - ! pCompo->IsValid()) - pCompo.Set( pCrvCompo_noSmooth) ; - pCrvLink->AddCurve( Release( pCompo)) ; - + // restituisco il Link + if ( IsNull( pCompoTest) || ! pCompoTest->IsValid() || pCompoTest->GetCurveCount() == 0) + return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; + pCrvLink->AddCurve( Release( pCompoTest)) ; return true ; } @@ -4962,7 +4917,9 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) dLenPercE = 0. ; } - double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; + #if 0 // nel caso volessi estendere anche prima del punto finale + double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; + #endif double dLStepE = ( dLenPercE < EPS_SMALL ? 0. : PockParams.dRad) ; dLenE = 0 ; @@ -5083,12 +5040,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! AssignFeedSpiral( vOffs[i], pSfrTool, false, bFirstOffs, pSfrForOpenEdges, PockParams, 2 * PockParams.dRad / 3)) return false ; // aggiorno la superificie svuotata - PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( vOffs[i]->Clone() , PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( ! IsNull( pSrfToolRegOffi)) { + PtrOwner pSrfToolOffs( GetSurfFlatRegionFromFatCurve( vOffs[i]->Clone() , PockParams.dRad + 5 * EPS_SMALL, false, false, 10 * EPS_SMALL, false)) ; + if ( ! IsNull( pSrfToolOffs)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) - pSfrTool.Set( pSrfToolRegOffi) ; + pSfrTool.Set( pSrfToolOffs) ; else - pSfrTool->Add( *pSrfToolRegOffi) ; + pSfrTool->Add( *pSrfToolOffs) ; } vOffs[i]->SetTempProp( nProp0, 0) ; vOffs[i]->SetTempProp( nProp1, 1) ; @@ -5109,12 +5066,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& ! AssignFeedSpiral( pCrvLink, pSfrTool, true, false, pSfrForOpenEdges, PockParams, 2 * PockParams.dRad / 3)) return false ; // aggiorno la regione svuotata - PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( pCrvLink->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ; - if ( ! IsNull( pSrfToolRegLinki)) { + PtrOwner pSfrToolLink( GetSurfFlatRegionFromFatCurve( pCrvLink->Clone(), PockParams.dRad + 10 * EPS_SMALL, false, false, 10 * EPS_SMALL, false)) ; + if ( ! IsNull( pSfrToolLink)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) - pSfrTool.Set( pSrfToolRegLinki) ; - else - pSfrTool->Add( *pSrfToolRegLinki) ; + pSfrTool.Set( pSfrToolLink) ; + else + pSfrTool->Add( *pSfrToolLink) ; } // risetto il Link come curva composita ... pCrvLink->SetTempProp( nProp0, 0) ; @@ -5134,8 +5091,108 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& //---------------------------------------------------------------------------- static bool -RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, - ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) +ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICRVCOMPOPOVECTOR& vOffsFirstCurve, + const Point3d& ptToGo, const PocketParams& PockParams, + int& nInd, Point3d& ptCloser, bool& bFirstOffs) +{ + /* + E' richiesto che le curve di Offset presentino le seguenti TempProps : + - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] + - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] + [per SPIRAL le proprietà sono ricavate automaticamente] + */ + + // controllo dei parametri + nInd = -1 ; + if ( vOffs.empty()) + return true ; + + // scorro tutte le curve di Offset + int nFlag ; + struct OffsPtMinDist { + int nInd = 0 ; + double dSqDist = INFINITO - 1 ; + Point3d ptMinDist = P_INVALID ; + bool bInVsOut = true ; + bool bFirstOffs = false ; + } ; + vector vOffsPtMinDist( vOffs.size()) ; + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + // indice dell'Offset + vOffsPtMinDist[i].nInd = i ; + // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca + if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + bool bSkip = false ; + for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) + bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; // prima iterazione + if ( bSkip) { + vOffsPtMinDist[i].bFirstOffs = true ; + continue ; + } + } + // Controllo se il punto da raggiungere è interno o esterno alla curva + // NB. cerco di privilegiare le curve che presentano il punto da raggiungere al loro esterno; + // in questo modo riesco a creare le curve a ricciolo + int nSide ; + DistPointCurve DistPtCrv( ptToGo, *vOffs[i]) ; + bool bFirstBorderIsland = false ; + if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { + // nel caso Spiral + if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { + // InVsOut + vOffsPtMinDist[i].bInVsOut = ( ( ! PockParams.bInvert && nSide == MDS_LEFT) || + ( PockParams.bInvert && nSide == MDS_RIGHT)) ; + // controllo se la curva in questione è di primo Offset + Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; + for ( int j = 0 ; j < int( vOffsFirstCurve.size()) ; ++ j) { + if ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) { + vOffsPtMinDist[i].bFirstOffs = true ; + // controllo se Isola o di bordo + double dArea = 0. ; + vOffs[i]->GetAreaXY( dArea) ; + bFirstBorderIsland = ( ( ! PockParams.bInvert && dArea < 0.) || + ( PockParams.bInvert && dArea > 0.)) ; + // se isola di primo Offset, InVsOut va invertito + if ( bFirstBorderIsland) + vOffsPtMinDist[i].bInVsOut = ( ! vOffsPtMinDist[i].bInVsOut) ; + break ; + } + } + } + // nel caso Conformal + else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { + if ( nSide != vOffs[i]->GetTempProp( 1)) + vOffsPtMinDist[i].bInVsOut = false ; + } + // recupero il punto a minima distanza e la distanza + DistPtCrv.GetMinDistPoint( EPS_SMALL, vOffsPtMinDist[i].ptMinDist, nFlag) ; + DistPtCrv.GetSqDist( vOffsPtMinDist[i].dSqDist) ; + // se il punto da raggiungere è interno alla curva, aggiungo una penalità ( euristica) + if ( vOffsPtMinDist[i].bInVsOut) { + vOffsPtMinDist[i].dSqDist += PockParams.dRad + PockParams.dRad + + PockParams.dSideStep + PockParams.dSideStep ; + } + // se curva di bordo esterno, aggiungo un'altra penalità ( euristica) + if ( vOffsPtMinDist[i].bFirstOffs && ! bFirstBorderIsland) + vOffsPtMinDist[i].dSqDist *= 2. ; + } + } + // ordino il vettore in base alle distanze calcolate + sort( vOffsPtMinDist.begin(), vOffsPtMinDist.end(), []( const OffsPtMinDist& a, const OffsPtMinDist& b) { + return a.dSqDist < b.dSqDist ; + }) ; + // recupero la curva migliore + OffsPtMinDist& BestOffs = vOffsPtMinDist[0] ; + nInd = BestOffs.nInd ; + ptCloser = BestOffs.ptMinDist ; + bFirstOffs = BestOffs.bFirstOffs ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, + ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { /* E' richiesto che le curve di Offset presentino le seguenti TempProps : @@ -5153,70 +5210,22 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs // scorro tutti i Chunk della regione ICRVCOMPOPOVECTOR vCrvCurl ; for ( int nC = 0 ; nC < pSfrUncleared->GetChunkCount() ; ++ nC) { - // recupero il centroide del Chunk da rimuovere Point3d ptCentroid ; pSfrUncleared->GetChunkCentroid( nC, ptCentroid) ; - /* Tra tutte le curve di Offset escludo le curve che : - Sono di primo Offset - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) - ... e cerco la più vicina tra le rimanenti + ... cerco la più vicina tra le rimanenti */ + // recupero la curva migliore int nInd = -1 ; - double dRefDist = INFINITO - 1 ; - Point3d ptCloser ; // serve nel caso non bastasse la curva a ricciolo per svuotare il chunk nC-esimo - int nFlag ; + Point3d ptCloser ; bool bFirstOffs = false ; - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { - // recupero il punto iniziale della curva - Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; - // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca - if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { - bool bSkip = false ; - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) - bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; - if ( bSkip) - continue ; - } - // se la curva contiene il centroide, allora la salto; l'idea è che il ricciolo sia esterno - // alla curva - int nSide ; - bool bCurrFirstOffs = false ; - DistPointCurve DistPtCrv( ptCentroid, *vOffs[i]) ; - if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { - // nel caso Spiral - if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { - // controllo se la curva in questione è di primo Offset, in questo caso devo determinare - // se MDS_LEFT o MDS_RIGHT - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bCurrFirstOffs ; ++ j) - bCurrFirstOffs = ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) ; - // se non è di primo Offset, allora ho già la classificazione MDS_ - if ( ! bCurrFirstOffs) { - if ( nSide == ( ! PockParams.bInvert ? MDS_LEFT : MDS_RIGHT)) - continue ; - } - // se di primo Offset allora non controllo MDS_ - /* NB. Se fosse esterna al loop 0 allora non ha senso, esattamente come se fosse interna alla isole - * La cosa si complica se avessi più Offset, Ma dato che cerco la cura più vicina dovrei - * considerare in automatico le curve di Offset appartenenti al chunk in esame */ - } - // nel caso Conformal - else if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG) { - if ( nSide == vOffs[i]->GetTempProp( 1)) - continue ; - } - } - // controllo se la distanza è ammissibile - double dCurrDist = INFINITO ; - if ( DistPtCrv.GetSqDist( dCurrDist) && dCurrDist < dRefDist) { - dRefDist = dCurrDist ; - nInd = i ; - bFirstOffs = bCurrFirstOffs ; - DistPtCrv.GetMinDistPoint( EPS_SMALL, ptCloser, nFlag) ; - } - } - // se non ho trovato alcun indice, salto il Chunk nC-esimo + if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, + nInd, ptCloser, bFirstOffs)) + return false ; + // se nessun indice trovato, salto il chunk if ( nInd == -1) continue ; @@ -5235,7 +5244,6 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs if ( ! bFirstOffs) bIsSmoothCrv = ( PockParams.bSmooth && pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; else - // controllo se la sottocurva è un raccordo di Offset bIsSmoothCrv = ( pCrv->GetTempProp( 1) > 0) ; // clono la curva di Offset corrente ( in questo modo non modifico l'originale) @@ -5249,74 +5257,82 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs Point3d pt1, pt2, ptMain ; // paramtro di uscita e di ingresso dall'Offset attuale per creazione della curva a ricciolo double dURef1, dURef2 ; + // numero di curve dell'offset corrente + int nCrvNumber = ( pMyOffs->GetCurveCount()) ; // inizializzo la curva a ricciolo PtrOwner pCrvCurl( CreateCurveComposite()) ; if ( IsNull( pCrvCurl)) return false ; - // se è di raccordo, "ricostruisco lo spigolo vivo della curva originale di Offset" + // se è di raccordo, ricostruisco lo spigolo vivo della curva originale di Offset if ( bIsSmoothCrv) { - // cerco la prima curva in precedenza e in successione non di raccordo vt1 = V_INVALID ; - for ( int i = nCrv - 1 ; i >= 0 ; -- i) { + vt2 = V_INVALID ; + // cerco la prima sottocurva che non sia di raccordo in precedenza + for ( int i = ( nCrv + nCrvNumber - 1) % nCrvNumber ; ( i % nCrvNumber) == i ; -- i) { + // recupero la sottocurva const ICurve* pCrvPrec = pMyOffs->GetCurve( i) ; if ( pCrvPrec == nullptr || ! pCrvPrec->IsValid()) break ; + // se non di raccordo if ( pCrvPrec->GetTempProp( 1) != TEMP_PROP_SMOOTH) { // definisco il versore uscente pCrvPrec->GetEndDir( vt1) ; // definisco il punto di uscita pCrvPrec->GetEndPoint( pt1) ; // definisco il parametro di uscita - dURef1 = i + 1 ; + dURef1 = ( i + 1) % nCrvNumber ; break ; } } - if ( ! vt1.IsValid()) - continue ; - vt2 = V_INVALID ; - for ( int i = nCrv + 1 ; i < pMyOffs->GetCurveCount() ; ++ i) { - const ICurve* pCrvSucc = pMyOffs->GetCurve( i) ; - if ( pCrvSucc == nullptr || ! pCrvSucc->IsValid()) - break ; - if ( pCrvSucc->GetTempProp( 1) != TEMP_PROP_SMOOTH) { - // definisco il versore entrante - pCrvSucc->GetStartDir( vt2) ; - // definisco il punto di entrata - pCrvSucc->GetStartPoint( pt2) ; - // definisco il parametro di entrata - dURef2 = i ; - break ; + bIsSmoothCrv = ( vt1.IsValid()) ; + if ( bIsSmoothCrv) { + // cerco la prima sottocurva che non sia di raccordo in sucessione + for ( int i = ( nCrv + nCrvNumber + 1) % nCrvNumber ; ( i % nCrvNumber) == i ; ++ i) { + // recupero la sottocurva + const ICurve* pCrvSucc = pMyOffs->GetCurve( i) ; + if ( pCrvSucc == nullptr || ! pCrvSucc->IsValid()) + break ; + // se non di raccordo + if ( pCrvSucc->GetTempProp( 1) != TEMP_PROP_SMOOTH) { + // definisco il versore entrante + pCrvSucc->GetStartDir( vt2) ; + // definisco il punto di entrata + pCrvSucc->GetStartPoint( pt2) ; + // definisco il parametro di entrata + dURef2 = ( i % nCrvNumber) ; + break ; + } } } - if ( ! vt2.IsValid()) - continue ; - // trovo il punto di intersezione tra le due direzioni tangenti applicate - const double EXTENSION_LEN = 1000. ; - // segmento iniziale ------- - PtrOwner pLineS( CreateCurveLine()) ; - if ( IsNull( pLineS) || ! pLineS->Set( pt1, pt1 + vt1 * EXTENSION_LEN)) - continue ; - // segmento finale -------- - PtrOwner pLineE( CreateCurveLine()) ; - if ( IsNull( pLineE) || ! pLineE->Set( pt2, pt2 - vt2 * EXTENSION_LEN)) - continue ; - // intersezione - IntersCurveCurve ILL( *pLineS, *pLineE) ; - if ( ILL.GetCrossIntersCount() == 1) { - IntCrvCrvInfo aInfo ; - if ( ILL.GetIntCrvCrvInfo( 0, aInfo)) { - if ( ! pCrvCurl->AddPoint( pt1) || - ! pCrvCurl->AddLine( aInfo.IciA[0].ptI)) - continue ; - ptMain = aInfo.IciA[0].ptI ; + bIsSmoothCrv = bIsSmoothCrv && ( vt2.IsValid()) ; + if ( bIsSmoothCrv) { + // trovo il punto di intersezione tra le due direzioni tangenti applicate + const double EXTENSION_LEN = 1000. ; + // segmento iniziale ------- + PtrOwner pLineS( CreateCurveLine()) ; + if ( IsNull( pLineS) || ! pLineS->Set( pt1, pt1 + vt1 * EXTENSION_LEN)) + continue ; + // segmento finale -------- + PtrOwner pLineE( CreateCurveLine()) ; + if ( IsNull( pLineE) || ! pLineE->Set( pt2, pt2 - vt2 * EXTENSION_LEN)) + continue ; + // intersezione + IntersCurveCurve ILL( *pLineS, *pLineE) ; + bIsSmoothCrv = ( ILL.GetCrossIntersCount() == 1) ; + if ( bIsSmoothCrv) { + IntCrvCrvInfo aInfo ; + bIsSmoothCrv = ( ( ILL.GetIntCrvCrvInfo( 0, aInfo)) && + pCrvCurl->AddPoint( pt1) && + pCrvCurl->AddLine( aInfo.IciA[0].ptI)) ; + if ( bIsSmoothCrv) + ptMain = aInfo.IciA[0].ptI ; } } - else - continue ; } - // se invece non è di raccordo, allora ho già lo spigolo vivo - else { + // se non è di raccordo, allora ho già lo spigolo vivo + if ( ! bIsSmoothCrv) { + pCrvCurl->Clear() ; // definisco il versore entrante ed uscente // definisco il punto di entrata e di uscita ( sono coincidenti) dURef1 = dURef ; @@ -5353,14 +5369,12 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vtDir, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc1, bSpecial) || ! CalcBoundedSmoothedLink( ptCentroid, vtDir, ptMain, vt2, bSameDir ? 0. : 0.5, vOffsFirstCurve, PockParams, pCrvBiArc2, bSpecial)) continue ; - // aggiorno la curva a ricciolo if ( ! pCrvCurl->AddCurve( Release( pCrvBiArc1)) || ! pCrvCurl->AddCurve( Release( pCrvBiArc2)) || ! pCrvCurl->IsValid()) continue ; } - // controllo se devo raccordarmi con Offset if ( bIsSmoothCrv) pCrvCurl->AddLine( pt2) ; @@ -5374,9 +5388,8 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs return false ; pSfrChunk->Subtract( *pSfrFatCurl) ; - // se la curva a ricciolo non svuota il Chunk nC-esimo -> percorro il bordo di tale Chunk + // controllo se la regione è tutta rimossa if ( pSfrChunk->IsValid() || pSfrChunk->GetChunkCount() > 0) { - // so che il punto più vicino alla curva è ptCloser // ricavo dunque il punto più vicino sul bordo del Chunk nC-esimo PtrOwner pCompoChunkBorder( ConvertCurveToComposite( pSfrUncleared->GetLoop( nC, 0))) ; @@ -5386,6 +5399,7 @@ RemoveExtraParts( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs pCompoChunkBorder->Invert() ; DistPointCurve distPtChunkBorder( ptCloser, *pCompoChunkBorder) ; Point3d ptCloserOnChunk ; + int nFlag ; if ( ! distPtChunkBorder.GetMinDistPoint( EPS_SMALL, ptCloserOnChunk, nFlag)) continue ; // cambio il punto di inizio della curva su tale punto @@ -5503,44 +5517,72 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { + // ricavo il punto inziale della curva corrente Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; - int nNextInd = -1 ; // indice della curva successiva - double dMinDist = INFINITO ; // distanza tra questa curva e la successiva - Point3d ptStartNext ; // punto iniziale della curva successiva // tra le curve successive cerco la curva interna e più vicina ad essa + int nNextInd = -1 ; // indice della curva successiva + double dMinDist = INFINITO ; // distanza tra questa curva e la successiva + Point3d ptStartNext ; // punto iniziale della curva successiva + bool bMinDistAtSmooth = false ; // se punto a minima distanza su curva di smusso for ( int j = i + 1 ; j < int( vOffs.size()) ; ++ j) { IntersCurveCurve IntCC( *vOffs[i], *vOffs[j]) ; CRVCVECTOR ccClass ; // se interna if ( IntCC.GetCurveClassification( 1, EPS_SMALL, ccClass) && - int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_IN) { + int( ccClass.size()) == 1 && + ( ( ! PockParams.bInvert && ccClass[0].nClass == CRVC_IN) || + ( PockParams.bInvert && ccClass[0].nClass == CRVC_OUT))) { // calcolo la distanza minima tra essa int nFlag ; + double dPar = 0. ; Point3d ptClosest ; - if ( DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptClosest, nFlag)) { - double dCurrDist = SqDist( ptS, ptClosest) ; - if ( dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nNextInd = j ; - ptStartNext = ptClosest ; + DistPointCurve DistPtCrv( ptS, *vOffs[j]) ; + if ( DistPtCrv.GetParamAtMinDistPoint( EPS_SMALL, dPar, nFlag)) { + // controllo se la curva ottenuta è di raccordo, in caso positivo considero come + // punto più vicino il suo punto finale ( per avere poi successivamente Link tra + // Offset in tangenza ) + const ICurve* pCrv = vOffs[j]->GetCurve( static_cast( floor( dPar))) ; + if ( pCrv != nullptr && pCrv->IsValid()) { + if ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) + pCrv->GetEndPoint( ptClosest) ; + else + DistPtCrv.GetMinDistPoint( EPS_SMALL, ptClosest, nFlag) ; + double dCurrDist = SqDist( ptS, ptClosest) ; + if ( dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nNextInd = j ; + ptStartNext = ptClosest ; + bMinDistAtSmooth = ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; + } } } } } + // se non ho trovato nessuna curva interna... cerco semplicemente la curva più vicina if ( nNextInd == -1) { for ( int j = i + 1 ; j < int( vOffs.size()) ; ++ j) { int nFlag ; + double dPar = 0. ; Point3d ptClosest ; - if ( DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptClosest, nFlag)) { - double dCurrDist = SqDist( ptS, ptClosest) ; - if ( dCurrDist < dMinDist) { - dMinDist = dCurrDist ; - nNextInd = j ; - ptStartNext = ptClosest ; + DistPointCurve DistPtCrv( ptS, *vOffs[j]) ; + if ( DistPtCrv.GetParamAtMinDistPoint( EPS_SMALL, dPar, nFlag)) { + const ICurve* pCrv = vOffs[j]->GetCurve( static_cast( floor( dPar))) ; + if ( pCrv != nullptr && pCrv->IsValid()) { + if ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) + pCrv->GetEndPoint( ptClosest) ; + else + DistPtCrv.GetMinDistPoint( EPS_SMALL, ptClosest, nFlag) ; + double dCurrDist = SqDist( ptS, ptClosest) ; + if ( dCurrDist < dMinDist) { + dMinDist = dCurrDist ; + nNextInd = j ; + ptStartNext = ptClosest ; + bMinDistAtSmooth = ( pCrv->GetTempProp( 1) == TEMP_PROP_SMOOTH) ; + } } } } @@ -5571,7 +5613,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con return false ; // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset double dLenPercS = ( i == 0 ? 0. : 10 * EPS_SMALL) ; - double dLenPercE = 10 * EPS_SMALL ; + double dLenPercE = ( bMinDistAtSmooth ? 0. : 10 * EPS_SMALL) ; if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, dLenPercS, dLenPercE, pCrvLink) || ! pCrvLink->IsValid()) { // se non sono riuscito, cerco una strada più semplice ripristinando le curve @@ -5618,8 +5660,8 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con //---------------------------------------------------------------------------- static bool -CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, - const int nIter, const PocketParams& PockParams, bool& bInsert) +CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* pCrvOffs, + double dOffs, double dOffsPrec, int nIter, const PocketParams& PockParams, bool& bInsert) { // controllo dei parametri @@ -5636,70 +5678,51 @@ CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, double dMaxOffs ; if ( ! CalcCurveLimitOffset( *pCrvOffs, dMaxOffs)) return false ; - // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive - if ( dMaxOffs < PockParams.dRad - dOffs + 5 * EPS_SMALL) { + // controllo se l'Offset rimuove materiale + if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < EPS_SMALL) { bInsert = false ; return true ; } - } - else - return true ; - - // se non richiesto percorso avanzato - if ( ! PockParams.bOptOffsetsAdv) - return true ; - - 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 ; - - // 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 < 4 * PockParams.dRad - 100 * EPS_SMALL) { - bInsert = false ; - return true ; + // controllo se l'Offset rimuove una quantità minima di materiale + else if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < TOL_REMOVE_OFFSET) { + // inizializzo la curva di bordo della regione non svuotata + PtrOwner pCrvBorder( CreateCurveComposite()) ; + if ( IsNull( pCrvBorder)) + return false ; + // recupero la regione non svuotata e calcolo la curva di bordo + PtrOwner pSfrA( pSfrAct->CreateOffsetSurf( - dOffsPrec - PockParams.dRad, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrA)) + return false ; + if ( AreOppositeVectorApprox( pSfrA->GetNormVersor(), Z_AX)) + pSfrA->Invert() ; + for ( int nC = 0 ; nC < pSfrA->GetChunkCount() ; ++ nC) { + PtrOwner pSfrChunk( pSfrA->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) + return false ; + PtrOwner pSfrB( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrB) || ! pSfrB->AddExtLoop( pCrvOffs->Clone())) + return false ; + if ( AreOppositeVectorApprox( pSfrB->GetNormVersor(), Z_AX)) + pSfrB->Invert() ; + if ( pSfrB->Intersect( *pSfrChunk) && pSfrB->IsValid()) { + if ( ! pCrvBorder.Set( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0)))) + return false ; + break ; + } + } + if ( pCrvBorder->IsValid()) { + // controllo se l'utensile posizionato nel centroide rimuove la regione + Point3d ptCentroid ; pCrvBorder->GetCentroid( ptCentroid) ; + PtrOwner pCrvArc( CreateCurveArc()) ; + if ( IsNull( pCrvArc)) + return false ; + pCrvArc->Set( ptCentroid, Z_AX, PockParams.dRad - 10 * EPS_SMALL) ; + IntersCurveCurve ICC( *pCrvBorder, *pCrvArc) ; + CRVCVECTOR ccClass ; + bInsert = ( ! ICC.GetCurveClassification( 0, EPS_SMALL, ccClass) || + int( ccClass.size()) != 1 || ccClass[0].nClass != CRVC_IN) ; + } + } } return true ; @@ -5809,7 +5832,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co pCrvCompoBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; - if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, nIter, PockParams, bInsert)) + if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert)) return false ; if ( bInsert) vOffs.emplace_back( Release( pCrvCompoBorder)) ; @@ -5909,7 +5932,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; if ( GetUnclearedRegionAndSetFeed( vOffsFirstCurve, vOffs, vLinks, pSfrOrig, PockParams, pSfrUncleared)) { // modifico i percorsi - if ( ! RemoveExtraParts( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) + if ( ! RemoveUnclearedRegions( pSfrUncleared, vOffs, vOffsFirstCurve, PockParams)) return false ; } @@ -7737,7 +7760,7 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const ISurfFlatR return false ; if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, pSfrOrig, PockParams, pSfrUncleared)) { // estendo i percorsi di Offset se richiesto - if ( ! RemoveExtraParts( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) + if ( ! RemoveUnclearedRegions( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) return false ; } @@ -7759,18 +7782,16 @@ AddLeadInLeadOutToCurveConformalPaths( const ISurfFlatRegion* pSfrOrig, const IS } // ricavo le curve aperte della superficie di pocketing + ICRVCOMPOPOVECTOR vCrvLoops ; + if ( ! GetSfrCrvCompoLoops( pSfrPock, vCrvLoops)) + return false ; ICRVCOMPOPOVECTOR vCrvOpenEdge ; - { - ICRVCOMPOPOVECTOR vCrvLoops ; - if ( ! GetSfrCrvCompoLoops( pSfrPock, vCrvLoops)) - return false ; - for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { - ICRVCOMPOPOVECTOR vpCrvs ; - GetHomogeneousParts( vCrvLoops[i], PockParams, vpCrvs) ; - for ( int j = 0 ; j < int( vpCrvs.size()) ; ++ j) { - if ( vpCrvs[j]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) - vCrvOpenEdge.emplace_back( Release( vpCrvs[j])) ; - } + for ( int i = 0 ; i < int( vCrvLoops.size()) ; ++ i) { + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( vCrvLoops[i], PockParams, vpCrvs) ; + for ( int j = 0 ; j < int( vpCrvs.size()) ; ++ j) { + if ( vpCrvs[j]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) + vCrvOpenEdge.emplace_back( Release( vpCrvs[j])) ; } } @@ -8466,8 +8487,14 @@ GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pS } } // concateno se necessario ( per tolleranza Offset) + int nTempProp0 = ( ! vCrvOffsInside.empty() ? vCrvOffsInside[0]->GetTempProp( 0) : TEMP_PROP_INVALID) ; + int nTempProp1 = ( ! vCrvOffsInside.empty() ? vCrvOffsInside[0]->GetTempProp( 1) : TEMP_PROP_INVALID) ; if ( ! ChainCompoCurves( vCrvOffsInside)) return false ; + for ( auto& CrvCompo : vCrvOffsInside) { + CrvCompo->SetTempProp( nTempProp0, 0) ; + CrvCompo->SetTempProp( nTempProp1, 1) ; + } // se ho trovato delle curve interne if ( ! bStop) { // inserisco le curva ricavate all'iterazione nIter nel vettore From e185c85d5e64297b79044f77e4cb4f44e881e9fe Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Thu, 29 May 2025 08:30:50 +0200 Subject: [PATCH 10/24] EgtGeomKernel : - piccola correzione provvisoria su Vmill a 5assi, in attesa di soluzione definitiva in sviluppo. --- VolZmapVolume.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index fd78d24..cd8f7d8 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -914,6 +914,8 @@ VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, co double dAlongAngDeg, dAcrossAngDeg ; GetAlongAcrossRotation( vtDs, vtDe, ptPe - ptPs, dAlongAngDeg, dAcrossAngDeg) ; // Divido il movimento in tratti con direzione utensile costante + // !!! Per errori riscontrati si eliminano i movimenti e si lasciano solo le posizioni utensile !!! + // !!! In attesa dell'algoritmo esatto !!! const double ANG_ACROSS_STEP = 0.04 ; const double ANG_ALONG_STEP = 1.0 ; int nStepCnt = int( max( { abs( dAlongAngDeg) / ANG_ALONG_STEP, abs( dAcrossAngDeg) / ANG_ACROSS_STEP, 1.})) ; @@ -932,7 +934,14 @@ VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, co Point3d ptEn = Media( ptPs, ptPe, dPosCoeff) ; Vector3d vtD = Media( vtDs, vtDe, dDirCoeff) ; vtD.Normalize() ; Vector3d vtA = Media( vtAs, vtAe, dDirCoeff) ; vtA.Normalize() ; - bOk = bOk && MillingTranslationStep( ptSt, ptEn, vtD, vtA) ; + if ( i == 0) + bOk = bOk && MillingTranslationStep( ptSt, ptSt, vtD, vtA) ; + else if ( i < nStepCnt) { + Point3d ptMid = Media( ptSt, ptEn) ; + bOk = bOk && MillingTranslationStep( ptMid, ptMid, vtD, vtA) ; + } + else + bOk = bOk && MillingTranslationStep( ptEn, ptEn, vtD, vtA) ; // aggiorno prossimo inizio ptSt = ptEn ; } From fa680b7799e702971eec90a4002a073047c17349 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 29 May 2025 11:52:19 +0200 Subject: [PATCH 11/24] EgtGeomKernel : - Aggiunto controllo sulla scalatura nella funzione GetSilhouette in SurfTriMesh - In CalcPocketing, aggiunte funzioni ausiliarie per Debug. --- CalcPocketing.cpp | 32 ++++++++++++++++++++++++++++++++ SurfTriMesh.cpp | 21 +++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 2c2fd39..c6dc49e 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -85,11 +85,43 @@ typedef vector VICRVCOMPOPOVECTOR ; #include "EgtDev/Include/EGkGeoObjSave.h" #include "EgtDev/Include/EGkGeoPoint3d.h" #include "EgtDev/Include/EGkGeoVector3d.h" + + // Varibili ausiliarie vector VT ; vector VC ; + + //--------------------------------------------------------------------------- inline Color GetRandomColor() { return Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; } + + //--------------------------------------------------------------------------- + inline void DrawCurve( const ICurveComposite* pCrvCompo) { + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return ; + for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() ; ++ nU) { + int nProp0 ; pCrvCompo->GetCurveTempProp( nU, nProp0, 0) ; + VT.emplace_back( static_cast( pCrvCompo->GetCurve( nU)->Clone())) ; + VC.emplace_back( nProp0 == 0 ? BLUE : RED) ; + } + return ; + } + + //--------------------------------------------------------------------------- + inline void DrawSfrAndLoops( const ISurfFlatRegion* pSfr, Color cCol = Color( 0., 255., 0., .5)) { + if ( pSfr == nullptr || ! pSfr->IsValid()) + return ; + VT.emplace_back( static_cast( pSfr->Clone())) ; + VC.emplace_back( cCol) ; + for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { + PtrOwner pCrvCompo( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; + DrawCurve( pCrvCompo->Clone()) ; + } + } + return ; + } + #endif //--------------------------------------------------------------------------- diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 87e5ffb..21c4386 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -1220,16 +1220,17 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR& // se rimasto qualcosa if ( pgTria.GetSideCount() > 0) { // lo proietto sul piano e creo la regione - pgTria.Scale( frOCS, 1, 1, 0) ; - PtrOwner pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ; - if ( ! IsNull( pSfrTria)) { - if ( bAllTria && Tria.GetN() * vtVers < 0) - pSfrTria->Invert() ; - pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ; - if ( IsNull( pSfr)) - pSfr.Set( pSfrTria) ; - else - pSfr->Add( *pSfrTria) ; + if ( pgTria.Scale( frOCS, 1, 1, 0)) { + PtrOwner pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ; + if ( ! IsNull( pSfrTria)) { + if ( bAllTria && Tria.GetN() * vtVers < 0) + pSfrTria->Invert() ; + pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ; + if ( IsNull( pSfr)) + pSfr.Set( pSfrTria) ; + else + pSfr->Add( *pSfrTria) ; + } } } } From 969f1266e7649ff8c2bf8f2be71201a0a9e0c72d Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Fri, 30 May 2025 10:59:40 +0200 Subject: [PATCH 12/24] EgtGeomKernel : - correzione euristica su Vmill a 5assi, in attesa di soluzione definitiva in sviluppo --- VolZmapVolume.cpp | 48 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index cd8f7d8..323ed2a 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -910,38 +910,50 @@ bool VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, const Vector3d& vtAs, const Point3d& ptPe, const Vector3d& vtDe, const Vector3d& vtAe) { - // Calcolo angoli di rotazione utensile longitudinale e trasversale rispetto al movimento + // Deve essere definito l'utensile corrente + if ( m_nCurrTool < 0 || m_nCurrTool >= int( m_vTool.size())) + return false ; + // Calcolo angoli di rotazione utensile longitudinale e trasversale rispetto al movimento per eventuale suddivisione double dAlongAngDeg, dAcrossAngDeg ; GetAlongAcrossRotation( vtDs, vtDe, ptPe - ptPs, dAlongAngDeg, dAcrossAngDeg) ; - // Divido il movimento in tratti con direzione utensile costante - // !!! Per errori riscontrati si eliminano i movimenti e si lasciano solo le posizioni utensile !!! - // !!! In attesa dell'algoritmo esatto !!! const double ANG_ACROSS_STEP = 0.04 ; const double ANG_ALONG_STEP = 1.0 ; int nStepCnt = int( max( { abs( dAlongAngDeg) / ANG_ALONG_STEP, abs( dAcrossAngDeg) / ANG_ACROSS_STEP, 1.})) ; + // Calcolo coefficiente di riduzione movimenti con direzione costante per evitare extra tagli + // !!! In attesa dell'algoritmo esatto !!! + double dToolLen = m_vTool[m_nCurrTool].GetHeigth() ; + double dToolCrad = m_vTool[m_nCurrTool].GetCornRadius() ; + Vector3d vtBase = ptPe - ptPs ; + double dBaseLen = vtBase.Len() ; + Vector3d vtTip = ptPe - dToolLen * vtDe - ( ptPs - dToolLen * vtDs) ; + double dTipLen = vtTip.Len() ; + double dK = ( vtBase * vtTip > EPS_SMALL ? dTipLen / dBaseLen : 0) ; + if ( dTipLen / nStepCnt < 0.1 * dToolCrad) + dK = 0 ; + // Divido il movimento in tratti con direzione utensile costante bool bOk = true ; - Point3d ptSt = ptPs ; for ( int i = 0 ; i <= nStepCnt && bOk ; ++ i) { - double dPosCoeff, dDirCoeff ; - if ( i < nStepCnt) { - dPosCoeff = ( i + 0.5) / nStepCnt ; + double dStCoeff, dEnCoeff, dDirCoeff ; + if ( i == 0) { + dStCoeff = 0 ; + dEnCoeff = dK / nStepCnt ; + dDirCoeff = 0 ; + } + else if ( i < nStepCnt) { + dStCoeff = ( i - dK) / nStepCnt ; + dEnCoeff = ( i + dK) / nStepCnt ; dDirCoeff = double( i) / nStepCnt ; } else { - dPosCoeff = 1 ; + dStCoeff = ( nStepCnt - dK) / nStepCnt ; + dEnCoeff = 1 ; dDirCoeff = 1 ; } - Point3d ptEn = Media( ptPs, ptPe, dPosCoeff) ; + Point3d ptSt = Media( ptPs, ptPe, dStCoeff) ; + Point3d ptEn = Media( ptPs, ptPe, dEnCoeff) ; Vector3d vtD = Media( vtDs, vtDe, dDirCoeff) ; vtD.Normalize() ; Vector3d vtA = Media( vtAs, vtAe, dDirCoeff) ; vtA.Normalize() ; - if ( i == 0) - bOk = bOk && MillingTranslationStep( ptSt, ptSt, vtD, vtA) ; - else if ( i < nStepCnt) { - Point3d ptMid = Media( ptSt, ptEn) ; - bOk = bOk && MillingTranslationStep( ptMid, ptMid, vtD, vtA) ; - } - else - bOk = bOk && MillingTranslationStep( ptEn, ptEn, vtD, vtA) ; + bOk = bOk && MillingTranslationStep( ptSt, ptEn, vtD, vtA) ; // aggiorno prossimo inizio ptSt = ptEn ; } From 504bb50b138058e315b2cac8568c5fe6013516d4 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 30 May 2025 11:46:37 +0200 Subject: [PATCH 13/24] EgtGeomKernel : - modifica prototipi - piccola miglioria per casi ottimizzati a Spirale in CalcPocketing. --- CalcPocketing.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index c6dc49e..7927a87 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -43,7 +43,8 @@ using namespace std ; // variabili d'appoggio ( per non passare troppi parametri tra le funzioni secondarie) struct PocketParams { - int nType = POCKET_SPIRALIN ; + int nType = POCKET_SPIRALIN ; // tipo di lavorazione + int dLiType = POCKET_LI_NONE ; // tipo di ingresso (LeadIn) double dRad = 0. ; // raggio utensile double dRad_prec = -1. ; // raggio utensile della lavorazione precedente double dSideStep = 0. ; // step @@ -54,6 +55,7 @@ struct PocketParams { double dOpenMinSafe = 5. ; // estensione minima di sicurezza double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag + double dLiTang = INFINITO ; // valore di LeadIn in ingresso bool bOptOffsets = true ; // flag per evitare Offset non necessari bool bAboveHead = true ; // flag per testa da sopra ( Z+) bool bSmooth = false ; // curve smussate @@ -3623,6 +3625,8 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; if ( bOkSpiral) { double dIntRad = 0 ; + if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nType == POCKET_LI_HELIX) + dIntRad = min( 0.5 * min( PockParam.dLiTang, 2. * PockParam.dRad), dRad - dOffs) ; bool bOkSpiral = CalcCircleSpiral( ptCen, pSfrChunk->GetNormVersor(), dRad - dOffs, dIntRad, PockParam, pCrvRes) ; if ( bOkSpiral && pCrvRes->IsValid() && pCrvRes->GetCurveCount() > 0) { // se curva di bordo OPEN e lavorazione SpiralIn, imposto i parametri per LeadIn @@ -8682,7 +8686,7 @@ SmoothExtensionLinesByIntersection( ICRVCOMPOPOVECTOR& vCrvPaths, const PocketPa for ( int i = 0 ; i < int( vCrvPaths.size()) - 1 ; ++ i) { // se uno dei due percorsi presenta meno di 3 curve, non faccio nulla if ( ! vCrvPaths[i]->IsValid() || vCrvPaths[i]->GetCurveCount() < 3 || - ! vCrvPaths[i+1]->IsValid() || vCrvPaths[i+1]->GetCurveCount() < 3) + ! vCrvPaths[i+1]->IsValid() || vCrvPaths[i+1]->GetCurveCount() < 3) continue ; // se il percorso i-esimo non presenta una estensione in uscita e il percorso (i+1)-esimo // non presenta una estensione in entrata, non faccio nulla @@ -8768,7 +8772,7 @@ bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, double dOpenMinSafe, int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, bool bCalcFeed, const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, - double dMaxOptSize, ICRVCOMPOPOVECTOR& vCrvCompoRes) + double dMaxOptSize, double dLiTang, int nLiType, ICRVCOMPOPOVECTOR& vCrvCompoRes) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || @@ -8795,6 +8799,8 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.bAllowZigZagOneWayBorders = bAllowZigZagOneWayBorders ; myParams.bOptOffsets = ( ! bAllOffs) ; myParams.dMaxOptSize = dMaxOptSize ; + myParams.dLiTang = dLiTang ; + myParams.dLiType = nLiType ; if ( ptEndPrec.IsValid()) myParams.ptStart = ptEndPrec ; if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) From b59b50136623b95d430ff7b42e523aaac0783fc6 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 30 May 2025 12:15:19 +0200 Subject: [PATCH 14/24] EgtGeomKernel : - piccola correnzione in CalcPocketing. --- CalcPocketing.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 7927a87..574c457 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3625,7 +3625,7 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; if ( bOkSpiral) { double dIntRad = 0 ; - if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nType == POCKET_LI_HELIX) + if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nType == LEAD_IN_HELIX) dIntRad = min( 0.5 * min( PockParam.dLiTang, 2. * PockParam.dRad), dRad - dOffs) ; bool bOkSpiral = CalcCircleSpiral( ptCen, pSfrChunk->GetNormVersor(), dRad - dOffs, dIntRad, PockParam, pCrvRes) ; if ( bOkSpiral && pCrvRes->IsValid() && pCrvRes->GetCurveCount() > 0) { @@ -7795,6 +7795,8 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const ISurfFlatR if ( IsNull( pSfrUncleared)) return false ; if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, pSfrOrig, PockParams, pSfrUncleared)) { + + // estendo i percorsi di Offset se richiesto if ( ! RemoveUnclearedRegions( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) return false ; From 8cfa41d09f60a6e2105c45f228ca69fdf7c3b5c9 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 30 May 2025 12:18:23 +0200 Subject: [PATCH 15/24] EgtGeomKernel : - piccola correzione in CalcPocketing. --- CalcPocketing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 574c457..1b51842 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -44,7 +44,7 @@ using namespace std ; // variabili d'appoggio ( per non passare troppi parametri tra le funzioni secondarie) struct PocketParams { int nType = POCKET_SPIRALIN ; // tipo di lavorazione - int dLiType = POCKET_LI_NONE ; // tipo di ingresso (LeadIn) + int dLiType = LEAD_IN_NONE ; // tipo di ingresso (LeadIn) double dRad = 0. ; // raggio utensile double dRad_prec = -1. ; // raggio utensile della lavorazione precedente double dSideStep = 0. ; // step From f16de3a20cdff42e8c3f3ff228ad1b1168a01a08 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 30 May 2025 13:28:10 +0200 Subject: [PATCH 16/24] EgtGeomKernel : - in CalcPocketing, corretta gestione aree non svuotate nel caso di assenza di smussi o di cambio tipo di lavorazione. --- CalcPocketing.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 1b51842..a9d0531 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -4800,9 +4800,9 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const return false ; pCrvLink->Clear() ; - // se senza smusso, ritorno tratto lineare + // se senza smusso (e non caso circonferenza), ritorno tratto lineare bSpecial = false ; - if ( ! PockParams.bSmooth) + if ( ! PockParams.bSmooth && dParMeet > EPS_ZERO) return CalcBoundedLink( ptStart, ptEnd, vCrvBorders, pCrvLink) ; // inizializzo la curva di Link da restituire @@ -7795,8 +7795,6 @@ ExtendConformalOffsAndSetFeed( const ISurfFlatRegion* pSfrPock, const ISurfFlatR if ( IsNull( pSfrUncleared)) return false ; if ( GetUnclearedRegionAndSetFeed( vCrvFirstOffs, vCrvOffs, vCrvLinks, pSfrOrig, PockParams, pSfrUncleared)) { - - // estendo i percorsi di Offset se richiesto if ( ! RemoveUnclearedRegions( pSfrUncleared, vCrvOffs, vCrvFirstOffs, PockParams)) return false ; @@ -8594,11 +8592,15 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, return true ; // se superifice tutta aperta, lavoro in SPIRAL_IN - if ( PockParams.bAllOpen) + if ( PockParams.bAllOpen) { + PockParams.nType = POCKET_SPIRALIN ; return ( AddSpiralIn( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; + } // se superficie tutta chiusa, lavoro in SPIRAL_OUT - if ( PockParams.bAllClosed) + if ( PockParams.bAllClosed) { + PockParams.nType = POCKET_SPIRALOUT ; return ( AddSpiralOut( pSfrPock, pSfrOrig, PockParams, vCrvCompoRes)) ; + } // scorro i chunk della superficie da lavorare for ( int nC = 0 ; nC < pSfrPock->GetChunkCount() ; ++ nC) { @@ -8612,13 +8614,19 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, return false ; // se Chunk tutto aperto, lo lavoro in SPIRAL_IN if ( bOpen) { + int nType = PockParams.nType ; + PockParams.nType = POCKET_SPIRALIN ; if ( ! AddSpiralIn( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) return false ; + PockParams.nType = nType ; } // se Chunk tutto chiuso, lo lavoro in SPIRAL_OUT else if ( bClose) { + int nType = PockParams.nType ; + PockParams.nType = POCKET_SPIRALOUT ; if ( ! AddSpiralOut( pSfrChunk, pSfrOrig, PockParams, vCrvCompoRes)) return false ; + PockParams.nType = nType ; } // se Chunk non omogeneo else { @@ -8628,10 +8636,13 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, return false ; // se non ottengo Curve di Offset, lavoro in SpiralIn ( il Chunk ha dei lati aperti) if ( vvCrvOffs.empty()) { + int nType = PockParams.nType ; + PockParams.nType = POCKET_SPIRALIN ; PtrOwner pSfrChunk_cl( CloneSurfFlatRegion( pSfrChunk)) ; if ( IsNull( pSfrChunk_cl) || ! pSfrChunk_cl->IsValid() || ! AddSpiralIn( pSfrChunk_cl, pSfrOrig, PockParams, vCrvCompoRes)) return false ; + PockParams.nType = nType ; } else { // definisco vettore degli Offset e dei Link @@ -8640,10 +8651,13 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, // ordino le curve di Offset e raccordo if ( ! CalcConformalOffsAndLinks( vvCrvOffs, pSfrChunk, pSfrPock, PockParams, vCrvOffs, vCrvLink)) { // se calcolare i raccordi risulta troppo ambiguo o complesso, ritorno a SpiralIn + int nType = PockParams.nType ; + PockParams.nType = POCKET_SPIRALIN ; PtrOwner pSfrChunk_cl( CloneSurfFlatRegion( pSfrChunk)) ; if ( IsNull( pSfrChunk_cl) || ! pSfrChunk_cl->IsValid() || ! AddSpiralIn( pSfrChunk_cl, pSfrOrig, PockParams, vCrvCompoRes)) return false ; + PockParams.nType = nType ; continue ; } // flag per controllo @@ -8657,10 +8671,13 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, bOk = bOk && OrderAndExtendConformalPaths( vCrvPaths, pSfrChunk, pSfrOrig, PockParams) ; if ( ! bOk) { // se qualche passaggio restituisce errore, provo in SpiralIn + int nType = PockParams.nType ; + PockParams.nType = POCKET_SPIRALIN ; PtrOwner pSfrChunk_cl( CloneSurfFlatRegion( pSfrChunk)) ; if ( IsNull( pSfrChunk_cl) || ! pSfrChunk_cl->IsValid() || ! AddSpiralIn( pSfrChunk_cl, pSfrOrig, PockParams, vCrvCompoRes)) return false ; + PockParams.nType = nType ; } else { // aggiungo i percorsi ricavati From 9cba0e6d15582347a218e261a8e37dd1593f0daa Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 30 May 2025 17:04:19 +0200 Subject: [PATCH 17/24] EgtGeomKernel : - piccoli miglioramenti in CalcPocketing. --- CalcPocketing.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index a9d0531..e47de23 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3713,7 +3713,8 @@ GetPocketingOptimizedCurves( ISurfFlatRegion* pSfr, const PocketParams& PockPara } // ricavo le curve ottimizzate a seconda della lavorazione richiesta - if ( PockParam.nType == POCKET_SPIRALIN || PockParam.nType == POCKET_SPIRALOUT) { + if ( PockParam.nType == POCKET_SPIRALIN || PockParam.nType == POCKET_SPIRALOUT || + PockParam.nType == POCKET_CONFORMAL_ZIGZAG || PockParam.nType == POCKET_CONFORMAL_ONEWAY) { // curva da resituire PtrOwner pCrvOptSpiral( CreateCurveComposite()) ; if ( IsNull( pCrvOptSpiral) || @@ -5721,6 +5722,10 @@ CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* } // controllo se l'Offset rimuove una quantità minima di materiale else if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < TOL_REMOVE_OFFSET) { + // evito questo passaggio se sono alla seconda iterazione, potrei creare regioni + // non svuotate raggiungibili mediante raccordi a circonferenza allacciati a tratti chiusi + if ( nIter == 1) + return true ; // inizializzo la curva di bordo della regione non svuotata PtrOwner pCrvBorder( CreateCurveComposite()) ; if ( IsNull( pCrvBorder)) From 6df1b90e95c2ffe70d82a84f88459eabad814df9 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Sat, 31 May 2025 11:54:21 +0200 Subject: [PATCH 18/24] =?UTF-8?q?EgtGeomKernel=202.7e3=20:=20-=20in=20Curv?= =?UTF-8?q?eComposite=20AddPoint=20comprende=20le=20funzionalit=C3=A0=20di?= =?UTF-8?q?=20FromPoint=20che=20=C3=A8=20stata=20eliminata=20-=20modifiche?= =?UTF-8?q?=20conseguenti=20in=20altre=20parti.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CurveComposite.cpp | 22 +++++----------------- CurveComposite.h | 3 +-- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes Tree.cpp | 12 ++++++------ 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 35bc353..6e3e776 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -192,7 +192,7 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT return false ; // verifico lo stato - if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && m_nStatus == TO_VERIFY)) + if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && ( m_nStatus == TO_VERIFY || m_nStatus == IS_A_POINT))) return false ; // controllo la tolleranza @@ -1778,10 +1778,11 @@ bool CurveComposite::AddPoint( const Point3d& ptStart) { // verifico lo stato - if ( m_nStatus != TO_VERIFY) + if ( m_nStatus != TO_VERIFY && m_nStatus != IS_A_POINT) return false ; - // assegno il punto + // assegno il punto e setto lo stato m_ptStart = ptStart ; + m_nStatus = IS_A_POINT ; return true ; } @@ -1825,7 +1826,7 @@ bool CurveComposite::AddLine( const Point3d& ptNew, bool bEndOrStart) { // verifico lo stato - if ( m_nStatus != OK && m_nStatus != TO_VERIFY) + if ( m_nStatus != OK && m_nStatus != IS_A_POINT) return false ; // costruisco la linea PtrOwner pLine( CreateBasicCurveLine()) ; @@ -3801,19 +3802,6 @@ CurveComposite::ResetVoronoiObject() const m_pVoronoiObj = nullptr ; } -//---------------------------------------------------------------------------- -bool -CurveComposite::FromPoint(Point3d& ptStart) -{ - // verifico lo stato - if ( m_nStatus != TO_VERIFY) - return false ; - // assegno il punto e setto lo stato - m_ptStart = ptStart ; - m_nStatus = IS_A_POINT ; - return true ; -} - //---------------------------------------------------------------------------- bool CurveComposite::GetOnlyPoint(Point3d& ptStart) const diff --git a/CurveComposite.h b/CurveComposite.h index 1c9b2eb..646105e 100644 --- a/CurveComposite.h +++ b/CurveComposite.h @@ -177,8 +177,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW bool GetCurveTempProp( int nCrv, int& nProp, int nPropInd = 0) const override ; bool SetCurveTempParam( int nCrv, double dParam, int nParamInd = 0) override ; bool GetCurveTempParam( int nCrv, double& dParam, int nParamInd = 0) const override ; - bool FromPoint( Point3d& ptStart) override ; // funzione per settare la curva ad un unico punto - bool GetOnlyPoint( Point3d& ptStart) const override ; // funzione per recuperare l'unico punto da cui è composta la curva ( degenere) + bool GetOnlyPoint( Point3d& ptStart) const override ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index e014c00dc63a316a07a1b561484b40a85eb97592..b40b3361193baf76e09ad01df8c0c3b7da9e2b01 100644 GIT binary patch delta 94 zcmdlNy)SyhFE&Qw&A-_cnHh~ID{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-W11TR delta 94 zcmdlNy)SyhFE&P_&A-_cnHh~HD{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-Vf-5U diff --git a/Tree.cpp b/Tree.cpp index 47f0bfc..5064b47 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -2101,7 +2101,7 @@ Tree::UpdateSplitLoop( ICurveComposite* pCC, Point3d& pt) // potrei avere una compo vuota o con solo un punto // se non riesco ad aggiungere una linea allora era una compo vuota if ( ! pCC->GetOnlyPoint( ptLast)) { - pCC->FromPoint( pt) ; + pCC->AddPoint( pt) ; ptLast = pt ; } else { @@ -4139,7 +4139,7 @@ Tree::GetEdges3D( vector& mCCEdges, POLYLINEVECTOR& vPolygons pt3d = ORIG ; GetPoint( cNeigh.GetBottomLeft().x, cNeigh.GetTopRight().y, pt3d) ; mCCEdges.back().back()->AddLine( pt3d) ; if ( ! mCCEdges.back().back()->IsValid()) - mCCEdges.back().back()->FromPoint( pt3d) ; + mCCEdges.back().back()->AddPoint( pt3d) ; } else if ( i == 1 ) { while ( ! AreSamePointXYApprox(pt, cNeigh.GetTopLeft()) && plCell.GetNextPoint( pt)) { @@ -4155,7 +4155,7 @@ Tree::GetEdges3D( vector& mCCEdges, POLYLINEVECTOR& vPolygons pt3d = ORIG ; GetPoint( cNeigh.GetBottomLeft().x, cNeigh.GetBottomLeft().y, pt3d) ; mCCEdges.back().back()->AddLine( pt3d) ; if ( ! mCCEdges.back().back()->IsValid()) - mCCEdges.back().back()->FromPoint( pt3d) ; + mCCEdges.back().back()->AddPoint( pt3d) ; } else if ( i == 2) { while ( ! AreSamePointXYApprox(pt, cNeigh.GetBottomLeft()) && plCell.GetNextPoint( pt)) { @@ -4171,7 +4171,7 @@ Tree::GetEdges3D( vector& mCCEdges, POLYLINEVECTOR& vPolygons pt3d = ORIG ; GetPoint( cNeigh.GetTopRight().x, cNeigh.GetBottomLeft().y, pt3d) ; mCCEdges.back().back()->AddLine( pt3d) ; if ( ! mCCEdges.back().back()->IsValid()) - mCCEdges.back().back()->FromPoint( pt3d) ; + mCCEdges.back().back()->AddPoint( pt3d) ; } else if ( i == 3) { while ( ! AreSamePointXYApprox(pt, cNeigh.GetBottomRight()) && plCell.GetNextPoint( pt)) { @@ -4187,7 +4187,7 @@ Tree::GetEdges3D( vector& mCCEdges, POLYLINEVECTOR& vPolygons pt3d = ORIG ; GetPoint( cNeigh.GetTopRight().x, cNeigh.GetTopRight().y, pt3d) ; mCCEdges.back().back()->AddLine( pt3d) ; if ( ! mCCEdges.back().back()->IsValid()) - mCCEdges.back().back()->FromPoint( pt3d) ; + mCCEdges.back().back()->AddPoint( pt3d) ; } } } @@ -4212,7 +4212,7 @@ Tree::GetEdges3D( vector& mCCEdges, POLYLINEVECTOR& vPolygons pCC3D->AddLine( pt3D) ; } if ( ! pCC3D->IsValid()) - pCC3D->FromPoint( pt3D) ; + pCC3D->AddPoint( pt3D) ; // qui devo fare dei controlli prima di aggiungere questa polyline? mCCEdges[i].emplace_back( Release(pCC3D)) ; } From bf56d53fafa0b021cf1dcdfa62a7f40555c4e5ca Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 4 Jun 2025 16:26:33 +0200 Subject: [PATCH 19/24] EgtGeomKernel : - In CalcPocketing sistemate le tolleranze di merge per le curve e migliorati i controlli per raccordi a circonferenza. - In CurveComposite aggiunto controllo su Archi con angolo al centro circa a giro seguiti/precedeuti da curve di lunghezza sotto alla tolleranza lineare. --- CalcPocketing.cpp | 48 ++++++++++++++++++++++++++-------------------- CurveComposite.cpp | 41 +++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index e47de23..06a61b8 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -512,10 +512,10 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, // lo semplifico // recupero la lunghezza del tratto e imposto associo la Feed corrente // se curva corta -> il parametro di Feed è definito da quello precedente - pCrv->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; + pCrv->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG, false) ; pCrv->GetLength( dLen) ; - for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) - pCrv->SetCurveTempParam( u, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; + for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU) + pCrv->SetCurveTempParam( nU, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; pCrvSimple->AddCurve( Release( pCrv)) ; dCurrTempParam = dTempParam ; nParStart = i ; @@ -524,10 +524,10 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, // ultima parte di curva uniforme ... PtrOwner pCrvLast( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, pCrvCompo->GetCurveCount()))) ; if ( ! IsNull( pCrvLast)) { - pCrvLast->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; + pCrvLast->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG, false) ; double dLen ; pCrvLast->GetLength( dLen) ; - for ( int u = 0 ; u < pCrvLast->GetCurveCount() ; ++ u) - pCrvLast->SetCurveTempParam( u, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; + for ( int nU = 0 ; nU < pCrvLast->GetCurveCount() ; ++ nU) + pCrvLast->SetCurveTempParam( nU, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; pCrvSimple->AddCurve( Release( pCrvLast)) ; } @@ -545,7 +545,7 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, PtrOwner pCrv( ConvertCurveToComposite( pCrvSimple->CopyParamRange( nParStart, i))) ; if ( IsNull( pCrv)) return false ; - pCrv->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; + pCrv->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG, false) ; // recupero la lunghezza di tale curve double dLen ; pCrv->GetLength( dLen) ; for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) @@ -559,11 +559,11 @@ SimplifyCurveByFeeds( ICurveComposite* pCrvCompo, const PocketParams& PockParam, pCrvLast.Set( ConvertCurveToComposite( pCrvSimple->CopyParamRange( nParStart, pCrvSimple->GetCurveCount()))) ; if ( ! IsNull( pCrvLast)) { // semplifico - pCrvLast->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; + pCrvLast->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG, false) ; // recupero la lunghezza di tale curva e imposto la Feed pCrvLast->GetLength( dLen) ; - for ( int u = 0 ; u < pCrvLast->GetCurveCount() ; ++ u) - pCrvLast->SetCurveTempParam( u, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; + for ( int nU = 0 ; nU < pCrvLast->GetCurveCount() ; ++ nU) + pCrvLast->SetCurveTempParam( nU, ( 0.1 * PockParam.dRad < dLen ? dCurrTempParam : dTempParam), 0) ; pCrvCompo->AddCurve( Release( pCrvLast)) ; } @@ -4816,12 +4816,13 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const if ( SqDist( ptStart, ptEnd) > dSqTol) bSpecial = ( CalcSpecialBoundedSmoothedLink( ptStart, vtStart, ptEnd, vtEnd, PockParams, pMyCrvLink)) ; if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) { - // ...in caso negativo creo il Biarco ( se parametro a zero, allora circonferenza) + // ...in caso negativo creo il Biarco double dAngStart ; vtStart.GetAngleXY( X_AX, dAngStart) ; double dAngEnd ; vtEnd.GetAngleXY( X_AX, dAngEnd) ; if ( dParMeet > EPS_ZERO) pMyCrvLink.Set( ConvertCurveToComposite( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet))) ; else { + // ... o una circonferenza, orientata in modo da poter essere classificata con le curve di bordo PtrOwner pCrvCir( CreateBasicCurveArc()) ; if ( IsNull( pCrvCir)) return false ; @@ -4908,6 +4909,15 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const } // La curva necessita di un ulteriore smusso, in quanto tagliata su un bordo ModifyCurveToSmoothed( pCompoTest, PockParams, PockParams.dRad / 4., PockParams.dRad / 4., false) ; + // nel caso speciale della circonferenza, devo impostare il punto iniziale + if ( dParMeet < EPS_ZERO) { + if ( pCompoTest->IsClosed()) { // sempre... + double dU = 0. ; + int nFlag = 0 ; + if ( DistPointCurve( ptStart, *pCompoTest).GetParamAtMinDistPoint( 0., dU, nFlag)) + pCompoTest->ChangeStartPoint( dU) ; + } + } // restituisco il Link if ( IsNull( pCompoTest) || ! pCompoTest->IsValid() || pCompoTest->GetCurveCount() == 0) @@ -5384,7 +5394,7 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& bool bSpecial = false ; // se parallele, allora trasformo in una circonferenza if ( bSameDir) { - if ( ! CalcBoundedSmoothedLink( ptMain, V_INVALID, ptCentroid, V_INVALID, 0., vOffsFirstCurve, PockParams, pCrvCurl, bSpecial)) + if ( ! CalcBoundedSmoothedLink( ptMain, vt1, ptCentroid, vt2, 0., vOffsFirstCurve, PockParams, pCrvCurl, bSpecial)) continue ; Vector3d vtStartCheck ; pCrvCurl->GetStartDir( vtStartCheck) ; if ( AreOppositeVectorApprox( vtStartCheck, vt1)) @@ -5520,21 +5530,21 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& if ( IsNull( pCrvTest)) return false ; // aggiungo tratto iniziale di Offset - pCrvTest->AddCurve( ConvertCurveToBasicComposite( pMyOffs->CopyParamRange( 0, dURef1))) ; + pCrvTest->AddCurve( ConvertCurveToComposite( pMyOffs->CopyParamRange( 0, dURef1))) ; // aggiungo la curva a ricciolo if ( ! pCrvTest->AddCurve( Release( pCrvCurl))) continue ; // aggiungo il tratto finale di Offset - pCrvTest->AddCurve( ConvertCurveToBasicComposite( pMyOffs->CopyParamRange( dURef2, pMyOffs->GetCurveCount()))) ; + pCrvTest->AddCurve( ConvertCurveToComposite( pMyOffs->CopyParamRange( dURef2, pMyOffs->GetCurveCount()))) ; // provo a controllare che i punti inziali e finali coincidano, in caso aggiorno il nuovo Offset Point3d ptStart_Old ; vOffs[nInd]->GetStartPoint( ptStart_Old) ; Point3d ptEnd_Old ; vOffs[nInd]->GetEndPoint( ptEnd_Old) ; Point3d ptStart_New ; pCrvTest->GetStartPoint( ptStart_New) ; Point3d ptEnd_New ; pCrvTest->GetEndPoint( ptEnd_New) ; if ( AreSamePointApprox( ptStart_Old, ptStart_New) && AreSamePointApprox( ptEnd_Old, ptEnd_New)) { - pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 0), 0) ; - pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 1), 1) ; - vOffs[nInd].Set( pCrvTest) ; + pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 0), 0) ; + pCrvTest->SetTempProp( vOffs[nInd]->GetTempProp( 1), 1) ; + vOffs[nInd].Set( pCrvTest) ; } } @@ -5722,10 +5732,6 @@ CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* } // controllo se l'Offset rimuove una quantità minima di materiale else if ( dMaxOffs + ( dOffs - dOffsPrec) - PockParams.dRad < TOL_REMOVE_OFFSET) { - // evito questo passaggio se sono alla seconda iterazione, potrei creare regioni - // non svuotate raggiungibili mediante raccordi a circonferenza allacciati a tratti chiusi - if ( nIter == 1) - return true ; // inizializzo la curva di bordo della regione non svuotata PtrOwner pCrvBorder( CreateCurveComposite()) ; if ( IsNull( pCrvBorder)) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 6e3e776..6943ea0 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -3169,11 +3169,26 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn // se precedente molto corta double dLenP ; if ( pCrvP->GetLength( dLenP) && dLenP < dCurrLinTol) { - // se abbastanza allineata alla successiva + // se abbastanza allineata alla successiva Vector3d vtDirP, vtDirC ; if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) { - Point3d ptStart ; - return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ; + bool bModifStart = ( pCrvC->GetType() != CRV_ARC) ; + if ( ! bModifStart) { + /* nel caso in cui la curva corrente sia un arco, bisogna controllare che la somma tra + l'angolo al centro e l'angolo sotteso dalla curva precedente non superi l'angolo giro; in + caso positivo, la modifica del punto inziale dell'arco ( curva corrente) rimoverebbe + tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */ + Point3d ptS ; pCrvP->GetStartPoint( ptS) ; + Point3d ptE ; pCrvC->GetStartPoint( ptE) ; + const ICurveArc* pArcC = GetBasicCurveArc( pCrvC) ; + double dAngRef = ( Dist( ptS, ptE) / pArcC->GetRadius()) * RADTODEG ; + bModifStart = ( abs( pArcC->GetAngCenter()) + dAngRef < ANG_FULL - 10 * EPS_ANG_SMALL) ; + + } + if ( bModifStart) { + Point3d ptStart ; + return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ; + } } } // se corrente molto corta @@ -3182,10 +3197,24 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn // se abbastanza allineata alla precedente Vector3d vtDirP, vtDirC ; if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) { - Point3d ptEnd ; - return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ; + bool bModifEnd = ( pCrvP->GetType() != CRV_ARC) ; + if ( ! bModifEnd) { + /* nel caso in cui la curva predecente sia un arco, bisogna controllare che la somma tra + l'angolo al centro e l'angolo sotteso dalla curva corrente non superi l'angolo giro; in + caso positivo, la modifica del punto finale dell'arco ( curva precedente) rimoverebbe + tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */ + Point3d ptS ; pCrvP->GetEndPoint( ptS) ; + Point3d ptE ; pCrvC->GetEndPoint( ptE) ; + const CurveArc* pArcP = GetBasicCurveArc( pCrvP) ; + double dAngRef = ( Dist( ptS, ptE) / pArcP->GetRadius()) * RADTODEG ; + bModifEnd = ( abs( pArcP->GetAngCenter()) + dAngRef < ANG_FULL - 10. * EPS_ANG_SMALL) ; + } + if ( bModifEnd) { + Point3d ptEnd ; + return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ; + } } - } + } // coefficiente deduzione tolleranza const double COEFF_TOL = 0.7 ; // se entrambe rette From afa4872c97be9f3b3d062d4cb7e25182f1a8a572 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 6 Jun 2025 16:51:25 +0200 Subject: [PATCH 20/24] EgtGeomKernel : - In CalcPocketing piccola modifica per smussi sui raccordi speciali. --- CalcPocketing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 06a61b8..de95494 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -4784,6 +4784,14 @@ CalcSpecialBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, pZigZagLink->AddLine( ptNew) ; } + // questa composita contiene al massimo 5 curve e, in generale, quella una curva molto più lunga + // delle altre ( quella che collega le due estensioni calcolate). Spezzo la composita ottenuta in curve + // la cui lunghezza massima è circa il raggio utensile + PolyLine PL ; + pZigZagLink->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ; + PL.AdjustForMaxSegmentLen( PockParams.dRad + 10 * EPS_SMALL) ; + pZigZagLink->Clear() ; + pZigZagLink->FromPolyLine( PL) ; // Smusso il raccordo a ZigZag ModifyCurveToSmoothed( pZigZagLink, PockParams, .4, .4, true) ; pCrvLink->CopyFrom( pZigZagLink) ; From 53ab6767508de7dea7e369f5497bedb4f13d7233 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 9 Jun 2025 11:38:46 +0200 Subject: [PATCH 21/24] EgtGeomKernel : - In CalcPocketing correzione piccolo errore. --- CalcPocketing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index de95494..8b53af7 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3625,7 +3625,7 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; if ( bOkSpiral) { double dIntRad = 0 ; - if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nType == LEAD_IN_HELIX) + if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.dLiType == LEAD_IN_HELIX) dIntRad = min( 0.5 * min( PockParam.dLiTang, 2. * PockParam.dRad), dRad - dOffs) ; bool bOkSpiral = CalcCircleSpiral( ptCen, pSfrChunk->GetNormVersor(), dRad - dOffs, dIntRad, PockParam, pCrvRes) ; if ( bOkSpiral && pCrvRes->IsValid() && pCrvRes->GetCurveCount() > 0) { From 9819c8cee89e012e9e713b2a1d71334ac47b0c4a Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 9 Jun 2025 12:13:56 +0200 Subject: [PATCH 22/24] EgtGeomKernel : - In CalcPocketing piccola modifica sui nomi dei parametri della funzione. --- CalcPocketing.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 8b53af7..d98d22d 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -44,7 +44,7 @@ using namespace std ; // variabili d'appoggio ( per non passare troppi parametri tra le funzioni secondarie) struct PocketParams { int nType = POCKET_SPIRALIN ; // tipo di lavorazione - int dLiType = LEAD_IN_NONE ; // tipo di ingresso (LeadIn) + int nLiType = LEAD_IN_NONE ; // tipo di ingresso (LeadIn) double dRad = 0. ; // raggio utensile double dRad_prec = -1. ; // raggio utensile della lavorazione precedente double dSideStep = 0. ; // step @@ -3625,7 +3625,7 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; if ( bOkSpiral) { double dIntRad = 0 ; - if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.dLiType == LEAD_IN_HELIX) + if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nLiType == LEAD_IN_HELIX) dIntRad = min( 0.5 * min( PockParam.dLiTang, 2. * PockParam.dRad), dRad - dOffs) ; bool bOkSpiral = CalcCircleSpiral( ptCen, pSfrChunk->GetNormVersor(), dRad - dOffs, dIntRad, PockParam, pCrvRes) ; if ( bOkSpiral && pCrvRes->IsValid() && pCrvRes->GetCurveCount() > 0) { @@ -8838,7 +8838,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.bOptOffsets = ( ! bAllOffs) ; myParams.dMaxOptSize = dMaxOptSize ; myParams.dLiTang = dLiTang ; - myParams.dLiType = nLiType ; + myParams.nLiType = nLiType ; if ( ptEndPrec.IsValid()) myParams.ptStart = ptEndPrec ; if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) From 0bffa0039c9b408d824a9b0d576c37b1c60e4a58 Mon Sep 17 00:00:00 2001 From: SaraP Date: Mon, 9 Jun 2025 15:47:11 +0200 Subject: [PATCH 23/24] EgtGeomKernel 2.7f1 : - migliorie e piccole correzioni varie nelle trimesh ( booleane, chiusura). --- CurveComposite.cpp | 2 - EgtGeomKernel.rc | Bin 11710 -> 11710 bytes PolygonPlane.cpp | 10 +- SurfTriMesh.cpp | 80 +++++++++++---- SurfTriMesh.h | 4 + SurfTriMeshBooleans.cpp | 125 ++++++++-------------- SurfTriMeshUtilities.cpp | 217 ++++++++++++++++++++++++++++++++++----- Triangulate.cpp | 63 ++++++------ 8 files changed, 332 insertions(+), 169 deletions(-) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 6943ea0..fa9f197 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -3309,8 +3309,6 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn CurveArc NewArc ; if ( NewArc.Set3P( ptP1, ptP2, ptP3, bCirc)) { // se vicino a circonferenza arco per 3 punti potrebbe non dare il risultato desiderato quindi faccio controllo su raggio e centro - double dDist = Dist( NewArc.GetCenter(), ptC1Fin) ; - double dDelta = abs( NewArc.GetRadius() - pArcP->GetRadius()) ; if ( Dist( NewArc.GetCenter(), ptC1Fin) > 2 * dCurrLinTol || abs( NewArc.GetRadius() - pArcP->GetRadius()) > 2 * dCurrLinTol) return 0 ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index b40b3361193baf76e09ad01df8c0c3b7da9e2b01..cdc95ef3f0ae957f1f1ade7344b446ee3b842263 100644 GIT binary patch delta 262 zcmdlNy)SyhI%aiGhCGIJh8%`ehGHOAV9;O)W+-7u1ma8}FBB-731Uy?R&U)L$1;P7 z)r>)h!Ep0$HhE^|GzP=Tirl)Jy|{Wc1_cHUhESkLCPN8BDnkm89}HwAf_cT0PijeT z{=m${%xcP@!(hDmyqr8Ub1IPWQL&V9b04=0LgGBra2s4xtNztex=643-W*`*vUBzl^_RC{=l5Ixkp`x8C7cYNv*F;0AR{QEC2ui diff --git a/PolygonPlane.cpp b/PolygonPlane.cpp index 54cdcbe..1f2a567 100644 --- a/PolygonPlane.cpp +++ b/PolygonPlane.cpp @@ -19,10 +19,10 @@ void PolygonPlane::AddPoint( const Point3d& ptP) { - // se è il primo punto (parto da -1 perchè verrà contato alla chiusura) + // se è il primo punto (parto da -1 perchè verrà contato alla chiusura) if ( m_nPntNbr == -1) { // inizializzazioni - m_dLenN = 0 ; + m_dLenN = -1 ; m_vtN = V_NULL ; m_ptMid = ORIG ; m_dSXy = 0 ; m_dSXz = 0 ; @@ -60,16 +60,16 @@ PolygonPlane::AddPoint( const Point3d& ptP) bool PolygonPlane::Finalize( void) { - // almeno 3 punti (il triangolo è il poligono con minimo numero di lati) + // almeno 3 punti (il triangolo è il poligono con minimo numero di lati) if ( m_nPntNbr + 1 < 3) return false ; - // se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato + // se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato if ( ! AreSamePointExact( m_ptFirst, m_ptLast)) { // aggiungo il primo punto per far eseguire i conti sul lato di chiusura AddPoint( m_ptFirst) ; } // se non effettuato, eseguo il calcolo finale - if ( m_dLenN < EPS_SMALL) { + if ( m_dLenN < 0) { // lunghezza della normale (doppio dell'area del poligono) m_dLenN = m_vtN.Len() ; if ( m_dLenN < SQ_EPS_SMALL) diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 21c4386..d7ff791 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -3044,7 +3044,7 @@ SurfTriMesh::AddBiTriangle( const int nIdVert[4]) //---------------------------------------------------------------------------- bool SurfTriMesh::DoCompacting( double dTol) -{ +{ // imposto ricalcolo m_nStatus = ERR ; m_OGrMgr.Reset() ; @@ -3085,6 +3085,7 @@ SurfTriMesh::DoCompacting( double dTol) int nVIdSize = int( vVId.size()) ; // sistemo gli indici dei vertici nei triangoli + INTVECTOR vInvalidIds ; for ( int nId = 0 ; nId < GetTriangleSize() ; ++ nId) { // salto i triangoli cancellati if ( m_vTria[nId].nIdVert[0] == SVT_DEL) @@ -3101,15 +3102,51 @@ SurfTriMesh::DoCompacting( double dTol) // aggiorno il triangolo m_vTria[nId].nIdVert[0] = vVId[vOId[0]] ; m_vTria[nId].nIdVert[1] = vVId[vOId[1]] ; - m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ; - // se due vertici coincidono o la normale non è calcolabile, cancello il triangolo - if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1] || - m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2] || - m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2] || - ! CalcTriangleNormal( nId)) - RemoveTriangle( nId) ; + m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ; + + // verifico se triangolo da rimuovere per vertici coincidenti + bool bRemove = false ; + int nTAdj1 = SVT_NULL, nTAdj2 = SVT_NULL ; + if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1]) { + nTAdj1 = m_vTria[nId].nIdAdjac[1] ; + nTAdj2 = m_vTria[nId].nIdAdjac[2] ; + bRemove = true ; + } + else if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2]) { + nTAdj1 = m_vTria[nId].nIdAdjac[0] ; + nTAdj2 = m_vTria[nId].nIdAdjac[1] ; + bRemove = true ; + } + else if ( m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2]) { + nTAdj1 = m_vTria[nId].nIdAdjac[0] ; + nTAdj2 = m_vTria[nId].nIdAdjac[2] ; + bRemove = true ; + } + if ( bRemove) { + // sistemo le contro adiacenze + if ( nTAdj1 != SVT_NULL) { + for ( int j = 0 ; j < 3 ; ++ j) + if ( m_vTria[nTAdj1].nIdAdjac[j] == nId) + m_vTria[nTAdj1].nIdAdjac[j] = nTAdj2 ; + } + if ( nTAdj2 != SVT_NULL) { + for ( int j = 0 ; j < 3 ; ++ j) + if ( m_vTria[nTAdj2].nIdAdjac[j] == nId) + m_vTria[nTAdj2].nIdAdjac[j] = nTAdj1 ; + } + // rimuovo il triangolo + RemoveTriangle( nId) ; + } + + // verifico se il triangolo va rimosso per normale non calcolabile + else if ( ! CalcTriangleNormal( nId)) + vInvalidIds.emplace_back( nId) ; } + // elimino triangoli invalidi ( con gestione speciale per evitare T-junctions) + if ( ! vInvalidIds.empty()) + RemoveInvalidTriangles( vInvalidIds) ; + // compatto il vettore dei vertici if ( ! PackVertices()) return false ; @@ -3346,22 +3383,23 @@ SurfTriMesh::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ; bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ; - // aggiorno le facce - for ( int i = 0 ; i < GetTriangleSize() ; ++ i) { - if ( m_vTria[i].nIdVert[0] != SVT_DEL) { - // se c'è mirror, devo invertire la faccia - if ( bMirror) - InvertTriangle( i) ; - // aggiorno la normale - if ( ! CalcTriangleNormal( i)) { - // elimino il triangolo - RemoveTriangle( i) ; - } - } + // se c'è mirror, devo invertire le facce + if ( bMirror) { + for ( int i = 0 ; i < GetTriangleSize() ; ++ i) + if ( m_vTria[i].nIdVert[0] != SVT_DEL) + InvertTriangle( i) ; } + + // rimuovo i triangoli resi invalidi dalla scalatura + bool bOk = DoCompacting() ; - return DoCompacting() ; + // rimuovo i triangoli doppi + bool bModified = false ; + bOk = bOk && RemoveDoubleTriangles( bModified) ; + if ( bModified) + bOk = bOk && ( AdjustVertices() && DoCompacting()) ; + return bOk ; } //---------------------------------------------------------------------------- diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 5fbec74..90bf43d 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -440,6 +440,10 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) ; bool ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) ; bool SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) ; + bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const ; + bool RemoveInvalidTriangles( const INTVECTOR& vIds) ; + bool FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const ; + private : ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index ff10d40..3aed42c 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -502,9 +502,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } } - // ------------------------------------------------------------------------------------------- - - + // Creo il loop chiuso padre di tutti, il perimetro del triangolo. Questo viene diviso in sotto-loop // chiusi mediante quelli aperti. I loop chiusi trovati precedentemente sono interni a uno dei // sotto-loop chiusi di cui è formato il perimetro. @@ -704,16 +702,18 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } } } - // Elimino loop interni non validi - bool bDouble = true ; + // Verifico se i loop interni sono validi + bool bAllInvalid = true ; for ( int nInnLoop = 0 ; nInnLoop < int( vInnerLoop.size()) ; ++ nInnLoop) { - if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 2) { - bDouble = false ; + // se chain formata da tre segmenti significa che si tratta di due linee sovrapposte ( il terzo tratto è quello aggiunto + // per forzare la chiusura) + if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 3) { + bAllInvalid = false ; break ; } } - if ( vInnerLoop.empty() || bDouble) { + if ( vInnerLoop.empty() || bAllInvalid) { // Eseguo triangolazione PNTVECTOR vPt ; INTVECTOR vTr ; @@ -753,63 +753,20 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT vPolygons.emplace_back( CurLoop) ; } - // poligono - Polygon3d pgPol ; - pgPol.FromPolyLine( vPolygons[1]) ; - - // controllo direzioni delle normali - bool bCodirectedNormals = trTria.GetN() * pgPol.GetVersN() > 0. ; - - // Aggiungo al loop esterno i punti dei loop interni che si trovano su di esso - PNTULIST& ExternLoopList = vPolygons[0].GetUPointList() ; - // Ciclo sui segmenti del loop esterno - auto itSt = ExternLoopList.begin() ; - auto itEn = itSt ; - ++ itEn ; - for ( ; itSt != ExternLoopList.end() && itEn != ExternLoopList.end() ; ++ itSt, ++ itEn) { - // Estremi del segmento corrente del loop esterno e scorrispondente vettore - Point3d ptSt = itSt->first ; - Point3d ptEn = itEn->first ; - Vector3d vtSeg = ptEn - ptSt ; - double dSegLen = vtSeg.Len() ; - vtSeg /= dSegLen ; - // Vettore dei punti dei loop interni che stanno sul segmento del loop esterno - PNTUVECTOR vPointWithOrder ; - // Ciclo sui loop interni - for ( int nInnPoly = 1 ; nInnPoly < int( vPolygons.size()) ; ++ nInnPoly) { - // Ciclo sui punti dei loop interni - Point3d ptInnPoint ; - bool bIsFirst = true ; - bool bContinue = vPolygons[nInnPoly].GetFirstPoint( ptInnPoint) ; - while ( bContinue) { - DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ; - double dDist ; - DistCalculator.GetDist( dDist) ; - double dLongPos = ( ptInnPoint - ptSt) * vtSeg ; - if ( dDist < EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) { - POINTU NewPointU ; - NewPointU.first = ptInnPoint ; - NewPointU.second = dLongPos ; - if ( ! bIsFirst) - vPointWithOrder.emplace_back( NewPointU) ; - } - bIsFirst = false ; - bContinue = vPolygons[nInnPoly].GetNextPoint( ptInnPoint) ; - } - } - // Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso - for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) { - for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) { - if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) { - swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ; - } - } - } - // Aggiungo i punti al loop esterno - for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) { - itSt = ExternLoopList.emplace( itEn, vPointWithOrder[nPi]) ; - } + // controllo la direzione della normale del triangolo con quella del poligono di area maggiore + // ( per gestire eventuali inscatolamenti) + Vector3d vtPoly = V_NULL ; + double dMaxArea = -1 ; + for ( int i = 1 ; i < int( vPolygons.size()) ; i ++) { + Plane3d plPoly ; + double dAreaPoly ; + vPolygons[i].IsClosedAndFlat( plPoly, dAreaPoly) ; + if ( dAreaPoly > dMaxArea) { + vtPoly = plPoly.GetVersN() ; + dMaxArea = dAreaPoly ; + } } + bool bCodirectedNormals = trTria.GetN() * vtPoly > 0. ; PNTVECTOR vPt ; INTVECTOR vTr ; @@ -836,6 +793,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT } // Divido i loop che si autointercettano + // TO DO : da verificare. Questa porzione di codice non dovrebbe andare prima della triangolazione? int nInitialLoopNum = int( vPolygons.size()) ; for ( int nL = 1 ; nL < nInitialLoopNum ; ++ nL) { // Lista dei punti della PolyLine Loop corrente @@ -883,11 +841,11 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT itSt2 = LoopPointList.emplace( itEn2, vAddingPointWithOrder[nPi]) ; } } - + // Spezzo i loop autointersecantesi POLYLINEVECTOR vAuxPolygons ; vAuxPolygons.emplace_back( vPolygons[nL]) ; - + bool bSplitted = true ; while ( bSplitted) { bSplitted = false ; @@ -956,16 +914,13 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT vPolygons.erase( vPolygons.begin() + i) ; else ++ i ; - } - - bool bCordirectedNormals_intLoop = bCodirectedNormals ; + // eventuale inversione della prima curva ( che determina il verso della triangolazione) per averla orientata + // come il triangolo if ( ! vPolygons.empty()) { Polygon3d pgPol ; pgPol.FromPolyLine( vPolygons[0]) ; - // controllo direzioni delle normali - bCordirectedNormals_intLoop = trTria.GetN() * pgPol.GetVersN() > 0. ; - if ( ! bCordirectedNormals_intLoop) + if ( trTria.GetN() * pgPol.GetVersN() < 0.) vPolygons[0].Invert() ; } @@ -981,7 +936,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ; Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; - if ( bCordirectedNormals_intLoop) + if ( bCodirectedNormals) Surf.m_vTria[nNewTriaNum].nTempShell = 1 ; else Surf.m_vTria[nNewTriaNum].nTempShell = -1 ; @@ -1123,7 +1078,7 @@ SurfTriMesh::AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Su //---------------------------------------------------------------------------- bool SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) -{ +{ bool bModif = false ; SurfTriMesh& SurfB = Other ; @@ -1176,7 +1131,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) INTVECTOR vNearTria ; SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ; - // I scorro tutti i triangoli di B che intersecano il box di A + // Scorro tutti i triangoli di B che intersecano il box di A for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) { // Se il triangolo B non è valido, continuo @@ -1365,7 +1320,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) // Triangoli sovrapposti if ( bContinue) { int nTriaNum2A = GetTriangleSize() ; - // Resetto e ricalcolo la HashGrid della superficie B + // Resetto e ricalcolo la HashGrid della superficie B SurfB.ResetHashGrids3d() ; for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) { // Se il triangolo A non è valido, continuo @@ -1375,15 +1330,19 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) // Box del triangolo A BBox3d b3dTriaA ; trTriaA.GetLocalBBox( b3dTriaA) ; - // Recupero i triangoli di B che interferiscono col box del triangolo di A + // Recupero i triangoli di B che interferiscono col box del triangolo di A INTVECTOR vNearTria ; SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ; for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) { - // Se il triangolo B non è valido, continuo + // Se il triangolo B non è valido, continuo Triangle3d trTriaB ; if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true)) continue ; - // Se i triangoli sono sovrapposti + // Se sono già stati classificati entrambi come sovrapposti continuo + if ( abs( m_vTria[nTA].nTempShell) == 2 && abs( SurfB.m_vTria[vNearTria[nTB]].nTempShell) == 2) + continue ; + + // Se i triangoli sono sovrapposti TRIA3DVECTOR vTriaAB ; Point3d ptTempA, ptTempB ; int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ; @@ -1475,7 +1434,7 @@ SurfTriMesh::Add( const ISurfTriMesh& Other) // tengo una copia di B ( la superficie B viene modificata durante la ritriangolazione ) SurfTriMesh SurfA_cl ; SurfA_cl.CopyFrom( this) ; - + // ritriangolo le due superfici mediante ogni intersezione Triangolo-Triangolo IntersectTriMeshTriangle( SurfB) ; @@ -1625,12 +1584,12 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other) AddTriangle( nNewVert, m_nMaxTFlag) ; } } - + // sistemazioni varie bool bOk = ( AdjustVertices() && DoCompacting()) ; bool bModified = false ; - bOk = bOk && RemoveDoubleTriangles( bModified) ; - if ( bModified) + bOk = bOk && RemoveDoubleTriangles( bModified) ; + if ( bModified) bOk = bOk && ( AdjustVertices() && DoCompacting()) ; bOk = bOk && RemoveTJunctions( bModified) ; if ( bModified) diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp index 4bbc787..b1f10f1 100644 --- a/SurfTriMeshUtilities.cpp +++ b/SurfTriMeshUtilities.cpp @@ -17,7 +17,6 @@ #include "Triangulate.h" #include "/EgtDev/Include/EGkDistPointLine.h" #include "/EgtDev/Include/EGkDistLineLine.h" -#include using namespace std ; @@ -35,6 +34,7 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified) // recupero i vertici dei triangoli int nIdV[3] ; GetTriangle( nT, nIdV) ; + bool bToRemove = false ; // ciclo sui triangoli adiacenti for ( int nE = 0 ; nE < 3 ; ++ nE) { // recupero triangolo adiacente, se non esiste passo al successivo @@ -53,10 +53,14 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified) } } if ( nCoinc == 3) { - RemoveTriangle( nAdjT) ; + // se i vertici coincidono rimuovo entrambi i triangoli + bToRemove = true ; bModified = true ; + RemoveTriangle( nAdjT) ; } } + if ( bToRemove) + RemoveTriangle( nT) ; } return true ; @@ -86,8 +90,8 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB) // Recupero i vertici del triangolo A Point3d ptSegSt, ptSegEn, ptVertA ; if ( ! GetVertex( m_vTria[nTA].nIdVert[nEdgeA], ptSegSt) || - ! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) || - ! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA)) + ! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) || + ! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA)) return false ; // Recupero il vertice opposto del triangolo B Point3d ptVertB ; @@ -98,17 +102,37 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB) if ( ! DiagDist.IsSmall()) return false ; double dPos1, dPos2 ; - if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2) || - dPos1 < EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() - EPS_SMALL || - dPos2 < EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() - EPS_SMALL) - return false ; + if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2)) + return false ; + if ( dPos1 < - EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() + EPS_SMALL || + dPos2 < - EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() + EPS_SMALL) + return false ; + // Eseguo il flipping m_vTria[nTA].nIdVert[nEdgeA] = m_vTria[nTB].nIdVert[( nEdgeB + 2) % 3] ; m_vTria[nTB].nIdVert[nEdgeB] = m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3] ; m_vTria[nTA].nIdAdjac[nEdgeA] = m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] ; - m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ; m_vTria[nTB].nIdAdjac[nEdgeB] = m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] ; + m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ; m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] = nTA ; + + // sistemo anche le contro-adiacenze + int nTC = m_vTria[nTA].nIdAdjac[nEdgeA] ; + if ( nTC != SVT_NULL) { + for ( int i = 0 ; i < 3 ; i++) + if ( m_vTria[nTC].nIdAdjac[i] == nTB) { + m_vTria[nTC].nIdAdjac[i] = nTA ; + break ; + } + } + int nTD = m_vTria[nTB].nIdAdjac[nEdgeB] ; + if ( nTD != SVT_NULL) { + for ( int i = 0 ; i < 3 ; i++) + if ( m_vTria[nTD].nIdAdjac[i] == nTA) { + m_vTria[nTD].nIdAdjac[i] = nTB ; + break ; + } + } return true ; } @@ -150,6 +174,8 @@ SurfTriMesh::RemoveTJunctions( bool& bModified) if ( dSegLen < EPS_SMALL) continue ; vtSeg /= dSegLen ; + int nV1 = m_vTria[nT].nIdVert[nSeg] ; + int nV2 = m_vTria[nT].nIdVert[Next( nSeg)] ; // Ciclo sui triangoli vicini for ( int nI = 0 ; nI < int( vNearTria.size()) ; ++ nI) { // Salto il triangolo se è quello di riferimento @@ -157,6 +183,9 @@ SurfTriMesh::RemoveTJunctions( bool& bModified) continue ; // Cerco i vertici che stanno sul lato del triangolo for ( int nVert = 0 ; nVert < 3 ; ++ nVert) { + int nCurrVert = m_vTria[vNearTria[nI]].nIdVert[nVert] ; + if ( nCurrVert == nV1 || nCurrVert == nV2) + continue ; Point3d ptVert ; if ( ! GetVertex( m_vTria[vNearTria[nI]].nIdVert[nVert], ptVert)) continue ; @@ -307,16 +336,44 @@ ChooseGoodStartPoint( PNTULIST& PointList) return false ; } -//---------------------------------------------------------------------------- -static bool -AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif) +// ------------------------------------------------------------- +bool +SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const { // Ciclo sui punti del loop auto itLast = PointList.begin() ; for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) { - - // Se dal punto corrente inizia un segmento adiacente a un'altra faccia - if ( itLast->second != it->second) { + + // bisogna fermarsi per analizzare il tratto corrente alla ricerca di punti allineati se dal punto corrente + // inizia un tratto adiacente ad un'altra faccia oppure se il punto corrente non verrà eliminato dal loop + // della faccia adiacente + bool bAnalyze = ( itLast->second != it->second) ; + if ( ! bAnalyze && itLast->second != - 1) { + // recupero i loop della faccia adiacente + POLYLINEVECTOR LoopVec ; + GetFacetLoops( int( itLast->second), LoopVec) ; + bool bFound = false ; + for ( int i = 0 ; i < int( LoopVec.size()) && ! bFound ; i ++) { + const PNTULIST& PointListAdj = LoopVec[i].GetUPointList() ; + for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) && ! bFound ; ++ itAdj) { + // cerco il punto corrente sul loop della faccia adiacente + if ( itAdj->second == nF && AreSamePointApprox( it->first, itAdj->first)) { + bFound = true ; + auto itPrev = ( itAdj == PointListAdj.begin() ? prev( prev( PointListAdj.end())) : prev( itAdj)) ; + auto itNext = next( itAdj) ; + DistPointLine PointLineDistCalc( itAdj->first, itPrev->first, itNext->first) ; + double dDist ; + if ( PointLineDistCalc.GetDist( dDist) && dDist > 50 * EPS_SMALL) + // se il punto non è allineato al precedente e al successivo non verrà rimosso dal loop della faccia adiacente, + // quindi non deve essere rimosso dal loop corrente altrimenti si genererebbe una T-Junction. Quindi posso + // interrompere e analizzare il tratto trovato fino ad ora + bAnalyze = true ; + } + } + } + } + + if ( bAnalyze) { // Raccolgo i punti in una polyline PolyLine PL ; int nPar = -1 ; @@ -433,8 +490,8 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) // Ciclo sulle facce della mesh per trovare quelle da ritriangolare unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ; for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) { - - // Recupero i loop della faccia (il parametro indica la faccia adiacente) + + // Recupero i loop della faccia ( il parametro indica la faccia adiacente) POLYLINEVECTOR LoopVec ; GetFacetLoops( nF, LoopVec) ; @@ -451,7 +508,7 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) // Sistemo il loop bool bModif = false ; - if ( ! AdjustLoop( PointList, dMaxEdgeLen, bModif)) + if ( ! AdjustLoop( PointList, dMaxEdgeLen, nF, bModif)) return false ; if ( bModif) bToRetriangulate = true ; @@ -483,8 +540,8 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) FacetMap.emplace( nF, make_pair( vPt, vTr)) ; } // Se non riesco a triangolare anche solo questa faccia, interrompo tutto - else - return false ; + else + return false ; } } @@ -502,17 +559,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) // Cancello i triangoli for ( int nT : vDelTria) RemoveTriangle( nT) ; - + // Applico le nuove triangolazioni delle facce for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) { const PNTVECTOR& vPt = itF->second.first ; const INTVECTOR& vTr = itF->second.second ; - // Inserisco i nuovi triangoli + // Inserisco i nuovi triangoli bool bFirstTria = true ; for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { int nNewId[3] = { AddVertex( vPt[vTr[n]]), - AddVertex( vPt[vTr[n + 1]]), - AddVertex( vPt[vTr[n + 2]])} ; + AddVertex( vPt[vTr[n + 1]]), + AddVertex( vPt[vTr[n + 2]])} ; auto itCol = ColorMap.find( itF->first) ; int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ; int nNewTriaId = AddTriangle( nNewId, nTFlag) ; @@ -525,7 +582,7 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) } } } - + // dichiaro necessità ricalcolo della grafica e di hashgrids3d m_OGrMgr.Reset() ; ResetHashGrids3d() ; @@ -722,3 +779,113 @@ SurfTriMesh::SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECT return true ; } + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const +{ + // recupero il lato più lungo del triangolo + double dLen0 = SqDist( m_vVert[m_vTria[nT].nIdVert[0]].ptP, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + double dLen1 = SqDist( m_vVert[m_vTria[nT].nIdVert[1]].ptP, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + double dLen2 = SqDist( m_vVert[m_vTria[nT].nIdVert[2]].ptP, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + nEdge = -1 ; + if ( dLen0 > dLen1 && dLen0 > dLen2) + nEdge = 0 ; + else if ( dLen1 > dLen2) + nEdge = 1 ; + else + nEdge = 2 ; + + // recupero il triangolo adiacente sul lato più lungo + nAdjTrg = m_vTria[nT].nIdAdjac[nEdge] ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::RemoveInvalidTriangles( const INTVECTOR& vIds) +{ + // al momento gestito solo per trimesh con adiacenze definite, eventualmente da estendere. + // Analoga a RemoveFistInvalidTrg in Triangulate.cpp + // TO DO da capire e gestire casi in cui flip lascia triangoli invalidi + + unordered_map InvalidMap ; + for ( auto nId : vIds) + InvalidMap[nId] = true ; + + for ( int i = 0 ; i < int( vIds.size()) ; i++) { + + int nTA = vIds[i] ; + if ( ! InvalidMap[nTA]) + continue ; + + // recupero il triangolo adiacente sul suo lato più lungo + int nTB, nEdgeA ; + FindAdjacentOnLongerEdge( nTA, nEdgeA, nTB) ; + + // se adiacente è nullo posso rimuovere tranquillamente il triangolo senza creare TJunctions + if ( nTB == SVT_NULL) { + RemoveTriangle( nTA) ; + continue ; + } + // se adiacente è valido posso fare il flip per rendere valido nTA + else if ( ! InvalidMap[nTB]) { + FlipTriangles( nTA, nTB) ; + InvalidMap[nTA] = false ; + } + // se adiacente è invalido creo una catena da risolvere non appena si trova un triangolo valido + else { + INTVECTOR vChain = {nTA} ; + INTVECTOR vChainEdges = {nEdgeA} ; + int nTCurr = nTB ; + + while ( nTCurr != SVT_NULL && InvalidMap[nTCurr]) { + + // calcolo il successivo + int nTOther, nEdgeCurr ; + FindAdjacentOnLongerEdge( nTCurr, nEdgeCurr, nTOther) ; + + if ( nTOther == vChain.back()) { + // se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi) + // flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua + FlipTriangles( nTCurr, nTOther) ; + if ( vChain.size() > 1) { + vChain.pop_back() ; + vChainEdges.pop_back() ; + // individuo il nuovo adiacente all'ultimo triangolo della catena dopo aver fatto flip + nTOther = m_vTria[vChain.back()].nIdAdjac[vChainEdges.back()] ; + } + } + else { + vChain.emplace_back( nTCurr) ; + vChainEdges.emplace_back( nEdgeCurr) ; + } + // aggiorno per iterazione successiva + nTCurr = nTOther ; + } + + // se la catena termina su triangolo nullo, posso rimuovere tutti i triangoli della catena + if ( nTCurr == SVT_NULL) { + for ( int k = 0 ; k < int( vChain.size()) ; k++) { + RemoveTriangle( vChain[k]) ; + InvalidMap[vChain[k]] = false ; + } + } + // se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido trovato + else { + FlipTriangles( vChain.back(), nTCurr) ; + InvalidMap[vChain.back()] = false ; + for ( int i = int( vChain.size()) - 2 ; i >= 0 ; i--) { + int nTA = vChain[i] ; + if ( ! InvalidMap[nTA]) + continue ; + // eseguo il flip con il triangolo adiacente sul suo lato più lungo + int nTOther = m_vTria[nTA].nIdAdjac[vChainEdges[i]] ; + FlipTriangles( nTA, nTOther) ; + InvalidMap[nTA] = false ; + } + } + } + } + return true ; +} diff --git a/Triangulate.cpp b/Triangulate.cpp index 8545f2c..e942a08 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -1385,6 +1385,7 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr) // I triangoli cap se eliminati danno origine a T-junctions, quindi devono essere gestiti opportunamente con dei flip. // I triangoli needle se eliminati non sono problematici, ma i loro vertici coincidenti vanno gestiti opportunamente nel // calcolo delle adiacenze dei triangoli cap. + // TO DO da capire e gestire casi in cui flip lascia triangoli invalidi int nTria = int( vTr.size()) / 3 ; INTVECTOR vCapTria ; @@ -1482,46 +1483,40 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr) INTVECTOR vChain, vChainEdges ; vChain.emplace_back( nTA) ; vChainEdges.emplace_back( nEA) ; - - while ( nTB != -1 && ! vbIsValidTria[nTB]) { - // aggiungo alla catena - vChain.emplace_back( nTB) ; + int nTCurr = nTB ; + int nEOther ; + while ( nTCurr != -1 && ! vbIsValidTria[nTCurr]) { // calcolo il successivo - nTA = nTB ; - FindAdjacentOnLongerEdge( vPt, vTr, nTA, nEA, nTB, nEB) ; - vChainEdges.emplace_back( nEA) ; + int nTOther, nECurr ; + FindAdjacentOnLongerEdge( vPt, vTr, nTCurr, nECurr, nTOther, nEOther) ; - // verifico di non aver trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi) - // e quindi di non essere entrato in un loop - if ( nTB == vChain[vChain.size()-2]) { + if ( nTOther == vChain.back()) { + // se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi) // flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua - FlipTrg( vTr, nTA, nTB, nEA, nEB) ; - // aggiorno per iterazione successiva - if ( vChain.size() == 2) { + FlipTrg( vTr, nTCurr, nTOther, nECurr, nEOther) ; + if ( vChain.size() > 1) { vChain.pop_back() ; vChainEdges.pop_back() ; - FindAdjacentOnLongerEdge( vPt, vTr, vChain.back(), nEA, nTB, nEB) ; - vChainEdges[0] = nEA ; + // individuo il nuovo adiacente all'ultimo triangolo della catena tra i due appena flippati + TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTCurr, nTOther, nTB, nEB) ; + nTOther = nTB ; } - else { - // elimino gli ultimi due triangoli che sono appena stati flippati e ricalcolo adiacenza del triangolo - // precedente - vChain.pop_back() ; - vChain.pop_back() ; - vChainEdges.pop_back() ; - vChainEdges.pop_back() ; - int nTTest1 = nTA ; - int nTTest2 = nTB ; - TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTTest1, nTTest2, nTB, nEB) ; - } } + else { + vChain.emplace_back( nTCurr) ; + vChainEdges.emplace_back( nECurr) ; + } + // aggiorno per iterazione successiva + nTCurr = nTOther ; } // se la catena termina su triangolo nullo, annullo tutti i triangoli della catena - if ( nTB == -1) { + if ( nTCurr == -1) { bRemovedTrg = true ; for ( int k = 0 ; k < int( vChain.size()) ; k++) { + if ( vbIsValidTria[vChain[k]]) + continue ; vTr[3*vChain[k]] = -1 ; vTr[3*vChain[k] + 1] = -1 ; vTr[3*vChain[k] + 2] = -1 ; @@ -1530,14 +1525,16 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr) } // se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido else { - FlipTrg( vTr, vChain.back(), nTB, vChainEdges.back(), nEB) ; + FlipTrg( vTr, vChain.back(), nTCurr, vChainEdges.back(), nEOther) ; vbIsValidTria[vChain.back()] = true ; int nTrgTest1 = vChain.back() ; - int nTrgTest2 = nTB ; - for ( int i = int( vChain.size()-2) ; i >= 0 ; i--) { + int nTrgTest2 = nTCurr ; + for ( int j = int( vChain.size()-2) ; j >= 0 ; j--) { // triangolo corrente - int nTA = vChain[i] ; - int nEA = vChainEdges[i] ; + int nTA = vChain[j] ; + if ( vbIsValidTria[nTA]) + continue ; + int nEA = vChainEdges[j] ; // devo trovare il nuovo adiacente dopo il flip dei successivi nella catena TestAdjacentOnEdge( vTr, nTA, nEA, nTrgTest1, nTrgTest2, nTB, nEB) ; // flip per rendere valido il triangolo corrente @@ -1608,7 +1605,7 @@ MakeByFist( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr) vPt.reserve( fist.c_vertex.num_vertices) ; for ( int i = 0 ; i < fist.c_vertex.num_vertices ; i ++) vPt.emplace_back( fist.c_vertex.vertices[i].x, fist.c_vertex.vertices[i].y, fist.c_vertex.vertices[i].z) ; - + // recupero i triangoli da fist vTr.reserve( 3 * fist.c_vertex.num_triangles) ; for ( int i = 0 ; i < fist.c_vertex.num_triangles ; i ++) { From 626d5b0e51839670182ddc91e4981726f12aa48d Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 16 Jun 2025 11:34:23 +0200 Subject: [PATCH 24/24] EgtGeomKernel 2.7f2 : - Aggiunte funzioni per calcolo di Offset per superfici chiuse TriMesh - Piccola miglioria alla triangolazione (con SaraP) - Migliorie per rimozioni TJunction, calcolo delle normali dei triangoli e creazione di una TriMesh a partire da uno ZMap (con SaraP) - Aggiunte funzioni di SubtractMap e piccole modifiche per estensione dei Box di creazione per gli Zmap. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes EgtGeomKernel.vcxproj | 2 + EgtGeomKernel.vcxproj.filters | 6 + SurfTriMesh.cpp | 99 ++++++++++- SurfTriMesh.h | 15 +- SurfTriMeshOffset.cpp | 75 +++++++++ SurfTriMeshUtilities.cpp | 68 ++++---- Triangulate.cpp | 24 ++- Triangulate.h | 1 + VolZmap.cpp | 118 +++++++++++-- VolZmap.h | 19 ++- VolZmapCreation.cpp | 133 ++++++++++++--- VolZmapGraphics.cpp | 32 +++- VolZmapOffset.cpp | 300 ++++++++++++++++++++++++++++++++++ 14 files changed, 811 insertions(+), 81 deletions(-) create mode 100644 SurfTriMeshOffset.cpp create mode 100644 VolZmapOffset.cpp diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index cdc95ef3f0ae957f1f1ade7344b446ee3b842263..bfc65202e856703942494e91624054296ebcd77c 100644 GIT binary patch delta 81 zcmdlNy)SyhH#SD2&FAG5nSs + + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index a313b23..6120010 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -546,6 +546,12 @@ File di origine\GeoDist + + File di origine\Geo + + + File di origine\Geo + diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index d7ff791..0461250 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -237,6 +237,10 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag) // inserisco il triangolo try { m_vTria.emplace_back( nIdVert, nTFlag) ;} catch(...) { return SVT_NULL ;} + // aggiorno la sua normale + if ( ! vtN.Normalize( EPS_ZERO)) + return false ; + m_vTria.back().vtN = vtN ; // aggiorno massimo TFlag m_nMaxTFlag = max( m_nMaxTFlag, nTFlag) ; // ne determino l'indice @@ -1688,11 +1692,13 @@ SurfTriMesh::AdjustVertices( void) //---------------------------------------------------------------------------- bool -SurfTriMesh::AdjustAdjacencies( void) +SurfTriMesh::AdjustAdjacencies( bool AdjustVert) { // sistemo le relazioni tra triangoli e vertici - if ( ! AdjustVertices()) - return false ; + if ( AdjustVert) { + if ( ! AdjustVertices()) + return false ; + } // matrice di incidenza vertici-triangoli INTMATRIX mVertTria( GetVertexSize()) ; for ( int i = 0 ; i < GetTriangleSize() ; ++ i) { @@ -1875,7 +1881,7 @@ SurfTriMesh::TestSealing( void) m_vTria[i].nIdAdjac[1] == SVT_NULL || m_vTria[i].nIdAdjac[2] == SVT_NULL) { bClosed = false ; - break ; + break ; } } } @@ -1937,7 +1943,7 @@ SurfTriMesh::PackVertices( void) ++ nFirstFree ; } else - vVId.push_back( nId) ; + vVId.push_back( nId) ; } else { if ( nFirstFree == SVT_NULL) @@ -4361,3 +4367,86 @@ SurfTriMesh::SetTempInt( int nId, int nTempInt) const m_vTria[nId].nTemp = nTempInt ; return true ; } + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol) +{ + // scorro i triangoli + for ( const Triangle3dEx& Tria : vTria) { + // ciclo sui tre vertici + int nIdV[3]{} ; + for ( int nV = 0 ; nV < 3 ; ++ nV) { + // verifico se vertice già presente + int nId ; + if ( ! VertGrid.Find( Tria.GetP( nV), dVertexTol, nId)) { + // se non presente, lo aggiugo + nIdV[nV] = AddVertex( Tria.GetP( nV)) ; + if ( nIdV[nV] == SVT_NULL) + return false ; + VertGrid.InsertPoint( Tria.GetP( nV), nIdV[nV]) ; + } + else + nIdV[nV] = nId ; + } + // se i vertici sono tutti diversi tra loro, inserisco il triangolo + if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) { + int nT = AddTriangle( nIdV, Tria.GetGrade()) ; + if ( nT != SVT_NULL && nT != SVT_DEL) { + // associo relazione vertice-triangolo + for ( int i = 0 ; i < 3 ; ++ i) + m_vVert[nIdV[i]].nIdTria = nT ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::AdjustTopologyFromZMap( void) +{ + // cancello tutti i vertici che puntano a triangoli cancellati + bool bPack = false ; + for ( int i = 0 ; i < GetVertexSize() ; ++ i) { + if ( m_vVert[i].nIdTria == SVT_NULL) { + m_vVert[i].nIdTria = SVT_DEL ; + bPack = true ; + } + } + if ( bPack) + PackVertices() ; + m_nStatus = SurfTriMesh::OK ; + + // calcolo le adiacenze + if ( ! AdjustAdjacencies()) + return false ; + + // verifico l'orientamento ( TODO -- Da migliorare...) + // Ora per funzionare è necessario che il ciclo sui triangoli parta da un triangolo orientato + // correttamente e che i triangoli invertiti siano "circondati" da triangoli tutti orientati correttamente + if ( ! AdjustOrientations()) + return false ; + + // calcolo le facce + if ( ! VerifyFaceting()) + return false ; + + // rimozione delle TJunction + bool bModified = false ; + if ( ! RemoveTJunctions( bModified, SQ_EPS_SMALL)) + return false ; + if ( bModified) { + if ( ! AdjustVertices() || ! DoCompacting()) + return false ; + } + else + TestSealing() ; + + // semplifico le facce ( anche più piccola) + if ( ! SimplifyFacets( MAX_EDGE_LEN_STD, false, 5. * EPS_SMALL)) + LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::AdjustTopologyFromZMap") + + return true ; +} diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 90bf43d..36cc13a 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -18,6 +18,7 @@ #include "GeoObjRW.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkHashGrids3d.h" +#include "/EgtDev/Include/EGkPointGrid3d.h" #include #include @@ -327,7 +328,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool Intersect( const ISurfTriMesh& Other) override ; bool Subtract( const ISurfTriMesh& Other) override ; bool GetSurfClassification( const ISurfTriMesh& ClassifierSurf, - INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ; + INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ; bool CutWithOtherSurf( const ISurfTriMesh& CutterSurf, bool bInVsOut, bool bSaveOnEq) override ; bool Repair( double dMaxEdgeLen = MAX_EDGE_LEN_STD) override ; bool GetAllTriaOverlapBox( const BBox3d& b3Box, INTVECTOR& vT) const override ; @@ -373,6 +374,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool GetTempInt( int nId, int& nTempInt) const ; bool ResetTempInts( void) const ; bool SetTempInt( int nId, int nTempInt) const ; + bool AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol = 2 * EPS_SMALL) ; + bool AdjustTopologyFromZMap( void) ; private : typedef std::vector VERTVECTOR ; @@ -388,7 +391,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool CopyFrom( const SurfTriMesh& clSrc) ; bool Validate( bool bCorrect = false) ; bool AdjustVertices( void) ; - bool AdjustAdjacencies( void) ; + bool AdjustAdjacencies( bool AdjustVert = true) ; bool AdjustOrientations( void) ; bool AdjustTriaOrientation( TRINTDEQUE& S3iQ) ; bool TestSealing( void) ; @@ -433,18 +436,16 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool IntersectTriMeshTriangle( SurfTriMesh& Other) ; bool IdentifyShells( void) const ; bool RemoveDoubleTriangles( bool& bModified) ; - bool RemoveTJunctions( bool& bModified) ; + bool RemoveTJunctions( bool& bModified, double dMinSqDist = SQ_EPS_TRIA_H) ; bool FlipTriangles( int nTA, int nTB) ; - bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true) ; + bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true, double dTolAlign = 50 * EPS_SMALL) ; bool AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) ; bool DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) ; bool ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) ; bool SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) ; - bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const ; + bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const ; bool RemoveInvalidTriangles( const INTVECTOR& vIds) ; bool FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const ; - - private : ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto Status m_nStatus ; // stato diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp new file mode 100644 index 0000000..666e863 --- /dev/null +++ b/SurfTriMeshOffset.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2022 +//---------------------------------------------------------------------------- +// File : SurfTriMeshOffset.cpp Data : 10.06.25 Versione : 2.7e4 +// Contenuto : Implementazione funzione per Offset di Superfici TriMesh. +// +// +// +// Modifiche : 10.06.25 RE Creazione modulo. +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "SurfTriMesh.h" +#include "VolZmap.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +static ISurfTriMesh* +SumStm( const CISURFTMPVECTOR& vStm) +{ + // se vettore vuoto, non faccio nulla + if ( vStm.empty()) + return nullptr ; + // definisco la superficie somma tra tutte ( la prima deve essere valida) + PtrOwner pStmAdd( CreateSurfTriMesh()) ; + if ( IsNull( pStmAdd)) + return nullptr ; + // scorro le superfici + for ( const ISurfTriMesh* pStm : vStm) { + if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0) + continue ; + if ( ! pStmAdd->IsValid() || pStmAdd->GetTriangleCount() == 0) { + if ( ! pStmAdd->CopyFrom( pStm)) + return nullptr ; + } + else + pStmAdd->Add( *pStm) ; + } + // restituisco la superficie ottenuta + return ( Release( pStmAdd)) ; +} + +//---------------------------------------------------------------------------- +/* Funzione che crea l'Offset di una superficie TriMesh chiusa */ +ISurfTriMesh* +CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol) +{ + return CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol) ; +} + +//---------------------------------------------------------------------------- +/* Funzione che crea l'Offset di un insieme di superfici */ +ISurfTriMesh* +CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol) +{ + // se vettore delle superfici vuoto, non faccio nulla + if ( vStm.empty()) + return nullptr ; + // controllo sul valore di tolleranza lineare + double dMyLinTol = max( dLinTol, 10 * EPS_SMALL) ; + // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto) + // Nel caso sia minore, restituisco semplicemente la somma delle superfici + // ( questo valore serve per rimanere coerente con l'Offset delle curve) + if ( abs( dOffs) < 10 * EPS_SMALL) + return SumStm( vStm) ; + // --- NB. Per la creazione dello Zmap è necessario che le superfici siano chiuse + PtrOwner pVolZmap( CreateVolZmap()) ; + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol)) + return nullptr ; + // restituisco la superficie TriMesh + return ( pVolZmap->GetSurfTriMesh()) ; +} \ No newline at end of file diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp index b1f10f1..7174040 100644 --- a/SurfTriMeshUtilities.cpp +++ b/SurfTriMeshUtilities.cpp @@ -138,7 +138,7 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB) //---------------------------------------------------------------------------- bool -SurfTriMesh::RemoveTJunctions( bool& bModified) +SurfTriMesh::RemoveTJunctions( bool& bModified, double dMinSqDist) { bModified = false ; @@ -147,6 +147,11 @@ SurfTriMesh::RemoveTJunctions( bool& bModified) // Ciclo sui triangoli della superficie per determinare gli altri vertici sul loro perimetro for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) { + // se adiacenze tutte valide, passo al successivo + if ( m_vTria[nT].nIdAdjac[0] != SVT_DEL && m_vTria[nT].nIdAdjac[0] != SVT_NULL && + m_vTria[nT].nIdAdjac[1] != SVT_DEL && m_vTria[nT].nIdAdjac[1] != SVT_NULL && + m_vTria[nT].nIdAdjac[2] != SVT_DEL && m_vTria[nT].nIdAdjac[2] != SVT_NULL) + continue ; // Se il triangolo non è valido, passo al successivo Triangle3d trTria ; if ( ! GetTriangle( nT, trTria) || ! trTria.Validate( true)) @@ -190,9 +195,9 @@ SurfTriMesh::RemoveTJunctions( bool& bModified) if ( ! GetVertex( m_vTria[vNearTria[nI]].nIdVert[nVert], ptVert)) continue ; double dProj = ( ptVert - ptSegSt) * vtSeg ; - double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ; - if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < SQ_EPS_TRIA_H) - vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ; + double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ; + if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < dMinSqDist) + vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ; } } // Riordino i vertici sul segmento @@ -338,8 +343,10 @@ ChooseGoodStartPoint( PNTULIST& PointList) // ------------------------------------------------------------- bool -SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const +SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const { + // vettore dei loop della faccia adiacente + POLYLINEVECTOR LoopVec ; // Ciclo sui punti del loop auto itLast = PointList.begin() ; for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) { @@ -347,30 +354,26 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& // bisogna fermarsi per analizzare il tratto corrente alla ricerca di punti allineati se dal punto corrente // inizia un tratto adiacente ad un'altra faccia oppure se il punto corrente non verrà eliminato dal loop // della faccia adiacente + bool bAnalyze = ( itLast->second != it->second) ; + if ( bAnalyze) + LoopVec.clear() ; if ( ! bAnalyze && itLast->second != - 1) { - // recupero i loop della faccia adiacente - POLYLINEVECTOR LoopVec ; - GetFacetLoops( int( itLast->second), LoopVec) ; - bool bFound = false ; - for ( int i = 0 ; i < int( LoopVec.size()) && ! bFound ; i ++) { + if ( LoopVec.empty()) + GetFacetLoops( int( itLast->second), LoopVec) ; + for ( int i = 0 ; i < int( LoopVec.size()) && ! bAnalyze ; i ++) { const PNTULIST& PointListAdj = LoopVec[i].GetUPointList() ; - for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) && ! bFound ; ++ itAdj) { + int nSamePoints = 0 ; + for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) ; ++ itAdj) { // cerco il punto corrente sul loop della faccia adiacente - if ( itAdj->second == nF && AreSamePointApprox( it->first, itAdj->first)) { - bFound = true ; - auto itPrev = ( itAdj == PointListAdj.begin() ? prev( prev( PointListAdj.end())) : prev( itAdj)) ; - auto itNext = next( itAdj) ; - DistPointLine PointLineDistCalc( itAdj->first, itPrev->first, itNext->first) ; - double dDist ; - if ( PointLineDistCalc.GetDist( dDist) && dDist > 50 * EPS_SMALL) - // se il punto non è allineato al precedente e al successivo non verrà rimosso dal loop della faccia adiacente, - // quindi non deve essere rimosso dal loop corrente altrimenti si genererebbe una T-Junction. Quindi posso - // interrompere e analizzare il tratto trovato fino ad ora - bAnalyze = true ; + if ( AreSamePointApprox( it->first, itAdj->first)) + ++ nSamePoints ; + if ( ( nSamePoints == 1 && int( PointListAdj.size()) <= 4) || nSamePoints > 1) { + bAnalyze = true ; + break ; } - } - } + } + } } if ( bAnalyze) { @@ -383,7 +386,7 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& } PL.AddUPoint( ++nPar, it->first) ; // Provo ad eliminare i punti allineati - PL.RemoveAlignedPoints( 50 * EPS_SMALL) ; + PL.RemoveAlignedPoints( dTolAlign) ; if ( PL.GetPointNbr() < nPar + 1) { // rimuovo dalla lista dei punti gli eliminati (salto gli estremi) int nUCurr = 1 ; @@ -475,7 +478,7 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& //---------------------------------------------------------------------------- bool -SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) +SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced, double dTolAlign) { // La trimesh deve essere valida if ( ! IsValid()) @@ -502,13 +505,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) // Lista dei punti del loop PNTULIST& PointList = LoopVec[nL].GetUPointList() ; + // Se il loop è un triangolo, non va modificato + if ( int( PointList.size()) <= 4) + continue ; + // Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento if ( ! ChooseGoodStartPoint( PointList)) continue ; // Sistemo il loop bool bModif = false ; - if ( ! AdjustLoop( PointList, dMaxEdgeLen, nF, bModif)) + if ( ! AdjustLoop( PointList, dMaxEdgeLen, dTolAlign, bModif)) return false ; if ( bModif) bToRetriangulate = true ; @@ -536,12 +543,11 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced) // Eseguo la ritriangolazione della faccia PNTVECTOR vPt ; INTVECTOR vTr ; - if ( Triangulate().Make( LoopVec, vPt, vTr)) { + if ( Triangulate().Make( LoopVec, vPt, vTr) && ! vTr.empty()) FacetMap.emplace( nF, make_pair( vPt, vTr)) ; - } // Se non riesco a triangolare anche solo questa faccia, interrompo tutto - else - return false ; + else + return false ; } } diff --git a/Triangulate.cpp b/Triangulate.cpp index e942a08..4be97fb 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -818,7 +818,7 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol, } } // If vertex k is inside the ear triangle, then this is not an ear - else if ( TestPointInTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) { + else if ( TestPointInOrOnTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) { bIsEar = false ; break ; } @@ -978,6 +978,28 @@ Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const return true ; } +//---------------------------------------------------------------------------- +// test if point p is inside or on the border of triangle (a, b, c) +bool +Triangulate::TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) +{ + // If P is on a vertex is considered inside + if ( AreSamePoint( ptP, ptA)) + return true ; + if ( AreSamePoint( ptP, ptB)) + return true ; + if ( AreSamePoint( ptP, ptC)) + return true ; + // If P is on the right of at least one edge is outside + if ( TriangleIsCCW( ptA, ptP, ptB, EPS_SMALL)) + return false ; + if ( TriangleIsCCW( ptB, ptP, ptC, EPS_SMALL)) + return false ; + if ( TriangleIsCCW( ptC, ptP, ptA, EPS_SMALL)) + return false ; + return true ; +} + //---------------------------------------------------------------------------- bool Triangulate::SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd) diff --git a/Triangulate.h b/Triangulate.h index 7145157..b0d9d91 100644 --- a/Triangulate.h +++ b/Triangulate.h @@ -45,6 +45,7 @@ class Triangulate bool TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler = 0.1 * EPS_SMALL) ; bool TestIntersection( const Point3d& ptA1, const Point3d& ptA2, const Point3d& ptB1, const Point3d& ptB2) ; bool TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ; + bool TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ; bool SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd) ; bool GetPntVectorFromPolyline( const PolyLine& PL, bool bXmaxStart, PNTVECTOR& vPi) ; bool GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& nI) ; diff --git a/VolZmap.cpp b/VolZmap.cpp index bdb0987..35a6ecd 100644 --- a/VolZmap.cpp +++ b/VolZmap.cpp @@ -1520,14 +1520,14 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm) // ciclo sulle griglie bool bCompleted = true ; - for ( int g = 0 ; g < m_nMapNum ; ++ g) { + for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // definisco dei sistemi di riferimento ausiliari Frame3d frMapFrame ; - if ( g == 0) + if ( nG == 0) frMapFrame = m_MapFrame ; - else if ( g == 1) + else if ( nG == 1) frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ; - else if ( g == 2) + else if ( nG == 2) frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ; // oggetto per calcolo massivo intersezioni @@ -1538,33 +1538,121 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm) vector> vRes ; vRes.resize( nThreadMax) ; // se dimensione griglia in X maggiore di dimensione Y - if ( m_nNx[g] > m_nNy[g]) { - int nDexNum = m_nNx[g] / nThreadMax ; - int nRemainder = m_nNx[g] % nThreadMax ; + if ( m_nNx[nG] > m_nNy[nG]) { + int nDexNum = m_nNx[nG] / nThreadMax ; + int nRemainder = m_nNx[nG] % nThreadMax ; int nInfI = 0 ; int nSupI = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; - vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g, - nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( m_MapFrame.Orig()), - ref( *pStm), ref( intPLSTM)) ; + vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG, + nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; } } // se dimensione griglia in Y maggiore di dimensione X else { - int nDexNum = m_nNy[g] / nThreadMax ; - int nRemainder = m_nNy[g] % nThreadMax ; + int nDexNum = m_nNy[nG] / nThreadMax ; + int nRemainder = m_nNy[nG] % nThreadMax ; int nInfJ = 0 ; int nSupJ = 0 ; // aggiungo le parti interessate alla mappa for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; - vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g, - 0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), - ref( *pStm), ref( intPLSTM)) ; + vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG, + 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; + } + } + + // ciclo per attendere che tutti gli async abbiano terminato. + int nTerminated = 0 ; + while ( nTerminated < nThreadMax) { + for ( int nL = 0 ; nL < nThreadMax ; ++ nL) { + // async terminato + if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) { + ++ nTerminated ; + bCompleted = bCompleted && vRes[nL].get() ; + } + } + } + + if ( ! bCompleted) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +VolZmap::SubtractSurfTm( const ISurfTriMesh* pStm) +{ + // controllo sulla superficie + double dVol ; + if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() || + ! pStm->GetVolume( dVol) || dVol < 0) + return false ; + + // controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente + BBox3d BBox_stm, BBox_curr ; + if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr)) + return false ; + BBox3d BBox_inters ; + if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty()) + return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap + Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone + + // ciclo sulle griglie + bool bCompleted = true ; + for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { + // definisco dei sistemi di riferimento ausiliari + Frame3d frMapFrame ; + if ( nG == 0) + frMapFrame = m_MapFrame ; + else if ( nG == 1) + frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ; + else if ( nG == 2) + frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ; + + // oggetto per calcolo massivo intersezioni + IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ; + + // numero massimo di thread + int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; + vector> vRes ; + vRes.resize( nThreadMax) ; + // se dimensione griglia in X maggiore di dimensione Y + if ( m_nNx[nG] > m_nNy[nG]) { + int nDexNum = m_nNx[nG] / nThreadMax ; + int nRemainder = m_nNx[nG] % nThreadMax ; + int nInfI = 0 ; + int nSupI = 0 ; + // aggiungo le parti interessate alla mappa + for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { + nInfI = nSupI ; + nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; + vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG, + nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; + } + } + // se dimensione griglia in Y maggiore di dimensione X + else { + int nDexNum = m_nNy[nG] / nThreadMax ; + int nRemainder = m_nNy[nG] % nThreadMax ; + int nInfJ = 0 ; + int nSupJ = 0 ; + // aggiungo le parti interessate alla mappa + for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { + nInfJ = nSupJ ; + nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; + vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG, + 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; } } diff --git a/VolZmap.h b/VolZmap.h index c7fcb86..e81bd23 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -18,6 +18,7 @@ #include "Tool.h" #include "/EgtDev/Include/EGkVolZmap.h" #include "/EgtDev/Include/EGkIntersLineVolZmap.h" +#include "/EgtDev/Include/EGkSurfTriMesh.h" #include #include #include @@ -80,10 +81,12 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ; bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ; bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex) override ; - bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex) override ; + bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 100 * EPS_SMALL) override ; + bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ; + ISurfTriMesh* GetSurfTriMesh( void) const override ; bool GetEdges( ICURVEPOVECTOR& vpCurve) const override ; bool GetVolume( double& dVol) const override ; bool IsTriDexel( void) const override @@ -144,6 +147,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW bool RemovePart( int nPart) override ; int GetPartMinDistFromPoint( const Point3d& ptP) const override ; bool AddSurfTm( const ISurfTriMesh* pStm) override ; + bool SubtractSurfTm( const ISurfTriMesh* pStm) override ; bool MakeUniform( double dToler) override ; public : // IGeoObjRW @@ -432,10 +436,21 @@ class VolZmap : public IVolZmap, public IGeoObjRW const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; + bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; + // Funzioni per Offset di superfici + bool CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) ; + bool CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid) ; + bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ, + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap = false) ; + bool AddIntervalsForOffset( int nGrid, int nI, int nJ, + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap = false) ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ; - enum Shape { GENERIC = 0, BOX = 1, EXTRUSION = 2} ; + enum Shape { GENERIC = 0, BOX = 1, EXTRUSION = 2, OFFSET = 3} ; static const int N_MAPS = 3 ; static const int N_VOXBLOCK = 32 ; diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index 4fefdee..fef6eae 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -17,6 +17,7 @@ #include "CurveLine.h" #include "VolZmap.h" #include "GeoConst.h" +#include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EgtNumUtils.h" #include @@ -597,6 +598,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co return true ; } +//---------------------------------------------------------------------------- bool VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) @@ -691,7 +693,100 @@ VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const //---------------------------------------------------------------------------- bool -VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex) +VolZmap::SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) +{ + // controllo sui parametri + if ( nMap < 0 || nMap > 2 || + nInfI < 0 || nInfI > m_nNx[nMap] || + nSupI < 0 || nSupI > m_nNx[nMap] || + nInfJ < 0 || nInfJ > m_nNy[nMap] || + nSupJ < 0 || nSupJ > m_nNy[nMap]) + return false ; + + // determinazione e ridimensionamento dei dexel interni alla trimesh + for ( int i = nInfI ; i < nSupI ; ++ i) { + for ( int j = nInfJ ; j < nSupJ ; ++ j) { + + // definisco la retta da intersecare con la trimesh + double dX = ( i + 0.5) * m_dStep ; + double dY = ( j + 0.5) * m_dStep ; + Point3d ptP0( dX, dY, 0) ; + + // intersezioni della retta con la TriMesh + ILSIVECTOR IntersectionResults ; + intPLSTM.GetInters( ptP0, vtLen.v[(nMap+2)%3], IntersectionResults) ; + + // rimuovo le intersezioni in eccesso + for ( int nI = 0 ; nI < int( IntersectionResults.size()) - 3 ; ++ nI) { + int nJ = nI + 1 ; // prima successiva + int nK = nJ + 1 ; // seconda successiva + int nT = nK + 1 ; // terza successiva + // determino i segni delle 4 intersezioni tra la linea e il trangolo della TriMesh + int nSgnI = IntersectionResults[nI].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nI].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnJ = IntersectionResults[nJ].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nJ].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnK = IntersectionResults[nK].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nK].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnT = IntersectionResults[nT].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nT].dCosDN > -EPS_SMALL ? 0 : - 1 ; + // parametri dell'intersezione sulla linea + double dUJ = IntersectionResults[nJ].dU ; + double dUK = IntersectionResults[nK].dU ; + // controllo coerenza con segni... + if ( nSgnI != 0 && nSgnI == nSgnJ && + nSgnK != 0 && nSgnK == nSgnT && + nSgnI == - nSgnT && + abs( dUJ - dUK) < EPS_SMALL) { + // ... ed elimino le intersezioni in eccesso... + IntersectionResults.erase( IntersectionResults.begin() + nK) ; + IntersectionResults.erase( IntersectionResults.begin() + nJ) ; + } + } + + int nInt = int( IntersectionResults.size()) ; // numero di intersezioni valide + bool bInside = false ; // Flag entrata/uscita per tratto di retta + Point3d ptIn ; Vector3d vtInN ; + + // per ogni intersezione valida trovata... + for ( int k = 0 ; k < nInt ; ++ k) { + // ricavo il tipo di intersezione + int nIntType = IntersectionResults[k].nILTT ; + // se c'è intersezione + if ( nIntType != ILTT_NO) { + // ricavo il cos tra i vettori ( normale del triangolo e tangente alla retta) + double dCos = IntersectionResults[k].dCosDN ; + + // se entro nella superficie trimesh... + if ( dCos < - EPS_SMALL) { + ptIn = IntersectionResults[k].ptI ; // punto di intersezione + int nT = IntersectionResults[k].nT ; // triangolo di interesse + int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse + Surf.GetFacetNormal( nF, vtInN) ; + bInside = true ; // entrata + } + // ...se esco dalla superficie trimesh ( prima sono per forza entrato) + else if ( dCos > EPS_SMALL && bInside) { + Point3d ptOut = IntersectionResults[k].ptI ; // punto di intersezione + int nT = IntersectionResults[k].nT ; // triangolo di interesse + int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse + Vector3d vtOutN ; Surf.GetFacetNormal( nF, vtOutN) ; // vettore d'uscita + + // Aggiungo un tratto al dexel + SubtractIntervals( nMap, i, j, + ptIn.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3], + ptOut.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3], + - vtInN, - vtOutN, 0, true) ; + bInside = false ; // uscita + } + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox) { // Se la superficie non è chiusa oppure orientata al contrario non ha senso continuare double dVol ; @@ -704,14 +799,14 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // Determino il bounding box della TriMesh BBox3d SurfBBox ; Surf.GetLocalBBox( SurfBBox) ; - - // Determino i punti estremi del bounding box - Point3d ptMapOrig, ptMapEnd ; - SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ; // Il dexel se parte da un triangolo della trimesh può non trovare l'intersezione, // quindi espandiamo il bounding box per ovviare al problema. - SurfBBox.Expand( 100 * EPS_SMALL, 100 * EPS_SMALL, 100 * EPS_SMALL) ; + SurfBBox.Expand( dExtraBox) ; + + // Determino i punti estremi del bounding box + Point3d ptMapOrig, ptMapEnd ; + SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ; // Sistema di riferimento intrinseco dello Zmap m_MapFrame.Set( ptMapOrig, Frame3d::TOP) ; @@ -760,15 +855,15 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // ciclo sulle griglie bool bCompleted = true ; - for ( int g = 0 ; g < m_nMapNum ; ++ g) { + for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) { // Definisco dei sistemi di riferimento ausiliari Frame3d frMapFrame ; - if ( g == 0) + if ( nG == 0) frMapFrame = m_MapFrame ; - else if ( g == 1) + else if ( nG == 1) frMapFrame.Set( ptMapOrig, Y_AX, Z_AX, X_AX) ; - else if ( g == 2) + else if ( nG == 2) frMapFrame.Set( ptMapOrig, Z_AX, X_AX, Y_AX) ; // Oggetto per calcolo massivo intersezioni @@ -778,28 +873,28 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; vector< future> vRes ; vRes.resize( nThreadMax) ; - if ( m_nNx[g] > m_nNy[g]) { - int nDexNum = m_nNx[g] / nThreadMax ; - int nRemainder = m_nNx[g] % nThreadMax ; + if ( m_nNx[nG] > m_nNy[nG]) { + int nDexNum = m_nNx[nG] / nThreadMax ; + int nRemainder = m_nNx[nG] % nThreadMax ; int nInfI = 0 ; int nSupI = 0 ; for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfI = nSupI ; nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; - vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g, - nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ; + vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, + nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ; } } else { - int nDexNum = m_nNy[g] / nThreadMax ; - int nRemainder = m_nNy[g] % nThreadMax ; + int nDexNum = m_nNy[nG] / nThreadMax ; + int nRemainder = m_nNy[nG] % nThreadMax ; int nInfJ = 0 ; int nSupJ = 0 ; for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { nInfJ = nSupJ ; nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; - vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g, - 0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ; + vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG, + 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ; } } diff --git a/VolZmapGraphics.cpp b/VolZmapGraphics.cpp index 01fe8ae..9fff5ef 100644 --- a/VolZmapGraphics.cpp +++ b/VolZmapGraphics.cpp @@ -19,6 +19,7 @@ #include "MC_Tables.h" #include "PolygonPlane.h" #include "IntersLineBox.h" +#include "SurfTriMesh.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkChainCurves.h" @@ -571,6 +572,35 @@ VolZmap::GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const } } +//---------------------------------------------------------------------------- +ISurfTriMesh* +VolZmap::GetSurfTriMesh( void) const +{ + // controllo che lo Zmap sia valido + if ( ! IsValid()) + return nullptr ; + + // inizializzo la superficie + PtrOwner pStm( CreateBasicSurfTriMesh()) ; + if ( IsNull( pStm) || ! pStm->Init( 3, 1)) + return nullptr ; + PointGrid3d VertGrid ; VertGrid.Init( 50000) ; + + // ciclo lungo i blocchi dello Zmap + for ( int nB = 0 ; nB < GetBlockCount() ; ++ nB) { + TRIA3DEXVECTOR vTria ; + GetBlockTriangles( nB, vTria) ; + if ( ! pStm->AddTriaFromZMap( vTria, VertGrid)) + return nullptr ; + } + + // sistemo la topologia + if ( ! pStm->AdjustTopologyFromZMap()) + return nullptr ; + + return ( Release( pStm)) ; +} + //---------------------------------------------------------------------------- int VolZmap::GetBlockCount( void) const @@ -1142,7 +1172,7 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const } // Controllo se il voxel ha una sola faccia che giace in un piano canonico e quindi ha gestione speciale - if ( m_nShape != BOX) { + if ( m_nShape != BOX && m_nShape != OFFSET) { // Faccia XY normale Z+ if ( nIndex == 15) { int nTool ; double dPos ; diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp new file mode 100644 index 0000000..1812b0a --- /dev/null +++ b/VolZmapOffset.cpp @@ -0,0 +1,300 @@ +//---------------------------------------------------------------------------- +// EgalTech 2025-2025 +//---------------------------------------------------------------------------- +// File : OffsetSurfTm.cpp Data : 09.06.25 Versione : 2.7e3 +// Contenuto : Dichiarazione della funzione per calcolare l'offset di superfici TriMesh +// mediante Zmap +// +// +// +// Modifiche : 09.06.25 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#include "stdafx.h" +#include "VolZmap.h" +#include "CurveLine.h" +#include "GeoConst.h" +#include "/EgtDev/Include/EGkStmFromCurves.h" +#include "/EgtDev/Include/EGkIntersLineSurfTm.h" +#include "/EgtDev/Include/EgtNumUtils.h" +#include + +using namespace std ; + + +//---------------------------------------------------------------------------- +/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +bool +VolZmap::SubtractIntervalsForOffset( int nGrid, int nI, int nJ, + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap) +{ + // per ora la funzione è la stessa della differenza in generale + // TODO -- Aggiustare eventuali tolleranze + return SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ; +} + +//---------------------------------------------------------------------------- +/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +bool +VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ, + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap) +{ + // per ora la funzione è la stessa della somma generale + // TODO -- Aggiustare eventuali tolleranze + return AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ; +} + +//---------------------------------------------------------------------------- +/* Funzione per la creazione di una sfera di Offset centrata sul vertice di una TriMesh con cui + aggiungere o sottrarre intervalli lungo i Dexel coinvolti */ +bool +VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) +{ + // determino il Box della sfera posizionata su tale vertice + BBox3d BBoxSphere( ptV - dOffs * Vector3d( 1., 1., 1.), + ptV + dOffs * Vector3d( 1., 1., 1.)) ; + // determino gli intervalli di interesse mediante intersezione con Box della sfera + int nStartI = max( 0, int( BBoxSphere.GetMin().x / m_dStep)) ; + int nEndI = min( m_nNx[nGrid] - 1, int( BBoxSphere.GetMax().x / m_dStep)) ; + int nStartJ = max( 0, int( BBoxSphere.GetMin().y / m_dStep)) ; + int nEndJ = min( m_nNy[nGrid] - 1, int( BBoxSphere.GetMax().y / m_dStep)) ; + // aggiorno gli spilloni interessati + double dSqRad = dOffs * dOffs ; + for ( int i = nStartI ; i <= nEndI ; ++ i) { + for ( int j = nStartJ ; j <= nEndJ ; ++ j) { + double dX = ( i + 0.5) * m_dStep ; + double dY = ( j + 0.5) * m_dStep ; + Point3d ptC( dX, dY, 0.) ; + double dStSqDXY = SqDistXY( ptC, ptV) ; + if ( dStSqDXY < dSqRad) { + double dMin = ptV.z - sqrt( dSqRad - dStSqDXY) ; + Vector3d vtNmin = Point3d( dX, dY, dMin) - ptV ; + vtNmin.Normalize() ; + double dMax = ptV.z + sqrt( dSqRad - dStSqDXY) ; + Vector3d vtNmax = Point3d( dX, dY, dMax) - ptV ; + vtNmax.Normalize() ; + if ( dOffs > 0.) + AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, 0) ; + else + SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, 0) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +/* Funzione per la creazione di un cilindro di Offset sul vertice di una TriMesh con cui + aggiungere o sottrarre intervalli lungo i Dexel coinvolti */ +bool +VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid) +{ + // determino la lunghezza dello spigolo corrente + double dH = Dist( ptP1, ptP2) ; + // asse del cilindro + Vector3d vtV = ptP2 - ptP1 ; vtV.Normalize() ; + // calcolo box del cilindro + BBox3d BBoxCylinder ; + BBoxCylinder.Add( ptP1) ; + BBoxCylinder.Add( ptP2) ; + if ( AreSameOrOppositeVectorApprox( vtV, X_AX)) + BBoxCylinder.Expand( 0., abs( dOffs), abs( dOffs)) ; + else if ( AreSameOrOppositeVectorApprox( vtV, Y_AX)) + BBoxCylinder.Expand( abs( dOffs), 0., abs( dOffs)) ; + else if ( AreSameOrOppositeVectorApprox( vtV, Z_AX)) + BBoxCylinder.Expand( abs( dOffs), abs( dOffs), 0.) ; + else { + double dExpandX = abs( dOffs) * sqrt( 1 - vtV.x * vtV.x) ; + double dExpandY = abs( dOffs) * sqrt( 1 - vtV.y * vtV.y) ; + double dExpandZ = abs( dOffs) * sqrt( 1 - vtV.z * vtV.z) ; + BBoxCylinder.Expand( dExpandX, dExpandY, dExpandZ) ; + } + // determino gli intervalli di interesse mediante intersezione + int nStartI = max( 0, int( BBoxCylinder.GetMin().x / m_dStep)) ; + int nEndI = min( m_nNx[nGrid] - 1, int( BBoxCylinder.GetMax().x / m_dStep)) ; + int nStartJ = max( 0, int( BBoxCylinder.GetMin().y / m_dStep)) ; + int nEndJ = min( m_nNy[nGrid] - 1, int( BBoxCylinder.GetMax().y / m_dStep)) ; + // aggiorno gli spilloni interessati + Frame3d CylFrame ; + if ( ! CylFrame.Set( ptP1, vtV)) + return false ; + for ( int i = nStartI ; i <= nEndI ; ++ i) { + for ( int j = nStartJ ; j <= nEndJ ; ++ j) { + Point3d ptC( ( i + 0.5) * m_dStep, ( j + 0.5) * m_dStep, 0) ; + Point3d ptInt1, ptInt2 ; + Vector3d vtN1, vtN2 ; + if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, abs( dOffs), true, true, + ptInt1, vtN1, ptInt2, vtN2)) { + if ( dOffs > 0.) + AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, 0) ; + else + SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, 0) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +/* Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da una + superficie TriMesh */ +bool +VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) +{ + // controllo delle superfici + for ( const ISurfTriMesh* Surf : vSurf) { + if ( Surf == nullptr) + return false ; + } + // verifica sul parametro di Offset ( coerente con Curve e FlatRegion) + if ( abs( dOffs) < 10 * EPS_SMALL) + return true ; + // se non ho superfici, non faccio nulla + if ( vSurf.empty()) + return true ; + + // definisco lo Zmap di partenza a partire dalle superfici + // se una sola superficie + double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; + if ( int( vSurf.size()) == 1) { + // controllo la validità della superficie + if ( ! vSurf[0]->IsValid() || vSurf[0]->GetTriangleCount() == 0) + return true ; + // definisco lo Zamp a partire dall'espansione del Box della superficie + if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion)) + return false ; + } + // se più superfici + else { + // calcolo il Box complessivo delle superfici TriMesh + BBox3d BBoxGlob ; + for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) { + // controllo la validità della superficie + if ( ! vSurf[i]->IsValid() || vSurf[i]->GetTriangleCount() == 0) + continue ; + // calcolo il Box della superficie + BBox3d BBoxSurf ; vSurf[i]->GetLocalBBox( BBoxSurf) ; + // aggiungo il Box a quello complessivo + BBoxGlob.Add( BBoxSurf) ; + } + // definisco uno Zmap vuoto a partire dal Box + BBoxGlob.Expand( dBoxExpansion) ; + if ( ! CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true)) + return false ; + for ( const ISurfTriMesh* Surf : vSurf) { + if ( ! AddSurfTm( Surf)) + return false ; + } + } + + /* Assunzioni : + - Idea Generale di Offset + - Su ogni vertice viene definita una sfera ( con raggio pari al valore di Offset e + centro il vertice corrente) + - Su ogni lato viene definito un cilindro ( con raggio di pase pari al valore di Offset + e asse definito dall'edge stesso) + - Su ogni faccia viene definita una superficie di estrusione ( dove le due basi sono + definite dalla traslazione sia in positivo che in negativo della faccia lungo la sua normale) + + - Segno dell'Offset : + - Positivo ( si sommano gli intervalli corrisipondenti alle entità create) + - Negativo ( si sottraggono gli intervalli corrispondenti alle enetità create) + + - Semplificazione entità : + La creazione di Sfere e Cilindri potrebbe essere resa più "corretta" definitendo solo + "spicchi 3d" di sfera e "spicchi 3d" di cilindri. Dato che le operazioni di somma, sottrazioni e + calcolo delle normali per gli spilloni sono elementari su queste figure, si rischia di appesantire + troppo i conti introducendo variabili angolari che non sommando tutte le parti. + */ + + // definisco vettore di frame Locali alle 3 griglie + FRAME3DVECTOR vFrGrid( 4) ; + vFrGrid[0].Set( ORIG, X_AX, Y_AX, Z_AX) ; + vFrGrid[1].Set( m_MapFrame.Orig(), m_MapFrame.VersX(), m_MapFrame.VersY(), m_MapFrame.VersZ()) ; + vFrGrid[2].Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ; + vFrGrid[3].Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ; + + + // scorro le superfici + for ( const ISurfTriMesh* Surf : vSurf) { + // se superficie non valida, passo alla successiva + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) + continue ; + // definisco una mappa dei vertici, in modo da sapere su quali sono state già create le sfere + BOOLVECTOR vbVert( Surf->GetVertexCount(), false) ; + // ----------------------- Cilindri e Sfere ----------------------- + // scorro gli Edge della superficie + for ( int nE = 0 ; nE < Surf->GetEdgeCount() ; ++ nE) { + // recupero lo spigolo + int nV1, nV2, nF1, nF2 ; double dAng ; + Surf->GetEdge( nE, nV1, nV2, nF1, nF2, dAng) ; + // controllo se il cilindro serve + // NB. la mancata creazione del cilindro comporta la mancata creazione delle sfere sui suoi vertici + // durante questa iterazione; non significa che questa sfera non verrà mai creata... + // Non esiste la sfera sul vertive V <=> non esiste alcun cilindro su tutti gli edge concorrenti + if ( dAng * dOffs < 0) + continue ; + // recupero le coordinate dei vertici + Point3d ptP1 ; Surf->GetVertex( nV1, ptP1) ; + Point3d ptP2 ; Surf->GetVertex( nV2, ptP2) ; + // ciclo sulle griglie + for ( int nGrid = 0 ; nGrid < 3 ; ++ nGrid) { + // esprimo gli estremi nel riferimento della griglia + ptP1.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + ptP2.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ; + // aggiungo/sottraggo gli intervalli definiti dal cilindro + if ( ! CreateOffsCylinderOnEdge( ptP1, ptP2, dOffs, nGrid)) + return false ; + // aggiungo/sottraggo gli intervalli definiti dalla sfera + if ( ! vbVert[nV1]) { + vbVert[nV1] = ( nGrid == 2) ; + if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid)) + return false ; + } + if ( ! vbVert[nV2]) { + vbVert[nV2] = ( nGrid == 2) ; + if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid)) + return false ; + } + } + } + // ----------------------- Facce ----------------------- + // scorro tutte le facce definendo una superficie di estrusione + for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) { + // recupero lo faccia + POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ; + // recupero la normale della faccia + Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ; + // definisco la superficie di estrusione + CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + vPL[i].Translate( - abs( dOffs) * vtN) ; + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i])) + return false ; + vpCrvs.emplace_back( Release( pCrvCompo)) ; + } + // recupero la TriMesh di estrusione + PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ; + if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0) + return false ; + // aggiorno gli spilloni + if ( dOffs > 0.) + AddSurfTm( pStmExtr) ; + else + SubtractSurfTm( pStmExtr) ; + } + } + m_nShape = OFFSET ; // OFFSET (?) ... per ora va bene così + + return true ; +} + + +