From 3b816e2a45a80a56ef0da3eb621a9083fbb87479 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 16 Dec 2025 11:27:19 +0100 Subject: [PATCH 01/44] EgtGeomKernel : - correzione alla conversione da sup nurbs a bezier. --- SurfAux.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SurfAux.cpp b/SurfAux.cpp index ada55d4..a21fca0 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -69,9 +69,13 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) if ( snData.bRat) snData.mW.resize( nuCurve.vW.size()) ; } - for ( int i = 0 ; i < snData.nCPU ; ++i) { + for ( int i = 0 ; i < int( nuCurve.vCP.size()) ; ++i) { + if( snData.mCP[i].size() == 0) + snData.mCP[i].resize( snData.nCPV) ; snData.mCP[i][j] = nuCurve.vCP[i] ; if ( snData.bRat) { + if( snData.mW[i].size() == 0) + snData.mW[i].resize( snData.nCPV) ; snData.mW[i][j] = nuCurve.vW[i] ; snData.mCP[i][j] *= nuCurve.vW[i] ; } From d27fdb99047755093266aa0b351d3ab85387837a Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 16 Dec 2025 13:03:59 +0100 Subject: [PATCH 02/44] EgtGeomKernel : - piccole migliorie. --- CalcPocketing.cpp | 9 ++++----- SurfAux.cpp | 14 +++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index a40159c..25fe4ff 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -1047,13 +1047,12 @@ ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketPa } // angoli di rotazione ( potrebbero servirne altri) - double dAng45 = ANG_RIGHT / 2. ; - static DBLVECTOR vAngles = { 0., ANG_RIGHT, 3 * ANG_RIGHT, - dAng45, 3 * dAng45, 5 * dAng45, 7 * dAng45 } ; + const double ANG_45 = ANG_RIGHT / 2. ; + const array vAngles{ 0., ANG_RIGHT, 3 * ANG_RIGHT, ANG_45, 3 * ANG_45, 5 * ANG_45, 7 * ANG_45} ; // ruoto il versore di uscita cercando un'entrata valida double dMinDist = PockParams.dRad + PockParams.dRadialOffset ; - for ( int i = 0 ; i < int( vAngles.size()) ; ++ i) { + for ( int i = 0 ; i < ssize( vAngles) ; ++ i) { // ruoto il versore d'uscita Vector3d vtRotOut = GetRotate( vtFirstOut, Z_AX, - vAngles[i]) ; // calcolo il punto di caduta dell'utensile @@ -4828,7 +4827,7 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const return false ; // controllo se la distanza lineare tra i due punti è maggiore della tolleranza... - static double dSqTol = 4 * PockParams.dRad * PockParams.dRad + PockParams.dSideStep * PockParams.dSideStep ; + const 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) { diff --git a/SurfAux.cpp b/SurfAux.cpp index a21fca0..75862f4 100644 --- a/SurfAux.cpp +++ b/SurfAux.cpp @@ -37,7 +37,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) bool bIsRational = snData.bRat ; // vettore dei nodi DBLVECTOR vU ; - int nKnot = (int) snData.vU.size() ; + int nKnot = ssize( snData.vU) ; for ( int k = 0 ; k < nKnot ; ++k ) { double dKnot = snData.vU[k] ; vU.push_back( dKnot) ; @@ -69,12 +69,12 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) if ( snData.bRat) snData.mW.resize( nuCurve.vW.size()) ; } - for ( int i = 0 ; i < int( nuCurve.vCP.size()) ; ++i) { - if( snData.mCP[i].size() == 0) + for ( int i = 0 ; i < ssize( nuCurve.vCP) ; ++i) { + if ( snData.mCP[i].empty()) snData.mCP[i].resize( snData.nCPV) ; snData.mCP[i][j] = nuCurve.vCP[i] ; if ( snData.bRat) { - if( snData.mW[i].size() == 0) + if ( snData.mW[i].empty()) snData.mW[i].resize( snData.nCPV) ; snData.mW[i][j] = nuCurve.vW[i] ; snData.mCP[i][j] *= nuCurve.vW[i] ; @@ -84,13 +84,13 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) } } snData.bPeriodicU = false ; - snData.nCPU = int( snData.mCP.size()) ; + snData.nCPU = ssize( snData.mCP) ; } if ( snData.bPeriodicV || ! snData.bClampedV) { bool bIsRational = snData.bRat ; // vettore dei nodi DBLVECTOR vV ; - int nKnot = (int) snData.vV.size() ; + int nKnot = ssize( snData.vV) ; for ( int k = 0 ; k < nKnot ; ++k ) { double dKnot = snData.vV[k] ; vV.push_back( dKnot) ; @@ -136,7 +136,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData) } } snData.bPeriodicV = false ; - snData.nCPV = int( snData.mCP[0].size()) ; + snData.nCPV = ssize( snData.mCP[0]) ; } return true ; } From 91ca84f77a42849265cad92a62800913574db529 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 19 Dec 2025 15:03:19 +0100 Subject: [PATCH 03/44] EgtGeomKernel : - miglioramento delle superfici di bezier. - aggiunta di una funzione per l'eliminazione delle span collassate e di una per l'inversione dei paramettri di una superficie. --- SurfBezier.cpp | 255 ++++++++++++++++++++++++++++++++++++++++++++-- SurfBezier.h | 2 + Tree.cpp | 99 +++++++++++------- VolZmapVolume.cpp | 1 - 4 files changed, 311 insertions(+), 46 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 6dbbe3f..92eed3d 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1771,6 +1771,8 @@ SurfBezier::GetCurveOnVApproxLen( double dU) const return dLen ; } +int nSurf = 0 ; + //---------------------------------------------------------------------------- const SurfTriMesh* SurfBezier::GetAuxSurf( void) const @@ -1800,6 +1802,7 @@ SurfBezier::GetAuxSurf( void) const } // eseguo calcolo m_pSTM = GetApproxSurf( s_dAuxSurfTol, 100 * EPS_SMALL, false) ; + ++nSurf ; if ( m_pSTM != nullptr) m_pSTM->SetTempParam( s_dAuxSurfTol) ; return m_pSTM ; @@ -1859,7 +1862,6 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) cons // costruttore della superficie POLYLINEMATRIX vvPL ; POLYLINEMATRIX vvPL3d ; - //POLYLINEVECTOR vPL ; // per usare i polygon basic Tree Tree ; if ( ! Tree.SetSurf( this)) return nullptr ; @@ -1868,29 +1870,25 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) cons // resetto il vettore degli edge m_mCCEdge.clear() ; m_vCCLoop.clear() ; + for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) { Point3d ptMin = get<0>( vTrees[i]) ; Point3d ptMax = get<1>( vTrees[i]) ; Tree.SetSurf( this, ptMin, ptMax) ; - Tree.BuildTree( dTol, dSideMin) ; + if( ! Tree.BuildTree( dTol, dSideMin)) { + LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface parametric space couldn't be split in cells") ; + return nullptr ; + } if ( ! Tree.GetPolygons( vvPL, vvPL3d, m_mCCEdge, m_vCCLoop, bUpdateEdges)) continue ; - //Tree.GetPolygonsBasic( vPL, true) ; // per usare i polygon basic // aggiorno la chiusura della superficie m_bClosedU = m_bClosedU || Tree.IsClosedU() ; m_bClosedV = m_bClosedV || Tree.IsClosedV() ; } - //// per usare i polygon basic////////////////////// - //for (int k = 0 ; k < (int)vPL.size(); ++k) { - // vvPL.emplace_back() ; - // vvPL.back().push_back(vPL[k]) ; - //} - //// per usare i polygon basic/////////////////// - if ( vvPL.empty()) - LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated") ; + LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated") StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) @@ -5901,5 +5899,240 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c ++ nAddedSpan ; } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::RemoveCollapsedSpans() +{ + //controllo se ho delle span collassate e le rimuovo + if( m_nSpanU > 1 || m_nSpanV > 1) { + CalcPoles() ; + if( ! m_vbPole[2]) { + // scorro i punti della prima riga + INTVECTOR vnCollapsedSpan ; + for( int i = 0 ; i < m_nSpanU ; ++i) { + bool bSamePoint = true ; + Point3d ptFirst = m_vPtCtrl[m_nDegU * i] ; + // cerco se trovo tutti i punti in U coincidenti in una delle Span + for( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) { + if( ! AreSamePointExact( ptFirst, m_vPtCtrl[m_nDegU * i + j])) + bSamePoint = false ; + } + if( bSamePoint) { + // se trovo un'altra riga collassata do per scontato che tutta span sia collassata + ptFirst = m_vPtCtrl[GetInd( m_nDegU * i, 1)] ; + for( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) { + if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( m_nDegU * i + j, 1)])) + bSamePoint = false ; + } + if( bSamePoint) + vnCollapsedSpan.push_back( i) ; + } + } + int nOldSpanU = m_nSpanU ; + if( ! vnCollapsedSpan.empty()) { + // cancello le span che risultano collassate + int nNewSpanU = m_nSpanU - ssize( vnCollapsedSpan) ; + int nNewDim = ( m_nDegU * nNewSpanU + 1) * ( m_nDegV * m_nSpanV + 1) ; + PNTVECTOR vNewCtrlPnt( nNewDim) ; + DBLVECTOR vNewWeight( nNewDim) ; + int nCurrSkipInd = -1 ; + int nCurrSkip = -1 ; + for( int nIndV = 0 ; nIndV < m_nSpanV * m_nDegV + 1 ; ++nIndV) { + nCurrSkipInd = 0 ; + nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ; + for( int i = 0 ; i < m_nSpanU ; ++i) { + if( i != nCurrSkip) { + for( int j = ( i - nCurrSkipInd) ==0 ? 0 : 1 ; j < m_nDegU + 1 ; ++j) { + vNewCtrlPnt[nIndV * ( m_nDegU * nNewSpanU + 1) + (i - nCurrSkipInd) * m_nDegU + j] = m_vPtCtrl[GetInd( m_nDegU * i + j, nIndV)] ; + if( m_bRat) { + vNewWeight[nIndV * ( m_nDegU * nNewSpanU + 1) + (i - nCurrSkipInd) * m_nDegU + j] = m_vWeCtrl[GetInd( m_nDegU * i + j, nIndV)] ; + } + } + } + else { + ++nCurrSkipInd ; + if( nCurrSkipInd > ssize( vnCollapsedSpan) - 1) + nCurrSkip = -1 ; + else + nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ; + } + } + } + // aggiorno i dati della superficie + // vettori dei punti e numero di span + ISurfFlatRegion* pSFRTrim = nullptr ; + bool bTrimmed = m_bTrimmed ; + if( bTrimmed) { + pSFRTrim = GetTrimRegion() ; + m_pTrimReg = nullptr ; + } + Init( m_nDegU, m_nDegV, nNewSpanU, m_nSpanV, m_bRat) ; + m_vPtCtrl = vNewCtrlPnt ; + if( m_bRat) + m_vWeCtrl = vNewWeight ; + if( bTrimmed) { + // elimino le span di troppo dallo spazio parametrico + PtrOwner pNewTrim( pSFRTrim->Clone()) ; + for( int i = ssize( vnCollapsedSpan) - 1 ; i >= 0 ; --i) { + int nSpan = vnCollapsedSpan[i] ; + // tolgo tutta la parte a destra della colonna da togliere + PtrOwner pSFRCut ( GetSurfFlatRegionRectangle( ( nOldSpanU - nSpan) * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF + 2)) ; + if( nSpan != 0) { + pSFRCut->Translate( Vector3d( nSpan * SBZ_TREG_COEFF, -1)) ; + pNewTrim->Subtract( *pSFRCut) ; + } + if( pNewTrim->IsValid()) { + // ritaglio dal parametrico originale la parte a destra della colonna da eliminare e la incollo alla parte a sinistra + PtrOwner pRightPart( pSFRTrim->Clone()) ; + pSFRCut.Set( GetSurfFlatRegionRectangle( ( nSpan + 1) * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF + 2)) ; + pSFRCut->Translate( Vector3d( nSpan * SBZ_TREG_COEFF, -1)) ; + if( pRightPart->Subtract( *pSFRCut) && pRightPart->IsValid()) { + if( ! pNewTrim->Add( *pRightPart) || ! pNewTrim->IsValid()) + break ; + } + } + else + break ; + } + SetTrimRegion( *pSFRTrim) ; + } + } + } + + if( ! m_vbPole[1]) { + // scorro i punti della prima colonna + INTVECTOR vnCollapsedSpan ; + for( int i = 0 ; i < m_nSpanV ; ++i) { + bool bSamePoint = true ; + Point3d ptFirst = m_vPtCtrl[GetInd( 0, i * m_nDegV)] ; + // cerco se trovo tutti i punti in U coincidenti in una delle Span + for( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) { + if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( 0, i * m_nDegV + j)])) + bSamePoint = false ; + } + if( bSamePoint) { + // se trovo un'altra colonna collassata do per scontato che tutta span sia collassata + ptFirst = m_vPtCtrl[GetInd( 1, i * m_nDegV)] ; + for( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) { + if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( 1, i * m_nDegV + j)])) + bSamePoint = false ; + } + if( bSamePoint) + vnCollapsedSpan.push_back( i) ; + } + } + int nOldSpanV = m_nSpanV ; + if( ! vnCollapsedSpan.empty()) { + // cancello le span che risultano collassate + int nNewSpanV = m_nSpanV - ssize( vnCollapsedSpan) ; + int nNewDim = ( m_nDegU * m_nSpanU + 1) * ( m_nDegV * nNewSpanV + 1) ; + PNTVECTOR vNewCtrlPnt( nNewDim) ; + DBLVECTOR vNewWeight( nNewDim) ; + int nCurrSkipInd = 0 ; + int nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ; + for( int nIndV = 0 ; nIndV < m_nSpanV * m_nDegV + 1 ; ++nIndV) { + if( nIndV / m_nDegV != nCurrSkip) { + for( int i = 0 ; i < m_nSpanU ; ++i) { + for( int j = i==0 ? 0 : 1 ; j < m_nDegU + 1 ; ++j) { + vNewCtrlPnt[( nIndV - ( nCurrSkipInd * m_nDegV)) * ( m_nDegU * m_nSpanU + 1) + i * m_nDegU + j] = m_vPtCtrl[GetInd( m_nDegU * i + j, nIndV)] ; + if( m_bRat) { + vNewWeight[( nIndV - ( nCurrSkipInd * m_nDegV)) * ( m_nDegU * m_nSpanU + 1) + i * m_nDegU + j] = m_vWeCtrl[GetInd( m_nDegU * i + j, nIndV)] ; + } + } + } + } + else { + nIndV += m_nDegV - 1 ; + ++nCurrSkipInd ; + if( nCurrSkipInd > ssize( vnCollapsedSpan) - 1) + nCurrSkip = -1 ; + else + nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ; + } + } + // aggiorno i dati della superficie + // vettori dei punti e numero di span + ISurfFlatRegion* pSFRTrim = nullptr ; + bool bTrimmed = m_bTrimmed ; + if( bTrimmed) { + pSFRTrim = GetTrimRegion() ; + m_pTrimReg = nullptr ; + } + Init( m_nDegU, m_nDegV, m_nSpanU, nNewSpanV, m_bRat) ; + m_vPtCtrl = vNewCtrlPnt ; + if( m_bRat) + m_vWeCtrl = vNewWeight ; + if( bTrimmed) { + // elimino le span di troppo dallo spazio parametrico + PtrOwner pNewTrim( pSFRTrim->Clone()) ; + for( int i = ssize( vnCollapsedSpan) - 1 ; i >= 0 ; --i) { + int nSpan = vnCollapsedSpan[i] ; + // tolgo tutta la parte a sopra la riga da togliere + PtrOwner pSFRCut ( GetSurfFlatRegionRectangle( m_nSpanU * SBZ_TREG_COEFF + 2, ( nOldSpanV - nSpan) * SBZ_TREG_COEFF)) ; + if( nSpan != 0) { + pSFRCut->Translate( Vector3d( -1, nSpan * SBZ_TREG_COEFF)) ; + pNewTrim->Subtract( *pSFRCut) ; + } + if( pNewTrim->IsValid()) { + // ritaglio dal parametrico originale la parte sopra la riga da eliminare e la incollo alla parte sotto la riga + PtrOwner pUpperPart( pSFRTrim->Clone()) ; + pSFRCut.Set( GetSurfFlatRegionRectangle( m_nSpanU * SBZ_TREG_COEFF + 2, ( nSpan + 1) * SBZ_TREG_COEFF)) ; + pSFRCut->Translate( Vector3d( -1, nSpan * SBZ_TREG_COEFF)) ; + if( pUpperPart->Subtract( *pSFRCut) && pUpperPart->IsValid()) { + if( ! pNewTrim->Add( *pUpperPart) || ! pNewTrim->IsValid()) + break ; + } + } + else + break ; + } + SetTrimRegion( *pSFRTrim) ; + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::SwapParameters() +{ + // inverto il parametro U con il parametro V + // salvo i vecchi dati + int nSpanU = m_nSpanV ; + int nSpanV = m_nSpanU ; + int nDegU = m_nDegV ; + int nDegV = m_nDegU ; + bool bTrimmed = m_bTrimmed ; + PtrOwner pSFRTRim ; + if( m_bTrimmed) { + pSFRTRim.Set( GetTrimRegion()) ; + m_pTrimReg = nullptr ; + } + + // creo il vettore dei punti di controllo + PNTVECTOR vNewCtrlPt( GetDim()) ; + DBLVECTOR vNewWeight( GetDim()) ; + for( int j = 0 ; j < m_nDegV * m_nSpanV + 1 ; ++j) { + for( int i = 0 ; i < m_nDegU * m_nSpanU + 1 ; ++ i) { + vNewCtrlPt[i * ( nDegU * nSpanU + 1) + j] = m_vPtCtrl[GetInd(i,j)] ; + if( m_bRat) + vNewWeight[i * ( nDegU * nSpanU + 1) + j] = m_vWeCtrl[GetInd(i,j)] ; + } + } + + Init( nDegU, nDegV, nSpanU, nSpanV, m_bRat) ; + if( bTrimmed) { + pSFRTRim->Mirror( ORIG, Vector3d(1,-1)) ; + SetTrimRegion( *pSFRTRim) ; + } + m_vPtCtrl = vNewCtrlPt ; + m_vWeCtrl = vNewWeight ; + return true ; } \ No newline at end of file diff --git a/SurfBezier.h b/SurfBezier.h index e977000..2e7b89b 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -151,6 +151,8 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW PNTVECTOR GetAllControlPoints( void) const ; bool GetAllPatchesIsocurves( bool bUorV, ICURVEPOVECTOR& vCrv) const ; bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv) ; + bool RemoveCollapsedSpans() override ; + bool SwapParameters() ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/Tree.cpp b/Tree.cpp index b4a318a..f27dc6f 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -474,7 +474,8 @@ Tree::Split( int nId, double dSplitValue) GetPoint( dSplitValue, cToSplit.GetTopLeft().y, ptP01) ; GetPoint( cToSplit.GetTopRight().x, cToSplit.GetTopRight().y, ptP11) ; } - if( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) + if( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11) && + ( cToSplit.GetBottomRight().x - dSplitValue < SBZ_TREG_COEFF - EPS_SMALL || dSplitValue - cToSplit.GetBottomLeft().x < SBZ_TREG_COEFF - EPS_SMALL)) bGoodSplitVert = false ; } if( bGoodSplitHoriz) { @@ -490,7 +491,8 @@ Tree::Split( int nId, double dSplitValue) GetPoint( cToSplit.GetTopLeft().x, cToSplit.GetTopLeft().y, ptP01) ; GetPoint( cToSplit.GetTopRight().x, cToSplit.GetTopRight().y, ptP11) ; } - if( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) + if( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11) && + ( cToSplit.GetTopLeft().y - dSplitValue < SBZ_TREG_COEFF - EPS_SMALL || dSplitValue - cToSplit.GetBottomLeft().y < SBZ_TREG_COEFF - EPS_SMALL)) bGoodSplitHoriz = false ; } @@ -786,6 +788,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) nCToSplit = pcToSplit->m_nChild1 ; pcToSplit = &m_mTree[nCToSplit] ; } + else + return false ; } else { // sono arrivato ad una cella Leaf, quindi salvo la cella @@ -899,6 +903,8 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) nCToSplit = pcToSplit->m_nChild1 ; pcToSplit = &m_mTree[nCToSplit] ; } + else + return false ; } else { // sono arrivato ad una cella Leaf, quindi salvo la cella @@ -1435,19 +1441,20 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec if ( ! TraceLoopLabelCell( vPolygonsBasic)) return false ; // scorro sulle celle e costruisco i poligoni - int nCells = int( vPolygonsBasic.size()) ; - for ( int i = 0 ; i < nCells ; ++ i) { + int nPoly = 0 ; + for ( int nId: m_vnLeaves) { // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps - int nId = m_vnLeaves[i] ; if ( m_mTree[nId].m_nFlag == 4) { // vettore dei poligoni ( loop) della cella nId vvPolygons.emplace_back() ; - vvPolygons.back().push_back(std::move(vPolygonsCorrected[i])) ; + vvPolygons.back().push_back(std::move(vPolygonsCorrected[nPoly])) ; vvPolygons3d.emplace_back() ; - vvPolygons3d.back().push_back(std::move(vPolygonsBasic3d[i])) ; + vvPolygons3d.back().push_back(std::move(vPolygonsBasic3d[nPoly])) ; } else if ( m_mTree[nId].m_nFlag == 0) continue ; + else if( m_mTree[nId].m_nCollapsed != Cell::Collapsed::NO_COLLAPSE) + continue ; else { // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella INTVECTOR vnParentChunk ; @@ -1461,13 +1468,14 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec while ( ! vToCheck.empty()) { int nPolyBefore = nPoly ; PolyLine pl3d ; - CreateCellPolygons( i, vvPolygons, vvPolygons3d, vToCheck, nPoly, vnParentChunk, vPolygonsCorrected[i], vPolygonsBasic3d[i]) ; + CreateCellPolygons( nId, vvPolygons, vvPolygons3d, vToCheck, nPoly, vnParentChunk, vPolygonsCorrected[nPoly], vPolygonsBasic3d[nPoly]) ; if ( nPolyBefore == nPoly) break ; } // ora analizzo anche i loop che sono contenuti nella cella - CreateIslandAndHoles( i, vvPolygons, vvPolygons3d, nPoly, vnParentChunk, vPolygonsCorrected[i], vPolygonsBasic3d[i]) ; + CreateIslandAndHoles( nId, vvPolygons, vvPolygons3d, nPoly, vnParentChunk, vPolygonsCorrected[nPoly], vPolygonsBasic3d[nPoly]) ; } + ++ nPoly ; } } @@ -1910,10 +1918,9 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs nCells.push_back( nId) ; if ( ! bRecurs) { // se sono in un vertice o su un lato devo controllare di aver trovato la cella giusta - Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ; - Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x , m_mTree.at( nId).GetTopRight().y) ; - if ( abs( ptToAssign.x - ptTl.x) < EPS_SMALL || abs( ptToAssign.x - ptBr.x) < EPS_SMALL || - abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL) { + int nEdge = - 2 ; + OnWhichEdge( nId, ptToAssign, nEdge) ; + if ( nEdge != - 2) { Vector3d vtDir ; clTrim.GetStartDir( vtDir) ; // proseguo lungo la curva di trim di EPS_SMALL @@ -1964,12 +1971,16 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells } // se non ho trovato nulla vuol dire che sono su un vertice o su un lato if ( nCells.empty() && ! bRecurs) { - int nEdge = -1 ; + int nEdge = -2 ; for ( int nCell : vCells) { - OnWhichEdge( nCell,ptToAssign, nEdge) ; - if ( nEdge != -1) - break ; + OnWhichEdge( nCell, ptToAssign, nEdge) ; + if ( nEdge != -2 && (m_mTree.at(nCell).m_nCollapsed == Cell::Collapsed::NO_COLLAPSE || m_mTree.at(nCell).m_nCollapsed == Cell::Collapsed::TO_VERIFY)) + nCells.push_back( nCell) ; + nEdge = -2 ; } + if( ssize( nCells) == 1) + return nCells ; + Vector3d vtDir ; cl.GetStartDir( vtDir) ; Point3d ptIntersPlus = ptToAssign ; @@ -1977,7 +1988,7 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells // potrei essere su un lato if ( nEdge == 0 || nEdge == 1 || nEdge == 2 || nEdge == 3) { // se è orientato con il lato mi sposto a destra - if ( ( nEdge == 0 || nEdge == 2 ) && abs(vtDir.x) > 1 - EPS_SMALL/100 ) { + if ( ( nEdge == 0 || nEdge == 2 ) && abs(vtDir.x) > 1 - EPS_SMALL/100) { Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, -90) ; ptIntersPlus = ptIntersPlus + vtDirDX * EPS_SMALL ; } @@ -1996,10 +2007,17 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells if ( abs(vtDir.x) < 1 - EPS_SMALL/100 && abs(vtDir.y) < 1 - EPS_SMALL/100 ) ptIntersPlus = ptIntersPlus + vtDir * EPS_SMALL ; // altrimenti ruoto a destra - else { + else if( ( nEdge == 4 && vtDir.x > 1 - EPS_SMALL / 100) || ( nEdge == 6 && vtDir.x < - 1 + EPS_SMALL / 100) || + ( nEdge == 5 && vtDir.y > 1 - EPS_SMALL / 100) || ( nEdge == 7 && vtDir.y < - 1 + EPS_SMALL / 100)) { Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, -45) ; ptIntersPlus = ptIntersPlus + vtDirDX * EPS_SMALL ; } + // altrimenti ruoto a sinistra + else /*if( ( nEdge == 4 && vtDir.y < - 1 + EPS_SMALL / 100) || ( nEdge == 6 && vtDir.y < 1 - EPS_SMALL / 100) || + ( nEdge == 5 && vtDir.x > 1 - EPS_SMALL / 100) || ( nEdge == 7 && vtDir.x < - 1 + EPS_SMALL / 100)) // + tutti gli altri casi */ { + Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, 45) ; + ptIntersPlus = ptIntersPlus + vtDirDX * EPS_SMALL ; + } } // else @@ -2011,7 +2029,7 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells ptIntersPlus = ptToAssign + vtDirSX * EPS_SMALL ; } // rilancio la rigida ricerca - nCells = FindCell( ptIntersPlus, cl, vCells, true) ; + nCells = FindCell( ptIntersPlus, cl, nCells, true) ; } return nCells ; @@ -2117,9 +2135,10 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) pCell->m_vInters.back().nChunk = m_mChunk[i] ; bool bLoopInside = true ; Point3d ptCurr ; - auto iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; - int nIdPolygon = distance( m_vnLeaves.begin(), iter) ; - if ( nIdPolygon > int( vplPolygons.size()) - 1) + int nIdPolygon = - 1; + if( ! pCell->m_vnPolyId.empty()) + nIdPolygon = pCell->m_vnPolyId[0] ; + else return false ; bool bEraseNextPoint = false ; while ( plLoop.GetNextPoint( ptCurr)) { @@ -2128,6 +2147,8 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) plLoop.GetNextPoint( ptTEnd) ; CurveLine clTrim ; clTrim.Set( ptTStart, ptTEnd) ; + Point3d ptLastInters = P_INVALID ; + int nInfiniteLoopCount = 0 ; // qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva while ( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { // sto uscendo dalla cella, quindi cerco l'intersezione @@ -2153,13 +2174,23 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) return false ; bEraseNextPoint = true ; } - // ricalcolo la posizione di nId nel vettore delle foglie - iter = find( m_vnLeaves.begin(), m_vnLeaves.end(), nId) ; - nIdPolygon = distance( m_vnLeaves.begin(), iter) ; - if ( nIdPolygon > int( vplPolygons.size()) - 1) - return false ; + // se l'intersezione e la stessa della precedente allora potrei essere entrato in un loop infinito + // se per più volte il punto di intersezione resta più o meno lo stesso allora blocco tutto + if( AreSamePointEpsilon( vptInters.back(), ptLastInters, 10 * EPS_SMALL)) { + ++ nInfiniteLoopCount ; + if( nInfiniteLoopCount == 4) { + LOG_ERROR( GetEGkLogger(), "Error Triangulating SurfBezier: infinte while loop occured in Tree::TraceLoopLabelCell") + return false ; + } + } + ptLastInters = vptInters.back() ; // aggiorno il puntatore alla cella pCell = &m_mTree[nId] ; + // recupero l'indice del poligono base associato alla cella + if( ! pCell->m_vnPolyId.empty()) + nIdPolygon = pCell->m_vnPolyId[0] ; + else + return false ; // salvo il verso del loop pCell->m_vInters.back().bCCW = bCCW ; // salvo il chunk del loop @@ -2783,11 +2814,10 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, //---------------------------------------------------------------------------- bool -Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, INTVECTOR& vToCheck, int& nPoly, +Tree::CreateCellPolygons( int nId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell, const PolyLine& plCell3d) { // conto quanti vertici in più ho per lato e creo un vettore dei vertici per lato - int nId = m_vnLeaves[nLeafId] ; Cell& cCell = m_mTree[nId] ; PNTMATRIX vEdgeVertex(4) ; PNTMATRIX vEdgeVertex3d(4) ; @@ -2795,7 +2825,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX Point3d ptTR = cCell.GetTopRight() ; Point3d ptTl = cCell.GetTopLeft() ; Point3d ptBr = cCell.GetBottomRight() ; - int nVertToErase = m_mTree.at(nId).m_nVertToErase ; + int nVertToErase = cCell.m_nVertToErase ; if ( nVertToErase != 2) vEdgeVertex[0].push_back( ptTR) ; if ( nVertToErase != 3) @@ -3116,11 +3146,10 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX //---------------------------------------------------------------------------- bool -Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, int& nPoly, INTVECTOR& vnParentChunk, +Tree::CreateIslandAndHoles( int nId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plPolygonsBasic, const PolyLine& plPolygonsBasic3d) { // costruisco i poligoni partendo dal vettore delle intersezioni - int nId = m_vnLeaves[nLeafId] ; Cell& cCell = m_mTree[nId] ; //capisco se sono in modalità ForTriangulation @@ -3994,7 +4023,9 @@ Tree::OnWhichEdge( int nId, const Point3d& ptToAssign, int& nEdge) const Point3d ptTl ( ptBL.x, ptTR.y) ; Point3d ptBr ( ptTR.x, ptBL.y) ; - if ( AreSamePointXYApprox( ptToAssign, ptTR)) + if( ptToAssign.y < ptBL.y - EPS_SMALL || ptToAssign.y > ptTR.y + EPS_SMALL || ptToAssign.x < ptBL.x - EPS_SMALL || ptToAssign.x > ptTR.x + EPS_SMALL) + return false ; + else if ( AreSamePointXYApprox( ptToAssign, ptTR)) nEdge = 7 ; else if ( AreSamePointXYApprox( ptToAssign, ptTl)) nEdge = 4 ; diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index c15ca17..bd28b54 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -1392,7 +1392,6 @@ IntersLineBezierSurfSet( const Point3d& ptLineStart, const Vector3d& vtLineDir, const SurfBezForInters& srf = vSurfBez[s] ; BBox3d bbox = srf.bbSurfOriented; - bool bNotValid = false ; Point3d rLoc = r ; Vector3d qLoc = q ; if ( ! bNeedToRot) { From a508da8b188f26a8dcb92019ab39d85e4100637d Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 19 Dec 2025 15:58:30 +0100 Subject: [PATCH 04/44] EgtGemoKernel : - piccola correzione. --- Tree.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index f27dc6f..e885059 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -1441,18 +1441,20 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec if ( ! TraceLoopLabelCell( vPolygonsBasic)) return false ; // scorro sulle celle e costruisco i poligoni - int nPoly = 0 ; + int nPolyInd = 0 ; // indice del poligono corrispondente alla cella, nel vettore dei poligoni for ( int nId: m_vnLeaves) { // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps if ( m_mTree[nId].m_nFlag == 4) { // vettore dei poligoni ( loop) della cella nId vvPolygons.emplace_back() ; - vvPolygons.back().push_back(std::move(vPolygonsCorrected[nPoly])) ; + vvPolygons.back().push_back(std::move(vPolygonsCorrected[nPolyInd])) ; vvPolygons3d.emplace_back() ; - vvPolygons3d.back().push_back(std::move(vPolygonsBasic3d[nPoly])) ; + vvPolygons3d.back().push_back(std::move(vPolygonsBasic3d[nPolyInd])) ; } - else if ( m_mTree[nId].m_nFlag == 0) + else if ( m_mTree[nId].m_nFlag == 0) { + ++ nPolyInd ; continue ; + } else if( m_mTree[nId].m_nCollapsed != Cell::Collapsed::NO_COLLAPSE) continue ; else { @@ -1468,14 +1470,14 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec while ( ! vToCheck.empty()) { int nPolyBefore = nPoly ; PolyLine pl3d ; - CreateCellPolygons( nId, vvPolygons, vvPolygons3d, vToCheck, nPoly, vnParentChunk, vPolygonsCorrected[nPoly], vPolygonsBasic3d[nPoly]) ; + CreateCellPolygons( nId, vvPolygons, vvPolygons3d, vToCheck, nPoly, vnParentChunk, vPolygonsCorrected[nPolyInd], vPolygonsBasic3d[nPolyInd]) ; if ( nPolyBefore == nPoly) break ; } // ora analizzo anche i loop che sono contenuti nella cella - CreateIslandAndHoles( nId, vvPolygons, vvPolygons3d, nPoly, vnParentChunk, vPolygonsCorrected[nPoly], vPolygonsBasic3d[nPoly]) ; + CreateIslandAndHoles( nId, vvPolygons, vvPolygons3d, nPoly, vnParentChunk, vPolygonsCorrected[nPolyInd], vPolygonsBasic3d[nPolyInd]) ; } - ++ nPoly ; + ++ nPolyInd ; } } From 176bbec8a72efe27ce66be19b501aca8998a2fe4 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 23 Dec 2025 15:35:32 +0100 Subject: [PATCH 05/44] EgtGeomKernel 2.7l3 : - aggiunta funzione DuplicateGeomDB. --- EgtGeomKernel.rc | Bin 11718 -> 11718 bytes GeomDB.cpp | 4 +- GeomDB.h | 2 + MultiGeomDB.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 106 insertions(+), 6 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 04141b893ab94ef59e1c6a199b4838a8e246f99e..60d72854e06929e776809705ebe44d2050a4d172 100644 GIT binary patch delta 260 zcmX>WeJpyzI%aKGhCGIJh8%`WhGK>c1_cHUhESkLCPN8BDnkm89}HwAf_cT0FKS6| z{=m$^%xJv%Hs5)s$u(R$lRrqRF&aWeJpyzI%aiGhCGIJh8%`ehGHOAV9;O)W+-7u1ma8}FBB-731Uyas3kpFPd#gM z9Lqc=Mx)L5`OY&hX`jGK#;zcG^Fwu6)J>CBt_NlipBAM6KDupe@OZchZce6ybVG-gbx%@?)4G64W1 CWk|>X diff --git a/GeomDB.cpp b/GeomDB.cpp index 964cf4b..ffe03d7 100644 --- a/GeomDB.cpp +++ b/GeomDB.cpp @@ -613,7 +613,7 @@ GeomDB::GetGdbObj( int nId) const // radice else if ( nId == GDB_ID_ROOT) return &m_GrpRadix ; - // un nodo qualubque + // un nodo qualunque else return m_IdManager.FindObj( nId) ; } @@ -660,7 +660,7 @@ GeomDB::InsertInGeomDB( GdbObj* pGObj, int nRefId, int nSonBeforeAfter, bool bLo return false ; } // inserisco come figlio, in testa alla lista del padre - else if ( nSonBeforeAfter == GDB_FIRST_SON){ + else if ( nSonBeforeAfter == GDB_FIRST_SON) { GdbGroup* pGroup = ::GetGdbGroup( pGRef) ; if ( pGroup == nullptr) return false ; diff --git a/GeomDB.h b/GeomDB.h index 6e0f18a..ef16fb8 100644 --- a/GeomDB.h +++ b/GeomDB.h @@ -31,6 +31,8 @@ class GeomDB : public IGeomDB friend class GdbGeo ; friend int CopyGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob) ; friend int CopyGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob) ; + friend int DuplicateGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId) ; + friend int DuplicateGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, bool bSkipTemp) ; public : ~GeomDB( void) override ; diff --git a/MultiGeomDB.cpp b/MultiGeomDB.cpp index b81b1cd..a5c43d8 100644 --- a/MultiGeomDB.cpp +++ b/MultiGeomDB.cpp @@ -23,9 +23,6 @@ using namespace std ; static int CopyGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob) { - // verifico i puntatori ai GeomDB - if ( pSouGDB == nullptr || pDstGDB == nullptr) - return GDB_ID_NULL ; // recupero l'oggetto da copiare dal GeomDB sorgente PtrOwner pGObj( pSouGDB->GetGeoObj( nSouId)->Clone()) ; if ( IsNull( pGObj)) @@ -109,7 +106,7 @@ CopyGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, i nSonNewId = CopyGeoObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ; // se altrimenti è un gruppo else if ( nSonSouType == GDB_TY_GROUP) - nSonNewId = CopyGroupObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ; + nSonNewId = CopyGroupObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ; // se copia non riuscita, esco con errore if ( nSonNewId == GDB_ID_NULL) return GDB_ID_NULL ; @@ -129,6 +126,9 @@ Copy( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, int nR GeomDB* pDstGDB = static_cast( pDestGeomDB) ; if ( pSouGDB == nullptr || pDstGDB == nullptr) return GDB_ID_NULL ; + // il sorgente non può essere il gruppo radice + if ( nSouId == GDB_ID_ROOT) + return GDB_ID_NULL ; // nuovo identificativo oggetto destinazione int nNewId = GDB_ID_NULL ; // recupero il tipo di oggetto sorgente @@ -158,3 +158,101 @@ CopyGlob( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, in { return Copy( pSouGeomDB, nSouId, pDestGeomDB, nDestId, nRefId, nSonBeforeAfter, true) ; } + +//---------------------------------------------------------------------------- +static int +DuplicateGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId) +{ + // recupero l'oggetto da copiare dal GeomDB sorgente + PtrOwner pGObj( pSouGDB->GetGeoObj( nSouId)->Clone()) ; + if ( IsNull( pGObj)) + return GDB_ID_NULL ; + // lo inserisco nel GeomDB destinazione + int nNewId = pDstGDB->InsertGeoObj( nDestId, nRefId, GDB_LAST_SON, Release( pGObj)) ; + if ( nNewId != nDestId) { + pDstGDB->Erase( nNewId) ; + return GDB_ID_NULL ; + } + // copio le caratteristiche non geometriche + const GdbObj* pSouGdbObj = pSouGDB->GetGdbObj( nSouId) ; + GdbObj* pDstGdbObj = pDstGDB->GetGdbObj( nNewId) ; + if ( pSouGDB == nullptr || pDstGdbObj == nullptr || + ! pDstGdbObj->CopyAttribsFrom( pSouGdbObj) || + ! pDstGdbObj->CopyTextureDataFrom( pSouGdbObj) || + ! pDstGdbObj->CopyStippleDataFrom( pSouGdbObj) || + ! pDstGdbObj->CopyUserObjFrom( pSouGdbObj)) { + pDstGDB->Erase( nNewId) ; + return GDB_ID_NULL ; + } + + return nNewId ; +} + +//---------------------------------------------------------------------------- +static int +DuplicateGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, bool bSkipTemp) +{ + int nNewId = GDB_ID_ROOT ; + if ( nSouId != GDB_ID_ROOT) { + // recupero il riferimento del gruppo + Frame3d frFrame = *( pSouGDB->GetGroupFrame( nSouId)) ; + // inserisco un nuovo gruppo nel GeomDB destinazione + nNewId = pDstGDB->InsertGroup( nDestId, nRefId, GDB_LAST_SON, frFrame) ; + if ( nNewId != nSouId) { + pDstGDB->Erase( nNewId) ; + return GDB_ID_NULL ; + } + // copio le caratteristiche non geometriche + const GdbObj* pSouGdbObj = pSouGDB->GetGdbObj( nSouId) ; + GdbObj* pDstGdbObj = pDstGDB->GetGdbObj( nNewId) ; + if ( pSouGDB == nullptr || pDstGdbObj == nullptr || + ! pDstGdbObj->CopyAttribsFrom( pSouGdbObj) || + ! pDstGdbObj->CopyTextureDataFrom( pSouGdbObj) || + ! pDstGdbObj->CopyStippleDataFrom( pSouGdbObj) || + ! pDstGdbObj->CopyUserObjFrom( pSouGdbObj)) { + pDstGDB->Erase( nNewId) ; + return GDB_ID_NULL ; + } + } + // copio gli eventuali figli + int nSonSouId = pSouGDB->GetFirstInGroup( nSouId) ; + while ( nSonSouId != GDB_ID_NULL) { + // verifico se non richiesto di saltare i temporanei oppure non lo è + int nLevel ; + if ( ! bSkipTemp || ! pSouGDB->GetLevel( nSonSouId, nLevel) || nLevel != GDB_LV_TEMP) { + // nuovo identificativo oggetto destinazione + int nSonNewId = GDB_ID_NULL ; + // recupero il tipo di oggetto sorgente + int nSonSouType = pSouGDB->GetGdbType( nSonSouId) ; + // se l'oggetto da copiare è geometrico + if ( nSonSouType == GDB_TY_GEO) + nSonNewId = DuplicateGeoObj( pSouGDB, nSonSouId, pDstGDB, nSonSouId, nNewId) ; + // se altrimenti è un gruppo + else if ( nSonSouType == GDB_TY_GROUP) + nSonNewId = DuplicateGroupObj( pSouGDB, nSonSouId, pDstGDB, nSonSouId, nNewId, bSkipTemp) ; + // se copia non riuscita, esco con errore + if ( nSonNewId != nSonSouId) + return GDB_ID_NULL ; + } + // passo al figlio successivo + nSonSouId = pSouGDB->GetNext( nSonSouId) ; + } + + return nNewId ; +} + +//---------------------------------------------------------------------------- +bool +DuplicateGeomDB( IGeomDB* pSouGeomDB, IGeomDB* pDestGeomDB, bool bSkipTemp) +{ + // adatto e verifico i GeomDB + const GeomDB* pSouGDB = static_cast( pSouGeomDB) ; + GeomDB* pDstGDB = static_cast( pDestGeomDB) ; + if ( pSouGDB == nullptr || pDstGDB == nullptr) + return false ; + // verifico che la destinazione sia vuota + if ( pDstGDB->GetFirstInGroup( GDB_ID_ROOT) != GDB_ID_NULL) + return false ; + // eseguo la copia di tutto (se richiesto salto gli oggetti temporanei) + return ( DuplicateGroupObj( pSouGDB, GDB_ID_ROOT, pDstGDB, GDB_ID_ROOT, GDB_ID_ROOT, bSkipTemp) != GDB_ID_NULL) ; +} From 51c584c6c4c9e37e002e35340d6c242f39245b63 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 29 Dec 2025 08:45:03 +0100 Subject: [PATCH 06/44] EgtGeomKernel 2.7l6 : - modifiche a NgeWriter per semplificare e velocizzare scrittura file binari (ora anche compressi). --- EgtGeomKernel.rc | Bin 11718 -> 11718 bytes NgeWriter.cpp | 148 ++++++++++++++++++++--------------------------- NgeWriter.h | 10 +--- 3 files changed, 67 insertions(+), 91 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 60d72854e06929e776809705ebe44d2050a4d172..1f6bfb593c3d7b2ac29d9052211428416c763f63 100644 GIT binary patch delta 110 zcmX>WeJpyzA2vp_&G-4vGfl1&(wY2&Q;pGVvZAo=W*@FeEMOU1X1ItOWeJpyzA2vqg&G-4vGfl1&(wY2&Q;pGhvZAo=W*@FeEMOU1X1ItO diff --git a/NgeWriter.cpp b/NgeWriter.cpp index 681e4d1..1328353 100644 --- a/NgeWriter.cpp +++ b/NgeWriter.cpp @@ -23,23 +23,23 @@ using namespace std ; //---------------------------------------------------------------------------- -inline bool -WriteStringOutTxt( gzFile OutTxtFile, const char* szVal, const char* szSep, bool bEndL) +static bool +WriteStringOutTxt( gzFile OutFile, const char* szVal, const char* szSep, bool bEndL) { // verifico apertura file - if ( OutTxtFile == nullptr) + if ( OutFile == nullptr) return false ; // scrivo stringa - if ( gzputs( OutTxtFile, szVal) == Z_ERRNO) + if ( gzputs( OutFile, szVal) == Z_ERRNO) return false ; // se fornito, scrivo separatore if ( szSep != nullptr && szSep[0] != '\0') { - if ( gzputs( OutTxtFile, szSep) == Z_ERRNO) + if ( gzputs( OutFile, szSep) == Z_ERRNO) return false ; } // se richiesto, scrivo fine linea if ( bEndL) { - if ( gzputs( OutTxtFile, "\r\n") == Z_ERRNO) + if ( gzputs( OutFile, "\r\n") == Z_ERRNO) return false ; } return true ; @@ -50,25 +50,22 @@ bool NgeWriter::Init( const string& sFileOut, int nFlag) { // salvo tipo file - m_bBinary = ( nFlag == GDB_SV_BIN) ; + m_bBinary = ( nFlag == GDB_SV_BIN || nFlag == GDB_SV_CMPBIN) ; // apertura del file di uscita - if ( m_bBinary) { - m_OutBinFile.open( stringtoW( sFileOut), ios::out | ios::binary, _SH_DENYWR) ; - return m_OutBinFile.good() ; + if ( nFlag == GDB_SV_TXT || nFlag == GDB_SV_BIN) { + m_OutFile = gzopen_w( stringtoW( sFileOut), "wbT") ; + return ( m_OutFile != nullptr) ; } - else { - if ( nFlag == GDB_SV_TXT) - m_OutTxtFile = gzopen_w( stringtoW( sFileOut), "wbT") ; - else // GDB_SV_CMPTXT - m_OutTxtFile = gzopen_w( stringtoW( sFileOut), "wb") ; - if ( m_OutTxtFile == nullptr) + else { // GDB_SV_CMPTXT o GDB_SV_CMPBIN + m_OutFile = gzopen_w( stringtoW( sFileOut), "wb") ; + if ( m_OutFile == nullptr) return false ; const int DIM_BUFFER = 65536 ; - if ( gzbuffer( m_OutTxtFile, DIM_BUFFER) != Z_OK) + if ( gzbuffer( m_OutFile, DIM_BUFFER) != Z_OK) return false ; const int COMPR_LEVEL = 3 ; // 0 = no compression ... 9 = max compression - if ( gzsetparams( m_OutTxtFile, COMPR_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) + if ( gzsetparams( m_OutFile, COMPR_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) return false ; return true ; } @@ -78,20 +75,12 @@ NgeWriter::Init( const string& sFileOut, int nFlag) bool NgeWriter::Close( void) { - if ( m_bBinary) { - bool bOk = ( m_OutBinFile.good() && m_OutBinFile.is_open()) ; - if ( m_OutBinFile.is_open()) - m_OutBinFile.close() ; + if ( m_OutFile != nullptr) { + bool bOk = ( gzclose( m_OutFile) == Z_OK) ; + m_OutFile = nullptr ; return bOk ; } - else { - if ( m_OutTxtFile != nullptr) { - bool bOk = ( gzclose( m_OutTxtFile) == Z_OK) ; - m_OutTxtFile = nullptr ; - return bOk ; - } - return true ; - } + return true ; } //---------------------------------------------------------------------------- @@ -99,13 +88,12 @@ bool NgeWriter::WriteUchar( unsigned char ucVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &ucVal, sizeof( ucVal)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &ucVal, sizeof( ucVal)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( ucVal).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( ucVal).c_str(), szSep, bEndL) ; } } @@ -114,13 +102,12 @@ bool NgeWriter::WriteBool( bool bVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &bVal, sizeof( bVal)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &bVal, sizeof( bVal)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( bVal).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( bVal).c_str(), szSep, bEndL) ; } } @@ -129,13 +116,12 @@ bool NgeWriter::WriteInt( int nVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &nVal, sizeof( nVal)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &nVal, sizeof( nVal)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( nVal).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( nVal).c_str(), szSep, bEndL) ; } } @@ -144,13 +130,12 @@ bool NgeWriter::WriteDouble( double dVal, const char* szSep, bool bEndL, int nPrec) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &dVal, sizeof( dVal)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &dVal, sizeof( dVal)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( dVal, nPrec).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( dVal, nPrec).c_str(), szSep, bEndL) ; } } @@ -159,15 +144,14 @@ bool NgeWriter::WriteString( const string& sVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - int nDim = int( sVal.size()) ; - m_OutBinFile.write( (char*) &nDim, sizeof( nDim)) ; - m_OutBinFile.write( sVal.c_str(), sVal.size()) ; - return m_OutBinFile.good() ; + int nDim = ssize( sVal) ; + return ( gzwrite( m_OutFile, (char*) &nDim, sizeof( nDim)) > 0 && + ( nDim == 0 || gzwrite( m_OutFile, sVal.c_str(), sVal.size()) > 0)) ; } else { - return WriteStringOutTxt( m_OutTxtFile, sVal.c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, sVal.c_str(), szSep, bEndL) ; } } @@ -176,13 +160,12 @@ bool NgeWriter::WriteVector( const Vector3d& vtV, const char* szSep, bool bEndL, int nPrec) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &vtV.v, sizeof( vtV.v)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &vtV.v, sizeof( vtV.v)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( vtV, nPrec).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( vtV, nPrec).c_str(), szSep, bEndL) ; } } @@ -191,13 +174,12 @@ bool NgeWriter::WritePoint( const Point3d& ptP, const char* szSep, bool bEndL, int nPrec) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &ptP.v, sizeof( ptP.v)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &ptP.v, sizeof( ptP.v)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( ptP, nPrec).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( ptP, nPrec).c_str(), szSep, bEndL) ; } } @@ -206,14 +188,13 @@ bool NgeWriter::WritePointW( const Point3d& ptP, double dW, const char* szSep, bool bEndL, int nPrecP, int nPrecW) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &ptP.v, sizeof( ptP.v)) ; - m_OutBinFile.write( (char*) &dW, sizeof( dW)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &ptP.v, sizeof( ptP.v)) > 0 && + gzwrite( m_OutFile, (char*) &dW, sizeof( dW)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( ptP, dW, nPrecP, nPrecW).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( ptP, dW, nPrecP, nPrecW).c_str(), szSep, bEndL) ; } } @@ -222,16 +203,15 @@ bool NgeWriter::WriteFrame( const Frame3d& frF, const char* szSep, bool bEndL, int nPrecP, int nPrecV) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &frF.Orig().v, sizeof( frF.Orig().v)) ; - m_OutBinFile.write( (char*) &frF.VersX().v, sizeof( frF.VersX().v)) ; - m_OutBinFile.write( (char*) &frF.VersY().v, sizeof( frF.VersY().v)) ; - m_OutBinFile.write( (char*) &frF.VersZ().v, sizeof( frF.VersZ().v)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &frF.Orig().v, sizeof( frF.Orig().v)) > 0 && + gzwrite( m_OutFile, (char*) &frF.VersX().v, sizeof( frF.VersX().v)) > 0 && + gzwrite( m_OutFile, (char*) &frF.VersY().v, sizeof( frF.VersY().v)) > 0 && + gzwrite( m_OutFile, (char*) &frF.VersZ().v, sizeof( frF.VersZ().v)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( frF, nPrecP, nPrecV).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( frF, nPrecP, nPrecV).c_str(), szSep, bEndL) ; } } @@ -243,13 +223,12 @@ NgeWriter::WriteKey( int nKey) return false ; if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; - m_OutBinFile.write( (char*) &NgeBinKeyW[nKey], sizeof( int)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) &NgeBinKeyW[nKey], sizeof( int)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, NgeAscKeyW[nKey].c_str(), nullptr, true) ; + return WriteStringOutTxt( m_OutFile, NgeAscKeyW[nKey].c_str(), nullptr, true) ; } } @@ -258,18 +237,17 @@ bool NgeWriter::WriteCol( const Color& cCol, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_OutBinFile.is_open()) + if ( m_OutFile == nullptr) return false ; unsigned char ucCol[4] ; ucCol[0] = cCol.GetIntRed() ; ucCol[1] = cCol.GetIntGreen() ; ucCol[2] = cCol.GetIntBlue() ; ucCol[3] = cCol.GetIntAlpha() ; - m_OutBinFile.write( (char*) ucCol, sizeof( ucCol)) ; - return m_OutBinFile.good() ; + return ( gzwrite( m_OutFile, (char*) ucCol, sizeof( ucCol)) > 0) ; } else { - return WriteStringOutTxt( m_OutTxtFile, ToString( cCol).c_str(), szSep, bEndL) ; + return WriteStringOutTxt( m_OutFile, ToString( cCol).c_str(), szSep, bEndL) ; } } @@ -277,9 +255,11 @@ NgeWriter::WriteCol( const Color& cCol, const char* szSep, bool bEndL) bool NgeWriter::WriteRemark( const string& sVal) { - if ( m_bBinary) + if ( m_bBinary) { return true ; - else - return ( WriteStringOutTxt( m_OutTxtFile, "//", nullptr, false) && - WriteStringOutTxt( m_OutTxtFile, sVal.c_str(), nullptr, true)) ; + } + else { + return ( WriteStringOutTxt( m_OutFile, "//", nullptr, false) && + WriteStringOutTxt( m_OutFile, sVal.c_str(), nullptr, true)) ; + } } diff --git a/NgeWriter.h b/NgeWriter.h index 3fc05b3..63b0139 100644 --- a/NgeWriter.h +++ b/NgeWriter.h @@ -16,7 +16,6 @@ #include "NgeConst.h" #include "/EgtDev/Include/EGkPoint3d.h" #include "/EgtDev/Include/EGkColor.h" -#include struct gzFile_s ; @@ -24,7 +23,7 @@ struct gzFile_s ; class NgeWriter { public : - NgeWriter( void) : m_bBinary( false), m_OutTxtFile( nullptr) {} + NgeWriter( void) : m_bBinary( false), m_OutFile( nullptr) {} ~NgeWriter( void) { Close() ; } bool Init( const std::string& sFileOut, int nFlag) ; @@ -44,9 +43,6 @@ class NgeWriter bool WriteRemark( const std::string& sVal /* bEndL = true*/) ; private : - bool m_bBinary ; - // per file binari - std::ofstream m_OutBinFile ; - // per file ASCII - gzFile_s* m_OutTxtFile ; + bool m_bBinary ; + gzFile_s* m_OutFile ; } ; From d92344f2bbc8da76b1e9be342d33cf2fd2d9f9e2 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 29 Dec 2025 11:55:09 +0100 Subject: [PATCH 07/44] EgtGeomKernel : - - modifiche a NgeReader per semplificare e velocizzare lettura file binari. --- NgeReader.cpp | 99 +++++++++++++++++++++++++-------------------------- NgeReader.h | 12 ++++--- NgeWriter.cpp | 30 ++++++++-------- NgeWriter.h | 4 +-- 4 files changed, 72 insertions(+), 73 deletions(-) diff --git a/NgeReader.cpp b/NgeReader.cpp index b76c4d3..9a4eadf 100644 --- a/NgeReader.cpp +++ b/NgeReader.cpp @@ -17,6 +17,8 @@ #include "NgeKeyW.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtStringConverter.h" +#include "/EgtDev/Extern/zlib/Include/zlib.h" +#include using namespace std ; @@ -34,8 +36,12 @@ NgeReader::Init( const string& sFileIn) break ; case NGE_BINARY : m_bBinary = true ; - m_InFile.open( stringtoW( sFileIn), ios::in | ios::binary, _SH_DENYWR) ; - return ( ! m_InFile.fail()) ; + m_InFile = gzopen_w( stringtoW( sFileIn), "rb") ; + if ( m_InFile == nullptr) + return false ; + const int DIM_BUFFER = 65536 ; + gzbuffer( m_InFile, DIM_BUFFER) ; + return true ; break ; } return false ; @@ -46,10 +52,12 @@ bool NgeReader::Close( void) { if ( m_bBinary) { - bool bOk = ( m_InFile.good() && m_InFile.is_open()) ; - if ( m_InFile.is_open()) - m_InFile.close() ; - return bOk ; + if ( m_InFile != nullptr) { + bool bOk = ( gzclose( m_InFile) == Z_OK) ; + m_InFile = nullptr ; + return bOk ; + } + return true ; } else return m_Scan.Terminate() ; @@ -91,7 +99,7 @@ int NgeReader::GetCurrPos( void) { if ( m_bBinary) - return int( m_InFile.tellg()) ; + return int( gztell( m_InFile)) ; else return m_Scan.GetCurrLineNbr() ; } @@ -131,10 +139,9 @@ bool NgeReader::ReadUchar( unsigned char& ucVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &ucVal, sizeof( ucVal)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &ucVal, sizeof( ucVal)) != Z_ERRNO) ; } else { // recupero il token @@ -154,10 +161,9 @@ bool NgeReader::ReadBool( bool& bVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &bVal, sizeof( bVal)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &bVal, sizeof( bVal)) != Z_ERRNO) ; } else { // recupero il token @@ -173,10 +179,9 @@ bool NgeReader::ReadInt( int& nVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &nVal, sizeof( nVal)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &nVal, sizeof( nVal)) != Z_ERRNO) ; } else { // recupero il token @@ -203,10 +208,9 @@ bool NgeReader::ReadDouble( double& dVal, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &dVal, sizeof( dVal)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &dVal, sizeof( dVal)) != Z_ERRNO) ; } else { // recupero il token @@ -222,10 +226,9 @@ bool NgeReader::ReadVector( Vector3d& vtV, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &vtV.v, sizeof( vtV.v)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &vtV.v, sizeof( vtV.v)) != Z_ERRNO) ; } else { // recupero il token @@ -241,10 +244,9 @@ bool NgeReader::ReadPoint( Point3d& ptP, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &ptP.v, sizeof( ptP.v)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &ptP.v, sizeof( ptP.v)) != Z_ERRNO) ; } else { // recupero il token @@ -260,11 +262,10 @@ bool NgeReader::ReadPointW( Point3d& ptP, double& dW, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - m_InFile.read( (char*) &ptP.v, sizeof( ptP.v)) ; - m_InFile.read( (char*) &dW, sizeof( dW)) ; - return m_InFile.good() ; + return ( gzread( m_InFile, &ptP.v, sizeof( ptP.v)) != Z_ERRNO && + gzread( m_InFile, &dW, sizeof( dW)) != Z_ERRNO) ; } else { // recupero il token @@ -280,17 +281,13 @@ bool NgeReader::ReadFrame( Frame3d& frF, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; - Point3d ptOrig ; - m_InFile.read( (char*) &ptOrig.v, sizeof( ptOrig.v)) ; - Vector3d vtDirX ; - m_InFile.read( (char*) &vtDirX.v, sizeof( vtDirX.v)) ; - Vector3d vtDirY ; - m_InFile.read( (char*) &vtDirY.v, sizeof( vtDirY.v)) ; - Vector3d vtDirZ ; - m_InFile.read( (char*) &vtDirZ.v, sizeof( vtDirZ.v)) ; - if ( ! m_InFile.good()) + Point3d ptOrig ; Vector3d vtDirX, vtDirY, vtDirZ ; + if ( gzread( m_InFile, &ptOrig.v, sizeof( ptOrig.v)) == Z_ERRNO || + gzread( m_InFile, &vtDirX.v, sizeof( vtDirX.v)) == Z_ERRNO || + gzread( m_InFile, &vtDirY.v, sizeof( vtDirY.v)) == Z_ERRNO || + gzread( m_InFile, &vtDirZ.v, sizeof( vtDirZ.v)) == Z_ERRNO) return false ; return frF.Set( ptOrig, vtDirX, vtDirY, vtDirZ) ; } @@ -308,18 +305,20 @@ bool NgeReader::ReadString( string& sVal, const char* szSep, bool bEndL) { if ( m_bBinary) { + if ( m_InFile == nullptr) + return false ; const int MAX_STR_DIM = 65535 ; - if ( ! m_InFile.is_open()) - return false ; int nDim ; - m_InFile.read( (char*) &nDim, sizeof( nDim)) ; - if ( nDim > MAX_STR_DIM || ! m_InFile.good()) + if ( gzread( m_InFile, &nDim, sizeof( nDim)) == Z_ERRNO || nDim > MAX_STR_DIM) return false ; + if ( nDim == 0) { + sVal = "" ; + return true ; + } char* szBuff = new( nothrow) char[ nDim + 1] ; if ( szBuff == nullptr) return false ; - m_InFile.read( szBuff, nDim) ; - if ( ! m_InFile.good()) { + if ( gzread( m_InFile, szBuff, nDim) == Z_ERRNO) { delete[] szBuff ; return false ; } @@ -348,12 +347,11 @@ NgeReader::ReadKey( int& nKey) return true ; } if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; // leggo il dato int nVal ; - m_InFile.read( (char*) &nVal, sizeof( nVal)) ; - if ( ! m_InFile.good()) + if ( gzread( m_InFile, &nVal, sizeof( nVal)) == Z_ERRNO) return false ; // ricavo l'indice for ( int i = 0 ; i <= NGE_LAST_ID ; ++ i) { @@ -386,11 +384,10 @@ bool NgeReader::ReadCol( Color& cCol, const char* szSep, bool bEndL) { if ( m_bBinary) { - if ( ! m_InFile.is_open()) + if ( m_InFile == nullptr) return false ; unsigned char ucCol[4] ; - m_InFile.read( (char*) &ucCol, sizeof( ucCol)) ; - if ( ! m_InFile.good()) + if ( gzread( m_InFile, &ucCol, sizeof( ucCol)) == Z_ERRNO) return false ; cCol.Set( ucCol[0], ucCol[1], ucCol[2], ucCol[3]) ; return true ; diff --git a/NgeReader.h b/NgeReader.h index 7f39b98..0df0e9a 100644 --- a/NgeReader.h +++ b/NgeReader.h @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------- -// EgalTech 2014-2014 +// EgalTech 2014-2025 //---------------------------------------------------------------------------- -// File : NgeReader.h Data : 14.04.14 Versione : 1.5d5 +// File : NgeReader.h Data : 29.12.25 Versione : 2.7l6 // Contenuto : Dichiarazione della classe NgeReader. // // @@ -18,14 +18,16 @@ #include "/EgtDev/Include/EGkColor.h" #include "/EgtDev/Include/EGnScanner.h" #include "/EgtDev/Include/EgtStringBase.h" -#include + +struct gzFile_s ; //---------------------------------------------------------------------------- class NgeReader { public : NgeReader( void) - : m_iPosStart( std::string::npos), m_bUngetKey( false), m_nFileVer() {} + : m_bBinary( false), m_InFile( nullptr), m_iPosStart( std::string::npos), + m_bUngetKey( false), m_nLastKey(), m_nFileVer() {} ~NgeReader( void) { Close() ; } bool Init( const std::string& sFileIn) ; @@ -60,7 +62,7 @@ class NgeReader private : bool m_bBinary ; // per file binari - std::ifstream m_InFile ; + gzFile_s* m_InFile ; // per file ASCII Scanner m_Scan ; std::string::size_type m_iPosStart ; diff --git a/NgeWriter.cpp b/NgeWriter.cpp index 1328353..31a8ce7 100644 --- a/NgeWriter.cpp +++ b/NgeWriter.cpp @@ -90,7 +90,7 @@ NgeWriter::WriteUchar( unsigned char ucVal, const char* szSep, bool bEndL) if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &ucVal, sizeof( ucVal)) > 0) ; + return ( gzwrite( m_OutFile, &ucVal, sizeof( ucVal)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( ucVal).c_str(), szSep, bEndL) ; @@ -104,7 +104,7 @@ NgeWriter::WriteBool( bool bVal, const char* szSep, bool bEndL) if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &bVal, sizeof( bVal)) > 0) ; + return ( gzwrite( m_OutFile, &bVal, sizeof( bVal)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( bVal).c_str(), szSep, bEndL) ; @@ -118,7 +118,7 @@ NgeWriter::WriteInt( int nVal, const char* szSep, bool bEndL) if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &nVal, sizeof( nVal)) > 0) ; + return ( gzwrite( m_OutFile, &nVal, sizeof( nVal)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( nVal).c_str(), szSep, bEndL) ; @@ -132,7 +132,7 @@ NgeWriter::WriteDouble( double dVal, const char* szSep, bool bEndL, int nPrec) if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &dVal, sizeof( dVal)) > 0) ; + return ( gzwrite( m_OutFile, &dVal, sizeof( dVal)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( dVal, nPrec).c_str(), szSep, bEndL) ; @@ -147,7 +147,7 @@ NgeWriter::WriteString( const string& sVal, const char* szSep, bool bEndL) if ( m_OutFile == nullptr) return false ; int nDim = ssize( sVal) ; - return ( gzwrite( m_OutFile, (char*) &nDim, sizeof( nDim)) > 0 && + return ( gzwrite( m_OutFile, &nDim, sizeof( nDim)) > 0 && ( nDim == 0 || gzwrite( m_OutFile, sVal.c_str(), sVal.size()) > 0)) ; } else { @@ -162,7 +162,7 @@ NgeWriter::WriteVector( const Vector3d& vtV, const char* szSep, bool bEndL, int if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &vtV.v, sizeof( vtV.v)) > 0) ; + return ( gzwrite( m_OutFile, &vtV.v, sizeof( vtV.v)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( vtV, nPrec).c_str(), szSep, bEndL) ; @@ -176,7 +176,7 @@ NgeWriter::WritePoint( const Point3d& ptP, const char* szSep, bool bEndL, int nP if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &ptP.v, sizeof( ptP.v)) > 0) ; + return ( gzwrite( m_OutFile, &ptP.v, sizeof( ptP.v)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( ptP, nPrec).c_str(), szSep, bEndL) ; @@ -190,8 +190,8 @@ NgeWriter::WritePointW( const Point3d& ptP, double dW, const char* szSep, bool b if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &ptP.v, sizeof( ptP.v)) > 0 && - gzwrite( m_OutFile, (char*) &dW, sizeof( dW)) > 0) ; + return ( gzwrite( m_OutFile, &ptP.v, sizeof( ptP.v)) > 0 && + gzwrite( m_OutFile, &dW, sizeof( dW)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( ptP, dW, nPrecP, nPrecW).c_str(), szSep, bEndL) ; @@ -205,10 +205,10 @@ NgeWriter::WriteFrame( const Frame3d& frF, const char* szSep, bool bEndL, int nP if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &frF.Orig().v, sizeof( frF.Orig().v)) > 0 && - gzwrite( m_OutFile, (char*) &frF.VersX().v, sizeof( frF.VersX().v)) > 0 && - gzwrite( m_OutFile, (char*) &frF.VersY().v, sizeof( frF.VersY().v)) > 0 && - gzwrite( m_OutFile, (char*) &frF.VersZ().v, sizeof( frF.VersZ().v)) > 0) ; + return ( gzwrite( m_OutFile, &frF.Orig().v, sizeof( frF.Orig().v)) > 0 && + gzwrite( m_OutFile, &frF.VersX().v, sizeof( frF.VersX().v)) > 0 && + gzwrite( m_OutFile, &frF.VersY().v, sizeof( frF.VersY().v)) > 0 && + gzwrite( m_OutFile, &frF.VersZ().v, sizeof( frF.VersZ().v)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( frF, nPrecP, nPrecV).c_str(), szSep, bEndL) ; @@ -225,7 +225,7 @@ NgeWriter::WriteKey( int nKey) if ( m_bBinary) { if ( m_OutFile == nullptr) return false ; - return ( gzwrite( m_OutFile, (char*) &NgeBinKeyW[nKey], sizeof( int)) > 0) ; + return ( gzwrite( m_OutFile, &NgeBinKeyW[nKey], sizeof( int)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, NgeAscKeyW[nKey].c_str(), nullptr, true) ; @@ -244,7 +244,7 @@ NgeWriter::WriteCol( const Color& cCol, const char* szSep, bool bEndL) ucCol[1] = cCol.GetIntGreen() ; ucCol[2] = cCol.GetIntBlue() ; ucCol[3] = cCol.GetIntAlpha() ; - return ( gzwrite( m_OutFile, (char*) ucCol, sizeof( ucCol)) > 0) ; + return ( gzwrite( m_OutFile, ucCol, sizeof( ucCol)) > 0) ; } else { return WriteStringOutTxt( m_OutFile, ToString( cCol).c_str(), szSep, bEndL) ; diff --git a/NgeWriter.h b/NgeWriter.h index 63b0139..ae2b95a 100644 --- a/NgeWriter.h +++ b/NgeWriter.h @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------- -// EgalTech 2014-2014 +// EgalTech 2014-2025 //---------------------------------------------------------------------------- -// File : NgeWriter.h Data : 12.04.14 Versione : 1.5d5 +// File : NgeWriter.h Data : 29.12.25 Versione : 2.7l6 // Contenuto : Dichiarazione della classe NgeWriter. // // From d0ac226753586423348b83dc1948c12e0f3b0d87 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 29 Dec 2025 19:24:56 +0100 Subject: [PATCH 08/44] EgtGeomKernel : - aggiunta lettura file Nge binari compressi. --- NgeReader.cpp | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/NgeReader.cpp b/NgeReader.cpp index 9a4eadf..0f122c1 100644 --- a/NgeReader.cpp +++ b/NgeReader.cpp @@ -18,7 +18,6 @@ #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtStringConverter.h" #include "/EgtDev/Extern/zlib/Include/zlib.h" -#include using namespace std ; @@ -67,31 +66,24 @@ NgeReader::Close( void) int NgeReader::NgeType( const string& sFile) { - // apertura del file di ingresso - ifstream InFile ; - InFile.open( stringtoW( sFile), ios::in | ios::binary) ; - if ( InFile.fail()) + // apertura file + gzFile_s* InFile = gzopen_w( stringtoW( sFile), "rb") ; + if ( InFile == nullptr) return NGE_ERROR ; - - // lettura dei primi 31 byte - char cBuff[32] ; - InFile.read( cBuff, 31) ; - cBuff[InFile.gcount()] = '\0' ; - - // chiusura del file - InFile.close() ; - - // verifico se file compresso (gz) - if ( cBuff[0] == '\x1F' && cBuff[1] == '\x8B') - return NGE_ASCII ; - - // verifico se iniziano con "START" - string sBuff = cBuff ; - size_t nPos = sBuff.find( "START") ; - if ( nPos != string::npos && nPos < 10) - return NGE_ASCII ; - else + // lettura dei primi caratteri + char szBuff[9] = "\0\0\0\0\0\0\0\0" ; + int nLen = gzread( InFile, &szBuff, 8) ; + if ( gzclose( InFile) != Z_OK || nLen == Z_ERRNO) + return NGE_ERROR ; + // se binario + if ( szBuff[0] == '\x0F' && szBuff[1] == '\x0F') return NGE_BINARY ; + // se testo + string sBuff{ szBuff} ; + if ( sBuff.find( "START") != string::npos) + return NGE_ASCII ; + // altrimenti errore + return NGE_ERROR ; } //---------------------------------------------------------------------------- From 0c435a646df9c4beddfd4a0a0a668af5d64df192 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 30 Dec 2025 19:24:56 +0100 Subject: [PATCH 09/44] EgtGeomKernel : - migliorato controllo e sistemazione chiusura curva di intersezione piano con Zmap. --- CurveComposite.cpp | 17 ++++++++++++----- CurveComposite.h | 2 +- VolZmapCalculus.cpp | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 51abec2..d2fbc95 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -889,14 +889,21 @@ CurveComposite::Validate( void) //---------------------------------------------------------------------------- bool -CurveComposite::TestClosure( void) +CurveComposite::TestClosure( double dLinTol) { - // se non è chiusa, esco subito - if ( ! IsClosed()) + // se non valida o vuota, esco subito + if ( m_nStatus != OK || m_CrvSmplS.empty()) + return true ; + // se non è chiusa entro la tolleranza, esco subito + Point3d ptStart, ptEnd ; + if ( ! m_CrvSmplS.front()->GetStartPoint( ptStart) || + ! m_CrvSmplS.back()->GetEndPoint( ptEnd) || + ! AreSamePointEpsilon( ptStart, ptEnd, dLinTol)) + return true ; + // se singola retta, esco subito + if ( m_CrvSmplS.size() == 1 && m_CrvSmplS.front()->GetType() == CRV_LINE) return true ; // verifico ed eventualmente aggiusto coincidenza punti estremi - Point3d ptStart ; m_CrvSmplS.front()->GetStartPoint( ptStart) ; - Point3d ptEnd ; m_CrvSmplS.back()->GetEndPoint( ptEnd) ; // se distanza superiore al limite ridotto forzo i punti a coincidere if ( ! AreSamePointEpsilon( ptStart, ptEnd, EPS_CONNECT)) { // se un solo arco diff --git a/CurveComposite.h b/CurveComposite.h index cc07fdf..f202bd4 100644 --- a/CurveComposite.h +++ b/CurveComposite.h @@ -198,13 +198,13 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW return *this ; } bool RelocateFrom( CurveComposite& ccSrc) ; bool GetApproxLength( double& dLen) const ; + bool TestClosure( double dLinTol = EPS_SMALL) ; Voronoi* GetVoronoiObject( void) const ; void ResetVoronoiObject( void) const ; private : bool CopyFrom( const CurveComposite& ccSrc) ; bool Validate( void) ; - bool TestClosure( void) ; bool AddCurveByRelocate( CurveComposite& ccSrc, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; bool AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; bool GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const ; diff --git a/VolZmapCalculus.cpp b/VolZmapCalculus.cpp index 178f2ae..bb57461 100644 --- a/VolZmapCalculus.cpp +++ b/VolZmapCalculus.cpp @@ -3177,6 +3177,7 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c if ( ! pLoop->AddCurve( vLine[i - 1], true, 10 * EPS_SMALL)) return false ; } + pLoop->TestClosure( 10 * EPS_SMALL) ; pLoop->SetExtrusion( plPlane.GetVersN()) ; pLoop->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ; // Inserisco la curva composita nella raccolta da ritornare From d374e133f0cf501f90281be586deaf48606ed7b1 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Fri, 2 Jan 2026 12:33:47 +0100 Subject: [PATCH 10/44] EgtGeomKernel 3.1a1 : - ricompilazione con cambio major versione. --- EgtGeomKernel.rc | Bin 11718 -> 11710 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 1f6bfb593c3d7b2ac29d9052211428416c763f63..5febf3abeef249400a18f3e3f28c0af4cefea82c 100644 GIT binary patch delta 314 zcmX>Wy)SyhJ2qZp1|0@N7@mBePn8ucvYC^ADbwUSA)U!TIORBv8T5dP5*Z99D+=pQ z_Tk#VXtwz;S3V<9El^@}Ax}IL9)q}aMai*05UU&=JOj!S29f+WY}f1F~RMhtpD zr8z)Firl)By|^|onr{BhmCp!N50sdEkwbiQos1RZ<^#NZjCjrEX2xdL|-zmvB-i From f144cda136caf0d03ba7185ad3d97cea8f518090 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Sun, 4 Jan 2026 12:55:28 +0100 Subject: [PATCH 11/44] EgtGeomKernel : - modifiche per consentire di proiettare curve chiuse su superfici conservando i punti di inizio e fine. --- PolyLine.cpp | 6 +++--- ProjectCurveSurf.cpp | 30 ++++++++++++++++++------------ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/PolyLine.cpp b/PolyLine.cpp index f52f459..d11f74c 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -775,7 +775,7 @@ DouglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const //---------------------------------------------------------------------------- bool -PolyLine::RemoveAlignedPoints( double dToler) +PolyLine::RemoveAlignedPoints( double dToler, bool bStartEnd) { // se non ci sono almeno 3 punti, esco subito if ( m_lUPoints.size() < 3) @@ -825,8 +825,8 @@ PolyLine::RemoveAlignedPoints( double dToler) // ordino in senso crescente sort( vInd.begin(), vInd.end()) ; - // se chiusa e almeno 4 punti rimasti, controllo allineamento dell'inizio con precedente e successivo rimasti - if ( IsClosed() && vInd.size() >= 4) { + // se richiesto e chiusa e almeno 4 punti rimasti, controllo allineamento dell'inizio con precedente e successivo rimasti + if ( bStartEnd && IsClosed() && vInd.size() >= 4) { if ( DistPointLine( vPtU[vInd[0]].first, vPtU[vInd[1]].first, vPtU[vInd[int(vInd.size())-2]].first).IsEpsilon( dToler)) { vInd.erase( vInd.begin()) ; vInd.back() = vInd.front() ; diff --git a/ProjectCurveSurf.cpp b/ProjectCurveSurf.cpp index e845fb8..821d91d 100644 --- a/ProjectCurveSurf.cpp +++ b/ProjectCurveSurf.cpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------- -// EgalTech 2023-2025 +// EgalTech 2023-2026 //---------------------------------------------------------------------------- -// File : ProjectCurveSurfTm.cpp Data : 29.08.25 Versione : 2.7h2 +// File : ProjectCurveSurfTm.cpp Data : 03.01.26 Versione : 3.1a1 // Contenuto : Implementazione funzioni proiezione curve su superficie Trimesh. // // @@ -311,9 +311,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; - // approssimo la curva con una polilinea entro la metà della tolleranza + // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; - if ( ! crCrv.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) @@ -443,9 +444,11 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect // controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; - // approssimo la curva con una polilinea alla massima risoluzione + + // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; - if ( ! crCrv.ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) @@ -597,9 +600,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; - // approssimo la curva con una polilinea entro la metà della tolleranza + // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; - if ( ! crCrv.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) @@ -736,9 +740,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; - // Approssimo la curva con una polilinea alla massima risoluzione + // Approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; - if ( ! crCrv.ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) @@ -911,9 +916,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; - // approssimo la curva con una polilinea entro la metà della tolleranza + // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; - if ( ! crCrv.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) From 3245f7fe75f6d14a02c5002296746893e148f6c6 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Sun, 4 Jan 2026 20:39:33 +0100 Subject: [PATCH 12/44] EgtGeomKernel : - aggiunte funzioni di striping per trimming dei termoformati. --- EgtGeomKernel.vcxproj | 1 + EgtGeomKernel.vcxproj.filters | 6 + SurfTriMesh.cpp | 18 + SurfTriMesh.h | 1 + SurfTriMeshOffset.cpp | 3 +- Trimming.cpp | 3764 +++++++++++++++++++++++++++++++++ 6 files changed, 3792 insertions(+), 1 deletion(-) create mode 100644 Trimming.cpp diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 5fe8537..c571c4d 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -322,6 +322,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index e07bdb6..06c76e0 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -55,6 +55,9 @@ {865b76ee-b10d-41fc-861c-b48ce52fa277} + + {54901321-08f6-4428-80c7-a1f859136a32} + @@ -561,6 +564,9 @@ File di origine\GeoInters + + File di origine\GeoStriping + diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 789b8a5..16f22f2 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -4514,3 +4514,21 @@ SurfTriMesh::AdjustTopologyFromZMap( void) return true ; } + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetTriaFromFace( int nF, int& nT) const +{ + // la superficie deve essere validata + if ( m_nStatus != OK) + return false ; + // verifico stato sfaccettatura + if ( ! VerifyFaceting()) + return false ; + // l'indice della faccia deve essere nei limiti + if ( nF < 0 || nF >= int( m_vFacet.size())) + return false ; + // recupero la normale di un triangolo della faccetta + nT = m_vFacet[nF] ; + return true ; +} diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 12c886e..49b92a7 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -380,6 +380,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool SetTempInt( int nId, int nTempInt) const ; bool AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol = 2 * EPS_SMALL) ; bool AdjustTopologyFromZMap( void) ; + bool GetTriaFromFace( int nF, int& nT) const ; private : typedef std::vector VERTVECTOR ; diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp index dd1841a..f1579f9 100644 --- a/SurfTriMeshOffset.cpp +++ b/SurfTriMeshOffset.cpp @@ -733,6 +733,7 @@ CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec) } if ( nIndOffsCrv == -1) return nullptr ; + vIndMatched[ nIndOffsCrv] = true ; // associo le due curve ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nIndOffsCrv] ; double dParMinDist = 0. ; @@ -787,4 +788,4 @@ CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec) #endif return ( ( ! IsNull( pStmRef) && pStmRef->IsValid()) ? Release( pStmRef) : nullptr) ; -} \ No newline at end of file +} diff --git a/Trimming.cpp b/Trimming.cpp new file mode 100644 index 0000000..bf42b82 --- /dev/null +++ b/Trimming.cpp @@ -0,0 +1,3764 @@ +//---------------------------------------------------------------------------- +// EgalTech 2025-2025 +//---------------------------------------------------------------------------- +// File : Trimming.cpp Data : 16.11.23 Versione : 2.7j1 +// Contenuto : Dichiarazione delle funzioni per calcolare una superficie di Bezier +// Ruled mediante Estrazione di Edge e Selezione di Facce/Superfici +// +// +// +// Modifiche : 16.11.23 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "BiArcs.h" +#include "GeoConst.h" +#include "CurveArc.h" +#include "CurveComposite.h" +#include "SurfTriMesh.h" +#include "SurfBezier.h" +#include "CurveBezier.h" +#include "/EgtDev/Include/EGkTrimming.h" +#include "/EgtDev/Include/EGkCurveAux.h" +#include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EGkDistPointLine.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkDistPointSurfTm.h" +#include "/EgtDev/Include/EGkDistPointSurfBz.h" +#include "/EgtDev/Include/EGkDistPointTria.h" +#include "/EgtDev/Include/EGkDistLineLine.h" +#include "/EgtDev/Include/EGkSbzFromCurves.h" +#include "/EgtDev/Include/EGkStmFromTriangleSoup.h" +#include "/EgtDev/Include/EGkIntersLineBox.h" +#include "/EgtDev/Include/EGkSurfTriMeshAux.h" +#include "/EgtDev/Include/EgtNumUtils.h" +#include +#include + +// -------------------------- Debug -------------------------------------------- +#define DEBUG 0 +#define DEBUG_BASIC_BORDERS 0 +#define DEBUG_CHAIN_CURVES 0 +#define DEBUG_ANG_APPROX 0 +#define DEBUG_BEZIER_INTERP 0 +#define DEBUG_FACE_SEARCH 0 +#define DEBUG_BRK_POINTS 0 +#define DEBUG_BRK_THICK 0 +#define DEBUG_BRK 0 +#define DEBUG_BORDERS_BY_NORMALS 0 +#define DEBUG_SYNC_POINTS 0 +#define DEBUG_BEZIER_RULED 0 +#define DEBUG_CURVATURE 0 +#define DEBUG_SIMPLE_PATCHES 0 +#define DEBUG_SURF_PATCHES 0 +#define DEBUG_EDGES 0 +#define DEBUG_SHAPE_STM 0 +#if DEBUG_BASIC_BORDERS || DEBUG_CHAIN_CURVES || DEBUG_ANG_APPROX || DEBUG_BEZIER_INTERP || \ + DEBUG_FACE_SEARCH || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || \ + DEBUG_SYNC_POINTS || DEBUG_BEZIER_RULED || DEBUG_CURVATURE || DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || \ + DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG + #include "CurveLine.h" + #include "/EgtDev/Include/EGkGeoObjSave.h" + #include "/EgtDev/Include/EgtPerfCounter.h" + #include "/EgtDev/Include/EGnStringUtils.h" + #include "/EgtDev/Include/EGkGeoPoint3d.h" + #include "/EgtDev/Include/EGkGeoVector3d.h" + std::vector VT ; + std::vector VC ; + std::vector VT_Glob ; + std::vector VC_Glob ; + std::string sFileName = "C:\\Temp\\Debug.nge" ; +#endif + +using namespace std ; + +// Vettori e Matrici di curva composite +typedef vector COMPOVECTOR ; +typedef vector COMPOMATRIX ; +// Strutta per Patch semplici, Bordi e insieme di Bordi +struct SimplePatch { + Point3d ptStart ; + Point3d ptEnd ; + bool bErase ; + int nBorder ; + SimplePatch() + : ptStart( P_INVALID), ptEnd( P_INVALID), bErase( true), nBorder( 0) {} ; + SimplePatch( const Point3d& ptS, const Point3d& ptE, int nB, bool bDelete) + : ptStart( ptS), ptEnd( ptE), bErase( bDelete), nBorder( nB) {} ; +} ; +typedef vector SimpleBorder ; +typedef vector SimpleBorderVector ; +typedef vector SimpleBorderMatrix ; +// Struttura per superficie con relative Patch +struct SurfPatches { + int nIndSurf ; + const ISurf* pSurf ; + vector vPatches ; // non definiscono per forza un bordo, sono solo patch non ordinate + COMPOVECTOR CompoPathces ; +} ; +typedef vector SURFPATCHESVECTOR ; +// Struttura per Calcolo delle Normali su una superficie lungo il suo bordo ( per parallelismo ) +struct BorderInfo { + const ISurf* pSurf ; + const ICurveComposite* pCompo ; + int nInd ; + double dParam ; + Point3d ptCrv ; + Vector3d vtTan ; + Vector3d vtNorm ; + Point3d ptFinal ; + BorderInfo( const ISurf* pS, const ICurveComposite* pC, int nI, double dP) + : pSurf( pS), pCompo( pC), nInd( nI), dParam( dP) {} +} ; +typedef vector VBORDERINFO ; + +//----------------------------------------------------------------------------- +static const string sCircle{ "circle"} ; + +//----------------------------------------------------------------------------- +//--------------------------- Approssimazione --------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Funzione per spezzare una PolyLine in un insieme di Patches, ovvero un insieme di +// PolyLine dove per ogni punto si discosta da due successivi per non più della tolleranza +// angolare passata +static bool +GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL) +{ + // Se PL chiusa, deve contenere almeno 3 punti + if ( PL.IsClosed() && PL.GetPointNbr() < 3) + return false ; + // Se PL aperta, deve contenere almeno 2 punti + if ( ! PL.IsClosed() && PL.GetPointNbr() < 2) + return false ; + + // Se PL aperta con solo due punti, allora non devo fare nulla + if ( ! PL.IsClosed() && PL.GetPointNbr() == 2) { + vPL.emplace_back( PL) ; + return true ; + } + + // Recupero l'insieme di punti associati alla PolyLine + PNTVECTOR vPoints ; vPoints.reserve( PL.GetPointNbr()) ; + Point3d ptCurr = P_INVALID ; + bool bFound = PL.GetFirstPoint( ptCurr) ; + while ( bFound) { + vPoints.emplace_back( ptCurr) ; + bFound = PL.GetNextPoint( ptCurr) ; + } + #if DEBUG_ANG_APPROX + VT.clear() ; VC.clear() ; + Color _col = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + for ( auto _p : vPoints) { + IGeoPoint3d* _pt = CreateGeoPoint3d() ; + _pt->Set( _p) ; + VT.emplace_back( _pt) ; + VC.emplace_back( _col) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\RawPoints.nge") ; + #endif + + // Sin della tolleranza angolare massima + double dCosTol = cos( dAngTol * DEGTORAD) ; + + // Scorro i punti controllando le loro deviazioni angolari + PNTMATRIX vvPoints ; + Vector3d vtTanCurr = V_INVALID, vtTanNext = V_INVALID ; + bool bNewCurve = true ; + int nPoints = int( vPoints.size()) ; + for ( int nP = 0 ; nP < nPoints - 2 ; ++ nP) { + // Recupero il punto corrente e i due punti successivi + Point3d& ptCurr = vPoints[nP] ; + Point3d& ptNext = vPoints[nP + 1] ; + Point3d& ptNextNext = vPoints[nP + 2] ; + // Recupero i versori tangenti definiti dai tre punti ( ptCurr|ptNext e ptNext|ptNextNext) + if ( nP == 0) { + vtTanCurr = ptNext - ptCurr ; + vtTanCurr.Normalize() ; + } + else + vtTanCurr = vtTanNext ; + vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ; + // Calcolo il Coseno tra i due versori + double dCos = vtTanCurr * vtTanNext ; + // Se dentro alla tolleranza, allora i punti apparterranno alla stessa curva + if ( dCos > dCosTol) { + // Se devo definire una curva nuova + if ( bNewCurve) { + vvPoints.emplace_back( PNTVECTOR()) ; + vvPoints.back().emplace_back( ptCurr) ; + vvPoints.back().emplace_back( ptNext) ; + bNewCurve = false ; + } + // Aggiungo il punto + vvPoints.back().emplace_back( ptNextNext) ; + } + // Se tratto al di fuori della tolleranza, devo definire una nuova curva + else { + // Se curva nuova, allora è solamente tratto lineare + if ( bNewCurve) { + vvPoints.emplace_back( PNTVECTOR()) ; + vvPoints.back().emplace_back( ptCurr) ; + vvPoints.back().emplace_back( ptNext) ; + } + bNewCurve = true ; + } + } + // Se PolyLine originale chiusa + if ( PL.IsClosed()) { + // Se ho più tratti, potrei riuniore il primo con l'ultimo + if ( int( vvPoints.size()) > 1) { + Point3d& ptCurr = vPoints[int( vPoints.size()) - 2] ; + Point3d& ptNext = vPoints[0] ; + Point3d& ptNextNext = vPoints[1] ; + vtTanCurr = ptNext - ptCurr ; vtTanCurr.Normalize() ; + vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ; + double dCos = vtTanCurr * vtTanNext ; + // Se dentro alla tolleranza + if ( dCos > dCosTol) { + // Recupero la tangenza del tratto finale dell'ultimo tratto + Point3d& ptLast = vvPoints.back()[int( vvPoints.back().size()) - 1] ; + Point3d& ptLastLast = vvPoints.back()[int( vvPoints.back().size()) - 2] ; + Vector3d vtTanLast = ptLast - ptLastLast ; vtTanLast.Normalize() ; + dCos = vtTanLast * vtTanCurr ; + // Se nella tolleranza allora posso allacciare il primo e l'ultimo tratto + if ( dCos > dCosTol) { + for ( int i = bNewCurve ? 1 : 0 ; i < int( vvPoints[0].size()) ; ++ i) + vvPoints.back().emplace_back( vvPoints[0][i]) ; + vvPoints.erase( vvPoints.begin()) ; + } + // Altrimenti sposto il punto d'inizio in ptCurr del primo tratto + else { + PNTVECTOR vPointsFirst ; vPointsFirst.reserve( vvPoints.front().size() + 1) ; + vPointsFirst.emplace_back( ptCurr) ; + for ( const Point3d& pt : vvPoints.front()) + vPointsFirst.emplace_back( pt) ; + vvPoints.front() = vPointsFirst ; + } + } + // Se fuori dalla tolleranza, e l'ultimo punto non è già stato aggiunto + else if ( bNewCurve) { + // tratto lineare finale + vvPoints.emplace_back( PNTVECTOR{}) ; + vvPoints.back().emplace_back( ptCurr) ; + vvPoints.back().emplace_back( ptNext) ; + } + } + } + // Se invece PolyLine Aperta + else { + // Se devo creare una curva nuova, aggiungo il tratto finale + if ( bNewCurve) { + vvPoints.emplace_back( PNTVECTOR{}) ; + vvPoints.back().emplace_back( vPoints[int( vPoints.size()) - 2]) ; + vvPoints.back().emplace_back( vPoints[int( vPoints.size()) - 1]) ; + } + } + #if DEBUG_ANG_APPROX + VT.clear() ; VC.clear() ; + for ( auto _v : vvPoints) { + Color _col = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + for ( auto _p : _v) { + IGeoPoint3d* _pt = CreateGeoPoint3d() ; + _pt->Set( _p) ; + VT.emplace_back( _pt) ; + VC.emplace_back( _col) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\GroupPoints.nge") ; + #endif + + // Converto i punti ricavati in PolyLine risultati + for ( int i = 0 ; i < int( vvPoints.size()) ; ++ i) { + vPL.emplace_back( PolyLine()) ; + double dPar = -1. ; + for ( int j = 0 ; j < int( vvPoints[i].size()) ; ++ j) { + vPL.back().AddUPoint( ++ dPar, vvPoints[i][j]) ; + } + } + + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante +// Patches di curve di Bezier +static bool +ApproxCurveWithBezier( ICurveComposite* pCrvCompo, double dLinTol, double dAngTol) +{ + // Controllo dei parametri + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + + // Recupero la PolyLine associata ( senza alcuna approssimazione) + PolyLine myPL ; + if ( ! pCrvCompo->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL)) + return false ; + + // Approssimo la curva mediante Set di punti considerando la tolleranza angolare + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( myPL, dAngTol, vPL)) + return false ; + #if DEBUG_BEZIER_INTERP + VT.clear() ; VC.clear() ; + VT.emplace_back( pCrvCompo->Clone()) ; + VC.emplace_back( RED) ; + for ( PolyLine& PL : vPL) { + if ( PL.GetPointNbr() > 1) { + Point3d ptCurr ; PL.GetFirstPoint( ptCurr) ; + IGeoPoint3d* pt = CreateGeoPoint3d() ; + pt->Set( ptCurr) ; + VT.emplace_back( pt) ; + VC.emplace_back( AQUA) ; + PL.GetLastPoint( ptCurr) ; + pt->Set( ptCurr) ; + VT.emplace_back( pt) ; + VC.emplace_back( AQUA) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\AngBorderApprox.nge") ; + VT.clear() ; VC.clear() ; + #endif + + // Pulisco la curva originale + pCrvCompo->Clear() ; + + // Ogni PolyLine ricavata viene approssimata con un tratto di Bezier + const double MAXLEN = 1.5 ; + for ( const PolyLine& PL : vPL) { + // Se meno di due punti, non la considero ( non dovrebbe mai capitare ) + if ( PL.GetPointNbr() < 2) + continue ; + // Recupero i punti + PNTVECTOR vPoints ; + Point3d ptCurr ; + bool bFound = PL.GetFirstPoint( ptCurr) ; + while ( bFound) { + vPoints.emplace_back( ptCurr) ; + bFound = PL.GetNextPoint( ptCurr) ; + } + #if DEBUG_BEZIER_INTERP + Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + for ( int i = 0 ; i < int( vPoints.size()) ; ++ i) { + IGeoPoint3d* pt = CreateGeoPoint3d() ; + pt->Set( vPoints[i]) ; + VT.emplace_back( pt) ; + VC.emplace_back( myCol) ; + } + #endif + // Approssimo con una Bezier + PtrOwner pCrvBz( InterpolatePointSetWithBezier( vPoints, dLinTol, MAXLEN)) ; + if ( IsNull( pCrvBz) || ! pCrvBz->IsValid()) { + LOG_ERROR( GetEGkLogger(), "Error : Interpolating points to bezier curve failed") ; + return false ; + } + #if DEBUG_BEZIER_INTERP + VT.emplace_back( pCrvBz->Clone()) ; + myCol.Set( myCol.GetRed() * .95, myCol.GetGreen() * .95, myCol.GetBlue() * .95) ; + VC.emplace_back( myCol) ; + #endif + // Aggiungo il tratto approssimato alla curva finale complessiva + if ( ! pCrvCompo->AddCurve( Release( pCrvBz))) + return false ; + } + #if DEBUG_BEZIER_INTERP + SaveGeoObj( VT, VC, "C:\\Temp\\InterpolationCurveBezier.nge") ; + #endif + + return ( pCrvCompo->IsValid()) ; +} + +//----------------------------------------------------------------------------- +//-------------------------------- Analisi Bordi ------------------------------ +//----------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// Funzione per controllare e sistemare le curve di bordo di una riagata Bezier +static bool +ManageRuledBorders( ICurveComposite* pCompoEdge1, ICurveComposite* pCompoEdge2) +{ + // Se curve non valide, errore + if ( pCompoEdge1 == nullptr || ! pCompoEdge1->IsValid() || + pCompoEdge2 == nullptr || ! pCompoEdge2->IsValid()) + return false ; + + // Le due curve devono essere entrambe aperte o entrambe chiuse + bool bAllClosed = ( pCompoEdge1->IsClosed() && pCompoEdge2->IsClosed()) ; + bool bAllOpen = ( ! pCompoEdge1->IsClosed() && ! pCompoEdge2->IsClosed()) ; + if ( ! bAllClosed && ! bAllOpen) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Mixed Edges") ; + return false ; + } + + // Eseguo una copia delle curve composite per non modificare i parametri + PtrOwner pCrvEdge1CL( pCompoEdge1->Clone()) ; + PtrOwner pCrvEdge2CL( pCompoEdge2->Clone()) ; + if ( IsNull( pCrvEdge1CL) || IsNull( pCrvEdge2CL) || + ! pCrvEdge1CL->IsValid() || ! pCrvEdge2CL->IsValid()) + return false ; + PtrOwner pMyCompoEdge1( ConvertCurveToComposite( Release( pCrvEdge1CL))) ; + PtrOwner pMyCompoEdge2( ConvertCurveToComposite( Release( pCrvEdge2CL))) ; + if ( IsNull( pMyCompoEdge1) || IsNull( pMyCompoEdge2) || + ! pMyCompoEdge1->IsValid() || ! pMyCompoEdge2->IsValid()) + return false ; + + // Modifico il punto iniziale o oriento le curve allo stesso modo + // --- Se entrambe aperte + if ( bAllOpen) { + // Recupero il punto iniziale della prima curva + Point3d ptStart1 ; pMyCompoEdge1->GetStartPoint( ptStart1) ; + // Recupero gli estremi della seconda curva + Point3d ptStart2 ; pMyCompoEdge2->GetStartPoint( ptStart2) ; + Point3d ptEnd2 ; pMyCompoEdge2->GetEndPoint( ptEnd2) ; + // Se necessario inverto la seconda curva + if ( SqDist( ptStart1, ptEnd2) < SqDist( ptStart1, ptStart2)) + pMyCompoEdge2->Invert() ; + } + // --- Se entrambe chiuse + else { + // Modifico il punto iniziale della prima curva a metà del suo tratto più lungo + double dMaxLen = - INFINITO ; + int nCrvInd = 0 ; + for ( int nCrv = 0 ; nCrv < pMyCompoEdge1->GetCurveCount() ; ++ nCrv) { + const ICurve* pCurve = pMyCompoEdge1->GetCurve( nCrv) ; + if ( pCurve == nullptr || ! pCurve->IsValid()) + return false ; + double dLen = 0. ; + pCurve->GetLength( dLen) ; + if ( dLen > dMaxLen) { + dMaxLen = dLen ; + nCrvInd = nCrv ; + } + } + pMyCompoEdge1->ChangeStartPoint( nCrvInd + 0.5) ; + // Recupero il punto iniziale della prima curva + Point3d ptStart1 ; pMyCompoEdge1->GetStartPoint( ptStart1) ; + // Recupero il punto più vicino sulla seconda curva + double dUStart = 0. ; + int nFlag = 0 ; + DistPointCurve( ptStart1, *pMyCompoEdge2).GetParamAtMinDistPoint( 0., dUStart, nFlag) ; + pMyCompoEdge2->ChangeStartPoint( dUStart) ; + // Verifico che le tangenti iniziali siano concordi + Vector3d vtStart1 ; pMyCompoEdge1->GetStartDir( vtStart1) ; + Vector3d vtStart2 ; pMyCompoEdge2->GetStartDir( vtStart2) ; + if ( vtStart1 * vtStart2 < - EPS_SMALL) + pMyCompoEdge2->Invert() ; + } + + // Sostiuisco i risultati + pCompoEdge1->Clear() ; pCompoEdge1->CopyFrom( pMyCompoEdge1) ; + pCompoEdge2->Clear() ; pCompoEdge2->CopyFrom( pMyCompoEdge2) ; + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per determinare la normale di una superficie generica in un punto +static bool +GetNormalAtPoint( const ISurf* pSurf, const Point3d& pt, Vector3d& vtN) +{ + // Verifico che le due superfici siano valide + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + const double dMinLen = 20. * EPS_SMALL ; + const double dMinArea = dMinLen * dMinLen ; + + // Se è Trimesh, recupero la normale del triangolo più vicino al punto scelto + if ( pSurf->GetType() == SRF_TRIMESH) { + const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + int nTria = 0 ; + DistPointSurfTm( pt, *pStm).GetMinDistTriaIndex( nTria) ; + Triangle3d Tria ; + if ( ! pStm->GetTriangle( nTria, Tria)) + return false ; + // se il triangolo è rappresentativo, recupero la sua normale + if ( Tria.GetArea() > dMinArea) + vtN = Tria.GetN() ; + else { + BBox3d BBoxPt ; + BBoxPt.Add( pt) ; + BBoxPt.Expand( dMinLen + 2. * EPS_SMALL) ; + INTVECTOR vT ; + pStm->GetAllTriaOverlapBox( BBoxPt, vT) ; + int nBestTria = -1 ; + double dMaxArea = dMinArea ; + for ( const int& nT : vT) { + if ( pStm->GetTriangle( nT, Tria)) { + double dCurrArea = Tria.GetArea() ; + if ( dCurrArea > dMaxArea) { + dMaxArea = dCurrArea ; + nBestTria = nT ; + } + } + } + if ( nBestTria == -1) // recupero lo stesso il più vicino ( calcolato prima) + nBestTria = nTria ; + if ( ! pStm->GetTriangle( nBestTria, Tria)) + return false ; + vtN = Tria.GetN() ; + } + } + // Se è Bezier, la normale è calcolata automaticamente + else if ( pSurf->GetType() == SRF_BEZIER) { + const ISurfBezier* pSbz = GetSurfBezier( pSurf) ; + if ( pSbz == nullptr || ! pSbz->IsValid()) + return false ; + if ( ! DistPointSurfBz( pt, *pSbz).GetNorm( vtN)) + return false ; + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per Splittare una Patch con un'altra +static bool +SplitPatchWithPatch( SurfPatches& SurfPatchA, SurfPatches& SurfPatchB, double dLinTol) +{ + // Definisco la tolleranza di parametro + const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- euristica, modificabile + + // Scorro le Patch della superficie A + for ( int nPatchA = 0 ; nPatchA < int( SurfPatchA.CompoPathces.size()) ; ++ nPatchA) { + // Recupero la PatchA + CurveComposite& PatchA = SurfPatchA.CompoPathces[nPatchA] ; + Point3d& ptStartA = SurfPatchA.vPatches[nPatchA].ptStart ; + Point3d& ptEndA = SurfPatchA.vPatches[nPatchA].ptEnd ; + // Scorro le Patch della supericie B + for ( int nPatchB = 0 ; nPatchB < int( SurfPatchB.CompoPathces.size()) ; ++ nPatchB) { + // Recupero la PatchB + CurveComposite& PatchB = SurfPatchB.CompoPathces[nPatchB] ; + Point3d& ptStartB = SurfPatchB.vPatches[nPatchB].ptStart ; + Point3d& ptEndB = SurfPatchB.vPatches[nPatchB].ptEnd ; + + // Verifico se gli estremi giaciono sulle linee + double dDist = 0. ; + double dPar = 0., dParS = 0., dParE = 0. ; + int nFlag = 0 ; + bool bSplit = false ; + Point3d ptInters ; + + // Estremi B su PatchA ( sono tutti tratti lineari, quindi nel 3d va bene) + DistPointCurve DLL0( ptStartB, PatchA) ; + bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol && + DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) && + PatchA.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + if ( ! bSplit) { + DistPointCurve DLL1( ptEndB, PatchA) ; + bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol && + DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) && + PatchA.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + } + // Se Split della PatchA richiesto + if ( bSplit) { + // Split della Patch + PatchA.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; + SimplePatch NextPatch( ptInters, ptEndA, 0, false) ; + SurfPatchA.vPatches.insert( SurfPatchA.vPatches.begin() + nPatchA + 1, NextPatch) ; + ptEndA = ptInters ; + // Split della curva composita associata + CurveComposite* pCompoAfter( PatchA.Clone()) ; + PatchA.TrimEndAtParam( dPar) ; + pCompoAfter->TrimStartAtParam( dPar) ; + SurfPatchA.CompoPathces.insert( SurfPatchA.CompoPathces.begin() + nPatchA + 1, *pCompoAfter) ; + // Aggiorno i contatori + -- nPatchA ; + break ; + } + + // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene) + DistPointCurve DLL2( ptStartA, PatchB) ; + bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol && + DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) && + PatchB.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + if ( ! bSplit) { + DistPointCurve DLL3( ptEndA, PatchB) ; + bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol && + DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) && + PatchB.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + } + // Se Split della PatchB richiesto + if ( bSplit) { + // Split della Patch + PatchB.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; + SimplePatch NextPatch( ptInters, ptEndB, 0, false) ; + SurfPatchB.vPatches.insert( SurfPatchB.vPatches.begin() + nPatchB + 1, NextPatch) ; + ptEndB = ptInters ; + // Split della curva composita associata + CurveComposite* pCompoAfter( PatchB.Clone()) ; + PatchB.TrimEndAtParam( dPar) ; + pCompoAfter->TrimStartAtParam( dPar) ; + SurfPatchB.CompoPathces.insert( SurfPatchB.CompoPathces.begin() + nPatchB + 1, *pCompoAfter) ; + // Aggiorno i contatori + -- nPatchB ; + } + } + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per ottenere le Patch dei bordi di una superficie +static bool +CalcPatches( const POLYLINEVECTOR& vPLBorders, double dAngTol, POLYLINEMATRIX& matPLPatches) +{ + // Ogni PolyLine di bordo viene vista come un insieme di Patches + matPLPatches.reserve( vPLBorders.size()) ; + for ( const PolyLine& PL : vPLBorders) { + // Approssimo mediante tolleranza angolare ricavando l'insieme delle Patches + matPLPatches.emplace_back( POLYLINEVECTOR{}) ; + if ( ! GetPointSetByAngTol( PL, dAngTol, matPLPatches.back())) + return false ; + // Trasferisco le TempProps + for ( PolyLine newPL : matPLPatches.back()) + newPL.SetTempProp( 0, PL.GetTempProp( 0)) ; + } + + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione per scremare le curve di Bordo tenendo solo i tratti utili concatenabili +static bool +ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, + ICRVCOMPOPOVECTOR& vCompoResult) +{ + // Se non ho Polyline non faccio nulla + if ( vPLBorders.empty()) + return true ; + vCompoResult.clear() ; + + // Approssimo le curve + // NB. Per Patch si intende un tratto di PolyLine dove la tangenza di ogni punto con i suoi 2 successivi + // rimane all'interno della tolleranza angolare definita + // Ogni curva di bordo viene quindi vista come un insieme di Patches + POLYLINEMATRIX matPLPatches ; + if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatches)) + return false ; + // Tengo anche la curva composita rispettiva per ogni Patch ( serve più avanti) [*] + COMPOMATRIX matCompoPatches ; matCompoPatches.reserve( vPLBorders.size()) ; + for ( const POLYLINEVECTOR& PLBorder : matPLPatches) { + matCompoPatches.emplace_back( COMPOVECTOR{}) ; + for ( const PolyLine& PLPatch : PLBorder) { + matCompoPatches.back().emplace_back( CurveComposite()) ; + matCompoPatches.back().back().FromPolyLine( PLPatch) ; + } + } + + // Ogni curva Patch diventa un insieme di tratti attivi definiti dagli estremi calcolati + // NB. In questo modo si salvano solo gli estremi della curva Patch, mentre la sua geometria + // è rimasta memorizzata in precedenza [*] + // Ogni bordo viene quindi visto come un insieme di Patch semplici ( per adesso tutte attive) + SimpleBorderVector vvSimpleBorder ; vvSimpleBorder.reserve( matPLPatches.size()) ; + for ( int i = 0 ; i < int( matPLPatches.size()) ; ++ i) { + vvSimpleBorder.emplace_back( SimpleBorder()) ; + for ( int j = 0 ; j < int( matPLPatches[i].size()) ; ++ j) { + Point3d ptS ; matPLPatches[i][j].GetFirstPoint( ptS) ; + Point3d ptE ; matPLPatches[i][j].GetLastPoint( ptE) ; + vvSimpleBorder.back().emplace_back( ptS, ptE, i, false) ; + } + } + #if DEBUG_CHAIN_CURVES + VC.clear() ; VT.clear() ; + for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) { + for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) { + VT.emplace_back( matCompoPatches[i][j].Clone()) ; + VC.emplace_back( RED) ; + IGeoPoint3d* ptS = CreateGeoPoint3d() ; + ptS->Set( vvSimpleBorder[i][j].ptStart) ; + VT.emplace_back( ptS) ; + VC.emplace_back( AQUA) ; + IGeoPoint3d* ptE = CreateGeoPoint3d() ; + ptE->Set( vvSimpleBorder[i][j].ptEnd) ; + VT.emplace_back( ptE) ; + VC.emplace_back( AQUA) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\EdgesAndPoints.nge") ; + #endif + + // In generale se sono state selezionate più superfici, non è garantito che tutti gli estremi + // delle Patch coicidano solo con altri estremi di altre Patches ( può capitare che un estremo di + // una Patch cada ad esempio a metà di un'altra Patch e non nei suoi estremi ) + // Soluzione : si spezzano le Patch ulteriormente in modo che ogni estremo di patch sia o nell'intorno + // di un altro estremo di patch o isolato ( ad esempio nei bordi più esterni ) + const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- eursitica, modificabile + for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) { + // Recupero la curva corrente + SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ; + // Scorro i suoi Edges + for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) { + // Recupero il tratto di curva corrente + CurveComposite& CurrCompo = matCompoPatches[nCurrCrv][nCurrEdge] ; + // Scorro le curve successive + for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) { + // Recupero la curva successiva + SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ; + // Scorro i suoi Edges + for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) { + // Se appartiene allo stesso bordo, passo alla seguente + if ( NextCurve[nNextEdge].nBorder == CurrCurve[nCurrEdge].nBorder) + continue ; + // Recupero il tratto di curva corrente + CurveComposite& NextCompo = matCompoPatches[nNextCrv][nNextEdge] ; + // Verifico se gli estremi giaciono sulle linee + double dDist = 0. ; + double dPar = 0., dParS = 0., dParE = 0. ; + int nFlag = 0 ; + bool bSplit = false ; + Point3d ptInters ; + + // Estremi Next su LineCurr ( sono tutti tratti lineari, quindi nel 3d va bene) + DistPointCurve DLL0( NextCurve[nNextEdge].ptStart, CurrCompo) ; + bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol && + DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) && + CurrCompo.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + if ( ! bSplit) { + DistPointCurve DLL1( NextCurve[nNextEdge].ptEnd, CurrCompo) ; + bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol && + DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) && + CurrCompo.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + } + // Split dell'Edge se richiesto + if ( bSplit) { + #if DEBUG_CHAIN_CURVES + VT.clear() ; VC.clear() ; + VT.emplace_back( NextCompo.Clone()) ; + VC.emplace_back( ORANGE) ; + VT.emplace_back( CurrCompo.Clone()) ; + VC.emplace_back( LIME) ; + SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ; + #endif + // Aggiorno gli Edges + CurrCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; + SimplePatch NextEdge( ptInters, CurrCurve[nCurrEdge].ptEnd, + CurrCurve[nCurrEdge].nBorder, false) ; + CurrCurve.insert( CurrCurve.begin() + nCurrEdge + 1, NextEdge) ; + CurrCurve[nCurrEdge].ptEnd = ptInters ; + // Aggiorno le Curve + CurveComposite* pCompoAfter( CurrCompo.Clone()) ; + CurrCompo.TrimEndAtParam( dPar) ; + pCompoAfter->TrimStartAtParam( dPar) ; + matCompoPatches[nCurrCrv].insert( matCompoPatches[nCurrCrv].begin() + nCurrEdge + 1, *pCompoAfter) ; + // Aggiorno i contatori + -- nCurrEdge ; + nNextCrv = int( vvSimpleBorder.size()) ; + break ; + } + + // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene) + DistPointCurve DLL2( CurrCurve[nCurrEdge].ptStart, NextCompo) ; + bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol && + DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) && + NextCompo.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + if ( ! bSplit) { + DistPointCurve DLL3( CurrCurve[nCurrEdge].ptEnd, NextCompo) ; + bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol && + DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) && + NextCompo.GetDomain( dParS, dParE) && + dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; + } + // Split dell'Edge se richiesto + if ( bSplit) { + #if DEBUG_CHAIN_CURVES + VT.clear() ; VC.clear() ; + VT.emplace_back( NextCompo.Clone()) ; + VC.emplace_back( ORANGE) ; + VT.emplace_back( CurrCompo.Clone()) ; + VC.emplace_back( LIME) ; + SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ; + #endif + // Aggiorno gli Edges + NextCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; + SimplePatch NextEdge( ptInters, NextCurve[nNextEdge].ptEnd, + NextCurve[nNextEdge].nBorder, false) ; + NextCurve.insert( NextCurve.begin() + nNextEdge + 1, NextEdge) ; + NextCurve[nNextEdge].ptEnd = ptInters ; + // Aggiorno le curve + CurveComposite* pCompoAfter( NextCompo.Clone()) ; + NextCompo.TrimEndAtParam( dPar) ; + pCompoAfter->TrimStartAtParam( dPar) ; + matCompoPatches[nNextCrv].insert( matCompoPatches[nNextCrv].begin() + nNextEdge + 1, *pCompoAfter) ; + // Aggiorno i contatori + -- nNextEdge ; + } + } + } + } + } + #if DEBUG_CHAIN_CURVES + VC.clear() ; VT.clear() ; + for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) { + for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) { + VT.emplace_back( matCompoPatches[i][j].Clone()) ; + VC.emplace_back( RED) ; + IGeoPoint3d* pt = CreateGeoPoint3d() ; + pt->Set( vvSimpleBorder[i][j].ptStart) ; + VT.emplace_back( pt) ; + VC.emplace_back( AQUA) ; + pt = CreateGeoPoint3d() ; + pt->Set( vvSimpleBorder[i][j].ptEnd) ; + VT.emplace_back( pt) ; + VC.emplace_back( AQUA) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\BordersWithOverlaps.nge") ; + #endif + + // Si eliminano ora tutte le Patch che si sovrappongono, in modo da ottenere solo un + // le Patch che rappresentano il bordo esterno + const double MAXPOINT = 10 ; + for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) { + // Recupero la curva corrente + SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ; + // Scorro i suoi Edges + for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) { + // Se Edge cancellato, passo al successivo + if ( CurrCurve[nCurrEdge].bErase) + continue ; + // Recupero i due estremi dell'Edge + Point3d& ptCurrStart = CurrCurve[nCurrEdge].ptStart ; + Point3d& ptCurrEnd = CurrCurve[nCurrEdge].ptEnd ; + // Scorro le curve successive + for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) { + // Recupero la curva successiva + SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ; + // Scorro i suoi Edges + for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) { + // Se Edge cancellato, passo al successivo + #if 0 + // Se pezze si superficie piccolissime, si rischia di eliminare tutti i + // tratti Next con il primo tratto Curr e lasciare poi il Secondo Curr senza + // elementi da eliminare ( TrimTractor.nge) + if ( NextCurve[nNextEdge].bErase) + continue ; + #endif + // Recupero i due estremi di riferimento + Point3d& ptNextStart = NextCurve[nNextEdge].ptStart ; + Point3d& ptNextEnd = NextCurve[nNextEdge].ptEnd ; + // Controllo se i due estremi coincidono + if ( ( AreSamePointEpsilon( ptCurrStart, ptNextStart, dLinTol) && + AreSamePointEpsilon( ptCurrEnd, ptNextEnd, dLinTol)) || + ( AreSamePointEpsilon( ptCurrStart, ptNextEnd, dLinTol) && + AreSamePointEpsilon( ptCurrEnd, ptNextStart, dLinTol))) { + // Controllo che i punti coincidano + CurveComposite* pCompoCurr = &matCompoPatches[nCurrCrv][nCurrEdge] ; + CurveComposite* pCompoNext = &matCompoPatches[nNextCrv][nNextEdge] ; + if ( pCompoCurr == nullptr || pCompoNext == nullptr) + return false ; + double dLenCurr ; pCompoCurr->GetLength( dLenCurr) ; + bool bErase = true ; + for ( int nP = 1 ; bErase && nP <= MAXPOINT ; ++ nP) { + double dPar = 0. ; + pCompoCurr->GetParamAtLength( ( dLenCurr / MAXPOINT) * nP, dPar) ; + Point3d ptCurr ; + pCompoCurr->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptCurr) ; + double dSqDist = 0. ; + DistPointCurve( ptCurr, *pCompoNext).GetSqDist( dSqDist) ; + bErase = ( dSqDist < dLinTol * dLinTol + SQ_EPS_SMALL) ; + } + // Disabilito i rispettivi Edges se necessario + if ( bErase) { + CurrCurve[nCurrEdge].bErase = true ; + NextCurve[nNextEdge].bErase = true ; + } + } + } + } + } + } + + // Dalle PolyLine recupero delle curve composite ( quindi anch'esse come insieme di tratti linari) + ICRVCOMPOPOVECTOR vCompoPatches ; vCompoPatches.reserve( vvSimpleBorder.size()) ; + for ( const PolyLine& PL : vPLBorders) { + if ( ! vCompoPatches.emplace_back( CreateCurveComposite()) || + ! vCompoPatches.back()->FromPolyLine( PL)) + return false ; + vCompoPatches.back()->SetTempProp( PL.GetTempProp( 0), 0) ; + } + + // Recupero solo i sottotratti di curva validi ( quindi che non fanno overlap tra loro) + for ( int nCrv = 0 ; nCrv < int( vvSimpleBorder.size()) ; ++ nCrv) { + // Recupero la curva + SimpleBorder& CrvEdge = vvSimpleBorder[nCrv] ; + // Scorro i suoi edges + for ( int nEdge = 0 ; nEdge < int( CrvEdge.size()) ; ++ nEdge) { + // Se edge non attivo, passo al successivo + if ( CrvEdge[nEdge].bErase) + continue ; + // Se punto iniziale finale uguali + // [ Se pezze di superficie piccolissime, si rischia di eliminare tutti i + // tratti Next con il primo tratto Curr e lasciare poi il Secondo Curr senza + // elementi da eliminare ( TrimTractor.nge) ] + if ( AreSamePointApprox( CrvEdge[nEdge].ptStart, CrvEdge[nEdge].ptEnd)) + vCompoResult.emplace_back( Release( vCompoPatches[nCrv])) ; + else { + // Recupero il tratto di curva e lo memorizzo + double dUStart = 0., dUEnd = 0. ; + vCompoPatches[nCrv]->GetParamAtPoint( CrvEdge[nEdge].ptStart, dUStart, dLinTol) ; + vCompoPatches[nCrv]->GetParamAtPoint( CrvEdge[nEdge].ptEnd, dUEnd, dLinTol) ; + vCompoResult.emplace_back( ConvertCurveToComposite( vCompoPatches[nCrv]->CopyParamRange( dUStart, dUEnd))) ; + vCompoResult.back()->SetTempProp( vCompoPatches[nCrv]->GetTempProp( 0), 0) ; + } + } + } + // Conservo solo le curve valide + for ( int nCrv = 0 ; nCrv < int( vCompoResult.size()) ; ++ nCrv) { + if ( IsNull( vCompoResult[nCrv]) || ! vCompoResult[nCrv]->IsValid()) { + vCompoResult.erase( vCompoResult.begin() + nCrv) ; + -- nCrv ; + } + } + #if DEBUG_CHAIN_CURVES // Debug per le Patch risultanti + VT.clear() ; VC.clear() ; + for ( int i = 0 ; i < int( vCompoResult.size()) ; ++ i) { + VT.emplace_back( vCompoResult[i]->Clone()) ; + VC.emplace_back( ORANGE) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\FinalChainedBorders.nge") ; + #endif + + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione per concatenare nello spazio 3d le Curve Patches. +// NB. Tutte le vCompoPathes sono formate da tratti lineari. +static bool +ChainCompoPatches( ICRVCOMPOPOVECTOR& vCompoPatches, double dChainTol, + ICRVCOMPOPOVECTOR& vCompoChained) +{ + // Controllo dei parametri + if ( vCompoPatches.empty()) + return false ; + vCompoChained.clear() ; + + // Controllo la validità delle curve + for ( const ICurveComposite* pCrvCompo : vCompoPatches) { + if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + return false ; + } + + // La concatenazione parte dalla curva più lunga + double dMaxLen = - INFINITO ; + int nInd = 0 ; + for ( int i = 0 ; i < int( vCompoPatches.size()) ; ++ i) { + double dLen = 0. ; + vCompoPatches[i]->GetLength( dLen) ; + if ( dLen > dMaxLen) { + dMaxLen = dLen ; + nInd = i ; + } + } + swap( vCompoPatches[0], vCompoPatches[nInd]) ; + + // [ TODO : Algoritmo migliorabile nei controlli ] + // Scorro le curve + vCompoChained.reserve( vCompoPatches.size()) ; + BOOLVECTOR vbCrvChained( vCompoPatches.size(), false) ; + for ( int nCurrCrv = 0 ; nCurrCrv < int( vCompoPatches.size()) ; ++ nCurrCrv) { + // Se curva già concatenata, passo alla successiva ( no biforcazioni ammesse -> errore ) + if ( vbCrvChained[nCurrCrv]) + continue ; + // Definisco una nuova curva di concatenazione e recupero il suo estremo finale + Point3d ptEnd ; + if ( ! vCompoChained.emplace_back( CloneCurveComposite( vCompoPatches[nCurrCrv])) || + ! vCompoChained.back()->GetEndPoint( ptEnd)) + return false ; + // Trasferisco le TempProps alle sottocurve + for ( int nU = 0 ; nU < vCompoChained.back()->GetCurveCount() ; ++ nU) + vCompoChained.back()->SetCurveTempProp( nU, vCompoPatches[nCurrCrv]->GetTempProp( 0), 0) ; + // Cerco tra le altre curve disponibili una candidata alla concatenazione + for ( int nNextCrv = 0 ; nNextCrv < int( vCompoPatches.size()) ; ++ nNextCrv) { + if ( nNextCrv == nCurrCrv || vbCrvChained[nNextCrv]) + continue ; + // Recupero i suoi estremi [ sono tratti lineari, la ricerca è immediata ] + Point3d ptStartN ; vCompoPatches[nNextCrv]->GetStartPoint( ptStartN) ; + Point3d ptEndN ; vCompoPatches[nNextCrv]->GetEndPoint( ptEndN) ; + // Se estremi distanti, passo alla successiva + bool bChain = AreSamePointEpsilon( ptEnd, ptStartN, dChainTol) ; + bool bChainInv = ( ( ! bChain) && AreSamePointEpsilon( ptEnd, ptEndN, dChainTol)) ; + if ( ! bChain && ! bChainInv) + continue ; + // Recupero la lunghezza della curva + double dLenN = 0. ; vCompoPatches[nNextCrv]->GetLength( dLenN) ; + // Se la lunghezza della curva è più piccola della tolleranza + if ( dLenN < dChainTol + EPS_ZERO) { + // La curva corrente non viene aggiunta, ma viene modificato l'estremo finale corrente + // nel punto medio + vCompoChained.back()->ModifyEnd( Media( ptEndN, ptEnd)) ; + } + // Se la lunghezza è maggiore della tolleranza + else { + // Recupero la curva successiva + PtrOwner pCrv( CloneCurveComposite( vCompoPatches[nNextCrv])) ; + if ( IsNull( pCrv) || ! pCrv->IsValid()) + return false ; + // Se necessario inverto ( potrebbe capitare per triangoli male orientati) + if ( bChainInv) + pCrv->Invert() ; + // Trasferisco le TempProps alle sottocurve + for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU) + pCrv->SetCurveTempProp( nU, pCrv->GetTempProp( 0), 0) ; + // Concateno + if ( ! vCompoChained.back()->AddCurve( pCrv->Clone(), true, dChainTol)) + return false ; + } + // Aggiornamento dei parametri + vbCrvChained[nNextCrv] = true ; // curva in una concatenazione + nNextCrv = 0 ; // reset contatore per curva next + if ( ! vCompoChained.back()->GetEndPoint( ptEnd)) // aggiornamento punto finale della concatenazione + return false ; + } + } + // Verifico la validità delle curve ottenute + for ( int i = 0 ; i < int( vCompoChained.size()) ; ++ i) { + if ( IsNull( vCompoChained[i]) || ! vCompoChained[i]->IsValid()) + return false ; + // Se curva al di sotto della tolleranza, la scarto + // ( Capita se ci sono facce/superfici molto strette. La concatenazione chiude in automatico + // la curva complessiva isolando quindi queste entità) + double dLen = 0. ; + if ( ! vCompoChained[i]->GetLength( dLen) || dLen < dChainTol) { + vCompoChained.erase( vCompoChained.begin() + i) ; + -- i ; + } + } + #if DEBUG_CHAIN_CURVES // Debug curve concatenate grezze + VT.clear() ; VC.clear() ; + for ( const ICurveComposite* pCompo : vCompoChained) { + VT.emplace_back( pCompo->Clone()) ; + VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\ChainedCurves.nge") ; + #endif + + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione che restituisce una prima semplificazione e concatenazione delle curve +// di bordi definiti mediante PolyLines +static bool +GetRawEdges( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, + ICRVCOMPOPOVECTOR& vCompoChained) +{ + // Se non o curve di bordo, allora non faccio nulla + if ( vPLBorders.empty()) + return true ; + vCompoChained.clear() ; + + // Recupero le curve di Bordo che non effettuano Overlap tra loro ( sempre solo tratti lineari) + ICRVCOMPOPOVECTOR vCompoPatches ; + if ( ! ManagePatches( vPLBorders, dLinTol, dAngTol, vCompoPatches)) + return false ; + + // Concateno le curve risultanti + const double CHAIN_TOL = 50. * EPS_SMALL ; + if ( ! ChainCompoPatches( vCompoPatches, CHAIN_TOL, vCompoChained)) + return false ; + + // Se le curve risultano aperte con estremi entro la tolleranza, le chiudo + for ( int i = 0 ; i < int( vCompoChained.size()) ; ++ i) { + if ( vCompoChained[i] == nullptr || ! vCompoChained[i]->IsValid()) + return false ; + Point3d ptS ; vCompoChained[i]->GetStartPoint( ptS) ; + Point3d ptE ; vCompoChained[i]->GetEndPoint( ptE) ; + if ( AreSamePointEpsilon( ptS, ptE, dLinTol)) { + vCompoChained[i]->Close() ; + // Riporto la Temp Prop + int nTmpProp0 = vCompoChained[i]->GetFirstCurve()->GetTempProp( 0) ; + vCompoChained[i]->SetCurveTempProp( vCompoChained[i]->GetCurveCount() - 1, nTmpProp0, 0) ; + } + } + + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione per calcolare le Edge Curves per la creazione della superficie di Bezier Ruled +// mediante spessore e tolleranza associata +static bool +BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol, + double dThick, double dThickTol) +{ + // Se non ho curve, non faccio nulla + if ( vCompoChained.empty()) + return true ; + const double ANG_SPLIT = 65. ; + + // Scorro le curve + ICRVCOMPOPOVECTOR vCrvResult ; + for ( const ICurveComposite* pCompoChained : vCompoChained) { + // Verifico la sua validità + if ( pCompoChained == nullptr || ! pCompoChained->IsValid()) + return false ; + // Recupero la PolyLine associata ( senza alcuna approssimazione) + PolyLine myPL ; + if ( ! pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL)) + return false ; + // Approssimo la curva mediante Set di punti considerando la tolleranza angolare + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( myPL, ANG_SPLIT, vPL)) + return false ; + // Scorro le PolyLine ricavate e recupero i punti di Split ( tratti da rimuovere) + BIPNTVECTOR vBiPntSplit ; vBiPntSplit.reserve( 2) ; + for ( const PolyLine& PL : vPL) { + double dLen ; PL.GetLength( dLen) ; + if ( abs( dLen - dThick) < dThickTol) { + Point3d ptStart ; PL.GetFirstPoint( ptStart) ; + Point3d ptEnd ; PL.GetLastPoint( ptEnd) ; + vBiPntSplit.emplace_back( make_pair( ptStart, ptEnd)) ; + } + } + // Se non ho ottenuto esattamente due tratti, non analizzo più la curva corrente + if ( int( vBiPntSplit.size()) != 2) { + LOG_INFO( GetEGkLogger(), "Warning in Trimming : Detected more Curves by Thick values") ; + break ; // lascio la curva invariata + } + if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained))) + return false ; + double dU0 = 0., dU1 = 0. ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].second, dU0) ; + vCrvResult.back()->ChangeStartPoint( dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].first, dU1) ; + vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( 0., dU1))) ; + if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained))) + return false ; + vCrvResult.back()->ChangeStartPoint( dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].second, dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].first, dU1) ; + vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( dU0, dU1))) ; + } + + swap( vCrvResult, vCompoChained) ; + return true ; +} + +//----------------------------------------------------------------------------- +// Funzione per calcolare le Edge Curves per la creazione della superficie di Bezier Ruled +// mediante punti di rottura +static bool +BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol, + const BIPNTVECTOR& vBreakingPts) +{ + // Se non ho curve, non faccio nulla + if ( vCompoChained.empty()) + return true ; + // Se non ho punti di rottura, non faccio nulla + if ( vBreakingPts.empty()) + return true ; + // Se ho punti di rottura in comune, errore + for ( int i = 0 ; i < int( vBreakingPts.size()) ; ++ i) { + if ( AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[i].second, dLinTol)) + return false ; + for ( int j = i + 1 ; j < int( vBreakingPts.size()) ; ++ j) { + if ( AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[j].first, dLinTol) || + AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[j].second, dLinTol) || + AreSamePointEpsilon( vBreakingPts[i].second, vBreakingPts[j].first, dLinTol) || + AreSamePointEpsilon( vBreakingPts[i].second, vBreakingPts[j].second, dLinTol)) + return false ; + } + } + + #if DEBUG_BRK_POINTS + VC.clear() ; VT.clear() ; + for ( const ICurveComposite* _pCompoChained : vCompoChained) { + VT.emplace_back( _pCompoChained->Clone()) ; + VC.emplace_back( RED) ; + } + for ( const BIPOINT& _Bipt : vBreakingPts) { + IGeoPoint3d* _ptS = CreateGeoPoint3d() ; _ptS->Set( _Bipt.first) ; + IGeoPoint3d* _ptE = CreateGeoPoint3d() ; _ptE->Set( _Bipt.second) ; + VT.emplace_back( _ptS) ; + VT.emplace_back( _ptE) ; + VC.emplace_back( AQUA) ; + VC.emplace_back( LIME) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\Brk.nge") ; + #endif + + // Scorro le curve + ICRVCOMPOPOVECTOR vCrvResult ; + for ( const ICurveComposite* pCompoChained : vCompoChained) { + // Verifico che sia valida + if ( pCompoChained == nullptr || ! pCompoChained->IsValid()) + return false ; + // Copio la curva, dato che potrei spezzarla + ICRVCOMPOPOVECTOR vCompoParts ; vCompoParts.reserve( vBreakingPts.size()) ; + if ( ! vCompoParts.emplace_back( CloneCurveComposite( pCompoChained))) + return false ; + for ( const BIPOINT& BiPnts : vBreakingPts) { + // Scorro i tratti ( inizialmente la curva stessa) + for ( int i = 0 ; i < int( vCompoParts.size()) ; ++ i) { + // Controllo che la coppia di punti giacia su quella curva + if ( ! vCompoParts[i]->IsPointOn( BiPnts.first, dLinTol) || + ! vCompoParts[i]->IsPointOn( BiPnts.second, dLinTol)) + continue ; + // Se entrambi sulla curva, recupero il tratto più lungo da loro definito + double dUS = 0. ; vCompoParts[i]->GetParamAtPoint( BiPnts.first, dUS, dLinTol) ; + double dUE = 0. ; vCompoParts[i]->GetParamAtPoint( BiPnts.second, dUE, dLinTol) ; + PtrOwner pCrvA( vCompoParts[i]->CopyParamRange( dUS, dUE)) ; + PtrOwner pCrvB( vCompoParts[i]->CopyParamRange( dUE, dUS)) ; + // Se la curva corrente è chiusa + if ( vCompoParts[i]->IsClosed()) { + if ( IsNull( pCrvA) || IsNull( pCrvB)) + return false ; + double dLenA = 0. ; pCrvA->GetLength( dLenA) ; + double dLenB = 0. ; pCrvB->GetLength( dLenB) ; + if ( dLenA > dLenB) + vCompoParts[i].Set( ConvertCurveToComposite( Release( pCrvA))) ; + else + vCompoParts[i].Set( ConvertCurveToComposite( Release( pCrvB))) ; + } + // Se la curva è aperta + else { + double dUDomS = 0., dUDomE = 0. ; + vCompoParts[i]->GetDomain( dUDomS, dUDomE) ; + PtrOwner pCompoTmp( CloneCurveComposite( vCompoParts[i])) ; + if ( IsNull( pCompoTmp) || ! pCompoTmp->IsValid()) + return false ; + if ( IsNull( pCrvA)) { + pCompoTmp->TrimStartAtParam( dUS) ; + vCompoParts.emplace_back( Release( pCompoTmp)) ; + vCompoParts[i]->TrimEndAtParam( dUE) ; + } + else if ( IsNull( pCrvB)) { + pCompoTmp->TrimStartAtParam( dUE) ; + vCompoParts.emplace_back( Release( pCompoTmp)) ; + vCompoParts[i]->TrimEndAtParam( dUS) ; + } + } + } + } + // Memorizzo tutte le curve valide ottenute dai punti di rottura + for ( int i = 0 ; i < int( vCompoParts.size()) ; ++ i) { + if ( ! IsNull( vCompoParts[i]) && vCompoParts[i]->IsValid()) + vCrvResult.emplace_back( Release( vCompoParts[i])) ; + } + } + + swap( vCrvResult, vCompoChained) ; + return true ; +} + +//----------------------------------------------------------------------------- +static bool +BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol) +{ + // Se non ho curve, non faccio nulla + if ( vCompoChained.empty()) + return true ; + const double ANG_SPLIT = 65. ; + + // Scorro le curve + ICRVCOMPOPOVECTOR vCrvResult ; + for ( const ICurveComposite* pCompoChained : vCompoChained) { + // Verifico la sua validità + if ( pCompoChained == nullptr || ! pCompoChained->IsValid()) + return false ; + // Recupero la PolyLine associata ( senza alcuna approssimazione) + PolyLine myPL ; + if ( ! pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL)) + return false ; + // Approssimo la curva mediante Set di punti considerando la tolleranza angolare + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( myPL, ANG_SPLIT, vPL)) + return false ; + // Se meno di 4 PolyLine non faccio nulla + if ( int( vPL.size()) < 4) { + LOG_INFO( GetEGkLogger(), "Warning in Trimming : Not Detected 2 Curves") ; + return true ; + } + // Scorro le PolyLine e ricavo le due più corte + INTDBLVECTOR vIndPLLen ; vIndPLLen.reserve( vPL.size()) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + double dLen ; vPL[i].GetLength( dLen) ; + vIndPLLen.emplace_back( make_pair( i, dLen)) ; + } + sort( vIndPLLen.begin(), vIndPLLen.end(), []( const INTDBL& IndA, const INTDBL& IndB){ + return ( IndA.second < IndB.second) ; + }) ; + BIPNTVECTOR vBiPntSplit ; vBiPntSplit.reserve( 2) ; + for ( int i = 0 ; i < 2 ; ++ i) { + Point3d ptS ; vPL[vIndPLLen[i].first].GetFirstPoint( ptS) ; + Point3d ptE ; vPL[vIndPLLen[i].first].GetLastPoint( ptE) ; + vBiPntSplit.emplace_back( make_pair( ptS, ptE)) ; + } + + #if DEBUG_BRK + VT.emplace_back( pCompoChained->Clone()) ; + VC.emplace_back( ORANGE) ; + for ( PolyLine& _PL : vPL) { + IGeoPoint3d* _ptS = CreateGeoPoint3d() ; + Point3d _ptStart ; _PL.GetFirstPoint( _ptStart) ; _ptS->Set( _ptStart) ; + VT.emplace_back( _ptS) ; + VC.emplace_back( YELLOW) ; + IGeoPoint3d* _ptE = CreateGeoPoint3d() ; + Point3d _ptEnd ; _PL.GetLastPoint( _ptEnd) ; _ptE->Set( _ptEnd) ; + VT.emplace_back( _ptE) ; + VC.emplace_back( YELLOW) ; + } + for ( BIPOINT& BiPt : vBiPntSplit) { + ICurveLine* pLine = CreateCurveLine() ; + pLine->Set( BiPt.first, BiPt.second) ; + VT.emplace_back( pLine) ; + VC.emplace_back( FUCHSIA) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\SplitRawEdges.nge") ; + #endif + + if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained))) + return false ; + double dU0 = 0., dU1 = 0. ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].second, dU0) ; + vCrvResult.back()->ChangeStartPoint( dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].first, dU1) ; + vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( 0., dU1))) ; + if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained))) + return false ; + vCrvResult.back()->ChangeStartPoint( dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].second, dU0) ; + vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].first, dU1) ; + vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( dU0, dU1))) ; + } + + swap( vCrvResult, vCompoChained) ; + return true ; +} + +//----------------------------------------------------------------------------- +//---------------------------- Estrazione dei Bordi --------------------------- +//----------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// Funzione che restituisce l'insieme dei Bordi di una Superficie ( TriMesh o Bezier) +static bool +InsertLoopsOfSurf( const ISurf* pSurf, POLYLINEVECTOR& vPL) +{ + // Se superficie TriMesh + if ( pSurf->GetType() == SRF_TRIMESH) { + // Recupero la superficie, verificandone la validità + const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + // verifico che tutte le parti siano valide + // ( nel recupero dei Loop alcune superfici presentano delle Part non valide) + double dPartArea = 0. ; + bool bValidParts = true ; + BOOLVECTOR vValidParts ; vValidParts.reserve( pStm->GetPartCount()) ; + for ( int nP = 0 ; nP < pStm->GetPartCount() ; ++ nP) { + vValidParts.emplace_back( pStm->GetPartArea( nP, dPartArea) && dPartArea > SQ_EPS_SMALL) ; + bValidParts = bValidParts && ( vValidParts.back()) ; + } + // Recupero le PolyLine di bordo + if ( bValidParts) { + if ( ! pStm->GetLoops( vPL)) + return false ; + } + else { + for ( int nP = 0 ; nP < pStm->GetPartCount() ; ++ nP) { + if ( vValidParts[nP]) { + POLYLINEVECTOR vPLPart ; + if ( ! pStm->GetPartLoops( nP, vPLPart)) + return false ; + for ( const PolyLine& PL : vPLPart) + vPL.emplace_back( PL) ; + } + } + } + } + + // Se superficie di Bezier + else if ( pSurf->GetType() == SRF_BEZIER) { + // Recupero la superficie, verificandone la validità + const ISurfBezier* pSbz = GetSurfBezier( pSurf) ; + if ( pSbz == nullptr || ! pSbz->IsValid()) + return false ; + // Recupero i Bordi ( questa funzione restituisce dei tratti lineari) + ICRVCOMPOPOVECTOR vLoops ; + if ( ! pSbz->GetLoops( vLoops, true)) + return false ; + // Li inserisco nel vettore ( come insieme di tratti lineari) + // NB. Tengo le tolleranze molto basse per ottenere dei loop rappresentativi della geometria + for ( int nL = 0 ; nL < int( vLoops.size()) ; ++ nL) { + if ( ! IsNull( vLoops[nL]) && vLoops[nL]->IsValid()) { + vPL.emplace_back( PolyLine()) ; + if ( ! vLoops[nL]->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, vPL.back())) + return false ; + } + } + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per ottenere il bordo di una superficie TriMesh definito da un insieme di facce +static bool +GetSurfTmBordersByFaces( const SurfTriMesh* pStm, const INTVECTOR& vFaces, + double dLinTol, POLYLINEVECTOR& vPL) +{ + // Controllo che la superficie sia valida + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + + // Inserisco il primo triangolo valido di ogni faccia + INTVECTOR vTria ; + for ( const int& nF : vFaces) { + int nT = SVT_NULL ; + if ( pStm->GetTriaFromFace( nF, nT)) + vTria.emplace_back( nT) ; + } + + // Definisco un vettore di concatenamento delle curve ( in questo caso segmenti, lati di triangoli) + ICRVCOMPOPOVECTOR vCompoChain ; vCompoChain.reserve( 3 * pStm->GetTriangleCount()) ; + + // Collezione di triangoli già visitati + unordered_set SetTria ; SetTria.reserve( pStm->GetTriangleCount()) ; + // Collezione di Edges come coppia di punti + BIPNTVECTOR vEdges ; vEdges.reserve( 3 * pStm->GetTriangleCount()) ; + + // Finchè ho triangoli di adiacenza non ancora visitati + while ( ! vTria.empty()) { + // Recupero il triangolo corrente + int nCurrTria = vTria.back() ; + // Elimino il triangolo corrente + vTria.pop_back() ; + // Se triangolo non presente, lo aggiungo come visitato + auto IterTria = SetTria.find( nCurrTria) ; + if ( IterTria == SetTria.end()) + SetTria.insert( nCurrTria) ; + // Se triangolo già visitato, passo al successivo + else + continue ; + + // Recupero il triangolo corrente ( definito dai suoi 3 vertici ) + int nTriaVertices[3] ; + pStm->GetTriangle( nCurrTria, nTriaVertices) ; + + // Recupero i tre triangoli adiacenti al triangolo corrente + int nIdAdjTriaId[3] ; + if ( ! pStm->GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId)) + return false ; + // Scorro le adiacenze + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + // Recupero l'indice del triangolo adiacente + int nTriaAdj = nIdAdjTriaId[nAdj] ; + // Inserisco il lato orientato del triangolo se : + // - Non ho adiacenze + // - L'adiacenza avviene su una faccia da non considerare + bool bInsertEdge = false ; + if ( nTriaAdj == SVT_NULL) + bInsertEdge = true ; + else { + // Recupero la faccia del triangolo adiacente + int nFaceAdj = pStm->GetFacetFromTria( nTriaAdj) ; + // Se appartiene ad una faccia da inserire + if ( find( vFaces.begin(), vFaces.end(), nFaceAdj) != vFaces.end()) + vTria.push_back( nTriaAdj) ; + // Se appartiene ad una faccia da non considerare, memorizzo il suo Edge orientato + else + bInsertEdge = true ; + } + + // Se richiesto, memorizzo l'Edge + if ( bInsertEdge) { + Point3d ptS ; pStm->GetVertex( nTriaVertices[nAdj % 3], ptS) ; + Point3d ptE ; pStm->GetVertex( nTriaVertices[( nAdj + 1) % 3], ptE) ; + if ( vCompoChain.emplace_back( CreateCurveComposite())) { + vCompoChain.back()->AddPoint( ptS) ; + vCompoChain.back()->AddLine( ptE) ; + } + } + } + } + + // Recupero i tratti di PolyLine dei triangoli + ICRVCOMPOPOVECTOR vCompoChained ; + if ( ! ChainCompoPatches( vCompoChain, dLinTol, vCompoChained)) + return false ; + for ( const ICurveComposite* pCompoChained : vCompoChain) { + if ( pCompoChained != nullptr && pCompoChained->IsValid()) { + vPL.emplace_back( PolyLine()) ; + pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, vPL.back()) ; + } + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per il calcolo dei bordi delle superfici +static bool +GetSurfBorders( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace, double dLinTol, + POLYLINEVECTOR& vPLBorders) +{ + // Verifico che tutte le superfici siano valide e ben definite + for ( const ISurf* pSurf : vSurf) { + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + } + vPLBorders.clear() ; + + // Definisco l'insieme delle PolyLine ricavate dai bordi + // NB. I bordi possono derivare da : + // - Loop di una Bezier + // - Loop di una Superficie TriMesh + // - Insieme di facce di una supericie TriMesh + // Scorro il vettore delle superfici + for ( int nS = 0 ; nS < int( vSurf.size()) ; ++ nS) { + // Recupero la superficie + const ISurf* pSurf = vSurf[nS] ; + if ( pSurf == nullptr) + return false ; + // Recupero le facce associate a quella superficie dal vettore di selezione + INTVECTOR vFaces ; + for ( const SelData& SurfFace : vSurfFace) { + if ( SurfFace.nId == nS && + find( vFaces.begin(), vFaces.end(), SurfFace.nSub) == vFaces.end()) + vFaces.push_back( SurfFace.nSub) ; + } + // Recupero la dimensione del vettore delle PolyLine risultati attuale + int nSize = int( vPLBorders.size()) ; + // Se non ho nessuna faccia e nessun triangolo da scartare, estraggo i bordi complessivi della superficie + if ( int( vFaces.size()) == 1 && vFaces[0] == SEL_SUB_ALL) { + if ( ! InsertLoopsOfSurf( pSurf, vPLBorders)) + return false ; + } + // Se ho più facce da inserire + else { + // Se TriMesh + if ( pSurf->GetType() == SRF_TRIMESH) { + // Recupero la regione TriMesh di base + const SurfTriMesh* pStm = GetBasicSurfTriMesh( pSurf) ; + if ( pStm == nullptr) + return false ; + // Aggiungo i tratti di curva necessari + if ( ! GetSurfTmBordersByFaces( pStm, vFaces, dLinTol, vPLBorders)) + return false ; + } + // Se Bezier, errore, non ho facce per la superficie + if ( pSurf->GetType() == SRF_BEZIER) + return false ; + } + // Associo alle nuove PolyLine ricavate l'indice della superficie corrispondente + for ( int i = nSize ; i < int( vPLBorders.size()) ; ++ i) + vPLBorders[i].SetTempProp( nS, 0) ; + } + + #if DEBUG_BASIC_BORDERS // Debug per Bordi + VT.clear() ; VC.clear() ; + for ( const PolyLine& _PL : vPLBorders) { + ICurveComposite* _pCrv = CreateCurveComposite() ; + _pCrv->FromPolyLine( _PL) ; + VT.emplace_back( _pCrv->Clone()) ; + VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\BasicBorders.nge") ; + #endif + + return true ; +} + +// ---------------------------------------------------------------------------- +// ---------------------------------- Analisi Adiacenze ----------------------- +// ---------------------------------------------------------------------------- +static bool +ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTria, double dAngTol, + unordered_set& setAvoidTria, unordered_set& setNewTria) +{ + // Collezione di triangoli già visitati + unordered_set setTria ; setTria.reserve( vTBox.size()) ; + // Collezioni di triangoli da analizzare + INTVECTOR vTria ; vTria.reserve( int( vTBox.size()) + 1) ; + vTria.push_back( nFirstTria) ; + + // Finchè ho triangoli da visitare + while ( ! vTria.empty()) { + // Recupero il triangolo corrente + int nCurrTria = vTria.back() ; + // Elimino il triangolo corente + vTria.pop_back() ; + + // Se triangolo da evitare, passo al successivo + if ( setAvoidTria.find( nCurrTria) != setAvoidTria.end()) + continue ; + + // Se triangolo mai visitato lo aggiungo tra quelli visitati, altrimenti passo al successivo + if ( setTria.find( nCurrTria) != setTria.end()) + continue ; + setTria.insert( nCurrTria) ; + + // Inserisco il triangolo corrente + setNewTria.insert( nCurrTria) ; + + // Recupero il triangolo corrente e le sue adiacenze + int nTriaVertices[3] ; + if ( ! Stm.GetTriangle( nCurrTria, nTriaVertices)) + return false ; + Triangle3d Tria ; + if ( ! Stm.GetTriangle( nCurrTria, Tria)) + return false ; + int nIdAdjTriaId[3] ; + if ( ! Stm.GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId)) + return false ; + + // Scorro le adiacenze + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + // Recupero l'indice del triangolo corrente + int nTriaAdj = nIdAdjTriaId[nAdj] ; + // Se non ho adiacenza, non faccio nulla + if ( nTriaAdj == SVT_NULL) + continue ; + // Recupero il triangolo adiacente + Triangle3d TriaAdj ; + if ( ! Stm.GetTriangle( nTriaAdj, TriaAdj)) + return false ; + // Se l'adiacenza non è interna al Box corrente, il triangolo rimane visitato + if ( find( vTBox.begin(), vTBox.end(), nTriaAdj) == vTBox.end()) + setTria.insert( nTriaAdj) ; + // Se la normale è fuori dalla tolleranza + if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dAngTol + EPS_ANG_SMALL) * DEGTORAD)) { + // Se tale non è già stato scartato + if ( find( setAvoidTria.begin(), setAvoidTria.end(), nTriaAdj) == setAvoidTria.end()) { + // Azzero i triangoli correnti e ricomincio l'algoritmo + setAvoidTria.insert( nTriaAdj) ; + vTria.clear() ; + vTria.push_back( nFirstTria) ; + setTria.clear() ; + break ; + } + continue ; + } + // Inserisco il triangolo per la ricerca futura + vTria.push_back( nTriaAdj) ; + } + } + + #if DEBUG_FACE_SEARCH + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) { + VT.emplace_back( Stm.CloneTriangle( *Iter)) ; + VC.emplace_back( GREEN) ; + } + for ( auto Iter = setAvoidTria.begin() ; Iter != setAvoidTria.end() ; ++ Iter) { + VT.emplace_back( Stm.CloneTriangle( *Iter)) ; + VC.emplace_back( ORANGE) ; + } + //SaveGeoObj( VT, VC, "C:\\Temp\\2.nge") ; + #endif + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per il recupero delle curve concatenate di bordo dai triangoli classificati +static bool +GetBordersByTriaInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, double dLinTol, + const unordered_set& setNewTria, COMPOVECTOR& vCompoChain, + bool& bAmbiguous) +{ + // I bordi Locali sono definiti dall'insieme degli Edges dei triangoli trovati come validi + BIPNTVECTOR vBiPnts ; + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) { + int nIdVert[3] ; + if ( ! Stm.GetTriangle( *Iter, nIdVert)) + return false ; + int nIdAdjTriaId[3] ; + if ( ! Stm.GetTriangleAdjacencies( *Iter, nIdAdjTriaId)) + return false ; + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + int nTriaAdj = nIdAdjTriaId[nAdj] ; + if ( nTriaAdj == SVT_NULL || + find( setNewTria.begin(), setNewTria.end(), nTriaAdj) == setNewTria.end()) { + vBiPnts.emplace_back( BIPOINT()) ; + if ( ! Stm.GetVertex( nIdVert[nAdj], vBiPnts.back().first) || + ! Stm.GetVertex( nIdVert[( nAdj + 1) % 3], vBiPnts.back().second)) + return false ; + } + } + } + + // Per ogni Edge ricavato, conservo solo le parti interne al Box corrente + INTVECTOR vEdgeToSave ; vEdgeToSave.reserve( vBiPnts.size()) ; + for ( int nEdge = 0 ; nEdge < int( vBiPnts.size()) ; ++ nEdge) { + Point3d& ptL1 = vBiPnts[nEdge].first ; + Point3d& ptL2 = vBiPnts[nEdge].second ; + Vector3d vtDir = ptL2 - ptL1 ; + vtDir.Normalize() ; + INTDBLVECTOR vInters ; + if ( IntersLineBox( ptL1, ptL2, BBoxCurr, vInters, true)) { + if ( int( vInters.size()) == 2) { + vEdgeToSave.push_back( nEdge) ; + // Se edge sul bordo, lo spezzo + if ( vInters[1].first == ILBT_OUT) + ptL2 = ptL1 + ( vtDir * vInters[1].second) ; + if ( vInters[0].first == ILBT_IN) + ptL1 = ptL1 + ( vtDir * vInters[0].second) ; + } + } + } + unordered_set setBiPntsToSave( vEdgeToSave.begin(), vEdgeToSave.end()) ; + int nCurr = 0 ; + for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) { + if ( setBiPntsToSave.count( i)) + vBiPnts[nCurr ++] = vBiPnts[i] ; + } + vBiPnts.resize( nCurr) ; + + #if DEBUG_FACE_SEARCH + for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) { + ICurveLine* pLine = CreateCurveLine() ; + pLine->Set( vBiPnts[i].first, vBiPnts[i].second) ; + VT.emplace_back( pLine) ; + VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ; + } + // SaveGeoObj( VT, VC, "C:\\Temp\\3.nge") ; + #endif + + // Concateno i Segmenti interni al Box corrente + BOOLVECTOR vIndInChain ; vIndInChain.resize( vBiPnts.size(), false) ; + vCompoChain.reserve( vBiPnts.size()) ; + for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) { + // Se già in Chain, passo al successivo + if ( vIndInChain[i]) + continue ; + vIndInChain[i] = true ; + // Recupero gli estremi correnti + Point3d ptCurrStart = vBiPnts[i].first ; + Point3d ptCurrEnd = vBiPnts[i].second ; + // Definisco la nuova curve composita di concatenamento + vCompoChain.emplace_back( CurveComposite()) ; + vCompoChain.back().AddPoint( ptCurrStart) ; + vCompoChain.back().AddLine( ptCurrEnd) ; + // Punti di controllo per Biforcazioni + PNTVECTOR vPtForks ; vPtForks.reserve( vBiPnts.size()) ; + for ( int j = 0 ; j < int( vBiPnts.size()) ; ++ j) { + // Controllo un altro Edge non in Chain, recuperando i suoi estremi + if ( i == j || vIndInChain[j]) + continue ; + Point3d& ptOtherStart = vBiPnts[j].first ; + Point3d& ptOtherEnd = vBiPnts[j].second ; + // Se concatenamento ammissibile + if ( AreSamePointEpsilon( ptCurrEnd, ptOtherStart, dLinTol)) { + // Se su un punto di Biforcazione, sono in un caso ambiguo + for ( const Point3d& ptFork : vPtForks) { + if ( AreSamePointApprox( ptFork, ptCurrEnd)) { + bAmbiguous = true ; + return true ; + } + } + vPtForks.emplace_back( ptCurrEnd) ; + // Altrimenti aggiorno i parametri di ricerca + vCompoChain.back().AddLine( ptOtherEnd) ; + ptCurrEnd = ptOtherEnd ; + vIndInChain[j] = true ; + j = 0 ; + } + else if ( AreSamePointEpsilon( ptCurrEnd, ptOtherEnd, dLinTol)) { + // Se su un punto di Biforcazione, sono in un caso ambiguo + for ( const Point3d& ptFork : vPtForks) { + if ( AreSamePointApprox( ptFork, ptCurrEnd)) { + bAmbiguous = true ; + return true ; + } + } + vPtForks.emplace_back( ptCurrEnd) ; + // Altrimenti aggiorno i parametri di ricerca + vCompoChain.back().AddLine( ptOtherStart) ; + ptCurrEnd = ptOtherStart ; + vIndInChain[j] = true ; + j = 0 ; + } + else if ( AreSamePointEpsilon( ptCurrStart, ptOtherEnd, dLinTol)) { + // Se su un punto di Biforcazione, sono in un caso ambiguo + for ( const Point3d& ptFork : vPtForks) { + if ( AreSamePointApprox( ptFork, ptCurrStart)) { + bAmbiguous = true ; + return true ; + } + } + vPtForks.emplace_back( ptCurrStart) ; + // Altrimenti aggiorno i parametri di ricerca + vCompoChain.back().AddLine( ptOtherStart, false) ; + ptCurrStart = ptOtherStart ; + vIndInChain[j] = true ; + j = 0 ; + } + else if ( AreSamePointEpsilon( ptCurrStart, ptOtherStart, dLinTol)) { + // Se su un punto di Biforcazione, sono in un caso ambiguo + for ( const Point3d& ptFork : vPtForks) { + if ( AreSamePointApprox( ptFork, ptCurrStart)) { + bAmbiguous = true ; + return true ; + } + } + vPtForks.emplace_back( ptCurrStart) ; + // Altrimenti aggiorno i parametri di ricerca + vCompoChain.back().AddLine( ptOtherEnd, false) ; + ptCurrStart = ptOtherEnd ; + vIndInChain[j] = true ; + j = 0 ; + } + } + } + + #if DEBUG_FACE_SEARCH + for ( int i = 0 ; i < int( vCompoChain.size()) ; ++ i) { + VT.emplace_back( vCompoChain[i].Clone()) ; + VC.emplace_back( FUCHSIA) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\4.nge") ; + #endif + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per il calcolo dei punti medi tra due curve di Bordo +static bool +CalcMidPointForBorders( const CurveComposite& CompoA, const CurveComposite& CompoB, + const SurfTriMesh& Stm, const unordered_set& setNewTria, + Point3d& ptMid, Point3d& ptMid1, int& nTria, int& nTria1) +{ + // Se entrambe le curve non sono valide, errore + if ( ! CompoA.IsValid() && ! CompoB.IsValid()) + return false ; + + // Se entrambe le curve sono valide + if ( CompoA.IsValid() && CompoB.IsValid()) { + // Recupero ptMid1 e ptMid2 e i rispettivi triangoli di ricerca + Point3d ptA ; CompoA.GetStartPoint( ptA) ; + Point3d ptB ; CompoA.GetEndPoint( ptB) ; + Point3d ptC ; CompoB.GetStartPoint( ptC) ; + Point3d ptD ; CompoB.GetEndPoint( ptD) ; + if ( SqDist( ptA, ptD) < SqDist( ptA, ptC)) + swap( ptC, ptD) ; + ptMid = Media( ptB, ptD) ; + ptMid1 = Media( ptA, ptC) ; + } + // Se una sola valida + else { + const CurveComposite& CurveX = ( CompoA.IsValid() ? CompoA : CompoB) ; + Point3d ptA ; CurveX.GetStartPoint( ptA) ; + Point3d ptD ; CurveX.GetEndPoint( ptD) ; + ptMid = Media( ptA, ptD) ; + ptMid1 = P_INVALID ; + nTria1 = SVT_NULL ; + } + // Recupero il triangolo a distanza minima dai due punti ricavati + double dSqDistMin = INFINITO ; + double dSqDistMin1 = INFINITO ; + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) { + Triangle3d Tria ; + if ( ! Stm.GetTriangle( *Iter, Tria)) + return false ; + double dSqDist = 0., dSqDist1 = 0. ; + DistPointTriangle( ptMid, Tria).GetSqDist( dSqDist) ; + if ( dSqDist < dSqDistMin) { + dSqDistMin = dSqDist ; + nTria = *Iter ; + } + if ( ptMid1.IsValid()) { + DistPointTriangle( ptMid1, Tria).GetSqDist( dSqDist1) ; + if ( dSqDist1 < dSqDistMin1) { + dSqDistMin1 = dSqDist1 ; + nTria1 = *Iter ; + } + } + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per l'analisi locale delle curve di bordo +static bool +CheckCurvesInBox( const SurfTriMesh& Stm, const COMPOVECTOR& vCompoChain, const Point3d& ptSel, + const unordered_set& setNewTria, CurveComposite& CompoA,CurveComposite& CompoB, + Point3d& ptMid, Point3d& ptMid1, int& nTria, int& nTria1) +{ + const double HALF_LEN = .5 ; + const double ANG_SPLIT = 50. ; + + // Se non ho curve, errore + if ( vCompoChain.empty()) + return false ; + + #if DEBUG_FACE_SEARCH + for ( int _i = 0 ; _i < int( vCompoChain.size()) ; ++ _i) { + VT.emplace_back( vCompoChain[_i].Clone()) ; + VC.emplace_back( PURPLE) ; + } + #endif + + // Recupero le due curve di riferimento + CurveComposite CompoATmp, CompoBTmp ; + + // Se ho una sola curva, allora i bordi si sono uniti + if ( int( vCompoChain.size()) == 1) { + // Approssimo la curva in Patches + PolyLine PL ; + if ( ! vCompoChain[0].ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL)) + return false ; + POLYLINEMATRIX matPL ; + if ( ! CalcPatches( { PL}, ANG_SPLIT, matPL) && ! matPL.empty() && ! matPL[0].empty()) + return false ; + CompoATmp.FromPolyLine( matPL[0].front()) ; + CompoBTmp.FromPolyLine( matPL[0].back()) ; + } + // Se due curve di bordo + else if ( int( vCompoChain.size()) == 2) { + CompoATmp = vCompoChain[0] ; + CompoBTmp = vCompoChain[1] ; + } + // Se più di due, cerco le due curve più vicine + else if ( int( vCompoChain.size()) > 2) { + INTDBLVECTOR vIndSqDist ; vIndSqDist.reserve( vCompoChain.size()) ; + for ( int nCrv = 0 ; nCrv < int( vCompoChain.size()) ; ++ nCrv) { + vIndSqDist.emplace_back( make_pair( nCrv, 0.)) ; + if ( ! DistPointCurve( ptSel, vCompoChain[nCrv]).GetSqDist( vIndSqDist.back().second)) + return false ; + } + sort( vIndSqDist.begin(), vIndSqDist.end(), []( const INTDBL& A, const INTDBL& B) { + return ( A.second < B.second) ; + }) ; + CompoATmp = vCompoChain[vIndSqDist[0].first] ; + CompoBTmp = vCompoChain[vIndSqDist[1].first] ; + } + + // Entrambe le curve sono chiuse, non devo fare nulla + if ( CompoATmp.IsClosed() && CompoBTmp.IsClosed()) { + CompoA = CompoATmp ; + CompoB = CompoBTmp ; + return true ; + } + + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoATmp.Clone()) ; + VC.emplace_back( WHITE) ; + VT.emplace_back( CompoBTmp.Clone()) ; + VC.emplace_back( WHITE) ; + #endif + + // Definisco le due curve di riferimento + double dUA = 0., dUB = 0. ; + int nFlag = 0 ; + if ( ! DistPointCurve( ptSel, CompoATmp).GetParamAtMinDistPoint( 0., dUA, nFlag) || + ! DistPointCurve( ptSel, CompoBTmp).GetParamAtMinDistPoint( 0., dUB, nFlag)) + return false ; + // Se le curve sono chiuse devo fare attenzione + if ( CompoATmp.IsClosed()) { + // Se lunghezza inferiore del doppio della semilunghezza, errore ( curva troppo piccola per essere lavorata) + double dLenA ; + if ( ! CompoATmp.GetLength( dLenA) || dLenA < 2. * HALF_LEN + EPS_SMALL) + return false ; + // Cambio il punto inziale della curva + CompoATmp.ChangeStartPoint( dUA) ; + double dUS, dUE ; + if ( ! CompoATmp.GetDomain( dUS, dUE)) + return false ; + CompoATmp.ChangeStartPoint( ( dUS + dUE) / 2.) ; + if ( ! DistPointCurve( ptSel, CompoATmp).GetParamAtMinDistPoint( 0., dUA, nFlag)) + return false ; + } + if ( CompoBTmp.IsClosed()) { + // Se lunghezza inferiore del doppio della semilunghezza, errore ( curva troppo piccola per essere lavorata) + double dLenB ; + if ( ! CompoBTmp.GetLength( dLenB) || dLenB < 2. * HALF_LEN + EPS_SMALL) + return false ; + CompoBTmp.ChangeStartPoint( dUB) ; + double dUS, dUE ; + if ( ! CompoBTmp.GetDomain( dUS, dUE)) + return false ; + CompoBTmp.ChangeStartPoint( ( dUS + dUE) / 2.) ; + if ( ! DistPointCurve( ptSel, CompoBTmp).GetParamAtMinDistPoint( 0., dUB, nFlag)) + return false ; + } + // Recupero la lunghezza della curva e la lunghezza in tali parametri + double dULenA, dULenB, dLenA, dLenB ; + if ( ! CompoATmp.GetLengthAtParam( dUA, dULenA) || + ! CompoBTmp.GetLengthAtParam( dUB, dULenB) || + ! CompoATmp.GetLength( dLenA) || + ! CompoBTmp.GetLength( dLenB)) + return false ; + // Recupero i due tratti di curva per l'analisi + double dLenMinA = Clamp( dULenA - HALF_LEN, 0., dLenA) ; + double dLenMaxA = Clamp( dULenA + HALF_LEN, 0., dLenA) ; + double dLenMinB = Clamp( dULenB - HALF_LEN, 0., dLenB) ; + double dLenMaxB = Clamp( dULenB + HALF_LEN, 0., dLenB) ; + // Recupero i parametri e le curve + double dUAS, dUAE, dUBS, dUBE ; + if ( ! CompoATmp.GetParamAtLength( dLenMinA, dUAS) || + ! CompoATmp.GetParamAtLength( dLenMaxA, dUAE) || + ! CompoBTmp.GetParamAtLength( dLenMinB, dUBS) || + ! CompoBTmp.GetParamAtLength( dLenMaxB, dUBE)) + return false ; + CompoA.CopyFrom( ConvertCurveToBasicComposite( CompoATmp.CopyParamRange( dUAS, dUAE))) ; + CompoB.CopyFrom( ConvertCurveToBasicComposite( CompoBTmp.CopyParamRange( dUBS, dUBE))) ; + + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoA.Clone()) ; + VC.emplace_back( RED) ; + VT.emplace_back( CompoB.Clone()) ; + VC.emplace_back( RED) ; + #endif + + // Recupero ptMid1 e ptMid2 e i rispettivi triangoli di ricerca + if ( ! CalcMidPointForBorders( CompoA, CompoB, Stm, setNewTria, ptMid, ptMid1, nTria, nTria1)) + return false ; + + #if DEBUG_FACE_SEARCH + IGeoPoint3d* _ptMid = CreateGeoPoint3d() ; _ptMid->Set( ptMid) ; + VT.emplace_back( _ptMid) ; + VC.emplace_back( AQUA) ; + if ( ptMid1.IsValid()) { + IGeoPoint3d* _ptMid1 = CreateGeoPoint3d() ; _ptMid1->Set( ptMid1) ; + VT.emplace_back( _ptMid1) ; + VC.emplace_back( AQUA) ; + } + VT.emplace_back( Stm.CloneTriangle( nTria)) ; + VC.emplace_back( LIME) ; + if ( nTria1 != SVT_NULL) { + VT.emplace_back( Stm.CloneTriangle( nTria1)) ; + VC.emplace_back( LIME) ; + } + //SaveGeoObj( VT, VC, "C:\\Temp\\5.nge") ; + #endif + + // I punti, le curve e i triangoli ricavati, devono essere validi + return ( CompoA.IsValid() && CompoB.IsValid() && ptMid.IsValid() && ptMid1.IsValid() && + nTria != SVT_NULL && nTria1 != SVT_NULL) ; +} + +// ---------------------------------------------------------------------------- +// Funzione per aggiornare il Bordo mediante adiacenze di triangoli +static bool +UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& vCompoChain, + bool& bUpdate) +{ + bUpdate = false ; + // Se Curva corrente non valida, non devo aggiornare nulla + if ( ! Compo.IsValid()) + return true ; + // Se le Compo di concatenazione non sono valide, errore + for ( const CurveComposite& CompoChain : vCompoChain) { + if ( ! CompoChain.IsValid()) + return false ; + } + + // Recupero gli estremi della curva corrente + Point3d ptStart ; Compo.GetStartPoint( ptStart) ; + Point3d ptEnd ; Compo.GetEndPoint( ptEnd) ; + + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + VT.emplace_back( Compo.Clone()) ; + VC.emplace_back( RED) ; + for ( const CurveComposite& CompoChain : vCompoChain) { + VT.emplace_back( CompoChain.Clone()) ; + VC.emplace_back( AQUA) ; + } + #endif + + // Scorro le curve di concatenazione + bool bUpdateStart = false ; + bool bUpdateEnd = false ; + for ( const CurveComposite& CompoChain : vCompoChain) { + // Verifico gli estremi della curva corrente + bool bMyUpdateStart = ( CompoChain.IsPointOn( ptStart, dLinTol)) ; + bool bMyUpdateEnd = ( CompoChain.IsPointOn( ptEnd, dLinTol)) ; + if ( bMyUpdateStart || bMyUpdateEnd) { + // Recupero il dominio della curva di concatenzione + double dUS = 0., dUE = 0. ; + if ( ! CompoChain.GetDomain( dUS, dUE)) + return false ; + // Recupero gli Estremi della curva di concatenazione + Point3d ptS ; CompoChain.GetStartPoint( ptS) ; + Point3d ptE ; CompoChain.GetEndPoint( ptE) ; + // Se solo tratto antecedente valido + if ( bMyUpdateStart && ! bMyUpdateEnd) { + double dUBreak = 0. ; + if ( ! CompoChain.GetParamAtPoint( ptStart, dUBreak, dLinTol)) + return false ; + CurveComposite CompoPrev ; + if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) { + CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + CompoPrev.Invert() ; + } + else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) + CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoPrev.Clone()) ; + VC.emplace_back( LIME) ; + #endif + bUpdateStart = ( Compo.AddCurve( CompoPrev, false, dLinTol)) ; + } + // Se solo tratto successivo valido + else if ( ! bMyUpdateStart && bMyUpdateEnd) { + double dUBreak = 0. ; + if ( ! CompoChain.GetParamAtPoint( ptEnd, dUBreak, dLinTol)) + return false ; + CurveComposite CompoAft ; + if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) + CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) { + CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; + CompoAft.Invert() ; + } + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoAft.Clone()) ; + VC.emplace_back( LIME) ; + #endif + bUpdateEnd = Compo.AddCurve( CompoAft, true, dLinTol) ; + } + // Se entrambi i tratti sono validi + else { + double dUBreak = 0., dUBreak1 = 0. ; + if ( ! CompoChain.GetParamAtPoint( ptStart, dUBreak, dLinTol) || + ! CompoChain.GetParamAtPoint( ptEnd, dUBreak1, dLinTol)) + return false ; + if ( ! Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) { + CurveComposite CompoPrev ; + CurveComposite CompoAft ; + if ( dUBreak < dUBreak1) { + CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; + CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUE))) ; + } + else { + CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + CompoPrev.Invert() ; + CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak1))) ; + CompoAft.Invert() ; + } + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoPrev.Clone()) ; + VC.emplace_back( LIME) ; + VT.emplace_back( CompoAft.Clone()) ; + VC.emplace_back( LIME) ; + #endif + bUpdateStart = ( Compo.AddCurve( CompoPrev, false, dLinTol)) ; + bUpdateEnd = ( Compo.AddCurve( CompoAft, true, dLinTol)) ; + } + else if ( Compo.IsPointOn( ptS) && Compo.IsPointOn( ptE)) { + CurveComposite CompoSingle ; + if ( dUBreak < dUBreak1) { + CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUBreak1))) ; + CompoSingle.Invert() ; + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoSingle.Clone()) ; + VC.emplace_back( LIME) ; + #endif // false + if ( Compo.AddCurve( CompoSingle, true, dLinTol)) { + bUpdateStart = true ; + bUpdateEnd = true ; + } + } + else { + CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUBreak))) ; + #if DEBUG_FACE_SEARCH + VT.emplace_back( CompoSingle.Clone()) ; + VC.emplace_back( LIME) ; + #endif // false + if ( Compo.AddCurve( CompoSingle, true, dLinTol)) { + bUpdateStart = true ; + bUpdateEnd = true ; + } + } + } + } + } + } + + #if DEBUG_FACE_SEARCH + //SaveGeoObj( VT, VC, "C:\\Temp\\6.nge") ; + #endif + bUpdate = ( bUpdateStart || bUpdateEnd) ; + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per controllare le curve di Bordo all'interno del Box +static bool +CheckBordersInBox( CurveComposite& CompoA, CurveComposite& CompoB, + const SurfTriMesh& Stm, const unordered_set& setAvoidTria, + double dAngTol, double dLinTol, double dSize, double dSizeTol, bool& bBreak) +{ + bBreak = false ; + // Verifico la validità delle Curve + bool bValidA = ( CompoA.IsValid()) ; + bool bValidB = ( CompoB.IsValid()) ; + + // Se nessuna curva valida, errore + if ( ! bValidA && ! bValidB) + return false ; + + // Recupero i due tratti di curva in analisi e le loro proprietà + CurveComposite myCompoA, myCompoB ; + // NB. la parametrizzazione deve avvenire per lunghezza, non per parametro + double dLenA = 0., dLenB = 0. ; + double dLenStartA = 0., dLenStartB = 0., dLenEndA = 0., dLenEndB = 0. ; + + // Se entrambe le curve sono valide + if ( bValidA && bValidB) { + myCompoA = CompoA ; + myCompoB = CompoB ; + // Recupero la lunghezza delle due curve + if ( ! myCompoA.GetLength( dLenA) || ! myCompoB.GetLength( dLenB)) + return false ; + // Recupero la lunghezza di Analisi scorrendo le curve : + // - per CompoA devo indietreggiare + // - per CompoB devo avanzare + dLenStartA = Clamp( dLenA - dSize - dSizeTol, 0., dLenA) ; + dLenEndB = Clamp( dSize + dSizeTol, 0., dLenB) ; + // Se curve troppo corte non le analizzo + if ( dLenA - dLenStartA < dSizeTol || dLenEndB < dSizeTol) + return true ; + dLenEndA = dLenA ; + dLenStartB = 0. ; + } + // Se una delle due valida + else { + // Recupero la myCompoA come estremo finale e myCompoB come estremo iniziale + const CurveComposite& CompoX = ( CompoA.IsValid() ? CompoA : CompoB) ; + double dLen ; + if ( ! CompoX.GetLength( dLen)) + return false ; + if ( dLen < 2. * ( dSize + dSizeTol) + 5. * EPS_SMALL) + return true ; + double dUS, dUE, dUStartA, dUEndB ; + if ( ! CompoX.GetDomain( dUS, dUE) || + ! CompoX.GetParamAtLength( dLen - dSize - dSizeTol - 2. * EPS_SMALL, dUStartA) || + ! CompoX.GetParamAtLength( dSize + dSizeTol + 2. * EPS_SMALL, dUEndB)) + return false ; + // Per sicurezza [ migliorabile se stabile] + if ( ! myCompoA.CopyFrom( CompoX.CopyParamRange( dUStartA, dUE)) || + ! myCompoB.CopyFrom( CompoX.CopyParamRange( dUS, dUEndB))) + return false ; + dLenStartA = 0. ; + dLenStartB = 0. ; + if ( ! myCompoA.GetLength( dLenEndA) || ! myCompoB.GetLength( dLenEndB)) + return false ; + dLenA = dLenEndA ; + dLenB = dLenEndB ; + } + + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + // Disegno simbolico + if ( CompoA.IsValid()) { + VT.emplace_back( CompoA.Clone()) ; + VC.emplace_back( AQUA) ; + } + if ( CompoB.IsValid()) { + VT.emplace_back( CompoB.Clone()) ; + VC.emplace_back( ORANGE) ; + } + //SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ; + #endif + + // Campiono le Curve alla ricerca di restrizioni + const int MAX_SAMPLE = 5 ; + const int MAX_OUT_SAMPLE = 2 ; // Per ignorare le piccole imperfezioni + int nCountOut = 0 ; + bool bExpandBox = false ; + for ( int i = 0 ; i <= MAX_SAMPLE ; ++ i) { + // Recupero i parametri su tale Curva + double dLenUA = Clamp( ( dLenStartA + i * ( dLenEndA - dLenStartA) / MAX_SAMPLE), EPS_SMALL, dLenA - EPS_SMALL) ; + double dLenUB = Clamp( ( dLenEndB - i * ( dLenEndB - dLenStartB) / MAX_SAMPLE), EPS_SMALL, dLenB - EPS_SMALL) ; + // Recupero i punti associati e la loro distanza + double dUA, dUB ; + if ( ! myCompoA.GetParamAtLength( dLenUA, dUA) || ! myCompoB.GetParamAtLength( dLenUB, dUB)) + return false ; + Point3d ptA, ptB ; + if ( ! myCompoA.GetPointD1D2( dUA, ICurve::FROM_MINUS, ptA) || + ! myCompoB.GetPointD1D2( dUB, ICurve::FROM_PLUS, ptB)) + return false ; + if ( SqDist( ptA, ptB) < ( dSize - dSizeTol) * ( dSize - dSizeTol)) + ++ nCountOut ; + else + nCountOut = 0 ; + #if DEBUG_FACE_SEARCH + CurveLine _Line ; _Line.Set( ptA, ptB) ; + VT.emplace_back( _Line.Clone()) ; + VC.emplace_back( nCountOut == 0 ? LIME : RED) ; + #endif + if ( nCountOut >= MAX_OUT_SAMPLE) { + bExpandBox = true ; + break ; + } + } + + #if DEBUG_FACE_SEARCH + //SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ; + #endif + + // Se rilevata restrizione + if ( bExpandBox) { + // Recupero i due tratti lineari in tangenza + Vector3d vtA, vtB ; + if ( ! myCompoA.GetEndDir( vtA) || ! myCompoB.GetStartDir( vtB)) + return false ; + Point3d ptA, ptB ; + if ( ! myCompoA.GetEndPoint( ptA) || ! myCompoB.GetStartPoint( ptB)) + return false ; + // Cerco il punto a minima distanza tra esse ( suppongo che le linee tendano a convergere + // verso lo spigolo della striscia in analisi) + Point3d ptMinDistA, ptMinDistB ; + if ( ! DistLineLine( ptA, vtA, 1., ptB, - vtB, 1., false, false).GetMinDistPoints( ptMinDistA, ptMinDistB)) + return false ; + Point3d ptInt = Media( ptMinDistA, ptMinDistB) ; + // Definisco un Box centrato nel punto medio di taglio tra CompoA e CompoB sul Box + BBox3d BBoxCheck ; + Point3d ptCenter = Media( ptA, ptB) ; + BBoxCheck.Add( ptCenter) ; // dSize / cos( 60deg) + BBoxCheck.Expand( dSizeTol + min( Dist( ptCenter, ptInt), 2. * dSize)) ; + + #if DEBUG_FACE_SEARCH + CurveLine _LineA, _LineB ; + _LineA.Set( ptA, ptA + 1e2 * vtA) ; + _LineB.Set( ptB, ptB - 1e2 * vtB) ; + VT.emplace_back( _LineA.Clone()) ; + VC.emplace_back( YELLOW) ; + VT.emplace_back( _LineB.Clone()) ; + VC.emplace_back( YELLOW) ; + CurveComposite pCompoBox ; + pCompoBox.AddPoint( BBoxCheck.GetMin()) ; + pCompoBox.AddLine( BBoxCheck.GetMin() + BBoxCheck.GetDimX() * X_AX) ; + pCompoBox.AddLine( BBoxCheck.GetMax() - BBoxCheck.GetDimZ() * Z_AX) ; + pCompoBox.AddLine( BBoxCheck.GetMin() + BBoxCheck.GetDimY() * Y_AX) ; + pCompoBox.Close() ; + pCompoBox.SetExtrusion( Z_AX) ; + pCompoBox.SetThickness( BBoxCheck.GetDimZ()) ; + VT.emplace_back( pCompoBox.Clone()) ; + VC.emplace_back( YELLOW) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ; + #endif + + // Determino le due curve all'interno di questo Box + INTVECTOR vTBox ; + if ( ! Stm.GetAllTriaOverlapBox( BBoxCheck, vTBox) || vTBox.empty()) + return false ; + double dMinSqDist = INFINITO ; + int nTria = 0 ; + for ( int nT = 0 ; nT < int( vTBox.size()) ; ++ nT) { + Triangle3d Tria ; + if ( ! Stm.GetTriangle( vTBox[nT], Tria)) + return false ; + double dSqDist = 0. ; + if ( DistPointTriangle( ptCenter, Tria).GetSqDist( dSqDist) && dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + nTria = vTBox[nT] ; + } + } + unordered_set MysetAvoidTria( setAvoidTria) ; + unordered_set MysetNewTria ; + if ( ! ClassifyTriangles( Stm, vTBox, nTria, dAngTol, MysetAvoidTria, MysetNewTria)) + return false ; + COMPOVECTOR vCompoChain ; + if ( ! GetBordersByTriaInBox( Stm, BBoxCheck, dLinTol, MysetNewTria, vCompoChain, bBreak)) + return false ; + + #if DEBUG_FACE_SEARCH + for ( CurveComposite& Compo : vCompoChain) { + VT.emplace_back( Compo.Clone()) ; + VC.emplace_back( FUCHSIA) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ; + #endif + + // Se ottengo una sola curva, allora la striscia si è chiusa + if ( int( vCompoChain.size()) <= 1) + return true ; + // Se ottengo ancora due curve, allora la striscia non rispetta lo spessore minimo + bBreak = ( int( vCompoChain.size()) >= 2) ; + if ( bBreak) { + // Se devo fermare la ricerca e ho ancora CompoA e CompoB valide + if ( bValidA && bValidB) { + // Collego CompoA con CompoB e pulisco CompoB + Point3d ptStartB ; + if ( ! CompoB.GetStartPoint( ptStartB)) + return false ; + CompoA.AddLine( ptStartB) ; + if ( ! CompoA.AddCurve( CompoB, dLinTol)) + return false ; + CompoB.Clear() ; + } + } + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per analisi locale della superficie all'interno di un Box +static bool +GetBordersInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, int nFirstTria, const Point3d& ptSel, + double dSize, double dSizeTol, bool bAbsFirst, bool bRelFirst, double dAngTol, + double dLinTol, unordered_set& setAvoidTria, unordered_set& setNewTria, + CurveComposite& CompoA, CurveComposite& CompoB, Point3d& ptMid, Point3d& ptMid1, + int& nTria, int& nTria1, bool& bBreak, bool& bStop) +{ + // Controllo dei parametri + if ( ! Stm.IsValid()) + return false ; + bBreak = false ; + bStop = false ; + setNewTria.clear() ; + + // Recupero tutti i Triangoli all'interno del Box + INTVECTOR vTBox ; + if ( ! Stm.GetAllTriaOverlapBox( BBoxCurr, vTBox) || vTBox.empty()) { + // [Non devo mai capitare qui, non ha senso] + bStop = true ; + return true ; + } + + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + CurveComposite pCompoBox ; + pCompoBox.AddPoint( BBoxCurr.GetMin()) ; + pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimX() * X_AX) ; + pCompoBox.AddLine( BBoxCurr.GetMax() - BBoxCurr.GetDimZ() * Z_AX) ; + pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimY() * Y_AX) ; + pCompoBox.Close() ; + pCompoBox.SetExtrusion( Z_AX) ; + pCompoBox.SetThickness( BBoxCurr.GetDimZ()) ; + VT.emplace_back( pCompoBox.Clone()) ; + VC.emplace_back( YELLOW) ; + VT.emplace_back( Stm.CloneTriangle( nFirstTria)) ; + VC.emplace_back( YELLOW) ; + IGeoPoint3d* _ptSel = CreateGeoPoint3d() ; _ptSel->Set( ptSel) ; + VT.emplace_back( _ptSel) ; + VC.emplace_back( RED) ; + //if ( bAbsFirst) + //SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ; + #endif + + // Classifico i triangoli + if ( ! ClassifyTriangles( Stm, vTBox, nFirstTria, dAngTol, setAvoidTria, setNewTria)) + return false ; + + // Recupero solo i bordi validi interni al Box dai triangoli classificati + COMPOVECTOR vCompoChain ; + if ( ! GetBordersByTriaInBox( Stm, BBoxCurr, dLinTol, setNewTria, vCompoChain, bBreak)) + return false ; + + // Se primo triangolo in assoluto, ricavo i due tratti di interesse + if ( bAbsFirst) { + if ( ! CheckCurvesInBox( Stm, vCompoChain, ptSel, setNewTria, CompoA, CompoB, ptMid, ptMid1, nTria, nTria1)) + return false ; + // Se entrambe chiuse, ho finito + if ( CompoA.IsClosed() && CompoB.IsClosed()) { + bStop = true ; + return true ; + } + } + // Se non sono il primo triangolo + else { + + // Se primo triangolo relativo, tengo i punti di Trimming + if ( bRelFirst) { + // TODO -> non estendere le curve e tenerere i punti di Trim + } + + // Aggiorno la CompoA con il nuovo tratto trovato + bool bUpdateA = false ; + if ( ! UpdateBorderByTriaAdj( CompoA, dLinTol, vCompoChain, bUpdateA)) + return false ; + // Se CompoA si è aggiornata + if ( bUpdateA) { + // Se si è chiusa su se stessa, ho individuato il bordo + if ( CompoA.IsClosed()) { + bStop = true ; + return true ; + } + // Verifico se si è unita alla CompoB + if ( CompoB.IsValid()) { + CurveComposite CompoBTest ; + CompoBTest.CopyFrom( &CompoB) ; + bool bUpdateBTmp = false ; + if ( ! UpdateBorderByTriaAdj( CompoBTest, dLinTol, { CompoA}, bUpdateBTmp)) + return false ; + if ( bUpdateBTmp) { + CompoB.Clear() ; + CompoA.CopyFrom( &CompoBTest) ; + bUpdateA = true ; + bBreak = true ; + } + } + } + // Aggiorno la Compo B con il nuovo tratto trovato + bool bUpdateB = false ; + if ( CompoB.IsValid()) { + if ( ! UpdateBorderByTriaAdj( CompoB, dLinTol, vCompoChain, bUpdateB)) + return false ; + // Se CompoB si è aggiornata + if ( bUpdateB) { + // Se si è chiusa su se stessa, ho individuato il bordo + if ( CompoB.IsClosed()) { + bStop = true ; + return true ; + } + // Verifico se si è unita alla CompoA + if ( CompoA.IsValid()) { + CurveComposite CompoATest ; + CompoATest.CopyFrom( &CompoA) ; + bool bUpdateATmp = false ; + if ( ! UpdateBorderByTriaAdj( CompoATest, dLinTol, { CompoB}, bUpdateATmp)) + return false ; + if ( bUpdateATmp) { + CompoA.Clear() ; + CompoB.CopyFrom( &CompoATest) ; + bUpdateA = true ; + bBreak = true ; + } + } + } + } + + // Se sono il primo triangolo Relativo + if ( bRelFirst) { + // Accorcio le curve originarie + } + + // Se non ho aggiornato nessuna delle due curve, sono in caso di divergenza + if ( ! bUpdateA && ! bUpdateB) { + // Può capitare con il primo Cubetto per triangoli grandi ! + // ( da capire che cosa fare...) + // serve ???? + } + + // Verifico che le curve siano tra loro alla distanza stabilita + if ( dSizeTol > EPS_SMALL) { + if ( ! CheckBordersInBox( CompoA, CompoB, Stm, setAvoidTria, dAngTol, dLinTol, dSize, dSizeTol, bBreak)) + return false ; + } + if ( bBreak) { + // Se caso ambiguo nel cubetto corrente, non aggiungo i triangoli trovati + setNewTria.clear() ; + return true ; + } + + // Se CompoA e CompoB sono due curve distinte, calcolo i 2 punti medi e i 2 triangoli di ricerca, + // altrimenti ptMid1 sarà invalido e nTria1 sarà un triangolo nullo + if ( ! CalcMidPointForBorders( CompoA, CompoB, Stm, setNewTria, ptMid, ptMid1, nTria, nTria1)) + return false ; + } + + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + pCompoBox.Clear() ; + pCompoBox.AddPoint( BBoxCurr.GetMin()) ; + pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimX() * X_AX) ; + pCompoBox.AddLine( BBoxCurr.GetMax() - BBoxCurr.GetDimZ() * Z_AX) ; + pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimY() * Y_AX) ; + pCompoBox.Close() ; + pCompoBox.SetExtrusion( Z_AX) ; + pCompoBox.SetThickness( BBoxCurr.GetDimZ()) ; + VT.emplace_back( pCompoBox.Clone()) ; + VC.emplace_back( YELLOW) ; + VT.emplace_back( Stm.CloneTriangle( nFirstTria)) ; + VC.emplace_back( YELLOW) ; + _ptSel = CreateGeoPoint3d() ; _ptSel->Set( ptSel) ; + VT.emplace_back( _ptSel) ; + VC.emplace_back( RED) ; + if ( CompoA.IsValid()) { + VT.emplace_back( CompoA.Clone()) ; + VC.emplace_back( AQUA) ; + } + if ( CompoB.IsValid()) { + VT.emplace_back( CompoB.Clone()) ; + VC.emplace_back( ORANGE) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ; + #endif + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per muovere il BoxLocale lungo le curve di Bordo +static bool +MarchAlongPath( const BBox3d& BBoxCurr, const SurfTriMesh& Stm, + unordered_set& setAvoidTria, unordered_set& setValidTria, + bool bFollowA, const Point3d& ptMid, int nTria, double dSize, double dSizeTol, + double dAngTol, bool& bRelFirst, CurveComposite& CompoA, CurveComposite& CompoB, bool& bStop) +{ + // Variabili di controllo per la ricerca + BBox3d BBoxLast = BBoxCurr ; + Point3d ptRef = ptMid ; + int nTriaRef = nTria ; + bool bBreak = false ; + + // Costanti di ricerca e contatori associati + const double EXPAND_EXTRA_TOL = 10. * EPS_SMALL ; + const int MAX_TRY = 4 ; + int nCount = 0 ; + + // Inizio della ricerca + BBox3d MyBBoxCurr ; + while ( ! bBreak) { + // Definisco il nuovo Box + MyBBoxCurr.Reset() ; + MyBBoxCurr.Add( ptRef) ; + MyBBoxCurr.Expand( dSize + dSizeTol + EXPAND_EXTRA_TOL) ; + // Ricerco i triangoli + unordered_set setNewTria ; setNewTria.reserve( Stm.GetTriangleCount()) ; + Point3d myPtMid, myPtMid1 ; + int nMyTria = 0, nMyTria1 = 0 ; + if ( ! GetBordersInBox( Stm, MyBBoxCurr, nTriaRef, ptRef, dSize, dSizeTol, false, bRelFirst, + dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB, + myPtMid, myPtMid1, nMyTria, nMyTria1, bBreak, bStop)) + return false ; + bRelFirst = false ; + // Memorizzo i triangoli validi ricavati + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) + setValidTria.insert( *Iter) ; + // Se Direzione terminata o Curva chiusa + if ( bBreak || bStop) + break ; + // Ho determinato due curve distinte, il nuovo punto è quello più distante dal Box precedente + Point3d ptLast = ptRef ; + if ( myPtMid.IsValid() && myPtMid1.IsValid()) { + if ( bFollowA) { + ptRef = myPtMid ; + nTriaRef = nMyTria ; + } + else { + ptRef = myPtMid1 ; + nTriaRef = nMyTria1 ; + } + } + else { + if ( myPtMid.IsValid()) { + ptRef = myPtMid ; + nTriaRef = nMyTria ; + } + else { + ptRef = myPtMid1 ; + nTriaRef = nMyTria1 ; + } + } + // Se il nuovo punto è vicino al precedente, aggiorno il contatore + if ( SqDist( ptLast, ptRef) < ( ( dSize + dSizeTol) * ( dSize + dSizeTol) / 16.)) + ++ nCount ; + else + nCount = 0 ; + // Se troppi punti vicini tra loro, blocco la ricerca per sicurezza + if ( nCount >= MAX_TRY) + bBreak = true ; + // Il Box Corrente diventa il Box precedente + BBoxLast = MyBBoxCurr ; + + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + CurveComposite CompoBox ; + CompoBox.AddPoint( MyBBoxCurr.GetMin()) ; + CompoBox.AddLine( MyBBoxCurr.GetMin() + MyBBoxCurr.GetDimX() * X_AX) ; + CompoBox.AddLine( MyBBoxCurr.GetMax() - MyBBoxCurr.GetDimZ() * Z_AX) ; + CompoBox.AddLine( MyBBoxCurr.GetMin() + MyBBoxCurr.GetDimY() * Y_AX) ; + CompoBox.Close() ; + CompoBox.SetExtrusion( Z_AX) ; + CompoBox.SetThickness( MyBBoxCurr.GetDimZ()) ; + VT.emplace_back( CompoBox.Clone()) ; + VC.emplace_back( YELLOW) ; + IGeoPoint3d* _ptRef = CreateGeoPoint3d() ; _ptRef->Set( ptRef) ; + VT.emplace_back( _ptRef) ; + VC.emplace_back( RED) ; + if ( CompoA.IsValid()) { + VT.emplace_back( CompoA.Clone()) ; + VC.emplace_back( AQUA) ; + } + if ( CompoB.IsValid()) { + VT.emplace_back( CompoB.Clone()) ; + VC.emplace_back( ORANGE) ; + } + //SaveGeoObj( VT, VC, "C:\\Temp\\CurveUpdate.nge") ; + #endif + + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per definire se il bordo di una TriMesh è una circonferenza +static bool +IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d& vtN, double& dRad) +{ + // Se PolyLine aperta o non piana, non è un cerchio + Plane3d PlanePL ; + if ( ! PL.IsClosed() || ! PL.IsFlat( PlanePL, dShapeLinTol)) + return false ; + + // Creo un sistema di riferimento centrato nella PolyLine + Point3d ptCentroid ; + Frame3d frCurr ; + CurveComposite CurveCompo ; CurveCompo.FromPolyLine( PL) ; + if ( ! CurveCompo.GetCentroid( ptCentroid) || + ! frCurr.Set( ptCentroid, PlanePL.GetVersN())) + return false ; + + // Porto una copia della PL in questo frame + PolyLine PLLoc = PL ; PLLoc.ToLoc( frCurr) ; + + // Per ogni tratto salvo i suoi estremi e il punto medio in successione ( senza ripetizioni) + PNTVECTOR vPts ; + Point3d ptNext ; + PLLoc.GetFirstPoint( ptNext) ; + vPts.push_back( ptNext) ; + while ( PLLoc.GetNextPoint( ptNext)) { + vPts.push_back( Media( vPts.back(), ptNext)) ; + vPts.push_back( ptNext) ; + } + + // Per ogni coppia di punti calcolo la Distanza Massima e Minima dal centro del cerchio locale ( ORIG) + double dSqMaxDist = 0. ; + double dSqMinDist = INFINITO ; + for ( int i = 0 ; i < int( floor( 0.5 * int( vPts.size()))) ; i = i + 2) { + double dSqLineDist = INFINITO ; + DistPointLine( ORIG, vPts[i], vPts[i + 1]).GetSqDist( dSqLineDist) ; + if ( dSqLineDist < dSqMinDist) + dSqMinDist = dSqLineDist ; + double dSqPtDist = SqDist( ORIG, vPts[i]) ; + if ( dSqPtDist > dSqMaxDist) + dSqMaxDist = dSqPtDist ; + } + + // Se distanza minima e massima entro tolleranza, allora è una circonferenza + if ( abs( dSqMaxDist - dSqMinDist) < dShapeLinTol * dShapeLinTol) { + ptC = ptCentroid ; + vtN = PlanePL.GetVersN() ; + dRad = 0.5 * ( sqrt( dSqMaxDist) + sqrt( dSqMinDist)) ; + return true ; + } + + return false ; +} + +// ---------------------------------------------------------------------------- +// Funzione per estrarre Geometrie note da una sola TriMesh +static bool +GetShapesFromSurf( const ISurf* pSurf, double dShapeLinTol, double dShapeAngTol, double dLinTol, + double dEdgeLinTol, double dAngTol, double dFaceAngTol, const STRVECTOR& vsShapes, + ISURFPOVECTOR& vSurfSel, ICRVCOMPOPOMATRIX& matCompoBorders) +{ + vSurfSel.clear() ; + matCompoBorders.clear() ; + // Verifico la validità della superficie + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + + // Recupero il Tipo + int nType = pSurf->GetType() ; + + ISURFTMPOVECTOR vSurfTmSelTmp ; + // Se superficie di Besier, non faccio nulla (?) + if ( nType == SRF_BEZIER) + return true ; + // Se superficie TriMesh + else if ( nType == SRF_TRIMESH) { + // Recupero la TriMesh + const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pSurf) ; + if ( pStmBasic == nullptr || ! pStmBasic->IsValid()) + return false ; + // Ciclo di Analisi Triangoli + const int MAXTRY = 1000 ; + int nCount = 0 ; + int nTriaCheck = 0 ; + BOOLVECTOR vbTria( pStmBasic->GetTriangleCount(), false) ; + while ( nCount < MAXTRY && nTriaCheck < pStmBasic->GetTriangleCount()) { + // Recupero il primo triangolo valido disponibile non ancora analizzato + int nFirstTria = 0 ; + for ( int nT = 0 ; nT < ssize( vbTria) ; ++ nT) { + if ( ! vbTria[nT]) { + nFirstTria = nT ; + break ; + } + } + unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ; + unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ; + // Collezioni di triangoli da analizzare + INTVECTOR vTria ; vTria.reserve( pStmBasic->GetTriangleCount()) ; + vTria.push_back( nFirstTria) ; + // Finchè ho triangoli da visitare + while ( ! vTria.empty()) { + // Recupero il triangolo corrente + int nCurrTria = vTria.back() ; + // Elimino il triangolo corente + vTria.pop_back() ; + + // Se triangolo da evitare, passo al successivo + if ( setAvoidTria.find( nCurrTria) != setAvoidTria.end()) + continue ; + // Se triangolo mai visitato lo aggiungo tra quelli visitati, altrimenti passo al successivo + if ( vbTria[nCurrTria]) + continue ; + vbTria[nCurrTria] = true ; + ++ nTriaCheck ; + + // Inserisco il triangolo corrente + setNewTria.insert( nCurrTria) ; + + // Recupero il triangolo corrente e le sue adiacenze + int nTriaVertices[3] ; + if ( ! pStmBasic->GetTriangle( nCurrTria, nTriaVertices)) + return false ; + Triangle3d Tria ; + if ( ! pStmBasic->GetTriangle( nCurrTria, Tria)) + return false ; + int nIdAdjTriaId[3] ; + if ( ! pStmBasic->GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId)) + return false ; + + // Scorro le adiacenze + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + // Recupero l'indice del triangolo corrente + int nTriaAdj = nIdAdjTriaId[nAdj] ; + // Se non ho adiacenza, non faccio nulla + if ( nTriaAdj == SVT_NULL) + continue ; + // Recupero il triangolo adiacente + Triangle3d TriaAdj ; + if ( ! pStmBasic->GetTriangle( nTriaAdj, TriaAdj)) + return false ; + // Se la normale è fuori dalla tolleranza, memorizzo il triangolo tra quelli da scartare + if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dFaceAngTol + EPS_ANG_SMALL) * DEGTORAD)) { + setAvoidTria.insert( nTriaAdj) ; + continue ; + } + // Inserisco il triangolo per la ricerca futura + vTria.push_back( nTriaAdj) ; + } + } + ++ nCount ; + // Se ho nuovi triangoli, definisco una superficie da essi + if ( ! setNewTria.empty()) { + + #if DEBUG_SHAPE_STM + VT.clear() ; VC.clear() ; + VT.emplace_back( pStmBasic->Clone()) ; + VC.emplace_back( BLACK) ; + StmFromTriangleSoup _TriaSoup ; _TriaSoup.Start() ; + for ( auto _Iter = setNewTria.begin() ; _Iter != setNewTria.end() ; ++ _Iter) { + Triangle3d _Tria ; + if ( ! pStmBasic->GetTriangle( *_Iter, _Tria)) + return false ; + _TriaSoup.AddTriangle( _Tria) ; + } + _TriaSoup.End() ; + VT.emplace_back( _TriaSoup.GetSurf()) ; + VC.emplace_back( LIME) ; + //SaveGeoObj( VT, VC, "C:\\Temp\\MyShape.nge") ; + VT.clear() ; VC.clear() ; + #endif + + StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ; + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) { + Triangle3d Tria ; + if ( ! pStmBasic->GetTriangle( *Iter, Tria)) + return false ; + TriaSoup.AddTriangle( Tria) ; + } + TriaSoup.End() ; + PtrOwner pStmTmp( TriaSoup.GetSurf()) ; + if ( ! IsNull( pStmTmp) && pStmTmp->IsValid() && pStmTmp->GetTriangleCount() > 0) { + if ( ! vSurfTmSelTmp.emplace_back( Release( pStmTmp))) + return false ; + } + } + } + } + + // Se non ho ricavato superfici, esco + if ( vSurfTmSelTmp.empty()) + return true ; + + // Per ognuna di esse ricerco le geometrie compatibili + for ( int i = 0 ; i < ssize( vSurfTmSelTmp) ; ++ i) { + // Recupero i Loops + POLYLINEVECTOR vPL ; + vSurfTmSelTmp[i]->GetLoops( vPL) ; + // Elimino i Loop che non sono chiusi + vPL.erase( + remove_if( vPL.begin(), vPL.end(), []( const PolyLine& PL) { + return ( ! PL.IsClosed()) ; + }), + vPL.end() + ) ; + // Se non ho esattamente due Loops, passo alla superficie successiva + if ( ssize( vPL) != 2) + continue ; + // Se devo ricercare Circonferenze + if ( find_if( vsShapes.begin(), vsShapes.end(), [&]( const string& sStr) { + return ( sStr.compare( sCircle) == 0) ; + }) != vsShapes.end()) { + // Verifico che le due PolyLine siano circonferenze + Point3d ptCA, ptCB ; Vector3d vtNA, vtNB ; double dRadA, dRadB ; + if ( IsBorderACircle( vPL[0], dShapeLinTol, ptCA, vtNA, dRadA) && + IsBorderACircle( vPL[1], dShapeAngTol, ptCB, vtNB, dRadB)) { + // Definisco le due circonferenze + PtrOwner pCirA( CreateCurveArc()) ; + PtrOwner pCirB( CreateCurveArc()) ; + if ( ! IsNull( pCirA) && ! IsNull( pCirB) && + pCirA->Set( ptCA, vtNA, dRadA) && + pCirB->Set( ptCB, vtNB, dRadB)) { + vSurfSel.emplace_back( GetSurf( Release( vSurfTmSelTmp[i]))) ; + matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ; + matCompoBorders.back().resize( 2) ; + matCompoBorders.back()[0].Set( ConvertCurveToComposite( Release( pCirA))) ; + matCompoBorders.back()[1].Set( ConvertCurveToComposite( Release( pCirB))) ; + // l'Approssimazione delle curve prevede che io usi sempre tratti lineari, quindi approssimo + PolyLine PLA ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLA) ; + PolyLine PLB ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLB) ; + matCompoBorders.back()[0]->Clear() ; matCompoBorders.back()[0]->FromPolyLine( PLA) ; + matCompoBorders.back()[1]->Clear() ; matCompoBorders.back()[1]->FromPolyLine( PLB) ; + } + } + + #if DEBUG_SHAPE_STM + CurveComposite _CompoA ; _CompoA.FromPolyLine( vPL[0]) ; + CurveComposite _CompoB ; _CompoB.FromPolyLine( vPL[1]) ; + VT.emplace_back( _CompoA.Clone()) ; + VT.emplace_back( _CompoB.Clone()) ; + Color _cCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + VC.emplace_back( _cCol) ; + VC.emplace_back( _cCol) ; + #endif + } + } + + // #if DEBUG_SHAPE_STM + // SaveGeoObj( VT, VC, "C:\\Temp\\myAutoBorders.nge") ; + // #endif + + return true ; +} + +//----------------------------------------------------------------------------- +//-------------------------------- Funzioni Export ---------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Funzione per il calcolo degli Edges Grezzi +bool +GetTrimmingRawEdges( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace, + double dLinTol, double dAngTol, + ICRVCOMPOPOVECTOR& vCompoRawEdges) +{ + // Controllo la validità delle superfici + for ( const ISurf* pSurf : vSurf) { + if ( pSurf == nullptr || ! pSurf->IsValid()) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Detected invalid Surf") ; + return false ; + } + } + // Pulizia dei parametri di ritorno + vCompoRawEdges.clear() ; + // Se non ho elementi di selezione, non faccio nulla + if ( vSurfFace.empty()) + return true ; + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + // Controllo sulla tolleranza angolare + double dMyAngTol = Clamp( dAngTol, 1., 45.) ; + + // Recupero i bordi semplici definiti dalle superfici e dalle loro eventuali facce selezionate + POLYLINEVECTOR vPLBorders ; + if ( ! GetSurfBorders( vSurf, vSurfFace, dMyLinTol, vPLBorders)) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Borders extraction failed") ; + return false ; + } + + // Recupero le curve di bordo grezze + if ( ! GetRawEdges( vPLBorders, dMyLinTol, dMyAngTol, vCompoRawEdges)) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Border simplification failed") ; + return false ; + } + + return true ; +} + +//------------------------------------------------------------------------------ +// Funzione per il calcolo automatico degli Edge finali +// Se c'è la necessità di spezzare le curve di bordo si procede in questo modo : +// 1) Si controlla l'esistenza di eventuali punti di rottura +// 2) Se non ci sono punti di rottura, si cerca un valore di Thick e ThickTol +// 3) Se non c'è una valore di Thick e ThickTol si procede per una rottura generica +// Valori di Default dei parametri per evitare i rispettivi controlli : +// - vBreakingPts = {} +// - dThick = 0., dThickTol = 0. +bool +GetTrimmingFinalBorders( ICRVCOMPOPOVECTOR& vCompoBezierEdges, double dLinTol, double dAngTol, + BIPNTVECTOR& vBreakingPts, double dThick, double dThickTol) +{ + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + // Controllo sulla tolleranza angolare + double dMyAngTol = Clamp( dAngTol, 1., 45.) ; + + // Se non ho curve, errore + if ( vCompoBezierEdges.empty()) { + LOG_INFO( GetEGkLogger(), "Warning in Trimming : No Edges detected") ; + return false ; + } + // Se ho 1 curva, allora cerco di spezzarla + else if ( int( vCompoBezierEdges.size()) == 1) { + // Se sono presenti dei punti di rottura + bool bOk = true ; + if ( ! vBreakingPts.empty()) + bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol, vBreakingPts) ; + // Se invece è presente il valore di Thick + else if ( dThick > EPS_SMALL) + bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol, dThick, dThickTol) ; + else + // Se generica + bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol) ; + if ( ! bOk) + LOG_INFO( GetEGkLogger(), "Warning in Trimming : Breaking curves failed") ; + } + // Se ho 2 curve, perfetto ! + else if ( int( vCompoBezierEdges.size()) == 2) + return true ; + // Se più curve, errore + else { + LOG_INFO( GetEGkLogger(), "Warning in Trimming : More than 2 Edges detected") ; + return false ; + } + + return true ; +} + +// ----------------------------------------------------------------------------- +// Funzione per ricavare i bordi a partire da un insieme di superfici; questi vengono +// calcolati mediante analisi delle normali lungo il bordo delle Patches di Surfs +bool +GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dLinTol, double dAngTol, double dThick, + ICRVCOMPOPOVECTOR& vCompoBezierEdges) +{ + // Pulizia dei parametri di ritorno + vCompoBezierEdges.clear() ; + // Se non ho elementi di selezione, non faccio nulla + if ( vSurfFaces.empty()) + return true ; + // Lo spessore deve essere positivo + if ( dThick < 10. * EPS_SMALL) // coerente con Offset minimo + return false ; + + // Verifico che le superfici siano tutte valide ed aperte + for ( const ISurf* pSurf : vpSurf) { + if ( pSurf == nullptr || ! pSurf->IsValid() || pSurf->IsClosed()) + return false ; + } + + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + // Controllo sulla tolleranza angolare + double dMyAngTol = Clamp( dAngTol, 1., 45.) ; + + // Recupero la superficie TriMesh di cui fare l'Offset + PtrOwner pStm( nullptr) ; + if ( int( vpSurf.size()) == 1) { + const ISurf* pSurf = vpSurf[0] ; + if ( pSurf == nullptr) + return false ; + int nType = pSurf->GetType() ; + if ( nType == SRF_TRIMESH) + pStm.Set( CloneBasicSurfTriMesh( pSurf)) ; + else if ( nType == SRF_BEZIER) { + const ISurfBezier* pSurfBz = GetSurfBezier( pSurf) ; + if ( pSurfBz != nullptr) + pStm.Set( CloneBasicSurfTriMesh( pSurfBz->GetApproxSurf( dMyLinTol))) ; + } + } + else { + // [ Soluzione temporanea ] + StmFromTriangleSoup mySoup ; mySoup.Start() ; + for ( const ISurf* pSurf : vpSurf) { + if ( pSurf == nullptr) + return false ; + int nType = pSurf->GetType() ; + if ( nType == SRF_TRIMESH) + mySoup.AddSurfTriMesh( *GetSurfTriMesh( pSurf)) ; + else if ( nType == SRF_BEZIER) { + const ISurfBezier* pSrfBz = GetSurfBezier( pSurf) ; + if ( pSrfBz == nullptr) + return false ; + PtrOwner pStmTmp( pSrfBz->GetApproxSurf( dMyLinTol)) ; + if ( ! IsNull( pStmTmp) && pStmTmp->IsValid()) + mySoup.AddSurfTriMesh( *pStmTmp) ; + } + } + mySoup.End() ; + pStm.Set( GetBasicSurfTriMesh( mySoup.GetSurf())) ; + } + if ( IsNull( pStm) || ! pStm->IsValid() || pStm->IsClosed()) + return false ; + + // Eseguo l'Offset in negativo della superficie passando per lo ZMap + double dPrec = max( min( dThick / 4., 10. * max( dMyLinTol, EPS_SMALL)), 0.5) ; + PtrOwner pStmOffs( CreateSurfTriMeshesOffset( { pStm}, - dThick, dPrec)) ; + if ( IsNull( pStmOffs) || ! pStmOffs->IsValid()) + return false ; + + // Recupero i Loop dalla superficie originaria e i Loop della superficie di Offset + POLYLINEVECTOR vPL, vPLOffs ; + if ( ! pStm->GetLoops( vPL) || ! pStmOffs->GetLoops( vPLOffs)) + return false ; + + #if DEBUG_BORDERS_BY_NORMALS + for ( const ISurf* _pSurf : vpSurf) { + VT.emplace_back( _pSurf->Clone()) ; + VC.emplace_back( LIME) ; + } + VT.emplace_back( pStmOffs->Clone()) ; + VC.emplace_back( ORANGE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ; + #endif + + // Trasformo ogni Loop in curva composita + ICRVCOMPOPOVECTOR vCompoLoops ; vCompoLoops.reserve( vPL.size()) ; + for ( const PolyLine& PL : vPL) { + if ( PL.IsClosed()) { + if ( ! vCompoLoops.emplace_back( CreateBasicCurveComposite()) || + ! vCompoLoops.back()->FromPolyLine( PL) || + ! vCompoLoops.back()->IsValid()) + return false ; + } + } + ICRVCOMPOPOVECTOR vCompoOffsLoops ; vCompoOffsLoops.reserve( vPLOffs.size()) ; + for ( const PolyLine& PLOffs : vPLOffs) { + if ( PLOffs.IsClosed()) { + if ( ! vCompoOffsLoops.emplace_back( CreateCurveComposite()) || + ! vCompoOffsLoops.back()->FromPolyLine( PLOffs) || + ! vCompoOffsLoops.back()->IsValid()) + return false ; + } + } + + #if DEBUG_BORDERS_BY_NORMALS + for ( ICurveComposite* pCompo : vCompoLoops) { + VT.emplace_back( pCompo->Clone()) ; + VC.emplace_back( GREEN) ; + } + for ( ICurveComposite* pCompoOffs : vCompoOffsLoops) { + VT.emplace_back( pCompoOffs->Clone()) ; + VC.emplace_back( BLUE) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ; + #endif + + // Per ogni curva della superficie originale cerco la sua associata + BOOLVECTOR vIndMatched( vCompoOffsLoops.size(), false) ; + for ( const ICurveComposite* pCompoLoop : vCompoLoops) { + // sposto il punto iniziale della curva nel tratto più lungo + double dMaxLen = - INFINITO ; + int nIndCrv = 0 ; + for ( int nCrv = 0 ; nCrv < pCompoLoop->GetCurveCount() ; ++ nCrv) { + const ICurve* pCurve = pCompoLoop->GetCurve( nCrv) ; + if ( pCurve != nullptr && pCurve->IsValid()) { + double dCurrLen = 0. ; + pCurve->GetLength( dCurrLen) ; + if ( dCurrLen > dMaxLen) { + dMaxLen = dCurrLen ; + nIndCrv = nCrv ; + } + } + } + Point3d ptRef ; + pCompoLoop->GetPointD1D2( nIndCrv + 0.5, ICurve::FROM_MINUS, ptRef) ; + // dalle altre curve derivanti dalla superficie di Offset cerco quella più vicina al punto inziale + double dMinSqDist = INFINITO ; + int nIndOffsCrv = -1 ; + for ( int nOffsCrv = 0 ; nOffsCrv < int( vCompoOffsLoops.size()) ; ++ nOffsCrv) { + if ( vIndMatched[nOffsCrv]) + continue ; + // recupero la curva e calcolo la distanza + const ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nOffsCrv] ; + int nFlag = 0 ; + Point3d ptCurrMinDist ; + if ( DistPointCurve( ptRef, *pCompoOffsLoop).GetMinDistPoint( 0., ptCurrMinDist, nFlag)) { + double dCurrSqDist = SqDist( ptRef, ptCurrMinDist) ; + if ( dCurrSqDist < dMinSqDist) { + dMinSqDist = dCurrSqDist ; + nIndOffsCrv = nOffsCrv ; + } + } + } + if ( nIndOffsCrv == -1) + return false ; + vIndMatched[ nIndOffsCrv] = true ; + // associo le due curve ( quindi consecutive nel vettore delle curve risultanti) + vCompoBezierEdges.emplace_back( CloneCurveComposite( pCompoLoop)) ; + if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + return false ; + vCompoBezierEdges.emplace_back( CloneCurveComposite( vCompoOffsLoops[nIndOffsCrv])) ; + if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + return false ; + } + + return true ; +} + +// ----------------------------------------------------------------------------- +// Funzione per approssimare le curve di Bordo grezze ( tratti lineari) in +// Patch di curve di Bezier +bool +GetTrimmingBezierEdges( ICRVCOMPOPOVECTOR& vCompoRawEdges, double dLinTol, double dAngTol, + ICRVCOMPOPOVECTOR& vBezierEdges) +{ + // Pulizia del parametro di ritorno + vBezierEdges.clear() ; + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + // Controllo sulla tolleranza angolare + double dMyAngTol = Clamp( dAngTol, 1., 45.) ; + + #if DEBUG_EDGES + VC.clear() ; VT.clear() ; + for ( int _i = 0 ; _i < int( vCompoRawEdges.size()) ; ++ _i) { + VT.emplace_back( vCompoRawEdges[_i]->Clone()) ; + VC.emplace_back( RED) ; + } + #endif + + // Approssimo i bordi grezzi + vBezierEdges.reserve( vCompoRawEdges.size()) ; + for ( int i = 0 ; i < int( vCompoRawEdges.size()) ; ++ i) { + PtrOwner pCompoTmp( CloneCurveComposite( vCompoRawEdges[i])) ; + if ( IsNull( pCompoTmp) || + ! ApproxCurveWithBezier( pCompoTmp, dMyLinTol, dMyAngTol) || + ! vBezierEdges.emplace_back( Release( pCompoTmp))) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Approxing edge failed") ; + return false ; + } + } + + #if DEBUG_EDGES + VC.clear() ; VT.clear() ; + for ( int _i = 0 ; _i < int( vCompoTmpEdges.size()) ; ++ _i) { + VT.emplace_back( vCompoTmpEdges[_i]->Clone()) ; + VC.emplace_back( ORANGE) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\ApproxBorder.nge") ; + #endif + + return true ; +} + +//------------------------------------------------------------------------------ +// Funzione per ottenere i punti di sincronizzazione tra due curve di Bezier per +// la costruzione della superficie rigata stessa +bool +GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, + double dLinTol, BIPNTVECTOR& vSyncPoints) +{ + // Verifica validità delle curve per la creazione della Bezier rigata + PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; + PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; + if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) + return false ; + vSyncPoints.clear() ; + + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + + #if DEBUG_SYNC_POINTS + VT.clear() ; VC.clear() ; + VT.emplace_back( pCompoEdge1->Clone()) ; + VC.emplace_back( AQUA) ; + VT.emplace_back( pCompoEdge2->Clone()) ; + VC.emplace_back( ORANGE) ; + #endif + + // Definisco la superficie di Bezier rigata + PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ; + if ( IsNull( pSBzRuled) || ! pSBzRuled->IsValid()) + return false ; + + // Recupero i punti di sincronizzazione e li restituisco + ICURVEPOVECTOR vCrv ; + pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ; + vSyncPoints.reserve( vCrv.size()) ; + for ( int i = 0 ; i < int( vCrv.size()) ; ++ i) { + if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) { + #if DEBUG_SYNC_POINTS + VT.emplace_back( vCrv[i]->Clone()) ; + VC.emplace_back( LIME) ; + #endif + Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ; + Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ; + if ( ! AreSamePointApprox( ptStart, ptEnd)) + vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ; + } + } + + #if DEBUG_SYNC_POINTS + SaveGeoObj( VT, VC, "C:\\Temp\\BorderSyncPoints.nge") ; + #endif + + return true ; +} + +//------------------------------------------------------------------------------ +// Funzione per il calcolo della superficie di Bezier rigata +// NB. Possono essere passati dei parametri opzionali come vIndPriority e vIndVisible : +// - Se non presenti, la superficie Ruled Bezier viene costruita in modo standard +// - Se sono presenti degli indici di priorità e/o degli indici di visibilità, significa che +// si vuole costruire una superficie diversa da quella standard, dove i tratti prioritari +// sono quelli che più determinano il cambiamento della superficie ( in quanto diversi da quelli +// originali) e i tratti visibili servono per determinare l'intervallo di influenza della modifica +// alla superficie nei pressi dei tratti lineari di sincronizzazione prioritari +ISurfBezier* +GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, + const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints, + const INTVECTOR& vIndPriority, const INTVECTOR& vIndVisible) +{ + // Verifica validità delle curve per la creazione della Bezier rigata + PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; + PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; + if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) + return nullptr ; + // Controllo sulla tolleranza lineare + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + + #if DEBUG_BEZIER_RULED + VT_Glob.emplace_back( pCompoEdge1->Clone()) ; + VT_Glob.emplace_back( pCompoEdge2->Clone()) ; + VC_Glob.emplace_back( ORANGE) ; + VC_Glob.emplace_back( AQUA) ; + #endif + + // Creo la superficie di Bezier + PtrOwner pSurfBz( CreateSurfBezier()) ; + if ( IsNull( pSurfBz)) + return nullptr ; + + // Se non ho punti di controllo forzati + if ( vSyncPoints.empty()) { + pSurfBz.Set( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol)) ; + if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier invalid") ; + return nullptr ; + } + } + // Se ho punti di controllo forzati + else { + // Recupero i tratti lineari di sincronizzazione + ICURVEPOVECTOR vCrv ; vCrv.reserve( vSyncPoints.size()) ; + for ( const BIPOINT& PtSPtE : vSyncPoints) { + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine) || ! pLine->Set( PtSPtE.first, PtSPtE.second)) + return nullptr ; + vCrv.emplace_back( Release( pLine)) ; + } + #if DEBUG_BEZIER_RULED + for ( int _i = 0 ; _i < int( vCrv.size()) ; ++ _i) { + VT_Glob.emplace_back( vCrv[_i]) ; + VC_Glob.emplace_back( LIME) ; + } + #endif + // Definisco la superficie + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vCrv, dMyLinTol)) ; + if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { + LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; + return nullptr ; + } + } + + #if DEBUG_BEZIER_RULED + VT_Glob.emplace_back( pSurfBz->Clone()) ; + VC_Glob.emplace_back( LIME) ; + SaveGeoObj( VT_Glob, VC_Glob, "C:\\Temp\\TestBz.nge") ; + #endif + + // La superficie deve essere orientata correttamente con le geometrie iniziali ( privilegio le TriMesh) + if ( ! vSurf.empty()) { + bool bOk = true ; + Point3d ptPos ; + Vector3d vtN ; + if ( pSurfBz->GetPointNrmD1D2( 0.1, 0.1, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPos, vtN)) { + Point3d ptCheck = ptPos + 10. * EPS_SMALL * vtN ; + for ( const ISurf* pSurf : vSurf) { + if ( pSurf->GetType() == SRF_TRIMESH) { + if ( DistPointSurfTm( ptCheck, *GetSurfTriMesh( pSurf)).IsPointOnLeftSide()) + pSurfBz->Invert() ; + bOk = true ; + break ; + } + } + if ( ! bOk) { + for ( const ISurf* pSurf : vSurf) { + if ( pSurf->GetType() == SRF_BEZIER) { + if ( DistPointSurfBz( ptCheck, *GetSurfBezier( pSurf)).IsPointOnLeftSide()) + pSurfBz->Invert() ; + bOk = true ; + break ; + } + } + } + } + } + + return ( IsNull( pSurfBz) || ! pSurfBz->IsValid() ? nullptr : Release( pSurfBz)) ; +} + +//------------------------------------------------------------------------------ +// Funzione per la ricerca di facce adiacenti su una superficie TriMesh. +// Dato un insieme iniziale di facce, per ciascuna di esse vengono analizzate le facce adiacenti. +// Se la normale di una faccia adiacente forma un angolo entro la tolleranza specificata, +// quella faccia viene memorizzata e considerata come nuovo punto di partenza per la ricerca +// di ulteriori adiacenze. +bool +GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const PNTVECTOR& vPts, + double dAngTol, double dSize, double dSizeTol, INTVECTOR& vOtherTria) +{ + // Verifico la validità della superficie TriMesh e l'esistenza di triangoli di riferimento + if ( ! pStm->IsValid() || vTria.empty()) + return false ; + + // Recupero la superficie di base + const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pStm) ; + if ( pStmBasic == nullptr || ! pStmBasic->IsValid()) + return false ; + + // Definisco un Box3d nel punto di Selezione di dimensioni pari al doppio della dimensione della + // striscia di ricerca considerando la tolleranza + Triangle3d firstTria ; + if ( ! pStmBasic->GetTriangle( vTria[0], firstTria)) + return false ; + BBox3d BBoxCurr ; + BBoxCurr.Add( vPts[0]) ; + const double EXPAND_EXTRA_TOL = 10. * EPS_SMALL ; + BBoxCurr.Expand( ( dSize + dSizeTol + EXPAND_EXTRA_TOL)) ; + + // Recupero i triangoli validi all'interno del Box e definisco i primi due tratti lineari + // per le curve di Bordo + bool bBreak = false, bStop = false ; + unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ; + unordered_set setValidTria ; setValidTria.reserve( pStmBasic->GetTriangleCount()) ; + unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ; + Point3d ptMid, ptMid1 ; + int nTria = 0, nTria1 = 0 ; + CurveComposite CompoA, CompoB ; + if ( ! GetBordersInBox( *pStmBasic, BBoxCurr, vTria[0], vPts[0], dSize, dSizeTol, true, true, + dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB, + ptMid, ptMid1, nTria, nTria1, bBreak, bStop)) + return false ; + + // Se triangolo iniziale non significativo, devo sceglierne un altro + if ( bBreak) { + return true ; // ??? come lo comunico all'utente + } + // Se ho già ricavato tutto, ho finito + else if ( bStop) { + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) + vOtherTria.push_back( *Iter) ; + return true ; + } + + // I nuovi triangoli della striscia vengono memorizzati + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) + setValidTria.insert( *Iter) ; + + // Ricerco nella direzione di ptMid1 + bool bRelFirst = true ; + if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, true, ptMid1, nTria1, + dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + return false ; + + // Se Non ho ricavato un'intera striscia chiusa, allora avvio la ricerca in direzione di ptMid + if ( ! bStop) { + if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, false, ptMid, nTria, + dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + return false ; + } + + // Per ogni triangolo recuperato, cerco le facce a cui appartiene + unordered_set setValidFace ; + for ( auto Iter = setValidTria.begin() ; Iter != setValidTria.end() ; ++ Iter) + vOtherTria.push_back( *Iter) ; + + return true ; +} + +//------------------------------------------------------------------------------ +// Funzione per la ricerca di Superfici in tangenza ( Simile a quanto descritto nella funzione sopra) +bool +GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf, double dLinTol, + double dAngTol, double dFaceAngTol, INTVECTOR& vIndOtherSurf) +{ + // Verifica dei parametri + for ( const ISurf* pSurf : vSurf) { + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + } + for ( const ISurf* pOtherSurf : vOtherSurf) { + if ( pOtherSurf == nullptr || ! pOtherSurf->IsValid()) + return false ; + } + + // creo l'insieme delle curve di bordo in continuità + SURFPATCHESVECTOR vSurfPatches ; vSurfPatches.reserve( vSurf.size() + vOtherSurf.size()) ; + BOXVECTOR vBBox3d ; vBBox3d.reserve( vSurf.size() + vOtherSurf.size()) ; + for ( int nS = 0 ; nS < int( vSurf.size()) ; ++ nS) { + vSurfPatches.emplace_back( SurfPatches()) ; + vSurfPatches.back().pSurf = vSurf[nS] ; + vSurfPatches.back().nIndSurf = nS ; + vBBox3d.emplace_back( BBox3d()) ; + POLYLINEVECTOR vPLBorders ; + if ( ! InsertLoopsOfSurf( vSurf[nS], vPLBorders)) + return false ; + for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL) + vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ; + vBBox3d.back().Expand( 2. * dLinTol) ; + POLYLINEMATRIX matPLPatchBorders ; + if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders)) + return false ; + for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) { + for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) { + Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ; + Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ; + vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ; + vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ; + vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ; + } + } + } + for ( int nS = 0 ; nS < int( vOtherSurf.size()) ; ++ nS) { + vSurfPatches.emplace_back( SurfPatches()) ; + vSurfPatches.back().pSurf = vOtherSurf[nS] ; + vSurfPatches.back().nIndSurf = int( vSurf.size()) + nS ; + vBBox3d.emplace_back( BBox3d()) ; + POLYLINEVECTOR vPLBorders ; + if ( ! InsertLoopsOfSurf( vOtherSurf[nS], vPLBorders)) + continue ; + for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL) + vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ; + vBBox3d.back().Expand( 2. * dLinTol) ; + POLYLINEMATRIX matPLPatchBorders ; + if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders)) + return false ; + for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) { + for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) { + Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ; + Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ; + vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ; + vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ; + vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ; + } + } + } + + // Se necessario, Splitto le Patch per far combiaciare gli estremi + for ( int i = 0 ; i < int( vSurfPatches.size()) - 1 ; ++ i) { + for ( int j = i + 1 ; j < int( vSurfPatches.size()) ; ++ j) { + if ( vBBox3d[i].Overlaps( vBBox3d[j])) { + if ( ! SplitPatchWithPatch( vSurfPatches[i], vSurfPatches[j], dLinTol)) + return false ; + } + } + } + + #if DEBUG_SIMPLE_PATCHES + VT.clear() ; VC.clear() ; + for ( int i = 0 ; i < int( vSurfPatches.size()) ; ++ i) { + Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + for ( int j = 0 ; j < int( vSurfPatches[i].CompoPathces.size()) ; ++ j) { + VT.emplace_back( vSurfPatches[i].CompoPathces[j].Clone()) ; + VC.emplace_back( myCol) ; + IGeoPoint3d* _pt = CreateGeoPoint3d() ; _pt->Set( vSurfPatches[i].vPatches[j].ptStart) ; + VT.emplace_back( _pt) ; + VC.emplace_back( AQUA) ; + IGeoPoint3d* _pt1 = CreateGeoPoint3d() ; _pt1->Set( vSurfPatches[i].vPatches[j].ptEnd) ; + VT.emplace_back( _pt1) ; + VC.emplace_back( AQUA) ; + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\SimplePatch.nge") ; + #endif + + // Verifico ora se le tangenze nei punti di giunzione sono al di sotto della tolleranza angolare + INTVECTOR vSurfToCheck ; + INTSET setSurf ; + for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) + vSurfToCheck.push_back( i) ; + + // Finchè ho una superficie da analizzare + while ( ! vSurfToCheck.empty()) { + // Recupero l'indice della superficie corrente + int nSurf = vSurfToCheck.back() ; + // Elimino l'indice corrente + vSurfToCheck.pop_back() ; + // Se superficie non analizzata, la aggiungo come visitata + auto IterSurf = setSurf.find( nSurf) ; + if ( IterSurf == setSurf.end()) + setSurf.insert( nSurf) ; + // Se già visitata, passo alla successiva + else + continue ; + + // Recupero la superficie corrente + const ISurf* pCurrSurf = vSurfPatches[nSurf].pSurf ; + + // Scorro le sua Patches + for ( int nCurrPatch = 0 ; nCurrPatch < int( vSurfPatches[nSurf].vPatches.size()) ; ++ nCurrPatch) { + // Recupero la Patch attuale + SimplePatch& currPatch = vSurfPatches[nSurf].vPatches[nCurrPatch] ; + // Se Patch già analizzata, passo alla successiva + if ( currPatch.bErase) + continue ; + currPatch.bErase = true ; + // Scorro le altre Patches + for ( int nOtherSurf = 0 ; nOtherSurf < int( vSurfPatches.size()) ; ++ nOtherSurf) { + // Se stessa superficie, passo alla successiva + if ( nOtherSurf == nSurf) + continue ; + // Se superficie già analizzata, passo alla successiva + if ( setSurf.find( nOtherSurf) != setSurf.end()) + continue ; + // Recupero la superficie di confronto + const ISurf* pOtherSurf = vSurfPatches[nOtherSurf].pSurf ; + // Scorro le sua Patches + for ( int nOtherPatch = 0 ; nOtherPatch < int( vSurfPatches[nOtherSurf].vPatches.size()) ; ++ nOtherPatch) { + // Recupero la Patch di confronto + SimplePatch& nextPatch = vSurfPatches[nOtherSurf].vPatches[nOtherPatch] ; + // Se Patch già analizzata, passo alla successiva + if ( nextPatch.bErase) + continue ; + // Se gli estremi coincidono + if ( ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptStart, dLinTol) && + AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptEnd, dLinTol)) || + ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptEnd, dLinTol) && + AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptStart, dLinTol))) { + // Controllo se le tangenze rimangono nella tolleranza + bool bTangent = true ; + // Campiono la Patch corrente + const int MAX_POINTS = 5 ; + BIPNTVECTOR vPtAPtB ; vPtAPtB.reserve( MAX_POINTS + 1) ; + CurveComposite& currCompoPatch = vSurfPatches[nSurf].CompoPathces[nCurrPatch] ; + CurveComposite& otherCompoPatch = vSurfPatches[nOtherSurf].CompoPathces[nOtherPatch] ; + double dLen = 0.; + currCompoPatch.GetLength( dLen) ; + for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) { + double dU = 0. ; + currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ; + Point3d ptCurr ; + currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ; + Point3d ptOther ; + int nFlag = 0 ; + DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag) ; + // Recupero le due normali sulle curva patch campionate + Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ; + if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) || + ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther)) + return false ; + bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + } + // Se superficie in tangenza, aggiorno i parametri + if ( bTangent) { + vSurfToCheck.emplace_back( nOtherSurf) ; + nextPatch.bErase = true ; + if ( nOtherSurf >= int( vSurf.size()) && + find( vIndOtherSurf.begin(), vIndOtherSurf.end(), nOtherSurf - int( vSurf.size())) == vIndOtherSurf.end()) + vIndOtherSurf.push_back( nOtherSurf - int( vSurf.size())) ; + } + } + } + } + } + } + + #if DEBUG_SURF_PATCHES + VT.clear() ; VC.clear() ; + for ( const int& nInd : vIndOtherSurf) { + VT.emplace_back( vOtherSurf[nInd]->Clone()) ; + VC.emplace_back( GRAY) ; + } + for ( const ISurf* pSurf : vSurf) { + VT.emplace_back( pSurf->Clone()) ; + VC.emplace_back( YELLOW) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\SurfPatches.nge") ; + #endif + + return true ; +} + +//------------------------------------------------------------------------------ +// Funzione per la ricerca automatica delle Geometrie di Trimming +bool +GetTrimmingAutoEntities( const CISURFPVECTOR& vSurf, double dShapeLinTol, double dShapeAngTol, + double dLinTol, double dEdgeLinTol, double dAngTol, double dAngFaceTol, + const STRVECTOR& vsShapes, ISURFPOMATRIX& matSelSurf, + ICRVCOMPOPOMATRIX& matCompoBorders, ISURFBEZPOVECTOR& vSurfBz) +{ + // Pulizia dei parametri di ingresso + matSelSurf.clear() ; + matCompoBorders.clear() ; + vSurfBz.clear() ; + + // Se non ho superfici non devo fare nulla + if ( vSurf.empty()) + return true ; + // Verifico che le superfici presenti siano ben definite + for ( const ISurf* pSurf : vSurf) { + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + } + + // Controllo sulla tolleranza lineare + double dMyShapeLinTol = Clamp( dShapeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + double dMyEdgeLinTol = Clamp( dEdgeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; + // Controllo sulla tolleranza angolare + double dMyShapeAngTol = Clamp( dShapeAngTol, 1., 60.) ; + double dMyAngTol = Clamp( dAngTol, 1., 45.) ; + double dMyFaceAngTol = Clamp( dAngFaceTol, 1., 60.) ; + + ICRVCOMPOPOMATRIX matCompoBordersTmp ; + // Se una sola superficie, effettuo la ricerca per triangoli + if ( ssize( vSurf) == 1) { + ISURFPOVECTOR vSurfTmp ; + if ( ! GetShapesFromSurf( vSurf[0], dMyShapeLinTol, dMyShapeAngTol, dMyLinTol, dMyEdgeLinTol, + dMyAngTol, dMyFaceAngTol, vsShapes, vSurfTmp, matCompoBordersTmp)) + return false ; + for ( int i = 0 ; i < ssize( vSurfTmp) ; ++ i) { + matSelSurf.emplace_back( ISURFPOVECTOR{}) ; + matSelSurf.back().emplace_back( Release( vSurfTmp[i])) ; + } + } + // Se più superfici eseguo la ricerca per Patches + else { + + } + + // Se non ho alcuna Geometria voluta, esco + if ( matSelSurf.empty()) + return true ; + + // Per ogni Geometria, approssimo le Curve mediante delle Bezier e calolo la Rigata + for ( int i = 0 ; i < ssize( matSelSurf) ; ++ i) { + matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ; matCompoBorders.back().reserve( 2) ; + if ( ! GetTrimmingBezierEdges( matCompoBordersTmp[i], dLinTol, dAngTol, matCompoBorders.back())) + return false ; + vSurfBz.emplace_back( GetTrimmingRuledBezier( vSurf, matCompoBorders.back()[0], matCompoBorders.back()[1], + dMyLinTol, BIPNTVECTOR{}, INTVECTOR{}, INTVECTOR{})) ; + } + + return true ; +} From 3dddbdf5cde618fc38fb561a0b6924cbf09a992c Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Wed, 7 Jan 2026 09:23:02 +0100 Subject: [PATCH 13/44] EgtGeomKernel : - nelle TriMesh calcolo normali di vertici con peso da angoli - in Zmap pezza per movimenti 5assi sul tip (da correggere veramente). --- SurfTriMesh.cpp | 41 ++++++++++++++++++++++++++++++++++++----- SurfTriMesh.h | 1 + VolZmapVolume.cpp | 12 ++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 16f22f2..4402b1e 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -852,6 +852,9 @@ SurfTriMesh::GetTempInt( int nTriaId, int& nTempInt) const bool SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const { + // flag di pesatura con angolo al vertice + bool bAngWeighted = true ; + // recupero tutti i triangoli attorno al vertice bool bCirc ; INTVECTOR vT ; @@ -871,14 +874,21 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const return false ; // medio le normali, finchè non incontro degli spigoli - vtN = m_vTria[nT].vtN ; + double dAngW = 1 ; + if ( bAngWeighted) + GetTriangleVertexAngle( nT, nV, dAngW) ; + vtN = dAngW * m_vTria[nT].vtN ; // parto dal triangolo e vado in direzione positiva int nLim = nPos ; for ( int i = NextIndAroundVertex( nPos, nTria, bCirc) ; i != nPos && i < int( vT.size()) ; i = NextIndAroundVertex( i, nTria, bCirc)) { - if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) - vtN += m_vTria[vT[i]].vtN ; + if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) { + int nK ; double dAngW = 1 ; + if ( bAngWeighted && FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK)) + GetTriangleVertexAngle( vT[i], nK, dAngW) ; + vtN += dAngW * m_vTria[vT[i]].vtN ; + } else break ; nLim = i ; @@ -887,8 +897,12 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const for ( int i = PrevIndAroundVertex( nPos, nTria, bCirc) ; i != nLim && i >= 0 ; i = PrevIndAroundVertex( i, nTria, bCirc)) { - if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) - vtN += m_vTria[vT[i]].vtN ; + if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) { + int nK ; double dAngW = 1 ; + if ( bAngWeighted && FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK)) + GetTriangleVertexAngle( vT[i], nK, dAngW) ; + vtN += dAngW * m_vTria[vT[i]].vtN ; + } else break ; } @@ -897,6 +911,23 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const return true ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetTriangleVertexAngle( int nT, int nV, double& dAng) const +{ + // verifico esistenza del triangolo e validità vertice + if ( nT < 0 || nT >= GetTriangleSize() || m_vTria[nT].nIdVert[0] == SVT_DEL || nV < 0 || nV > 2) + return false ; + // determino i vettori dei due lati che partono dal vertice + Point3d ptVert = m_vVert[ m_vTria[nT].nIdVert[nV]].ptP ; + Point3d ptPrev = m_vVert[ m_vTria[nT].nIdVert[Prev( nV)]].ptP ; + Point3d ptNext = m_vVert[ m_vTria[nT].nIdVert[Next( nV)]].ptP ; + Vector3d vtPrev = ptPrev - ptVert ; + Vector3d vtNext = ptNext - ptVert ; + // determino l'angolo tra i due lati + return vtPrev.GetAngle( vtNext, dAng) ; +} + //---------------------------------------------------------------------------- SurfTriMesh* SurfTriMesh::CloneTriangle( int nT) const diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 49b92a7..3ab9637 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -414,6 +414,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW int NextIndAroundVertex( int nInd, int nSize, bool bCirc) const ; int PrevIndAroundVertex( int nInd, int nSize, bool bCirc) const ; bool GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const ; + bool GetTriangleVertexAngle( int nT, int nV, double& dAng) const ; bool MarchAlongLoop( int nT, int nV, int nTimeStamp, PolyLine& PL) const ; bool MarchOneTria( int& nT, int& nV, int nTimeStamp, PolyLine& PL, bool& bEnd) const ; bool VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const ; diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index bd28b54..2fa726a 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -1697,6 +1697,9 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c PtrOwner cBezTipEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF1, nDegU, bRat))); PtrOwner cBezTipStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartF2, nDegU, bRat))); PtrOwner cBezTipEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF2, nDegU, bRat))); + // !!!! DA SISTEMARE !!!! + if ( IsNull( cBezTipStartF1) || IsNull( cBezTipEndF1) || IsNull( cBezTipStartF2) || IsNull( cBezTipEndF2)) + return true ; // archi inferiori back CurveArc cArcTipStartB1, cArcTipEndB1, cArcTipStartB2, cArcTipEndB2; cArcTipStartB1.SetC2PN(ptP1T, vPntTipStartBack[0], vPntTipStartBack[1], vtLs); @@ -1707,6 +1710,9 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c PtrOwner cBezTipEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB1, nDegU, bRat))); PtrOwner cBezTipStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartB2, nDegU, bRat))); PtrOwner cBezTipEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB2, nDegU, bRat))); + // !!!! DA SISTEMARE !!!! + if ( IsNull( cBezTipStartB1) || IsNull( cBezTipEndB1) || IsNull( cBezTipStartB2) || IsNull( cBezTipEndB2)) + return true ; // archi superiori front CurveArc cArcTopStartF1, cArcTopEndF1, cArcTopStartF2, cArcTopEndF2; cArcTopStartF1.SetC2PN(ptS, vPntTopStartFront[0], vPntTopStartFront[1], vtLs); @@ -1717,6 +1723,9 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c PtrOwner cBezTopEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF1, nDegU, bRat))); PtrOwner cBezTopStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartF2, nDegU, bRat))); PtrOwner cBezTopEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF2, nDegU, bRat))); + // !!!! DA SISTEMARE !!!! + if ( IsNull( cBezTopStartF1) || IsNull( cBezTopEndF1) || IsNull( cBezTopStartF2) || IsNull( cBezTopEndF2)) + return true ; // archi superiori back CurveArc cArcTopStartB1, cArcTopEndB1, cArcTopStartB2, cArcTopEndB2; cArcTopStartB1.SetC2PN(ptS, vPntTopStartBack[0], vPntTopStartBack[1], vtLs); @@ -1727,6 +1736,9 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c PtrOwner cBezTopEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB1, nDegU, bRat))); PtrOwner cBezTopStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartB2, nDegU, bRat))); PtrOwner cBezTopEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB2, nDegU, bRat))); + // !!!! DA SISTEMARE !!!! + if ( IsNull( cBezTopStartB1) || IsNull( cBezTopEndB1) || IsNull( cBezTopStartB2) || IsNull( cBezTopEndB2)) + return true ; if ( n5AxisType == Move5Axis::NO_BASE_INTERS || n5AxisType == Move5Axis::ACROSS) { // inferiori From 913d5f60caeb315cbb630d0e37315cf384d68480 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Wed, 7 Jan 2026 11:29:57 +0100 Subject: [PATCH 14/44] EgtGeomKernel : - piccole sistemazioni per normali di vertici di Trimesh pesate su angoli. --- SurfTriMesh.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 4402b1e..2fdf8e2 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -852,9 +852,6 @@ SurfTriMesh::GetTempInt( int nTriaId, int& nTempInt) const bool SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const { - // flag di pesatura con angolo al vertice - bool bAngWeighted = true ; - // recupero tutti i triangoli attorno al vertice bool bCirc ; INTVECTOR vT ; @@ -875,8 +872,7 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const // medio le normali, finchè non incontro degli spigoli double dAngW = 1 ; - if ( bAngWeighted) - GetTriangleVertexAngle( nT, nV, dAngW) ; + GetTriangleVertexAngle( nT, nV, dAngW) ; vtN = dAngW * m_vTria[nT].vtN ; // parto dal triangolo e vado in direzione positiva int nLim = nPos ; @@ -885,9 +881,9 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const i = NextIndAroundVertex( i, nTria, bCirc)) { if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) { int nK ; double dAngW = 1 ; - if ( bAngWeighted && FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK)) - GetTriangleVertexAngle( vT[i], nK, dAngW) ; - vtN += dAngW * m_vTria[vT[i]].vtN ; + if ( FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK) && + GetTriangleVertexAngle( vT[i], nK, dAngW)) + vtN += dAngW * m_vTria[vT[i]].vtN ; } else break ; @@ -899,9 +895,9 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const i = PrevIndAroundVertex( i, nTria, bCirc)) { if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) { int nK ; double dAngW = 1 ; - if ( bAngWeighted && FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK)) - GetTriangleVertexAngle( vT[i], nK, dAngW) ; - vtN += dAngW * m_vTria[vT[i]].vtN ; + if ( FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK) && + GetTriangleVertexAngle( vT[i], nK, dAngW)) + vtN += dAngW * m_vTria[vT[i]].vtN ; } else break ; From 0d62cd9bbd88e27b1e130744855c43dba23703cc Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 7 Jan 2026 12:26:13 +0100 Subject: [PATCH 15/44] EgtGeomKernel : - aggiunta controlli e correzione al VM 5 assi in caso di movimento a perno sulla punta del tool. --- VolZmapVolume.cpp | 774 +++++++++++++++++++++++----------------------- 1 file changed, 393 insertions(+), 381 deletions(-) diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index 2fa726a..e1b835f 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -1549,429 +1549,441 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c { // tolgo il volume spazzato dal tool durante il movimento // Verifica sull'interferenza con lo Zmap - int nStartI, nStartJ, nEndI, nEndJ ; - if ( ! TestCompoBBox( nGrid, ptS, ptE, vtLs, vtLe, dMaxRad, dMinRad, dHeight, nStartI, nStartJ, nEndI, nEndJ)) - return true ; + int nStartI, nStartJ, nEndI, nEndJ ; + if ( ! TestCompoBBox( nGrid, ptS, ptE, vtLs, vtLe, dMaxRad, dMinRad, dHeight, nStartI, nStartJ, nEndI, nEndJ)) + return true ; // vettori di riferimento per trovare i punti ausiliari - int nDegU = 3 ; int nDegV = 1 ; - int nSpanU = 1 ; int nSpanV = 1 ; - bool bRat = false ; + int nDegU = 3 ; int nDegV = 1 ; + int nSpanU = 1 ; int nSpanV = 1 ; + bool bRat = false ; - int nSub = 2 ; // numero di bezier di grado 3x1 con cui approssimare il (quasi) semi-cilindro ellissoide che descrive il volume della punta e della cima del tool - PNTVECTOR d ; - Vector3d q = Z_AX ; + int nSub = 2 ; // numero di bezier di grado 3x1 con cui approssimare il (quasi) semi-cilindro ellissoide che descrive il volume della punta e della cima del tool + PNTVECTOR d ; + Vector3d q = Z_AX ; - int nTotSurf = 4 ; - if ( n5AxisType == Move5Axis::NO_BASE_INTERS) - nTotSurf = 2 + nSub * 2 + nSub * 2 + 8 ; // sup laterali, sup superiori e inferiori, superfici verticali di inizio e fine, superfici di base dei tool - else if ( n5AxisType == Move5Axis::ACROSS) - nTotSurf = 2 + nSub * 4 + nSub * 2 + 16 ; // come sopra + int nTotSurf = 4 ; + if ( n5AxisType == Move5Axis::NO_BASE_INTERS) + nTotSurf = 2 + nSub * 2 + nSub * 2 + 8 ; // sup laterali, sup superiori e inferiori, superfici verticali di inizio e fine, superfici di base dei tool + else if ( n5AxisType == Move5Axis::ACROSS) + nTotSurf = 2 + nSub * 4 + nSub * 2 + 16 ; // come sopra - int nSurfInd = 0 ; - vector vSurfBez( nTotSurf) ; - double dSide = 0 ; + int nSurfInd = 0 ; + vector vSurfBez( nTotSurf) ; + double dSide = 0 ; // punti di riferimento sul tool // tip del tool - Point3d ptP1T ; - Point3d ptP2T ; - // determino la posizione della punta del tool nella posizione iniziale e in quella finale - ptP1T = ptS - dHeight * vtLs ; - ptP2T = ptE - dHeight * vtLe ; - // determino la direzione di movimento del top del tool e della punta del tool - Vector3d vtDirTop = ptE - ptS ; - Vector3d vtDirTip = ptP2T - ptP1T ; + Point3d ptP1T ; + Point3d ptP2T ; + // determino la posizione della punta del tool nella posizione iniziale e in quella finale + ptP1T = ptS - dHeight * vtLs ; + ptP2T = ptE - dHeight * vtLe ; + // determino la direzione di movimento del top del tool e della punta del tool + Vector3d vtDirTop = ptE - ptS ; + Vector3d vtDirTip = ptP2T - ptP1T ; + bool bTopIsPivot = vtDirTop.IsSmall() ; + bool bTipIsPivot = vtDirTip.IsSmall() ; + bool bTopAndTipAreEquiverse = vtDirTop * vtDirTip > 0 ; // box dell'intero volume spazzato, nel riferimento object oriented - BBox3d bbVol ; - Frame3d frVol ; frVol.Set(ptS, vtLs, vtDirTop) ; + BBox3d bbVol ; + Frame3d frVol ; frVol.Set(ptS, vtLs, vtDirTop) ; - // punti sul top e tip del tool che servono per costruire le bilineare di congiunzione tra step - PNTVECTOR vPntTipStartFront(3) ; - PNTVECTOR vPntTipEndFront(3) ; - PNTVECTOR vPntTopStartFront(3) ; - PNTVECTOR vPntTopEndFront(3) ; - // punti addizionali che servono nei casi che rischiedono più superfici bilineari ( tutti tranne NO_BASE_INTERS) - PNTVECTOR vPntTipStartBack(3) ; - PNTVECTOR vPntTipEndBack(3) ; - PNTVECTOR vPntTopStartBack(3) ; - PNTVECTOR vPntTopEndBack(3) ; - if ( nSub > 1) { - // determino in che modo collegare il cilindro iniziale con quello finale - Vector3d vtTopBaseEnd = vtDirTop - (( vtDirTop * vtLe) * vtLe) ; - vtTopBaseEnd.Normalize() ; - vtTopBaseEnd *= dMaxRad ; - Point3d ptRefEnd = ptE - vtTopBaseEnd ; - Vector3d vtTopBaseStart = vtDirTop - (( vtDirTop * vtLs) * vtLs) ; - vtTopBaseStart.Normalize() ; - vtTopBaseStart *= dMaxRad ; - Point3d ptRefStart = ptS + vtTopBaseStart ; - dSide = ( ptRefEnd - ptRefStart) * vtLs ; + // punti sul top e tip del tool che servono per costruire le bilineare di congiunzione tra step + PNTVECTOR vPntTipStartFront(3) ; + PNTVECTOR vPntTipEndFront(3) ; + PNTVECTOR vPntTopStartFront(3) ; + PNTVECTOR vPntTopEndFront(3) ; + // punti addizionali che servono nei casi che rischiedono più superfici bilineari ( tutti tranne NO_BASE_INTERS) + PNTVECTOR vPntTipStartBack(3) ; + PNTVECTOR vPntTipEndBack(3) ; + PNTVECTOR vPntTopStartBack(3) ; + PNTVECTOR vPntTopEndBack(3) ; + if ( nSub > 1) { + if( bTopIsPivot) + vtDirTop = vtDirTip ; + if( bTipIsPivot) + vtDirTip = vtDirTop ; + // determino in che modo collegare il cilindro iniziale con quello finale + Vector3d vtTopBaseEnd = vtDirTop - (( vtDirTop * vtLe) * vtLe) ; + vtTopBaseEnd.Normalize() ; + vtTopBaseEnd *= dMaxRad ; + Point3d ptRefEnd = ptE - vtTopBaseEnd ; + Vector3d vtTopBaseStart = vtDirTop - (( vtDirTop * vtLs) * vtLs) ; + vtTopBaseStart.Normalize() ; + vtTopBaseStart *= dMaxRad ; + Point3d ptRefStart = ptS + vtTopBaseStart ; + dSide = ( ptRefEnd - ptRefStart) * vtLs ; - // calcolo anche i vettori per le basi inferiori - Vector3d vtTipBaseStart = -( vtLs ^ vtDirTip) ; - vtTipBaseStart.Normalize() ; - vtTipBaseStart *= dMinRad ; - Vector3d vtTipBaseEnd = -( vtLe ^ vtDirTip) ; - vtTipBaseEnd.Normalize() ; - vtTipBaseEnd *= dMinRad ; - // aggiungo il primo punto per ognuno dei gruppi - vtTopBaseStart.Rotate( vtLs, 90) ; - vtTopBaseEnd.Rotate( vtLe, 90) ; - vPntTopStartFront[0] = ptS - vtTopBaseStart ; - vPntTopEndFront[0] = ptE - vtTopBaseEnd ; - vPntTipStartFront[0] = ptP1T + vtTipBaseStart ; - vPntTipEndFront[0] = ptP2T + vtTipBaseEnd ; + // calcolo anche i vettori per le basi inferiori + Vector3d vtTipBaseStart = -( vtLs ^ vtDirTip) ; + vtTipBaseStart.Normalize() ; + vtTipBaseStart *= dMinRad ; + Vector3d vtTipBaseEnd = -( vtLe ^ vtDirTip) ; + vtTipBaseEnd.Normalize() ; + vtTipBaseEnd *= dMinRad ; + // aggiungo il primo punto per ognuno dei gruppi + vtTopBaseStart.Rotate( vtLs, 90) ; + vtTopBaseEnd.Rotate( vtLe, 90) ; + vPntTopStartFront[0] = ptS - vtTopBaseStart ; + vPntTopEndFront[0] = ptE - vtTopBaseEnd ; + vPntTipStartFront[0] = ptP1T + vtTipBaseStart ; + vPntTipEndFront[0] = ptP2T + vtTipBaseEnd ; - // punti addizionali per superfici bilineari - vPntTopStartBack[0] = ptS + vtTopBaseStart ; - vPntTopEndBack[0] = ptE + vtTopBaseEnd ; - vPntTipStartBack[0] = ptP1T - vtTipBaseStart ; - vPntTipEndBack[0] = ptP2T - vtTipBaseEnd ; - double dSubAng = 90 ; - // girano tutti in verso CCW rispetto alla normale del tool - for ( int i = 1; i < 3; ++i) { - // punti sulla base superiore dei cilindri - // start - // frontale - vPntTopStartFront[i] = vPntTopStartFront[i - 1] ; - vPntTopStartFront[i].Rotate( ptS, vtLs, dSubAng) ; - // posteriore - vPntTopStartBack[i] = vPntTopStartBack[i - 1]; - vPntTopStartBack[i].Rotate( ptS, vtLs, dSubAng) ; - // end - // frontale - vPntTopEndFront[i] = vPntTopEndFront[i - 1] ; - vPntTopEndFront[i].Rotate( ptE, vtLe, dSubAng) ; - // posteriore - vPntTopEndBack[i] = vPntTopEndBack[i - 1] ; - vPntTopEndBack[i].Rotate( ptE, vtLe, dSubAng) ; + // punti addizionali per superfici bilineari + vPntTopStartBack[0] = ptS + vtTopBaseStart ; + vPntTopEndBack[0] = ptE + vtTopBaseEnd ; + vPntTipStartBack[0] = ptP1T - vtTipBaseStart ; + vPntTipEndBack[0] = ptP2T - vtTipBaseEnd ; + double dSubAng = 90 ; + // girano tutti in verso CCW rispetto alla normale del tool + for ( int i = 1; i < 3; ++i) { + // punti sulla base superiore dei cilindri + // start + // frontale + vPntTopStartFront[i] = vPntTopStartFront[i - 1] ; + vPntTopStartFront[i].Rotate( ptS, vtLs, dSubAng) ; + // posteriore + vPntTopStartBack[i] = vPntTopStartBack[i - 1]; + vPntTopStartBack[i].Rotate( ptS, vtLs, dSubAng) ; + // end + // frontale + vPntTopEndFront[i] = vPntTopEndFront[i - 1] ; + vPntTopEndFront[i].Rotate( ptE, vtLe, dSubAng) ; + // posteriore + vPntTopEndBack[i] = vPntTopEndBack[i - 1] ; + vPntTopEndBack[i].Rotate( ptE, vtLe, dSubAng) ; - // punti sulla base inferiore dei cilindri - vPntTipStartFront[i] = vPntTipStartFront[i - 1] ; - vPntTipStartFront[i].Rotate( ptP1T, vtLs, dSubAng) ; - vPntTipStartBack[i] = vPntTipStartBack[i - 1] ; - vPntTipStartBack[i].Rotate( ptP1T, vtLs, dSubAng) ; + // punti sulla base inferiore dei cilindri + vPntTipStartFront[i] = vPntTipStartFront[i - 1] ; + vPntTipStartFront[i].Rotate( ptP1T, vtLs, dSubAng) ; + vPntTipStartBack[i] = vPntTipStartBack[i - 1] ; + vPntTipStartBack[i].Rotate( ptP1T, vtLs, dSubAng) ; - vPntTipEndFront[i] = vPntTipEndFront[i - 1] ; - vPntTipEndFront[i].Rotate( ptP2T, vtLe, dSubAng) ; - vPntTipEndBack[i] = vPntTipEndBack[i - 1] ; - vPntTipEndBack[i].Rotate( ptP2T, vtLe, dSubAng) ; - } - } + vPntTipEndFront[i] = vPntTipEndFront[i - 1] ; + vPntTipEndFront[i].Rotate( ptP2T, vtLe, dSubAng) ; + vPntTipEndBack[i] = vPntTipEndBack[i - 1] ; + vPntTipEndBack[i].Rotate( ptP2T, vtLe, dSubAng) ; + } + } - vector vvPtCtrl ; - // superficie laterale sinistra - CurveLine cLineLeftStart ; cLineLeftStart.Set( vPntTipStartFront.back(), vPntTopStartFront.back()) ; - PtrOwner cBezLeftStart( GetBasicCurveBezier( LineToBezierCurve( &cLineLeftStart, nDegU, bRat))) ; - CurveLine cLineLeftEnd ; cLineLeftEnd.Set( vPntTipEndFront.back(), vPntTopEndFront.back()) ; - PtrOwner cBezLeftEnd( GetBasicCurveBezier( LineToBezierCurve( &cLineLeftEnd, nDegU, bRat))) ; - vvPtCtrl.emplace_back( cBezLeftStart->GetAllControlPoints()) ; - PNTVECTOR vPntLeft = cBezLeftEnd->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntLeft.begin(), vPntLeft.end()) ; - // superficie laterale destra - CurveLine cLineRightStart ; cLineRightStart.Set( vPntTopStartFront.front(), vPntTipStartFront.front()) ; - PtrOwner cBezRightStart( GetBasicCurveBezier( LineToBezierCurve( &cLineRightStart, nDegU, bRat))) ; - CurveLine cLineRightEnd ; cLineRightEnd.Set( vPntTopEndFront.front(), vPntTipEndFront.front()) ; - PtrOwner cBezRightEnd( GetBasicCurveBezier( LineToBezierCurve( &cLineRightEnd, nDegU, bRat))) ; - vvPtCtrl.emplace_back( cBezRightStart->GetAllControlPoints()) ; - PNTVECTOR vPntRight = cBezRightEnd->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntRight.begin(), vPntRight.end()) ; - if ( nSub == 1) { - // superficie inferiore - vvPtCtrl.emplace_back( PNTVECTOR( { vPntTipStartFront.front(), vPntTipStartFront.back(), vPntTipEndFront.front(), vPntTipEndFront.back() })) ; - // superficie superiore - vvPtCtrl.emplace_back( PNTVECTOR( { vPntTopStartFront.back(), vPntTopStartFront.front(), vPntTopEndFront.back(), vPntTopEndFront.front() })) ; - } - else { - // costruisco tutti gli archi subito - // archi inferiori front - CurveArc cArcTipStartF1, cArcTipEndF1, cArcTipStartF2, cArcTipEndF2 ; - cArcTipStartF1.SetC2PN(ptP1T, vPntTipStartFront[0], vPntTipStartFront[1], vtLs); - cArcTipEndF1.SetC2PN(ptP2T, vPntTipEndFront[0], vPntTipEndFront[1], vtLe); - cArcTipStartF2.SetC2PN(ptP1T, vPntTipStartFront[1], vPntTipStartFront[2], vtLs); - cArcTipEndF2.SetC2PN(ptP2T, vPntTipEndFront[1], vPntTipEndFront[2], vtLe); - PtrOwner cBezTipStartF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartF1, nDegU, bRat))); - PtrOwner cBezTipEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF1, nDegU, bRat))); - PtrOwner cBezTipStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartF2, nDegU, bRat))); - PtrOwner cBezTipEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF2, nDegU, bRat))); - // !!!! DA SISTEMARE !!!! - if ( IsNull( cBezTipStartF1) || IsNull( cBezTipEndF1) || IsNull( cBezTipStartF2) || IsNull( cBezTipEndF2)) - return true ; - // archi inferiori back - CurveArc cArcTipStartB1, cArcTipEndB1, cArcTipStartB2, cArcTipEndB2; - cArcTipStartB1.SetC2PN(ptP1T, vPntTipStartBack[0], vPntTipStartBack[1], vtLs); - cArcTipEndB1.SetC2PN(ptP2T, vPntTipEndBack[0], vPntTipEndBack[1], vtLe); - cArcTipStartB2.SetC2PN(ptP1T, vPntTipStartBack[1], vPntTipStartBack[2], vtLs); - cArcTipEndB2.SetC2PN(ptP2T, vPntTipEndBack[1], vPntTipEndBack[2], vtLe); - PtrOwner cBezTipStartB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartB1, nDegU, bRat))); - PtrOwner cBezTipEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB1, nDegU, bRat))); - PtrOwner cBezTipStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartB2, nDegU, bRat))); - PtrOwner cBezTipEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB2, nDegU, bRat))); - // !!!! DA SISTEMARE !!!! - if ( IsNull( cBezTipStartB1) || IsNull( cBezTipEndB1) || IsNull( cBezTipStartB2) || IsNull( cBezTipEndB2)) - return true ; - // archi superiori front - CurveArc cArcTopStartF1, cArcTopEndF1, cArcTopStartF2, cArcTopEndF2; - cArcTopStartF1.SetC2PN(ptS, vPntTopStartFront[0], vPntTopStartFront[1], vtLs); - cArcTopEndF1.SetC2PN(ptE, vPntTopEndFront[0], vPntTopEndFront[1], vtLe); - cArcTopStartF2.SetC2PN(ptS, vPntTopStartFront[1], vPntTopStartFront[2], vtLs); - cArcTopEndF2.SetC2PN(ptE, vPntTopEndFront[1], vPntTopEndFront[2], vtLe); - PtrOwner cBezTopStartF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartF1, nDegU, bRat))); - PtrOwner cBezTopEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF1, nDegU, bRat))); - PtrOwner cBezTopStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartF2, nDegU, bRat))); - PtrOwner cBezTopEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF2, nDegU, bRat))); - // !!!! DA SISTEMARE !!!! - if ( IsNull( cBezTopStartF1) || IsNull( cBezTopEndF1) || IsNull( cBezTopStartF2) || IsNull( cBezTopEndF2)) - return true ; - // archi superiori back - CurveArc cArcTopStartB1, cArcTopEndB1, cArcTopStartB2, cArcTopEndB2; - cArcTopStartB1.SetC2PN(ptS, vPntTopStartBack[0], vPntTopStartBack[1], vtLs); - cArcTopEndB1.SetC2PN(ptE, vPntTopEndBack[0], vPntTopEndBack[1], vtLe); - cArcTopStartB2.SetC2PN(ptS, vPntTopStartBack[1], vPntTopStartBack[2], vtLs); - cArcTopEndB2.SetC2PN(ptE, vPntTopEndBack[1], vPntTopEndBack[2], vtLe); - PtrOwner cBezTopStartB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartB1, nDegU, bRat))); - PtrOwner cBezTopEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB1, nDegU, bRat))); - PtrOwner cBezTopStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartB2, nDegU, bRat))); - PtrOwner cBezTopEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB2, nDegU, bRat))); - // !!!! DA SISTEMARE !!!! - if ( IsNull( cBezTopStartB1) || IsNull( cBezTopEndB1) || IsNull( cBezTopStartB2) || IsNull( cBezTopEndB2)) - return true ; + vector vvPtCtrl ; + // superficie laterale sinistra + CurveLine cLineLeftStart ; cLineLeftStart.Set( vPntTipStartFront.back(), vPntTopStartFront.back()) ; + PtrOwner cBezLeftStart( GetBasicCurveBezier( LineToBezierCurve( &cLineLeftStart, nDegU, bRat))) ; + CurveLine cLineLeftEnd ; cLineLeftEnd.Set( vPntTipEndFront.back(), vPntTopEndFront.back()) ; + PtrOwner cBezLeftEnd( GetBasicCurveBezier( LineToBezierCurve( &cLineLeftEnd, nDegU, bRat))) ; + vvPtCtrl.emplace_back( cBezLeftStart->GetAllControlPoints()) ; + PNTVECTOR vPntLeft = cBezLeftEnd->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntLeft.begin(), vPntLeft.end()) ; + // superficie laterale destra + CurveLine cLineRightStart ; cLineRightStart.Set( vPntTopStartFront.front(), vPntTipStartFront.front()) ; + PtrOwner cBezRightStart( GetBasicCurveBezier( LineToBezierCurve( &cLineRightStart, nDegU, bRat))) ; + CurveLine cLineRightEnd ; cLineRightEnd.Set( vPntTopEndFront.front(), vPntTipEndFront.front()) ; + PtrOwner cBezRightEnd( GetBasicCurveBezier( LineToBezierCurve( &cLineRightEnd, nDegU, bRat))) ; + vvPtCtrl.emplace_back( cBezRightStart->GetAllControlPoints()) ; + PNTVECTOR vPntRight = cBezRightEnd->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntRight.begin(), vPntRight.end()) ; + if ( nSub == 1) { + // superficie inferiore + vvPtCtrl.emplace_back( PNTVECTOR( { vPntTipStartFront.front(), vPntTipStartFront.back(), vPntTipEndFront.front(), vPntTipEndFront.back() })) ; + // superficie superiore + vvPtCtrl.emplace_back( PNTVECTOR( { vPntTopStartFront.back(), vPntTopStartFront.front(), vPntTopEndFront.back(), vPntTopEndFront.front() })) ; + } + else { + // costruisco tutti gli archi subito + // archi inferiori front + CurveArc cArcTipStartF1, cArcTipEndF1, cArcTipStartF2, cArcTipEndF2 ; + if ( ! cArcTipStartF1.SetC2PN(ptP1T, vPntTipStartFront[0], vPntTipStartFront[1], vtLs) || + ! cArcTipEndF1.SetC2PN(ptP2T, vPntTipEndFront[0], vPntTipEndFront[1], vtLe) || + ! cArcTipStartF2.SetC2PN(ptP1T, vPntTipStartFront[1], vPntTipStartFront[2], vtLs) || + ! cArcTipEndF2.SetC2PN(ptP2T, vPntTipEndFront[1], vPntTipEndFront[2], vtLe)) + return false ; + PtrOwner cBezTipStartF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartF1, nDegU, bRat))); + PtrOwner cBezTipEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF1, nDegU, bRat))); + PtrOwner cBezTipStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartF2, nDegU, bRat))); + PtrOwner cBezTipEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndF2, nDegU, bRat))); + // archi inferiori back + CurveArc cArcTipStartB1, cArcTipEndB1, cArcTipStartB2, cArcTipEndB2; + if ( ! cArcTipStartB1.SetC2PN(ptP1T, vPntTipStartBack[0], vPntTipStartBack[1], vtLs) || + ! cArcTipEndB1.SetC2PN(ptP2T, vPntTipEndBack[0], vPntTipEndBack[1], vtLe) || + ! cArcTipStartB2.SetC2PN(ptP1T, vPntTipStartBack[1], vPntTipStartBack[2], vtLs) || + ! cArcTipEndB2.SetC2PN(ptP2T, vPntTipEndBack[1], vPntTipEndBack[2], vtLe)) + return false ; + PtrOwner cBezTipStartB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartB1, nDegU, bRat))); + PtrOwner cBezTipEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB1, nDegU, bRat))); + PtrOwner cBezTipStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipStartB2, nDegU, bRat))); + PtrOwner cBezTipEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTipEndB2, nDegU, bRat))); + if ( IsNull( cBezTipStartB1) || IsNull( cBezTipEndB1) || IsNull( cBezTipStartB2) || IsNull( cBezTipEndB2)) + return false ; + // archi superiori front + CurveArc cArcTopStartF1, cArcTopEndF1, cArcTopStartF2, cArcTopEndF2; + if ( ! cArcTopStartF1.SetC2PN(ptS, vPntTopStartFront[0], vPntTopStartFront[1], vtLs) || + ! cArcTopEndF1.SetC2PN(ptE, vPntTopEndFront[0], vPntTopEndFront[1], vtLe) || + ! cArcTopStartF2.SetC2PN(ptS, vPntTopStartFront[1], vPntTopStartFront[2], vtLs) || + ! cArcTopEndF2.SetC2PN(ptE, vPntTopEndFront[1], vPntTopEndFront[2], vtLe)) + return false ; + PtrOwner cBezTopStartF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartF1, nDegU, bRat))); + PtrOwner cBezTopEndF1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF1, nDegU, bRat))); + PtrOwner cBezTopStartF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartF2, nDegU, bRat))); + PtrOwner cBezTopEndF2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndF2, nDegU, bRat))); + if ( IsNull( cBezTopStartF1) || IsNull( cBezTopEndF1) || IsNull( cBezTopStartF2) || IsNull( cBezTopEndF2)) + return false ; + // archi superiori back + CurveArc cArcTopStartB1, cArcTopEndB1, cArcTopStartB2, cArcTopEndB2; + if ( ! cArcTopStartB1.SetC2PN(ptS, vPntTopStartBack[0], vPntTopStartBack[1], vtLs) || + ! cArcTopEndB1.SetC2PN(ptE, vPntTopEndBack[0], vPntTopEndBack[1], vtLe) || + ! cArcTopStartB2.SetC2PN(ptS, vPntTopStartBack[1], vPntTopStartBack[2], vtLs) || + ! cArcTopEndB2.SetC2PN(ptE, vPntTopEndBack[1], vPntTopEndBack[2], vtLe)) + return false ; + PtrOwner cBezTopStartB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartB1, nDegU, bRat))); + PtrOwner cBezTopEndB1(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB1, nDegU, bRat))); + PtrOwner cBezTopStartB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopStartB2, nDegU, bRat))); + PtrOwner cBezTopEndB2(GetBasicCurveBezier(ArcToBezierCurve(&cArcTopEndB2, nDegU, bRat))); + if ( IsNull( cBezTopStartB1) || IsNull( cBezTopEndB1) || IsNull( cBezTopStartB2) || IsNull( cBezTopEndB2)) + return false ; - if ( n5AxisType == Move5Axis::NO_BASE_INTERS || n5AxisType == Move5Axis::ACROSS) { + if ( n5AxisType == Move5Axis::NO_BASE_INTERS || n5AxisType == Move5Axis::ACROSS) { + if ( ! bTipIsPivot) { // inferiori - CurveArc cArcTipStart1, cArcTipEnd1, cArcTipStart2, cArcTipEnd2 ; if ( dSide > 0) { - vvPtCtrl.emplace_back(cBezTipStartF1->GetAllControlPoints()); - PNTVECTOR vPntTipEnd1 = cBezTipEndF1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd1.begin(), vPntTipEnd1.end()); - vvPtCtrl.emplace_back(cBezTipStartF2->GetAllControlPoints()); - PNTVECTOR vPntTipEnd2 = cBezTipEndF2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd2.begin(), vPntTipEnd2.end()); + vvPtCtrl.emplace_back(cBezTipStartF1->GetAllControlPoints()); + PNTVECTOR vPntTipEnd1 = cBezTipEndF1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd1.begin(), vPntTipEnd1.end()); + vvPtCtrl.emplace_back(cBezTipStartF2->GetAllControlPoints()); + PNTVECTOR vPntTipEnd2 = cBezTipEndF2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd2.begin(), vPntTipEnd2.end()); } else { - PNTVECTOR vPntTipEnd01 = cBezTipStartB1->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTipEnd01.rbegin(), vPntTipEnd01.rend()); - PNTVECTOR vPntTipEnd1 = cBezTipEndB1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd1.rbegin(), vPntTipEnd1.rend()); - PNTVECTOR vPntTipEnd02 = cBezTipStartB2->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTipEnd02.rbegin(), vPntTipEnd02.rend()); - PNTVECTOR vPntTipEnd2 = cBezTipEndB2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd2.rbegin(), vPntTipEnd2.rend()); + PNTVECTOR vPntTipEnd01 = cBezTipStartB1->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTipEnd01.rbegin(), vPntTipEnd01.rend()); + PNTVECTOR vPntTipEnd1 = cBezTipEndB1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd1.rbegin(), vPntTipEnd1.rend()); + PNTVECTOR vPntTipEnd02 = cBezTipStartB2->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTipEnd02.rbegin(), vPntTipEnd02.rend()); + PNTVECTOR vPntTipEnd2 = cBezTipEndB2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTipEnd2.rbegin(), vPntTipEnd2.rend()); } + } + if ( ! bTopIsPivot) { // superiori if ( dSide > 0) { - vvPtCtrl.emplace_back(cBezTopStartB1->GetAllControlPoints()); - PNTVECTOR vPntTopEnd1 = cBezTopEndB1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd1.begin(), vPntTopEnd1.end()); - vvPtCtrl.emplace_back(cBezTopStartB2->GetAllControlPoints()); - PNTVECTOR vPntTopEnd2 = cBezTopEndB2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd2.begin(), vPntTopEnd2.end()); + vvPtCtrl.emplace_back(cBezTopStartB1->GetAllControlPoints()); + PNTVECTOR vPntTopEnd1 = cBezTopEndB1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd1.begin(), vPntTopEnd1.end()); + vvPtCtrl.emplace_back(cBezTopStartB2->GetAllControlPoints()); + PNTVECTOR vPntTopEnd2 = cBezTopEndB2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd2.begin(), vPntTopEnd2.end()); } else { - PNTVECTOR vPntTopEnd01 = cBezTopStartF1->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTopEnd01.rbegin(), vPntTopEnd01.rend()); - PNTVECTOR vPntTopEnd1 = cBezTopEndF1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd1.rbegin(), vPntTopEnd1.rend()); - PNTVECTOR vPntTopEnd02 = cBezTopStartF2->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTopEnd02.rbegin(), vPntTopEnd02.rend()); - PNTVECTOR vPntTopEnd2 = cBezTopEndF2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd2.rbegin(), vPntTopEnd2.rend()); + PNTVECTOR vPntTopEnd01 = cBezTopStartF1->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTopEnd01.rbegin(), vPntTopEnd01.rend()); + PNTVECTOR vPntTopEnd1 = cBezTopEndF1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd1.rbegin(), vPntTopEnd1.rend()); + PNTVECTOR vPntTopEnd02 = cBezTopStartF2->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTopEnd02.rbegin(), vPntTopEnd02.rend()); + PNTVECTOR vPntTopEnd2 = cBezTopEndF2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTopEnd2.rbegin(), vPntTopEnd2.rend()); + } + } + + // aggiungo le superfici bilineari anche nell'altro verso sia per il top che per il tip + if ( n5AxisType == Move5Axis::ACROSS) { + if ( ! bTipIsPivot) { + // inferiori + if ( dSide > 0) { + PNTVECTOR vPntTip01 = cBezTipStartB1->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTip01.rbegin(), vPntTip01.rend()); + PNTVECTOR vPntTip1 = cBezTipEndB1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip1.rbegin(), vPntTip1.rend()); + PNTVECTOR vPntTip02 = cBezTipStartB2->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTip02.rbegin(), vPntTip02.rend()); + PNTVECTOR vPntTip2 = cBezTipEndB2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip2.rbegin(), vPntTip2.rend()); + } + else { + vvPtCtrl.emplace_back(cBezTipStartF1->GetAllControlPoints()); + PNTVECTOR vPntTip1 = cBezTipEndF1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip1.begin(), vPntTip1.end()); + vvPtCtrl.emplace_back(cBezTipStartF2->GetAllControlPoints()); + PNTVECTOR vPntTip2 = cBezTipEndF2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip2.begin(), vPntTip2.end()); + } } - // aggiungo le superfici bilineari anche nell'altro verso sia per il top che per il tip - if ( n5AxisType == Move5Axis::ACROSS) { - // inferiori - if ( dSide > 0) { - PNTVECTOR vPntTip01 = cBezTipStartB1->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTip01.rbegin(), vPntTip01.rend()); - PNTVECTOR vPntTip1 = cBezTipEndB1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip1.rbegin(), vPntTip1.rend()); - PNTVECTOR vPntTip02 = cBezTipStartB2->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTip02.rbegin(), vPntTip02.rend()); - PNTVECTOR vPntTip2 = cBezTipEndB2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip2.rbegin(), vPntTip2.rend()); - } - else { - vvPtCtrl.emplace_back(cBezTipStartF1->GetAllControlPoints()); - PNTVECTOR vPntTip1 = cBezTipEndF1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip1.begin(), vPntTip1.end()); - vvPtCtrl.emplace_back(cBezTipStartF2->GetAllControlPoints()); - PNTVECTOR vPntTip2 = cBezTipEndF2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTip2.begin(), vPntTip2.end()); - } - - // superiori - if ( dSide > 0) { - PNTVECTOR vPntTop01 = cBezTopStartF1->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTop01.rbegin(), vPntTop01.rend()); - PNTVECTOR vPntTop1 = cBezTopEndF1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop1.rbegin(), vPntTop1.rend()); - PNTVECTOR vPntTop02 = cBezTopStartF2->GetAllControlPoints(); - vvPtCtrl.emplace_back(vPntTop02.rbegin(), vPntTop02.rend()); - PNTVECTOR vPntTop2 = cBezTopEndF2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop2.rbegin(), vPntTop2.rend()); - } - else { - vvPtCtrl.emplace_back(cBezTopStartB1->GetAllControlPoints()); - PNTVECTOR vPntTop1 = cBezTopEndB1->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop1.begin(), vPntTop1.end()); - vvPtCtrl.emplace_back(cBezTopStartB2->GetAllControlPoints()); - PNTVECTOR vPntTop2 = cBezTopEndB2->GetAllControlPoints(); - vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop2.begin(), vPntTop2.end()); - } + if( ! bTopIsPivot) { + // superiori + if ( dSide > 0) { + PNTVECTOR vPntTop01 = cBezTopStartF1->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTop01.rbegin(), vPntTop01.rend()); + PNTVECTOR vPntTop1 = cBezTopEndF1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop1.rbegin(), vPntTop1.rend()); + PNTVECTOR vPntTop02 = cBezTopStartF2->GetAllControlPoints(); + vvPtCtrl.emplace_back(vPntTop02.rbegin(), vPntTop02.rend()); + PNTVECTOR vPntTop2 = cBezTopEndF2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop2.rbegin(), vPntTop2.rend()); + } + else { + vvPtCtrl.emplace_back(cBezTopStartB1->GetAllControlPoints()); + PNTVECTOR vPntTop1 = cBezTopEndB1->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop1.begin(), vPntTop1.end()); + vvPtCtrl.emplace_back(cBezTopStartB2->GetAllControlPoints()); + PNTVECTOR vPntTop2 = cBezTopEndB2->GetAllControlPoints(); + vvPtCtrl.back().insert(vvPtCtrl.back().end(), vPntTop2.begin(), vPntTop2.end()); + } } - } + } + } - // chiudo il volume con le superfici verticali e le basi dei tool + // chiudo il volume con le superfici verticali e le basi dei tool - // chiudo il volume con le superici verticali end 1 - vvPtCtrl.emplace_back( cBezTipEndF1->GetAllControlPoints()) ; - PNTVECTOR vPntEnd1 = cBezTopEndF1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntEnd1.begin(), vPntEnd1.end()) ; - // chiudo il volume con le superici verticali end 2 - vvPtCtrl.emplace_back( cBezTipEndF2->GetAllControlPoints()) ; - PNTVECTOR vPntEnd2 = cBezTopEndF2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntEnd2.begin(), vPntEnd2.end()) ; + // chiudo il volume con le superici verticali end 1 + vvPtCtrl.emplace_back( cBezTipEndF1->GetAllControlPoints()) ; + PNTVECTOR vPntEnd1 = cBezTopEndF1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntEnd1.begin(), vPntEnd1.end()) ; + // chiudo il volume con le superici verticali end 2 + vvPtCtrl.emplace_back( cBezTipEndF2->GetAllControlPoints()) ; + PNTVECTOR vPntEnd2 = cBezTopEndF2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntEnd2.begin(), vPntEnd2.end()) ; - // chiudo il volume con le superici verticali start 1 - vvPtCtrl.emplace_back( cBezTipStartB1->GetAllControlPoints()) ; - PNTVECTOR vPntStart1 = cBezTopStartB1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntStart1.begin(), vPntStart1.end()) ; - // chiudo il volume con le superfici verticali start 2 - vvPtCtrl.emplace_back( cBezTipStartB2->GetAllControlPoints()) ; - PNTVECTOR vPntStart2 = cBezTopStartB2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntStart2.begin(), vPntStart2.end()) ; + // chiudo il volume con le superici verticali start 1 + vvPtCtrl.emplace_back( cBezTipStartB1->GetAllControlPoints()) ; + PNTVECTOR vPntStart1 = cBezTopStartB1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntStart1.begin(), vPntStart1.end()) ; + // chiudo il volume con le superfici verticali start 2 + vvPtCtrl.emplace_back( cBezTipStartB2->GetAllControlPoints()) ; + PNTVECTOR vPntStart2 = cBezTopStartB2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntStart2.begin(), vPntStart2.end()) ; - // superfici di base dei tool - if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide < 0)) { - // start back tip - vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; - PNTVECTOR vPntTipStartBack1 = cBezTipStartB1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartBack1.begin(), vPntTipStartBack1.end()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; - PNTVECTOR vPntTipStartBack2 = cBezTipStartB2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartBack2.begin(), vPntTipStartBack2.end()) ; - // start front tip - vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; - PNTVECTOR vPntTipStartFront1 = cBezTipStartF1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartFront1.begin(), vPntTipStartFront1.end()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; - PNTVECTOR vPntTipStartFront2 = cBezTipStartF2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartFront2.begin(), vPntTipStartFront2.end()) ; - } - if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide > 0)) { - // end front tip - vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; - PNTVECTOR vPntTipEndFront1 = cBezTipEndF1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndFront1.begin(), vPntTipEndFront1.end()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; - PNTVECTOR vPntTipEndFront2 = cBezTipEndF2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndFront2.begin(), vPntTipEndFront2.end()) ; - // end back tip - vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; - PNTVECTOR vPntTipEndBack1 = cBezTipEndB1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndBack1.begin(), vPntTipEndBack1.end()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; - PNTVECTOR vPntTipEndBack2 = cBezTipEndB2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndBack2.begin(), vPntTipEndBack2.end()) ; - } + // superfici di base dei tool + if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide < 0)) { + // start back tip + vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; + PNTVECTOR vPntTipStartBack1 = cBezTipStartB1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartBack1.begin(), vPntTipStartBack1.end()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; + PNTVECTOR vPntTipStartBack2 = cBezTipStartB2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartBack2.begin(), vPntTipStartBack2.end()) ; + // start front tip + vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; + PNTVECTOR vPntTipStartFront1 = cBezTipStartF1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartFront1.begin(), vPntTipStartFront1.end()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptP1T, ptP1T, ptP1T, ptP1T }) ; + PNTVECTOR vPntTipStartFront2 = cBezTipStartF2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipStartFront2.begin(), vPntTipStartFront2.end()) ; + } + if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide > 0)) { + // end front tip + vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; + PNTVECTOR vPntTipEndFront1 = cBezTipEndF1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndFront1.begin(), vPntTipEndFront1.end()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; + PNTVECTOR vPntTipEndFront2 = cBezTipEndF2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndFront2.begin(), vPntTipEndFront2.end()) ; + // end back tip + vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; + PNTVECTOR vPntTipEndBack1 = cBezTipEndB1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndBack1.begin(), vPntTipEndBack1.end()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptP2T, ptP2T, ptP2T, ptP2T }) ; + PNTVECTOR vPntTipEndBack2 = cBezTipEndB2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTipEndBack2.begin(), vPntTipEndBack2.end()) ; + } - if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide > 0)) { - // start back top - vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; - PNTVECTOR vPntTopStartBack1 = cBezTopStartB1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartBack1.rbegin(), vPntTopStartBack1.rend()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; - PNTVECTOR vPntTopStartBack2 = cBezTopStartB2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartBack2.rbegin(), vPntTopStartBack2.rend()) ; - // start front top - vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; - PNTVECTOR vPntTopStartFront1 = cBezTopStartF1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartFront1.rbegin(), vPntTopStartFront1.rend()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; - PNTVECTOR vPntTopStartFront2 = cBezTopStartF2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartFront2.rbegin(), vPntTopStartFront2.rend()) ; - } - if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide < 0)) { - // end front top - vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; - PNTVECTOR vPntTopEndFront1 = cBezTopEndF1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndFront1.rbegin(), vPntTopEndFront1.rend()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; - PNTVECTOR vPntTopEndFront2 = cBezTopEndF2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndFront2.rbegin(), vPntTopEndFront2.rend()) ; - // end back top - vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; - PNTVECTOR vPntTopEndBack1 = cBezTopEndB1->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndBack1.rbegin(), vPntTopEndBack1.rend()) ; - vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; - PNTVECTOR vPntTopEndBack2 = cBezTopEndB2->GetAllControlPoints() ; - vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndBack2.rbegin(), vPntTopEndBack2.rend()) ; - } - } + if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide > 0)) { + // start back top + vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; + PNTVECTOR vPntTopStartBack1 = cBezTopStartB1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartBack1.rbegin(), vPntTopStartBack1.rend()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; + PNTVECTOR vPntTopStartBack2 = cBezTopStartB2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartBack2.rbegin(), vPntTopStartBack2.rend()) ; + // start front top + vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; + PNTVECTOR vPntTopStartFront1 = cBezTopStartF1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartFront1.rbegin(), vPntTopStartFront1.rend()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptS, ptS, ptS, ptS }) ; + PNTVECTOR vPntTopStartFront2 = cBezTopStartF2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopStartFront2.rbegin(), vPntTopStartFront2.rend()) ; + } + if ( ! ( n5AxisType == Move5Axis::NO_BASE_INTERS && dSide < 0)) { + // end front top + vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; + PNTVECTOR vPntTopEndFront1 = cBezTopEndF1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndFront1.rbegin(), vPntTopEndFront1.rend()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; + PNTVECTOR vPntTopEndFront2 = cBezTopEndF2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndFront2.rbegin(), vPntTopEndFront2.rend()) ; + // end back top + vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; + PNTVECTOR vPntTopEndBack1 = cBezTopEndB1->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndBack1.rbegin(), vPntTopEndBack1.rend()) ; + vvPtCtrl.emplace_back( PNTVECTOR{ ptE, ptE, ptE, ptE }) ; + PNTVECTOR vPntTopEndBack2 = cBezTopEndB2->GetAllControlPoints() ; + vvPtCtrl.back().insert( vvPtCtrl.back().end(), vPntTopEndBack2.rbegin(), vPntTopEndBack2.rend()) ; + } + } - // inizializzo le superfici bilineari e i parametri per le intersezioni - for ( int z = 0 ; z < int( vvPtCtrl.size()) ; ++z) { - vSurfBez[nSurfInd].sBez.Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 0, vvPtCtrl[z][0]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 1, vvPtCtrl[z][1]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 2, vvPtCtrl[z][2]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 3, vvPtCtrl[z][3]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 4, vvPtCtrl[z][4]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 5, vvPtCtrl[z][5]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 6, vvPtCtrl[z][6]) ; - vSurfBez[nSurfInd].sBez.SetControlPoint( 7, vvPtCtrl[z][7]) ; + // inizializzo le superfici bilineari e i parametri per le intersezioni + for ( int z = 0 ; z < int( vvPtCtrl.size()) ; ++z) { + vSurfBez[nSurfInd].sBez.Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 0, vvPtCtrl[z][0]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 1, vvPtCtrl[z][1]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 2, vvPtCtrl[z][2]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 3, vvPtCtrl[z][3]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 4, vvPtCtrl[z][4]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 5, vvPtCtrl[z][5]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 6, vvPtCtrl[z][6]) ; + vSurfBez[nSurfInd].sBez.SetControlPoint( 7, vvPtCtrl[z][7]) ; - Vector3d A = vvPtCtrl[z][4] - vvPtCtrl[z][0] ; - Vector3d B = vvPtCtrl[z][5] - vvPtCtrl[z][1] ; - Vector3d C = vvPtCtrl[z][6] - vvPtCtrl[z][2] ; - Vector3d D = vvPtCtrl[z][7] - vvPtCtrl[z][3] ; - Vector3d E = vvPtCtrl[z][0] - ORIG ; - Vector3d F = vvPtCtrl[z][1] - ORIG ; - Vector3d G = vvPtCtrl[z][2] - ORIG ; - Vector3d H = vvPtCtrl[z][3] - ORIG ; + Vector3d A = vvPtCtrl[z][4] - vvPtCtrl[z][0] ; + Vector3d B = vvPtCtrl[z][5] - vvPtCtrl[z][1] ; + Vector3d C = vvPtCtrl[z][6] - vvPtCtrl[z][2] ; + Vector3d D = vvPtCtrl[z][7] - vvPtCtrl[z][3] ; + Vector3d E = vvPtCtrl[z][0] - ORIG ; + Vector3d F = vvPtCtrl[z][1] - ORIG ; + Vector3d G = vvPtCtrl[z][2] - ORIG ; + Vector3d H = vvPtCtrl[z][3] - ORIG ; - vSurfBez[nSurfInd].a3 = -A + 3 * B - 3 * C + D ; - vSurfBez[nSurfInd].a2 = 3 * A - 6 * B + 3 * C ; - vSurfBez[nSurfInd].a1 = -3 * A + 3 * B ; - vSurfBez[nSurfInd].a0 = A ; + vSurfBez[nSurfInd].a3 = -A + 3 * B - 3 * C + D ; + vSurfBez[nSurfInd].a2 = 3 * A - 6 * B + 3 * C ; + vSurfBez[nSurfInd].a1 = -3 * A + 3 * B ; + vSurfBez[nSurfInd].a0 = A ; - vSurfBez[nSurfInd].b3 = -E + 3 * F - 3 * G + H ; - vSurfBez[nSurfInd].b2 = 3 * E - 6 * F + 3 * G ; - vSurfBez[nSurfInd].b1 = -3 * E + 3 * F ; - vSurfBez[nSurfInd].b0 = E ; + vSurfBez[nSurfInd].b3 = -E + 3 * F - 3 * G + H ; + vSurfBez[nSurfInd].b2 = 3 * E - 6 * F + 3 * G ; + vSurfBez[nSurfInd].b1 = -3 * E + 3 * F ; + vSurfBez[nSurfInd].b0 = E ; - Vector3d vtDirZ = vvPtCtrl[z][4] - vvPtCtrl[z][0] ; - Vector3d vtDirX = vvPtCtrl[z][3] - vvPtCtrl[z][0] ; + Vector3d vtDirZ = vvPtCtrl[z][4] - vvPtCtrl[z][0] ; + Vector3d vtDirX = vvPtCtrl[z][3] - vvPtCtrl[z][0] ; - // devo gestire il caso in cui uno dei due vettori sia == 0 - if (vtDirZ.IsSmall()) { - vtDirZ = vvPtCtrl[z][7] - vvPtCtrl[z][4]; - } - if (vtDirX.IsSmall()) { - vtDirX = vvPtCtrl[z][7] - vvPtCtrl[z][3]; - } - - // calcolo il box in un riferimento che usi come asse x la direzione P10 - P00 o P11 - P01 ( proiettata sul piano perperndicolare a Z) - if ( vSurfBez[nSurfInd].frBox.Set( ORIG, vtDirZ, vtDirX)) { - // porto tutti i punti in quel riferimento e calcolo il box - PNTVECTOR vPtCtrlLoc = vvPtCtrl[z] ; - for ( int p = 0 ; p < int( vPtCtrlLoc.size()) ; ++p) - vPtCtrlLoc[p].ToLoc( vSurfBez[nSurfInd].frBox) ; - vSurfBez[nSurfInd].bbSurfOriented.Add( vPtCtrlLoc) ; - } + // devo gestire il caso in cui uno dei due vettori sia == 0 + if (vtDirZ.IsSmall()) { + vtDirZ = vvPtCtrl[z][7] - vvPtCtrl[z][4]; + } + if (vtDirX.IsSmall()) { + vtDirX = vvPtCtrl[z][7] - vvPtCtrl[z][3]; + } + + // calcolo il box in un riferimento che usi come asse x la direzione P10 - P00 o P11 - P01 ( proiettata sul piano perperndicolare a Z) + if ( vSurfBez[nSurfInd].frBox.Set( ORIG, vtDirZ, vtDirX)) { + // porto tutti i punti in quel riferimento e calcolo il box + PNTVECTOR vPtCtrlLoc = vvPtCtrl[z] ; + for ( int p = 0 ; p < int( vPtCtrlLoc.size()) ; ++p) + vPtCtrlLoc[p].ToLoc( vSurfBez[nSurfInd].frBox) ; + vSurfBez[nSurfInd].bbSurfOriented.Add( vPtCtrlLoc) ; + } - // aggiungo i punti al box del volume spazzato - PNTVECTOR vPtCtrlLoc = vvPtCtrl[z] ; - for (int p = 0; p < int(vPtCtrlLoc.size()); ++p) - vPtCtrlLoc[p].ToLoc(frVol); - bbVol.Add(vPtCtrlLoc) ; + // aggiungo i punti al box del volume spazzato + PNTVECTOR vPtCtrlLoc = vvPtCtrl[z] ; + for (int p = 0; p < int(vPtCtrlLoc.size()); ++p) + vPtCtrlLoc[p].ToLoc(frVol); + bbVol.Add(vPtCtrlLoc) ; - ++ nSurfInd ; - } + ++ nSurfInd ; + } // scorro tutti gli spilloni interessati int j = 0 ; @@ -2386,7 +2398,7 @@ VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, co InitializePointsAndVectors( ptSti, ptEni, vtDSi, vtDEi, ptLs, ptLe, vtLs, vtLe) ; // Standard è multithread - constexpr bool MULTITHREAD = true ; + constexpr bool MULTITHREAD = false ; if ( MULTITHREAD) { // Ciclo sulle mappe vector> vRes( m_nMapNum) ; From 4bfb38b9d5c0043984f762554e394fe6dcadf452 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 7 Jan 2026 12:28:11 +0100 Subject: [PATCH 16/44] EgtGeomKernel : - piccola correzione alla triangolazione delle surf di bezier. --- Tree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tree.cpp b/Tree.cpp index e885059..8a7689a 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -3795,14 +3795,14 @@ Tree::CategorizeCell( int nId) Point3d ptIntersIn = m_mTree[nNeigh].m_vInters[r].vpt[0] ; if ( (m_mTree[nNeigh].m_vInters[r].nOut == 0 || m_mTree[nNeigh].m_vInters[r].nOut == 7) && ( CheckIfBefore( 2, ptBr, ptIntersOut) || AreSamePointApprox( ptBr, ptIntersOut))) { - if (ptIntersOut.x < ptLeftMostInters.x) { + if (ptIntersOut.x <= ptLeftMostInters.x) { ptLeftMostInters = ptIntersOut ; bFound = true ; } } if ( (m_mTree[nNeigh].m_vInters[r].nIn == 0 || m_mTree[nNeigh].m_vInters[r].nIn == 7) && ( CheckIfBefore( 2, ptBr, ptIntersIn) || AreSamePointApprox( ptBr, ptIntersIn))) { - if (ptIntersIn.x < ptLeftMostInters.x) { + if (ptIntersIn.x <= ptLeftMostInters.x) { ptLeftMostInters = ptIntersIn ; bFound = false ; } From 4a0bd638fae5188d3bb75f584df3602610ed078d Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 8 Jan 2026 19:19:08 +0100 Subject: [PATCH 17/44] EgtGeomKernel : - in CalcPocketing migliorata la gestione dei punti iniziali dei percorsi nel caso dei Trapezi o di punti di riferimento generici. --- CalcPocketing.cpp | 190 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 143 insertions(+), 47 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 25fe4ff..dc23fc0 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -2699,7 +2699,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr double dLen0, dLen2 ; pCrvTrap->GetCurve( 0)->GetLength( dLen0) ; pCrvTrap->GetCurve( 2)->GetLength( dLen2) ; - if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) + if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL) pCrvTrap->Clear() ; } @@ -2980,38 +2980,38 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr // se non ho trovato delle basi, allora cerco in maniera generale un trapezoide ( se esiste) if ( nBase == -1) { bool bOK = false ; - for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && !bOK ; ++ u) { + for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nU) { // cerco un lato chiuso ( esiste per forza) - if ( pCrvCompo->GetCurve( u)->GetTempProp( 0) == 0) { + if ( pCrvCompo->GetCurve( nU)->GetTempProp( 0) == 0) { // controllo se il lato corrente può essere una base int nType = -1 ; - if ( ! GetBoxCrvOptTrap( u, pCrvCompo, dDiam, nType, pCrvTrap)) + if ( ! GetBoxCrvOptTrap( nU, pCrvCompo, dDiam, nType, pCrvTrap)) return false ; // se è una base valida if ( nType != -1) { // ricavo la dimensione di svuotatura pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ; // ricavo la sua direzione iniziale - Vector3d vtBaseDir ; pCrvCompo->GetCurve( u)->GetStartDir( vtBaseDir) ; + Vector3d vtBaseDir ; pCrvCompo->GetCurve( nU)->GetStartDir( vtBaseDir) ; // ricavo il suo punto iniziale - Point3d ptBaseStart ; pCrvCompo->GetCurve( u)->GetStartPoint( ptBaseStart) ; + Point3d ptBaseStart ; pCrvCompo->GetCurve( nU)->GetStartPoint( ptBaseStart) ; // ricavo il suo punto finale - Point3d ptBaseEnd ; pCrvCompo->GetCurve( u)->GetEndPoint( ptBaseEnd) ; + Point3d ptBaseEnd ; pCrvCompo->GetCurve( nU)->GetEndPoint( ptBaseEnd) ; // cerco il lato chiuso lineare parallelo ad esso e distante circa dPocketSize - for ( int uu = 0 ; uu < pCrvCompo->GetCurveCount() && !bOK ; ++ uu) { - if ( uu == u || - pCrvCompo->GetCurve( uu)->GetType() != CRV_LINE || - pCrvCompo->GetCurve( uu)->GetTempProp() != 0) + for ( int nOtherU = 0 ; nOtherU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nOtherU) { + if ( nOtherU == nU || + pCrvCompo->GetCurve( nOtherU)->GetType() != CRV_LINE || + pCrvCompo->GetCurve( nOtherU)->GetTempProp() != 0) continue ; - Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( uu)->GetStartDir( vtSecondBaseDir) ; + Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( nOtherU)->GetStartDir( vtSecondBaseDir) ; if ( ! AreOppositeVectorEpsilon( vtBaseDir, vtSecondBaseDir, 5 * EPS_SMALL)) continue ; - Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( uu)->GetStartPoint( ptSecondBaseStart) ; + Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( nOtherU)->GetStartPoint( ptSecondBaseStart) ; double dDist = 0. ; - DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( uu), false) ; + DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( nOtherU), false) ; if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) { - nBase = u ; - nSecondBase = uu ; + nBase = nU ; + nSecondBase = nOtherU ; if ( ! PreparareTrapezoidTwoBases( pCrvCompo, dDiam, nType, nBase, nSecondBase, bOK, pCrvTrap)) return false ; } @@ -3049,7 +3049,8 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr //---------------------------------------------------- static bool SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed, - const ICurveComposite* pCrvPocket, const PocketParams& PockParams) + const ICurveComposite* pCrvPocket, const PocketParams& PockParams, + const Point3d& ptRef) { // parametri double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; @@ -3059,10 +3060,18 @@ SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenC // calcolo gli offset dei lati obliqui PtrOwner pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ; pLineS->SimpleOffset( - dRad) ; - pLineS->Invert() ; PtrOwner pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ; pLineE->SimpleOffset( - dRad) ; - pLineE->Invert() ; + + // verifico orientamento delle curve in base al punto di riferimento ( se valido) + double dSqDistS = 0., dSqDistE = 0. ; + if ( ! ptRef.IsValid() || + ( ( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 3 : 0)).GetSqDist( dSqDistS)) && + ( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 1 : 2)).GetSqDist( dSqDistE)) && + dSqDistS < dSqDistE)) { + pLineS->Invert() ; + pLineE->Invert() ; + } Point3d ptS, ptE ; pLineS->GetEndPoint( ptS) ; @@ -3133,10 +3142,10 @@ CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSe double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ; double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ; double dRad = 0.5 * dDiam + dOffsR ; - + // recupero la curva di interesse int nCrvId = ( bStart ? nSecondBase : nBase) + 1 ; - int nProp = - 1 ; + int nProp = -1 ; if ( ! pCrvPocket->GetCurveTempProp( nCrvId, nProp)) return false ; // se Open @@ -3416,6 +3425,9 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double // passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli // (possibilmente aperto) e centro nel punto iniziale del lato pCrvPocket->ToLoc( frTrap) ; + Point3d ptRef = P_INVALID ; + if ( PockParams.ptStart.IsValid()) + ptRef = GetToLoc( PockParams.ptStart, frTrap) ; // calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso) double dLen0, dLen1, dLen2, dLen3, dMaxLarg = 0. ; @@ -3434,14 +3446,17 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double BBox3d b3Dim ; pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ; dMaxLarg = ( vnProp[0] != 0 ? b3Dim.GetDimY() : dPocketSize) ; } - // calcolo percorso di svuotatura // se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale - if (( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) && - ((( vnProp[0] != 0 && vnProp[2] != 0) && ( vnProp[3] == 0 && vnProp[1] == 0) && ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) || - (( vnProp[1] != 0 && vnProp[3] != 0) && ( vnProp[0] == 0 && vnProp[2] == 0) && ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) { - if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, vnProp[0] == 0, pCrvPocket, PockParams)) { + if ( ( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) && + ( ( ( vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE) && + ( vnProp[3] == TEMP_PROP_CLOSE_EDGE && vnProp[1] == TEMP_PROP_CLOSE_EDGE) && + ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) || + ( ( vnProp[1] != TEMP_PROP_CLOSE_EDGE && vnProp[3] != TEMP_PROP_CLOSE_EDGE) && + ( vnProp[0] == TEMP_PROP_CLOSE_EDGE && vnProp[2] == TEMP_PROP_CLOSE_EDGE) && + ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) { + if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, ( vnProp[0] == TEMP_PROP_CLOSE_EDGE), pCrvPocket, PockParams, ptRef)) { pMCrv->Clear() ; return false ; } @@ -3451,7 +3466,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double double dYCoord ; // se base principale chiusa if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) - dYCoord = 0.5 * dDiam + dOffsR ; + dYCoord = 0.5 * dDiam + dOffsR ; // se base principale aperta e secondaria chiusa else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ; @@ -3462,15 +3477,32 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double // determino le quote coordinate in X inziale e finale double dXCoordStart = -INFINITO ; double dXCoordEnd = INFINITO ; - if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, - dPocketSize, PockParams) || dXCoordStart < - INFINITO + 1) + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, dPocketSize, PockParams) || + dXCoordStart < - INFINITO + 1) return false ; - if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, - dPocketSize, PockParams) || dXCoordEnd > INFINITO - 1) + if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, dPocketSize, PockParams) || + dXCoordEnd > INFINITO - 1) return false ; if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL) return false ; + // determino se devo invertire la curva dato il punto di riferimento + bool bInvertByRef = false ; + if ( ptRef.IsValid()) { + PtrOwner pCrvRight( pCrvPocket->CopyParamRange( nBase + 1, nSecondBase)) ; + PtrOwner pCrvLeft( pCrvPocket->CopyParamRange( nSecondBase + 1, nBase)) ; + if ( IsNull( pCrvRight) || IsNull( pCrvLeft) || + ! pCrvRight->IsValid() || ! pCrvLeft->IsValid()) + return false ; + double dSqDistBase = INFINITO, dSqDistSecondBase = INFINITO, dSqDistLeft = INFINITO, dSqDistRight = INFINITO ; + DistPointCurve( ptRef, *pCrvPocket->GetCurve( nBase)).GetSqDist( dSqDistBase) ; + DistPointCurve( ptRef, *pCrvPocket->GetCurve( nSecondBase)).GetSqDist( dSqDistSecondBase) ; + DistPointCurve( ptRef, *pCrvRight).GetSqDist( dSqDistRight) ; + DistPointCurve( ptRef, *pCrvLeft).GetSqDist( dSqDistLeft) ; + bInvertByRef = ( dSqDistSecondBase < min( {dSqDistBase, dSqDistLeft, dSqDistRight}) || + dSqDistRight < min( {dSqDistBase, dSqDistSecondBase, dSqDistLeft})) ; + } + // determino gli estremi del segmento di svuotatura Point3d ptStart( dXCoordStart, dYCoord) ; Point3d ptEnd( dXCoordEnd, dYCoord) ; @@ -3490,7 +3522,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double if ( ! pLine1->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset) || ! pLine3->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset)) return false ; - Point3d ptS, ptE ; if ( vtDir3 * X_AX > EPS_SMALL) { pLine1->GetStartPoint( ptS) ; @@ -3500,7 +3531,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pLine1->GetEndPoint( ptE) ; pLine3->GetEndPoint( ptS) ; } - if ( vnProp[0] != TEMP_PROP_CLOSE_EDGE) { pMCrv->AddPoint( ptS) ; if ( vnProp[2] != TEMP_PROP_CLOSE_EDGE) @@ -3516,34 +3546,37 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pMCrv->AddLine( ptStart) ; pMCrv->Invert() ; } - pMCrv->SetCurveTempProp( 0, TEMP_PROP_OPEN_EDGE) ; + // verifico se invertirla nel caso di un punto di riferimento + if ( bInvertByRef && + vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE) + pMCrv->Invert() ; } } // se estremi del segmento differenti, allora il percorso è definito else { + // creo la linea if ( ! pMCrv->AddPoint( ptStart)) return true ; if ( ! pMCrv->AddLine( ptEnd)) return true ; - // aggiustamenti al percorso per rimuovere materiale residuo negli angoli if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE || pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - Frame3d frOpen ; bool bSwitch = false ; - // Base principale chiusa e base Secondaria aperta - if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { + // Base Principale chiusa e Base Secondaria aperta o inversione per punto di riferimento + if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE || + bInvertByRef) { pCrvPocket->ChangeStartPoint( nSecondBase) ; // oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto) Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ; - Point3d ptORIG ; + Point3d ptOpen ; if ( vtDir.y > 0) - pCrvPocket->GetCurve( nBase)->GetEndPoint( ptORIG) ; + pCrvPocket->GetFirstCurve()->GetEndPoint( ptOpen) ; else - pCrvPocket->GetCurve( nBase)->GetStartPoint( ptORIG) ; - frOpen.Set( ptORIG, Z_AX, -X_AX) ; + pCrvPocket->GetFirstCurve()->GetStartPoint( ptOpen) ; + frOpen.Set( ptOpen, Z_AX, -X_AX) ; if ( ! frOpen.IsValid()) return false ; pCrvPocket->ToLoc( frOpen) ; @@ -3551,7 +3584,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double pMCrv->Invert() ; bSwitch = true ; } - + // la Base principale è sempre aperta if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, true)) { pMCrv->Clear() ; @@ -3848,7 +3881,7 @@ GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockPara //---------------------------------------------------------------------------- static bool -GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketParams& PockParams, +GetPtStartOnOpenEdgeByOrigCurve( const Point3d& ptRef, const ICurveComposite* pCrvOrig, const PocketParams& PockParams, const ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut) { @@ -3858,8 +3891,71 @@ GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketPa return false ; bMidOut = false ; - // cerco il lato aperto più lungo ( sufficientemente lungo) double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ; + + // se ho un punto di riferimento, cerco il lato aperto sull'originale più vicino ad essa ( sufficientemente lungo) + if ( ptRef.IsValid()) { + double dSqMinDist = INFINITO ; + int nIndCrv = -1 ; + for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { + // escludo le sottocurve chiuse + if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) + continue ; + // recupero la curva i-esima aperta dalla curva originale + const ICurve* pCrvOpen = pCrvOrig->GetCurve( i) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + // ricavo la lunghezza di tale curva + double dLen = 0. ; + pCrvOpen->GetLength( dLen) ; + // se lunghezza accettabile o maggiore della massima trovata + if ( dLen > dLenRef - 10. * EPS_SMALL) { + // verifico la distanza con il punto di riferimento + double dCurrSqDist = 0. ; + if ( DistPointCurve( ptRef, *pCrvOpen).GetSqDist( dCurrSqDist) && dCurrSqDist < dSqMinDist) { + dSqMinDist = dCurrSqDist ; + nIndCrv = i ; + } + } + } + // se ho un indice di curva valido, allora ricavo i valori + if ( nIndCrv != -1) { + // recupero la curva + const ICurve* pCrvOpen = pCrvOrig->GetCurve( nIndCrv) ; + if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid()) + return false ; + Point3d ptSTmp ; + Vector3d vtMidOutTmp ; + // ricavo il punto medio e il vettore tangente ad esso associato + if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) { + // versore d'uscita + vtMidOutTmp.Normalize() ; + vtMidOutTmp.Rotate( Z_AX, 0, -1) ; + ptSTmp += vtMidOutTmp * max( PockParams.dRad - PockParams.dSideStep, 0.) ; + // cerco la sottocurva più vicina a ptSTmp + int nFlag ; + double dMyPar ; + if ( DistPointCurve( ptSTmp, *pCrvCompo).GetParamAtMinDistPoint( 0, dMyPar, nFlag)) { + int nCrv = int( floor( dMyPar)) ; + // recupero tale sottocurva e controllo che anche essa sia OPEN + const ICurve* pMyCrv = pCrvCompo->GetCurve( nCrv) ; + if ( pMyCrv != nullptr && pMyCrv->IsValid() && pMyCrv->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // recupero ptStart + pMyCrv->GetMidPoint( ptStart) ; + // assegno direzione fuori + vtMidOut = vtMidOutTmp ; + // flag per possibile entrata da fuori + bMidOut = true ; + } + } + } + // esco + return true ; + } + } + + // se non ho un punto di riferimento valido, o avendolo non si riesce ad entrare dal lato aperto più vicino + // cerco il lato aperto più lungo ( sufficientemente lungo) for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) { // escludo le sottocurve chiuse if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) @@ -3943,7 +4039,7 @@ GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParam // se non ho trovato nulla, allora cerco un punto iniziale valido su una sottocurva OPEN if ( nStartCrv == -1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) { - return GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; + return GetPtStartOnOpenEdgeByOrigCurve( ptRef, pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ; } // se ho trovato la curva più vicina, cerco un punto iniziale valido else { @@ -4232,7 +4328,7 @@ SetPtStartForPath( ICurveComposite* pCrvOffs, const PocketParams& PockParams, co if ( pCrvOrig != nullptr && pCrvOrig->IsValid()) { // ... e non ho un punto di riferimento, lo cerco sulla curva originale if ( ! ptEndPrec.IsValid()) { - if ( ! GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) + if ( ! GetPtStartOnOpenEdgeByOrigCurve( P_INVALID, pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut)) return false ; } // ... e ho un punto di riferimento From afef5597b23525d82561c7d280c4e6a8d9592efc Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 12 Jan 2026 08:15:06 +0100 Subject: [PATCH 18/44] EgtGeomKernel : - tentaivo di correzione intersezione tra segmenti di retta quasi paralleli. --- IntersLineLine.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index 896df6c..c87691c 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -158,6 +158,16 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line bool bParallel = ( abs( dCrossXY) < SIN_EPS_ANG_ZERO * ( dLen1XY * dLen2XY)) ; // flag per segmenti che si allontanano significativamente bool bFarEnds = ( nS1Side != 0 || nE1Side != 0 || nS2Side != 0 || nE2Side != 0) ; + // analisi casi speciali di quasi parallelismo + if ( ! bParallel && abs( dCrossXY) < ( 0.1 * DEGTORAD) * ( dLen1XY * dLen2XY)) { + if (( nS1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) || + ( nS1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) || + ( nE1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptE1, ptS2, 2 * EPS_SMALL)) || + ( nE1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptE1, ptE2, 2 * EPS_SMALL))) { + bParallel = true ; + bFarEnds = false ; + } + } // se non sono paralleli e si allontanano tra loro abbastanza if ( ! bParallel && bFarEnds) { From 669f38a731e428de4f235a3763af88900068ba58 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 13 Jan 2026 14:36:02 +0100 Subject: [PATCH 19/44] EgtGeomKernel 3.1a2 : - In CalcPocketing aggiunti controlli per casi a Spirale e Trapezio in presenza di lati aperti. --- CalcPocketing.cpp | 70 +++++++++++++++++++++++++++++++++------------- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index dc23fc0..2805622 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3639,7 +3639,7 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& PtrOwner pCrvBorder( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ; if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) return false ; - pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; + pCrvBorder->MergeCurves( 10. * EPS_SMALL, 10. * EPS_ANG_SMALL, true, true) ; pCrvBorder->SetExtrusion( pSfrChunk->GetNormVersor()) ; /* SPIRALE EUCLIDEA @@ -3652,17 +3652,35 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& if ( bOkSpiral) { // controllo che sia una circonferenza Point3d ptCen ; double dRad ; - if ( ! OptimizedSpiralCircle( pCrvBorder, 50 * EPS_SMALL, dRad, ptCen, bOkSpiral)) + if ( ! OptimizedSpiralCircle( pCrvBorder, 50. * EPS_SMALL, dRad, ptCen, bOkSpiral)) return false ; // se è una circonferenza if ( bOkSpiral) { double dOffs = PockParam.dRad + PockParam.dRadialOffset ; - // se curva tutta Open, allora ingrandisco il raggio - if ( nTempPropRef == TEMP_PROP_OPEN_EDGE) + // se curva tutta Open + if ( nTempPropRef == TEMP_PROP_OPEN_EDGE) { + // ingrandisco il raggio dRad += 1.05 * PockParam.dRad + PockParam.dRadialOffset ; + // verifico che l'utensile ora non interferisca con la regione limite + if ( PockParam.SfrLimit.IsValid()) { + // definisco il nuovo bordo + PtrOwner pCrvArc( CreateCurveArc()) ; + bOkSpiral = ( ! IsNull( pCrvArc) && + pCrvArc->Set( ptCen, Z_AX, dRad + PockParam.dRad)) ; + if ( bOkSpiral) { + CRVCVECTOR ccClass ; + bOkSpiral = ( PockParam.SfrLimit.GetCurveClassification( *pCrvArc, EPS_SMALL, ccClass) && + ssize( ccClass) == 1 && ccClass[0].nClass == CRVC_OUT) ; + // NB. una versione più complessa dovrebbe verificare se la sottrazione tra la + // superficie dell'utensile e la regione limite non genera un'altra circonferenza... + // In questo caso si la sottrazione potrebbe essere trattata come una circonferenza + // chiusa ed essere ancora svotata a spirale... + } + } + } // se curva chiusa, controllo che il raggio sia compatibile con il primo Offset else - bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ; + bOkSpiral = ( dRad - dOffs > 10. * EPS_SMALL) ; if ( bOkSpiral) { double dIntRad = 0 ; if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nLiType == LEAD_IN_HELIX) @@ -3697,24 +3715,38 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& double dPocketSize ; int nBase, nSecondBase ; bool bOkTrap = ( GetTrapezoidFromShape( pCrvBorder, pCrvTrap, frTrap, PockParam, dPocketSize, nBase, nSecondBase) && - dPocketSize < PockParam.dMaxOptSize + 10 * EPS_SMALL) ; + dPocketSize < PockParam.dMaxOptSize + 10. * EPS_SMALL) ; if ( bOkTrap && pCrvTrap->IsValid()) { pCrvTrap->SetExtrusion( Z_AX) ; CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParam, pCrvRes, bOkTrap) ; if ( bOkTrap) { - // calcolo eventuali uscite e ingressi - if ( pCrvRes->GetTempProp( 0) > 0) { - Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ; - vtRef.Invert() ; - bool bIsStartExtended = false ; - if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, PockParam.dRad + PockParam.dOpenMinSafe, bIsStartExtended)) - return false ; - pCrvRes->GetEndDir( vtRef) ; - bool bIsEndExtended = false ; - if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, true, PockParam.dRad + PockParam.dOpenMinSafe, bIsEndExtended)) - return false ; - if ( bIsEndExtended && ! bIsStartExtended) - pCrvRes->Invert() ; + // verifico che tale curva non interferisca con la regione limite + if ( PockParam.SfrLimit.IsValid()) { + double dOffsCheck = PockParam.dRad + PockParam.dRadialOffset - 50. * EPS_SMALL ; // restrittivo per sicurezza + PtrOwner pSfrToolShape( GetSurfFlatRegionFromFatCurve( pCrvRes->Clone(), dOffsCheck, false, false)) ; + bOkTrap = ( ! IsNull( pSfrToolShape) && pSfrToolShape->IsValid()) ; + if ( bOkTrap) { + bOkTrap = ( pSfrToolShape->Intersect( PockParam.SfrLimit) && + ! pSfrToolShape->IsValid()) ; + if ( ! bOkTrap) + pCrvRes->Clear() ; + } + } + if ( bOkTrap) { + // calcolo eventuali uscite e ingressi + if ( pCrvRes->GetTempProp( 0) > 0) { + Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ; + vtRef.Invert() ; + bool bIsStartExtended = false ; + if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, PockParam.dRad + PockParam.dOpenMinSafe, bIsStartExtended)) + return false ; + pCrvRes->GetEndDir( vtRef) ; + bool bIsEndExtended = false ; + if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, true, PockParam.dRad + PockParam.dOpenMinSafe, bIsEndExtended)) + return false ; + if ( bIsEndExtended && ! bIsStartExtended) + pCrvRes->Invert() ; + } } } } diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 5febf3abeef249400a18f3e3f28c0af4cefea82c..bdbb1179bc575cea3bc0ff262be029ecd0018546 100644 GIT binary patch delta 238 zcmdlNy)SyhI%aiGhCGIJh8%`ehGHOAV9;O)W+-7u1ma8}FBB-731Uy?R&U)L$1;bB z(P;B;HbrJeqsfZgx|_YYCa?fSZu8k9MBErR_Xv9d`53|-(qLf}{T_^)vy{Iv66=o5 l-Kxcmg85*FdV(FA19V{GW^VP3%$UNHyHyWv?$S140s!YbI#U1u delta 249 zcmdlNy)SyhI%aKGhCGIJh8%`WhGK>c1_cHUhESkLCPN8BDnkm89}HwAf_cT0PijeT z{=m$}%xJjzyqqHQX#% w{>Dh6TMka Date: Wed, 14 Jan 2026 08:47:14 +0100 Subject: [PATCH 20/44] EgtGeomkernel : - piccola correzione alla remove span - aggiunto comando di debug. --- SurfBezier.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 92eed3d..1a6aa76 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -44,6 +44,11 @@ #define EIGEN_NO_IO #include "/EgtDev/Extern/Eigen/Dense" +//#define SAVEFAILEDTRIANGULATION +#ifdef SAVEFAILEDTRIANGULATION + #include "/EgtDev/Include/EGkGeoObjSave.h" +#endif + using namespace std ; //---------------------------------------------------------------------------- @@ -868,8 +873,10 @@ SurfBezier::CopyFrom( const SurfBezier& sbSrc) m_bTrimmed = true ; m_pTrimReg = sbSrc.m_pTrimReg->Clone() ; } +#ifndef SAVEFAILEDTRIANGULATION if( sbSrc.GetAuxSurf() != nullptr) m_pSTM = sbSrc.GetAuxSurf()->Clone() ; +#endif for ( int i = 0 ; i < int( sbSrc.m_mCCEdge.size()) ; ++i) { m_mCCEdge.emplace_back() ; for ( int j = 0 ; j < int( sbSrc.m_mCCEdge[i].size()) ; ++j ) { @@ -1842,6 +1849,10 @@ SurfBezier::GetAuxSurfRefined( void) const return m_pSTMRefined ; } +#ifdef SAVEFAILEDTRIANGULATION +static int nErr = 0 ; +#endif + //---------------------------------------------------------------------------- SurfTriMesh* SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) const @@ -1886,9 +1897,14 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) cons m_bClosedU = m_bClosedU || Tree.IsClosedU() ; m_bClosedV = m_bClosedV || Tree.IsClosedV() ; } - - if ( vvPL.empty()) + + if ( vvPL.empty()) { LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated") +#ifdef SAVEFAILEDTRIANGULATION + SaveGeoObj( Clone(),"D:\\Temp\\bezier\\not_triangulated\\" + ToString( nErr) + ".nge") ; + ++nErr ; +#endif + } StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) @@ -5906,6 +5922,7 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c bool SurfBezier::RemoveCollapsedSpans() { + double dTol = EPS_SMALL ; //controllo se ho delle span collassate e le rimuovo if( m_nSpanU > 1 || m_nSpanV > 1) { CalcPoles() ; @@ -5917,14 +5934,14 @@ SurfBezier::RemoveCollapsedSpans() Point3d ptFirst = m_vPtCtrl[m_nDegU * i] ; // cerco se trovo tutti i punti in U coincidenti in una delle Span for( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) { - if( ! AreSamePointExact( ptFirst, m_vPtCtrl[m_nDegU * i + j])) + if( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[m_nDegU * i + j], dTol)) bSamePoint = false ; } if( bSamePoint) { // se trovo un'altra riga collassata do per scontato che tutta span sia collassata ptFirst = m_vPtCtrl[GetInd( m_nDegU * i, 1)] ; for( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) { - if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( m_nDegU * i + j, 1)])) + if( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( m_nDegU * i + j, 1)], dTol)) bSamePoint = false ; } if( bSamePoint) @@ -6010,14 +6027,14 @@ SurfBezier::RemoveCollapsedSpans() Point3d ptFirst = m_vPtCtrl[GetInd( 0, i * m_nDegV)] ; // cerco se trovo tutti i punti in U coincidenti in una delle Span for( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) { - if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( 0, i * m_nDegV + j)])) + if( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( 0, i * m_nDegV + j)], dTol)) bSamePoint = false ; } if( bSamePoint) { // se trovo un'altra colonna collassata do per scontato che tutta span sia collassata ptFirst = m_vPtCtrl[GetInd( 1, i * m_nDegV)] ; for( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) { - if( ! AreSamePointExact( ptFirst, m_vPtCtrl[GetInd( 1, i * m_nDegV + j)])) + if( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( 1, i * m_nDegV + j)], dTol)) bSamePoint = false ; } if( bSamePoint) From e46768b14b821024fa4d52f9668f9cda39ce9d8a Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 15 Jan 2026 11:50:03 +0100 Subject: [PATCH 21/44] EgtGeomKernel : - modificata la funzione per la creazione di una surf Bezier ruled guided. --- SbzFromCurves.cpp | 5 +- SurfBezier.cpp | 152 +++++++++++++++++++++++++++++++++++++++++----- SurfBezier.h | 2 +- Trimming.cpp | 5 +- 4 files changed, 144 insertions(+), 20 deletions(-) diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp index da24792..f6a40a4 100644 --- a/SbzFromCurves.cpp +++ b/SbzFromCurves.cpp @@ -735,7 +735,8 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou //------------------------------------------------------------------------------- ISurfBezier* -GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const ICURVEPOVECTOR& vCrv, double dLinTol) +GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, + const INTVECTOR& vShown, const INTINTVECTOR& vNewOrEdited, double dLinTol) { // verifica parametri if ( pCurve1 == nullptr || pCurve2 == nullptr) @@ -762,7 +763,7 @@ GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const IC // creo e setto la superficie trimesh PtrOwner pSbz( CreateBasicSurfBezier()) ; - if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv)) + if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv, vNewCrv, vShown, vNewOrEdited)) return nullptr ; // restituisco la superficie diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 1a6aa76..e652741 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -44,8 +44,9 @@ #define EIGEN_NO_IO #include "/EgtDev/Extern/Eigen/Dense" -//#define SAVEFAILEDTRIANGULATION -#ifdef SAVEFAILEDTRIANGULATION +#define SAVEFAILEDTRIANGULATION 0 +#define SAVEISO 1 +#if SAVEFAILEDTRIANGULATION || SAVEISO #include "/EgtDev/Include/EGkGeoObjSave.h" #endif @@ -1068,6 +1069,15 @@ SurfBezier::Load( NgeReader& ngeIn) m_bTrimmed = true ; } +#if SAVEISO + ICURVEPOVECTOR vCrv ; + GetAllPatchesIsocurves( false, vCrv) ; + vector vGeo ; + for( int i = 0 ; i < ssize(vCrv) ; ++i) + vGeo.push_back( vCrv[i]->Clone()) ; + SaveGeoObj( vGeo, "D:\\Temp\\bezier\\ruled\\rebuild\\isoCrv.nge") ; +#endif + // eseguo validazione return Validate() ; } @@ -1849,7 +1859,7 @@ SurfBezier::GetAuxSurfRefined( void) const return m_pSTMRefined ; } -#ifdef SAVEFAILEDTRIANGULATION +#if SAVEFAILEDTRIANGULATION static int nErr = 0 ; #endif @@ -1900,7 +1910,7 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) cons if ( vvPL.empty()) { LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated") -#ifdef SAVEFAILEDTRIANGULATION +#if SAVEFAILEDTRIANGULATION SaveGeoObj( Clone(),"D:\\Temp\\bezier\\not_triangulated\\" + ToString( nErr) + ".nge") ; ++nErr ; #endif @@ -5629,11 +5639,11 @@ SurfBezier::GetAllPatchesIsocurves( bool bUOrV, ICURVEPOVECTOR& vCrv) const { // restituisce tutte le isocurve di separazione tra patch in un parametro o nell'altro if ( bUOrV) { - for ( int v = 0 ; v < m_nSpanV ; ++v) + for ( int v = 0 ; v <= m_nSpanV ; ++v) vCrv.emplace_back( GetCurveOnU( v)) ; } else { - for ( int u = 0 ; u < m_nSpanU ; ++u) + for ( int u = 0 ; u <= m_nSpanU ; ++u) vCrv.emplace_back( GetCurveOnV( u)) ; } return true ; @@ -5643,7 +5653,10 @@ struct IsoParam { int nCrv ; double dParam0 ; double dParam1 ; - IsoParam( int _nCrv, double _dParam0, double _dParam1): nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1){ } ; + bool bNew ; + bool bShown ; + IsoParam( int _nCrv, double _dParam0, double _dParam1, bool _bNew = false, bool _bShown = false) : + nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1), bNew( _bNew), bShown( _bShown){ } ; bool operator < ( IsoParam& b) { return ( abs(dParam0 - b.dParam0) > EPS_SMALL ? dParam0 < b.dParam0 : dParam1 < b.dParam1) ; @@ -5654,8 +5667,13 @@ typedef vector ISOPARVECT ; //---------------------------------------------------------------------------- bool -SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv) +SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, const INTVECTOR& vShown , const INTINTVECTOR& vNewOrEdited) { + // vCrv è il vettore delle isocurve (nel parametro V) di una surf ( creata come rigata) che si vuole modificare ( già ordinato) + // vNewCrv è il vettore delle isocurve mostrate durante l'editing, che comprende le curve editate e le curve nuove + // vShown indica gli indici delle curve in vCrv che sono mostrate in vCrv + // vNewOrEdited indica la coppia di indici (nId1, nId2) (in vCrv, in vNewCrv) per le curve editate e una coppia (-1, nId) per le curve aggiunte + // converto in bezier la curva iniziale CurveComposite CrvU0 ; CrvU0.AddCurve( CurveToBezierCurve(pCurve0)) ; if ( ! CrvU0.IsValid()) @@ -5691,20 +5709,122 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c double dLastParam0 = 0, dLastParam1 = 0 ; double dLenPrev0 = 0 ,dLenPrev1 = 0 ; - // mi assicuro che le isocurve siano in ordine + // costruisco il vettore delle nuove curve isoparamtriche per la nuova superficie ISOPARVECT vIso ; + int nNewCounter = 0 ; + int nShowCounter = 0 ; + // inserisco solo le isocurve che non sono state modificate for ( int i = 0 ; i < ssize( vCrv) ; ++i) { - Point3d ptU0 ; vCrv[i]->GetStartPoint( ptU0) ; - Point3d ptU1 ; vCrv[i]->GetEndPoint( ptU1) ; - double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; - double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; - vIso.emplace_back( i, dParam0, dParam1) ; + if( i != vNewOrEdited[nNewCounter].first) { + Point3d ptU0 ; vCrv[i]->GetStartPoint( ptU0) ; + Point3d ptU1 ; vCrv[i]->GetEndPoint( ptU1) ; + double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; + double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; + if( i != vShown[nShowCounter]) + vIso.emplace_back( i, dParam0, dParam1) ; + else { + vIso.emplace_back( i, dParam0, dParam1, false, true) ; + ++ nShowCounter ; + } + } + else { + ++ nNewCounter ; + while( nNewCounter < ssize( vNewOrEdited) - 1 && vNewOrEdited[nNewCounter].first == -1) + ++ nNewCounter ; + if( i == vShown[nShowCounter]) + ++nShowCounter ; + } + } + + // vNewCrv contiene tutto il nuovo set di curve + for( INTINT ii : vNewOrEdited) { + Point3d ptU0 ; vNewCrv[ii.second]->GetStartPoint( ptU0) ; + Point3d ptU1 ; vNewCrv[ii.second]->GetEndPoint( ptU1) ; + double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; + double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; + vIso.emplace_back( ii.second, dParam0, dParam1, true) ; } sort( vIso.begin(), vIso.end()) ; + // scorro vIso per eliminare le isocurve non più necessarie + int c = 0 ; + dLastParam0 = vIso[c].dParam0 ; + dLastParam1 = vIso[c].dParam1 ; + ++c ; + while( c < ssize( vIso)) { + if ( vIso[c].dParam1 >= dLastParam1 && ! vIso[c].bNew) + ; // non devo fare nulla + else { + dLastParam0 = vIso[c].dParam0 ; + dLastParam1 = vIso[c].dParam1 ; + // cancello tutte le curve avanti e indietro finché incontro una show che non viene intersecata + int c_temp = c + 1 ; + while( ! (vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { + if( vIso[c_temp].bNew) + ++c_temp ; + else + vIso.erase(vIso.begin() + c_temp) ; + } + c_temp = c - 1 ; + while( ! (vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { + if( vIso[c_temp].bNew) + --c_temp ; + else { + vIso.erase(vIso.begin() + c_temp) ; + --c_temp ; + --c ; + } + } + } + dLastParam0 = vIso[c].dParam0 ; + dLastParam1 = vIso[c].dParam1 ; + ++c ; + } + + /////////////////////QUESTI CONTROLLI LI DOVREI FARE IO SE NON AVESSI INFORMAZIONI SU QUALI CURVE SONO QUELLE NUOVE( o MODIFICATE) (da finire nel caso) + //// controllo anche se le curve sono ordinate anche nel parametro sulla seconda curva ( se sono state modificate delle curve) + //// elimino eventuali curve intersecate da curve modificate + //double dLastParam0 = 0 ; + //double dLastParam1 = 0 ; + //int nCountOrig = 0 ; + //int nCountOrigTemp = 0 ; + //int nErased = 0 ; + //for( int i = 0 ; i < ssize( vNewCrv); ++i) { + // bool bFoundPos = false ; + // bool bNew = false ; + // nCountOrigTemp = nCountOrig ; + // while( ! bFoundPos) { + // bool bSameCrv = false ; + // bool bEdited = false ; + // Point3d ptStartOrig ; vCrv[nCountOrig]->GetStartPoint( ptStartOrig) ; + // Point3d ptStartNew ; vNewCrv[i]->GetStartPoint( ptStartNew) ; + // bool bSameStart = false ; + // bool bSameEnd = false ; + // if( AreSamePointExact( ptStartOrig, ptStartNew)) + // bSameStart = true ; + // Point3d ptEndOrig ; vCrv[nCountOrig]->GetEndPoint( ptEndOrig) ; + // Point3d ptEndNew ; vNewCrv[i]->GetEndPoint( ptEndNew) ; + // if( AreSamePointExact( ptEndOrig, ptEndNew)) + // bSameEnd = true ; + // bSameCrv = bSameStart && bSameEnd ; + // bEdited = bSameStart ^ bSameEnd ; + // if( bEdited || bNew) { + // // cancello eventuali curve intersecate da questa modificata + // } + // bFoundPos = bSameCrv || bEdited || bNew ; + + // } + + + //} + + + dLastParam0 = 0 ; + dLastParam1 = 0 ; for ( int i = 0 ; i < ssize( vIso) ; ++i) { - Point3d ptU0 ; vCrv[vIso[i].nCrv]->GetStartPoint( ptU0) ; - Point3d ptU1 ; vCrv[vIso[i].nCrv]->GetEndPoint( ptU1) ; + ICurve* pCrv = vIso[i].bNew ? vNewCrv[vIso[i].nCrv] : vCrv[vIso[i].nCrv] ; + Point3d ptU0 ; pCrv->GetStartPoint( ptU0) ; + Point3d ptU1 ; pCrv->GetEndPoint( ptU1) ; double& dParam0 = vIso[i].dParam0 ; double& dParam1 = vIso[i].dParam1 ; // se sono vicino ad un'intero allora considero il parametro intero ( uno split già esistente) diff --git a/SurfBezier.h b/SurfBezier.h index 2e7b89b..2182d95 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -150,7 +150,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3) override ; PNTVECTOR GetAllControlPoints( void) const ; bool GetAllPatchesIsocurves( bool bUorV, ICURVEPOVECTOR& vCrv) const ; - bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv) ; + bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, const INTVECTOR& vShown ,const INTINTVECTOR& vNewOrEdited) ; bool RemoveCollapsedSpans() override ; bool SwapParameters() ; diff --git a/Trimming.cpp b/Trimming.cpp index bf42b82..4d7c22c 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -3373,7 +3373,10 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, } #endif // Definisco la superficie - pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vCrv, dMyLinTol)) ; + ICURVEPOVECTOR vNewCrv ; + INTVECTOR vShown ; + INTINTVECTOR vNewOrEdited ; + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vCrv, vNewCrv, vShown, vNewOrEdited, dMyLinTol)) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; return nullptr ; From 82accd45c1c24eeb1687b8aa743cd446fd157f98 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 15 Jan 2026 12:47:50 +0100 Subject: [PATCH 22/44] EgtGeomKernel : - piccola correzione. --- SurfBezier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index e652741..23f6dff 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -45,7 +45,7 @@ #include "/EgtDev/Extern/Eigen/Dense" #define SAVEFAILEDTRIANGULATION 0 -#define SAVEISO 1 +#define SAVEISO 0 #if SAVEFAILEDTRIANGULATION || SAVEISO #include "/EgtDev/Include/EGkGeoObjSave.h" #endif From 5f1255a62546caaf87b836dbc2338de3153366e7 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Fri, 16 Jan 2026 15:12:01 +0100 Subject: [PATCH 23/44] EgtGeomKernel : - piccola miglioria alla intersLineLine - piccola correzione alla intersCurveCurve. --- IntersCurveCurve.cpp | 24 ++++++++++++++++++++++++ IntersLineLine.cpp | 22 +++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/IntersCurveCurve.cpp b/IntersCurveCurve.cpp index 0b88c9e..ec3ee45 100644 --- a/IntersCurveCurve.cpp +++ b/IntersCurveCurve.cpp @@ -689,6 +689,30 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB iCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) nClass = CRVC_IN ; + else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT) + nClass = CRVC_OUT ; + else if ( aInfo.IciA[0].nPrevTy == ICCT_NULL) { + // se il primo punto scelto non va bene allora ne cerco uno che mi dia informazioni sull'essere interno o esterno + CurveLine clLine ; + Point3d ptNewChoice ; pCurveA->GetPointD1D2( 0.25, ICurve::FROM_MINUS, ptNewChoice) ; + if ( ! clLine.SetPDL( ptNewChoice, 0, dLen)) + return false ; + // calcolo l'intersezione + IntersCurveCurve iCC( clLine, *pCurveB) ; + if ( iCC.GetIntersCount() > 0) { + // se quanto precede la prima intersezione è interno, allora la curva è interna + IntCrvCrvInfo aInfo ; + iCC.GetIntCrvCrvInfo( 0, aInfo) ; + if ( aInfo.IciA[0].nPrevTy == ICCT_IN) + nClass = CRVC_IN ; + else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT) + nClass = CRVC_OUT ; + else + return false ; // se arrivo qui potrei ritentare la ricerca + } + else + return false ; + } } // altrimenti sono esterni tra loro else { diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index c87691c..5e204d2 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -158,7 +158,27 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line bool bParallel = ( abs( dCrossXY) < SIN_EPS_ANG_ZERO * ( dLen1XY * dLen2XY)) ; // flag per segmenti che si allontanano significativamente bool bFarEnds = ( nS1Side != 0 || nE1Side != 0 || nS2Side != 0 || nE2Side != 0) ; - // analisi casi speciali di quasi parallelismo + + // analisi casi speciali di quasi parallelismo + // segmento sovrapposto all'altro + double dDist1, dDist2 ; + if( nS1Side == 0 || nE1Side == 0 || nS1Side == nE1Side) { + dDist1 = CrossXY( ptS1 - ptS2, vtDir2) ; + dDist2 = CrossXY( ptE1 - ptS2, vtDir2) ; + if( abs( dDist1 - dDist2) < EPS_SMALL * dLen2XY) { + bParallel = true ; + bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ; + } + } + else if( nS2Side == 0 || nE2Side == 0 || nS2Side == nE2Side) { + dDist1 = CrossXY( ptS2 - ptS1, vtDir1) ; + dDist2 = CrossXY( ptE2 - ptS1, vtDir1) ; + if( abs( dDist1 - dDist2) < EPS_SMALL * dLen1XY){ + bParallel = true ; + bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ; + } + } + // estremità sovrapposte di poco if ( ! bParallel && abs( dCrossXY) < ( 0.1 * DEGTORAD) * ( dLen1XY * dLen2XY)) { if (( nS1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) || ( nS1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) || From 5195c23dfb54197d037071d9b6254c9f06e5780d Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 16 Jan 2026 17:27:33 +0100 Subject: [PATCH 24/44] EgtGeomKernel : - in CalcPocketing piccola modifica sulle Entrate per casi a Trapezio. --- CalcPocketing.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 2805622..80033b3 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3735,16 +3735,25 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& if ( bOkTrap) { // calcolo eventuali uscite e ingressi if ( pCrvRes->GetTempProp( 0) > 0) { + // Recupero gli estremi della curva corrente e la inverto in base alla Testa + Point3d ptS ; pCrvRes->GetStartPoint( ptS) ; + Point3d ptE ; pCrvRes->GetEndPoint( ptE) ; + Point3d ptSGlob = GetToGlob( ptS, PockParam.frLocXY) ; + Point3d ptEGlob = GetToGlob( ptE, PockParam.frLocXY) ; + if ( ( PockParam.bAboveHead && ptEGlob.z > ptSGlob.z) || + ( ! PockParam.bAboveHead && ptEGlob.z < ptSGlob.z)) + pCrvRes->Invert() ; + if ( PockParam.bInvert) + pCrvRes->Invert() ; + // Calcolo eventuale entrata da fuori Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ; vtRef.Invert() ; bool bIsStartExtended = false ; if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, PockParam.dRad + PockParam.dOpenMinSafe, bIsStartExtended)) return false ; - pCrvRes->GetEndDir( vtRef) ; - bool bIsEndExtended = false ; - if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, true, PockParam.dRad + PockParam.dOpenMinSafe, bIsEndExtended)) - return false ; - if ( bIsEndExtended && ! bIsStartExtended) + } + else { + if ( PockParam.bInvert) pCrvRes->Invert() ; } } From 3ded6fe87d0bf87903c75185087c4897ac3ef60d Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Fri, 16 Jan 2026 18:44:36 +0100 Subject: [PATCH 25/44] EgtGeomKernel : - piccole modifiche estetiche. --- IntersCurveCurve.cpp | 32 ++++++++++++++++---------------- IntersLineLine.cpp | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/IntersCurveCurve.cpp b/IntersCurveCurve.cpp index ec3ee45..7aa10d5 100644 --- a/IntersCurveCurve.cpp +++ b/IntersCurveCurve.cpp @@ -47,7 +47,7 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, // ciclo sulle curve per verificare se da approssimare for ( int i = 0 ; i < 2 ; ++ i) { - // se curva è arco da approssimare oppure è curva di Bezier + // se curva è arco da approssimare oppure è curva di Bezier if ( ( m_pCurve[i]->GetType() == CRV_ARC && IsArcToApprox( *m_pCurve[i])) || m_pCurve[i]->GetType() == CRV_BEZIER) { // approssimo con rette @@ -127,7 +127,7 @@ IntersCurveCurve::IsArcToApprox( const ICurve& Curve) const CurveArc* pArc = GetBasicCurveArc( &Curve) ; if ( pArc == nullptr) return false ; - // verifico se non è nel piano XY o ha più di un giro al centro + // verifico se non è nel piano XY o ha più di un giro al centro return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) || abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ; } @@ -252,10 +252,10 @@ IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve& bool IntersCurveCurve::AdjustIntersParams( bool bAdjCrvA, bool bAdjCrvB) { - // se non ci sono intersezioni, non va fatto alcunché + // se non ci sono intersezioni, non va fatto alcunché if ( m_Info.empty()) return true ; - // se le curve originali non sono state approssimate, non va fatto alcunché + // se le curve originali non sono state approssimate, non va fatto alcunché if ( ! bAdjCrvA && ! bAdjCrvB) return true ; // procedo ad aggiustare @@ -389,11 +389,11 @@ IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1) return false ; - // ricerca del punto più vicino tra le intersezioni singole + // ricerca del punto più vicino tra le intersezioni singole bool bFound = false ; double dMinSqDist = SQ_INFINITO ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) { - // se è un'intersezione singola + // se è un'intersezione singola if ( ! m_Info[i].bOverlap) { // faccio la verifica sul punto Point3d ptP = ( nCrv == 0 ? m_Info[i].IciA[0].ptI : m_Info[i].IciB[0].ptI) ; @@ -458,7 +458,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, double dLenMin, CRVCVECTOR& // se esiste almeno una intersezione if ( m_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[0], m_Info, dLenMin, ccClass) ; - // altrimenti la curva è completamente interna oppure completamente esterna + // altrimenti la curva è completamente interna oppure completamente esterna else return CalcCurveInOrOut( m_pCurve[0], m_pCurve[1], ccClass) ; } @@ -475,7 +475,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, double dLenMin, CRVCVECTOR& // se esiste almeno una intersezione if ( m_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[1], InfoTmp, dLenMin, ccClass) ; - // altrimenti la curva è completamente interna oppure completamente esterna + // altrimenti la curva è completamente interna oppure completamente esterna else return CalcCurveInOrOut( m_pCurve[1], m_pCurve[0], ccClass) ; } @@ -540,7 +540,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO double dU2 = Info[j].IciA[1].dU ; if ( dU2 < dU1 && pCurve->IsClosed()) dU2 += dEndPar ; - // se cade nell'intervallo è da saltare + // se cade nell'intervallo è da saltare if ( Info[i].IciA[0].dU >= dU1 && Info[i].IciA[0].dU <= dU2) { bToSkip = true ; break ; @@ -559,7 +559,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO double dCurrPar = dStartPar ; double dCurrLen = 0 ; double dEndLen ; pCurve->GetLength( dEndLen) ; - // se è chiusa, recupero come finisce + // se è chiusa, recupero come finisce if ( pCurve->IsClosed()) { if ( ! InfoCorr[nNumInters-1].bOverlap) nLastTy = InfoCorr[nNumInters-1].IciA[0].nNextTy ; @@ -577,7 +577,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO } // costruisco il vettore delle classificazioni for ( int i = 0 ; i < nNumInters ; ++ i) { - // se è definito un tratto precedente + // se è definito un tratto precedente double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].IciA[0].dU, dLenU) ; if ( InfoCorr[i].IciA[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) { // verifico che la definizione sul tratto sia omogenea e valida @@ -599,7 +599,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO // altrimenti, salvo il tipo else nLastTy = InfoCorr[i].IciA[0].nNextTy ; - // se è definito un tratto in sovrapposizione + // se è definito un tratto in sovrapposizione if ( InfoCorr[i].bOverlap) { // assegno i dati CrvClass segClass ; @@ -639,7 +639,7 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB double dStartParB, dEndParB ; if ( ! pCurveB->GetDomain( dStartParB, dEndParB)) return false ; - // se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne + // se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne BBox3d boxCrvA, boxCrvB ; if ( ! pCurveA->GetLocalBBox( boxCrvA) || ! pCurveB->GetLocalBBox( boxCrvB)) @@ -682,9 +682,9 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB IntersCurveCurve iCC( clLine, *pCurveB) ; // dichiaro la classe della curva per default int nClass = CRVC_OUT ; - // se c'è almeno una intersezione + // se c'è almeno una intersezione if ( iCC.GetIntersCount() > 0) { - // se quanto precede la prima intersezione è interno, allora la curva è interna + // se quanto precede la prima intersezione è interno, allora la curva è interna IntCrvCrvInfo aInfo ; iCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) @@ -700,7 +700,7 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB // calcolo l'intersezione IntersCurveCurve iCC( clLine, *pCurveB) ; if ( iCC.GetIntersCount() > 0) { - // se quanto precede la prima intersezione è interno, allora la curva è interna + // se quanto precede la prima intersezione è interno, allora la curva è interna IntCrvCrvInfo aInfo ; iCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index 5e204d2..12e0ce7 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -162,18 +162,18 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line // analisi casi speciali di quasi parallelismo // segmento sovrapposto all'altro double dDist1, dDist2 ; - if( nS1Side == 0 || nE1Side == 0 || nS1Side == nE1Side) { + if ( nS1Side == 0 || nE1Side == 0 || nS1Side == nE1Side) { dDist1 = CrossXY( ptS1 - ptS2, vtDir2) ; dDist2 = CrossXY( ptE1 - ptS2, vtDir2) ; - if( abs( dDist1 - dDist2) < EPS_SMALL * dLen2XY) { + if ( abs( dDist1 - dDist2) < EPS_SMALL * dLen2XY) { bParallel = true ; bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ; } } - else if( nS2Side == 0 || nE2Side == 0 || nS2Side == nE2Side) { + else if ( nS2Side == 0 || nE2Side == 0 || nS2Side == nE2Side) { dDist1 = CrossXY( ptS2 - ptS1, vtDir1) ; dDist2 = CrossXY( ptE2 - ptS1, vtDir1) ; - if( abs( dDist1 - dDist2) < EPS_SMALL * dLen1XY){ + if ( abs( dDist1 - dDist2) < EPS_SMALL * dLen1XY) { bParallel = true ; bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ; } From b971eda771c62f6007ed2e9c32129d4596ab63b7 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 19 Jan 2026 08:03:57 +0100 Subject: [PATCH 26/44] EgtGeomJKernel : - in Zmap sostituiti mutex con atomic_flag. --- VolZmap.h | 7 +++---- VolZmapGraphics.cpp | 36 ++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/VolZmap.h b/VolZmap.h index c8d6f76..b41d063 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -21,9 +21,8 @@ #include "/EgtDev/Include/EGkSurfTriMesh.h" #include #include -#include -#include #include +#include typedef std::pair PNTVEC3D ; typedef std::vector PNTVEC3DVECTOR ; // vettore di intersezioni punto, vettore, tipo superficie @@ -557,9 +556,9 @@ class VolZmap : public IVolZmap, public IGeoObjRW mutable std::vector m_SliceXY ; mutable std::vector m_SliceXZ ; mutable std::vector m_SliceYZ ; - mutable std::mutex m_SliceMutex ; + mutable std::atomic_flag m_SliceFlag ; - std::atomic m_bIsBox ; + bool m_bIsBox ; int m_nCurrTool ; std::vector m_vTool ; diff --git a/VolZmapGraphics.cpp b/VolZmapGraphics.cpp index 3159877..2cd8b29 100644 --- a/VolZmapGraphics.cpp +++ b/VolZmapGraphics.cpp @@ -1271,13 +1271,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const bDefTopology = true ; } if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; auto it = m_SliceYZ[nSlBlockN].find( nSliceN) ; if ( it != m_SliceYZ[nSlBlockN].end()) { bMatOnSlice = it->second ; bDefTopology = true ; } - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } else if ( abs( nAdjVox3[nCount]) == 2) { @@ -1287,13 +1289,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const bDefTopology = true ; } if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; auto it = m_SliceXZ[nSlBlockN].find( nSliceN) ; if ( it != m_SliceXZ[nSlBlockN].end()) { bMatOnSlice = it->second ; bDefTopology = true ; } - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } else if ( abs( nAdjVox3[nCount]) == 3) { @@ -1303,13 +1307,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const bDefTopology = true ; } if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; auto it = m_SliceXY[nSlBlockN].find( nSliceN) ; if ( it != m_SliceXY[nSlBlockN].end()) { bMatOnSlice = it->second ; bDefTopology = true ; } - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } } @@ -1374,27 +1380,33 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const if ( nSlBlockN == nBlock) SliceYZ.emplace( nSliceN, bMatOnSlice) ; else { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; m_SliceYZ[nSlBlockN].emplace( nSliceN, bMatOnSlice) ; - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } else if ( abs(nAdjVox3[nCount]) == 2) { if ( nSlBlockN == nBlock) SliceXZ.emplace( nSliceN, bMatOnSlice) ; else { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; m_SliceXZ[nSlBlockN].emplace( nSliceN, bMatOnSlice) ; - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } else if ( abs(nAdjVox3[nCount]) == 3) { if ( nSlBlockN == nBlock) SliceXY.emplace(nSliceN, bMatOnSlice) ; else { - m_SliceMutex.lock() ; + while ( m_SliceFlag.test_and_set( memory_order_acquire)) + m_SliceFlag.wait( true, memory_order_relaxed) ; m_SliceXY[nSlBlockN].emplace( nSliceN, bMatOnSlice) ; - m_SliceMutex.unlock() ; + m_SliceFlag.clear( memory_order_release) ; + m_SliceFlag.notify_one() ; } } } From 4726cf4d3524ae8943e14b9473c2c1fce8713929 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jan 2026 12:32:13 +0100 Subject: [PATCH 27/44] EgtGeomKernel : - cambiamento della chiamata alla GetSurfBezierRuledGuided. --- SbzFromCurves.cpp | 6 +-- SurfBezier.cpp | 100 +++++++++++++--------------------------------- SurfBezier.h | 2 +- Trimming.cpp | 7 ++-- 4 files changed, 35 insertions(+), 80 deletions(-) diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp index f6a40a4..0fa537b 100644 --- a/SbzFromCurves.cpp +++ b/SbzFromCurves.cpp @@ -735,8 +735,8 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou //------------------------------------------------------------------------------- ISurfBezier* -GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, - const INTVECTOR& vShown, const INTINTVECTOR& vNewOrEdited, double dLinTol) +GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const BIPNTVECTOR& vCrv, + const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew, double dLinTol) { // verifica parametri if ( pCurve1 == nullptr || pCurve2 == nullptr) @@ -763,7 +763,7 @@ GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const IC // creo e setto la superficie trimesh PtrOwner pSbz( CreateBasicSurfBezier()) ; - if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv, vNewCrv, vShown, vNewOrEdited)) + if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv, vShown, vEdited, vNew)) return nullptr ; // restituisco la superficie diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 23f6dff..6d1f714 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -5653,7 +5653,7 @@ struct IsoParam { int nCrv ; double dParam0 ; double dParam1 ; - bool bNew ; + bool bNew ; // new or edited bool bShown ; IsoParam( int _nCrv, double _dParam0, double _dParam1, bool _bNew = false, bool _bShown = false) : nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1), bNew( _bNew), bShown( _bShown){ } ; @@ -5667,7 +5667,7 @@ typedef vector ISOPARVECT ; //---------------------------------------------------------------------------- bool -SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, const INTVECTOR& vShown , const INTINTVECTOR& vNewOrEdited) +SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv, const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew) { // vCrv è il vettore delle isocurve (nel parametro V) di una surf ( creata come rigata) che si vuole modificare ( già ordinato) // vNewCrv è il vettore delle isocurve mostrate durante l'editing, che comprende le curve editate e le curve nuove @@ -5713,37 +5713,29 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c ISOPARVECT vIso ; int nNewCounter = 0 ; int nShowCounter = 0 ; - // inserisco solo le isocurve che non sono state modificate + int nEditCounter = 0 ; for ( int i = 0 ; i < ssize( vCrv) ; ++i) { - if( i != vNewOrEdited[nNewCounter].first) { - Point3d ptU0 ; vCrv[i]->GetStartPoint( ptU0) ; - Point3d ptU1 ; vCrv[i]->GetEndPoint( ptU1) ; - double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; - double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; - if( i != vShown[nShowCounter]) - vIso.emplace_back( i, dParam0, dParam1) ; - else { - vIso.emplace_back( i, dParam0, dParam1, false, true) ; - ++ nShowCounter ; - } + Point3d ptU0 = vCrv[i].first ; + Point3d ptU1 = vCrv[i].second ; + double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; + double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; + if ( nEditCounter < ssize( vEdited) && i == vEdited[nEditCounter]) { + vIso.emplace_back( i, dParam0, dParam1, true, true) ; + ++ nEditCounter ; + ++ nShowCounter ; } - else { + else if ( nNewCounter < ssize( vNew) && i == vNew[nNewCounter]) { + vIso.emplace_back( i, dParam0, dParam1, true) ; ++ nNewCounter ; - while( nNewCounter < ssize( vNewOrEdited) - 1 && vNewOrEdited[nNewCounter].first == -1) - ++ nNewCounter ; - if( i == vShown[nShowCounter]) - ++nShowCounter ; } + else if ( nShowCounter < ssize( vShown) && i == vShown[nShowCounter]) { + vIso.emplace_back( i, dParam0, dParam1, false, true) ; + ++ nShowCounter ; + } + else + vIso.emplace_back( i, dParam0, dParam1) ; } - // vNewCrv contiene tutto il nuovo set di curve - for( INTINT ii : vNewOrEdited) { - Point3d ptU0 ; vNewCrv[ii.second]->GetStartPoint( ptU0) ; - Point3d ptU1 ; vNewCrv[ii.second]->GetEndPoint( ptU1) ; - double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; - double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; - vIso.emplace_back( ii.second, dParam0, dParam1, true) ; - } sort( vIso.begin(), vIso.end()) ; // scorro vIso per eliminare le isocurve non più necessarie @@ -5751,7 +5743,7 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c dLastParam0 = vIso[c].dParam0 ; dLastParam1 = vIso[c].dParam1 ; ++c ; - while( c < ssize( vIso)) { + while ( c < ssize( vIso)) { if ( vIso[c].dParam1 >= dLastParam1 && ! vIso[c].bNew) ; // non devo fare nulla else { @@ -5759,15 +5751,15 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c dLastParam1 = vIso[c].dParam1 ; // cancello tutte le curve avanti e indietro finché incontro una show che non viene intersecata int c_temp = c + 1 ; - while( ! (vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { - if( vIso[c_temp].bNew) + while ( ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { + if ( vIso[c_temp].bNew) ++c_temp ; else vIso.erase(vIso.begin() + c_temp) ; } c_temp = c - 1 ; - while( ! (vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { - if( vIso[c_temp].bNew) + while ( ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { + if ( vIso[c_temp].bNew) --c_temp ; else { vIso.erase(vIso.begin() + c_temp) ; @@ -5781,50 +5773,12 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c ++c ; } - /////////////////////QUESTI CONTROLLI LI DOVREI FARE IO SE NON AVESSI INFORMAZIONI SU QUALI CURVE SONO QUELLE NUOVE( o MODIFICATE) (da finire nel caso) - //// controllo anche se le curve sono ordinate anche nel parametro sulla seconda curva ( se sono state modificate delle curve) - //// elimino eventuali curve intersecate da curve modificate - //double dLastParam0 = 0 ; - //double dLastParam1 = 0 ; - //int nCountOrig = 0 ; - //int nCountOrigTemp = 0 ; - //int nErased = 0 ; - //for( int i = 0 ; i < ssize( vNewCrv); ++i) { - // bool bFoundPos = false ; - // bool bNew = false ; - // nCountOrigTemp = nCountOrig ; - // while( ! bFoundPos) { - // bool bSameCrv = false ; - // bool bEdited = false ; - // Point3d ptStartOrig ; vCrv[nCountOrig]->GetStartPoint( ptStartOrig) ; - // Point3d ptStartNew ; vNewCrv[i]->GetStartPoint( ptStartNew) ; - // bool bSameStart = false ; - // bool bSameEnd = false ; - // if( AreSamePointExact( ptStartOrig, ptStartNew)) - // bSameStart = true ; - // Point3d ptEndOrig ; vCrv[nCountOrig]->GetEndPoint( ptEndOrig) ; - // Point3d ptEndNew ; vNewCrv[i]->GetEndPoint( ptEndNew) ; - // if( AreSamePointExact( ptEndOrig, ptEndNew)) - // bSameEnd = true ; - // bSameCrv = bSameStart && bSameEnd ; - // bEdited = bSameStart ^ bSameEnd ; - // if( bEdited || bNew) { - // // cancello eventuali curve intersecate da questa modificata - // } - // bFoundPos = bSameCrv || bEdited || bNew ; - - // } - - - //} - - dLastParam0 = 0 ; dLastParam1 = 0 ; for ( int i = 0 ; i < ssize( vIso) ; ++i) { - ICurve* pCrv = vIso[i].bNew ? vNewCrv[vIso[i].nCrv] : vCrv[vIso[i].nCrv] ; - Point3d ptU0 ; pCrv->GetStartPoint( ptU0) ; - Point3d ptU1 ; pCrv->GetEndPoint( ptU1) ; + const BIPOINT& pCrv = vCrv[vIso[i].nCrv] ; + Point3d ptU0 = pCrv.first ; + Point3d ptU1 ; pCrv.second ; double& dParam0 = vIso[i].dParam0 ; double& dParam1 = vIso[i].dParam1 ; // se sono vicino ad un'intero allora considero il parametro intero ( uno split già esistente) diff --git a/SurfBezier.h b/SurfBezier.h index 2182d95..32e7d97 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -150,7 +150,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3) override ; PNTVECTOR GetAllControlPoints( void) const ; bool GetAllPatchesIsocurves( bool bUorV, ICURVEPOVECTOR& vCrv) const ; - bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, const INTVECTOR& vShown ,const INTINTVECTOR& vNewOrEdited) ; + bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv, const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew) ; bool RemoveCollapsedSpans() override ; bool SwapParameters() ; diff --git a/Trimming.cpp b/Trimming.cpp index 4d7c22c..fd12433 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -3373,10 +3373,11 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, } #endif // Definisco la superficie - ICURVEPOVECTOR vNewCrv ; + BIPNTVECTOR vGuides ; INTVECTOR vShown ; - INTINTVECTOR vNewOrEdited ; - pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vCrv, vNewCrv, vShown, vNewOrEdited, dMyLinTol)) ; + INTVECTOR vEdited ; + INTVECTOR vNew ; + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vGuides, vShown, vEdited, vNew, dMyLinTol)) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; return nullptr ; From 3c5d2571fedd942181782afcc6064e1f38476f64 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jan 2026 15:15:11 +0100 Subject: [PATCH 28/44] EgtGeomKernel : - piccola correzione. --- SurfBezier.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 6d1f714..65982c5 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -5751,14 +5751,14 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c dLastParam1 = vIso[c].dParam1 ; // cancello tutte le curve avanti e indietro finché incontro una show che non viene intersecata int c_temp = c + 1 ; - while ( ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { + while ( c_temp < ssize( vIso) && ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { if ( vIso[c_temp].bNew) ++c_temp ; else vIso.erase(vIso.begin() + c_temp) ; } c_temp = c - 1 ; - while ( ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { + while ( c_temp > 0 && ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { if ( vIso[c_temp].bNew) --c_temp ; else { From 96907d5952e58e199e8f7a8cf4a09feed385bd82 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jan 2026 15:27:19 +0100 Subject: [PATCH 29/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20aggiunta=20di=20u?= =?UTF-8?q?na=20funzionalit=C3=A0=20per=20il=20chain=20diretto=20di=20un?= =?UTF-8?q?=20vettore=20di=20curve.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChainCurves.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/ChainCurves.cpp b/ChainCurves.cpp index ad5d615..3c12153 100644 --- a/ChainCurves.cpp +++ b/ChainCurves.cpp @@ -16,6 +16,7 @@ #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkCurve.h" +#include "/EgtDev/Include/EGkCurveComposite.h" #include using namespace std ; @@ -496,3 +497,46 @@ ChainCurves::GetForkPoint( const Point3d& ptP) return ( find_if( m_vForkData.begin(), m_vForkData.end(), [&]( const ForkData& frkData) { return AreSamePointEpsilon( frkData.ptFork, ptP, m_dToler) ; })) ; } + +//---------------------------------------------------------------------------- +bool +ChainCurves::GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert) +{ + if( ssize( vCrv) == 1) + return true ; + // modifico direttamente le curve passate in input + Init( bAllowInvert, dChainTol, ssize( vCrv)) ; + for ( int c = 0 ; c < ssize( vCrv) ; ++c) { + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + vCrv[c]->GetStartPoint( ptStart) ; + vCrv[c]->GetEndPoint( ptEnd) ; + vCrv[c]->GetStartDir( vtStart) ; + vCrv[c]->GetEndDir( vtEnd) ; + AddCurve( 1 + c, ptStart, vtStart, ptEnd, vtEnd) ; + } + INTVECTOR vIds ; + Point3d ptStart = ORIG ; + while ( GetChainFromNear( ptStart, false, vIds)) { + ICurveComposite* pFirstCrv = vCrv[vIds[0]] ; + for ( int nId : vIds) { + bool bInvert = false ; + if( nId < 0) + bInvert = true ; + nId = abs( nId) - 1 ; + if( bInvert) + vCrv[nId]->Invert() ; + if( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol)) ; + return false ; + } + pFirstCrv->GetEndPoint( ptStart) ; + } + // elimino gli elementi del vettore che non contengono più curve + int c = ssize( vCrv) ; + while( c > -1) { + if( IsNull( vCrv[c])) + vCrv.erase( vCrv.begin() + c) ; + --c ; + } + return true ; +} From 4f48337f62888ef84e0694e6e90b89bc7b5a2e4d Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jan 2026 15:31:56 +0100 Subject: [PATCH 30/44] EgtGeomKernel : - piccola correzione. --- ChainCurves.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChainCurves.cpp b/ChainCurves.cpp index 3c12153..c41ff51 100644 --- a/ChainCurves.cpp +++ b/ChainCurves.cpp @@ -526,7 +526,7 @@ ChainCurves::GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool b nId = abs( nId) - 1 ; if( bInvert) vCrv[nId]->Invert() ; - if( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol)) ; + if( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol)) return false ; } pFirstCrv->GetEndPoint( ptStart) ; From b7fee9696e344182718018d04867a440adf6690b Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 19 Jan 2026 15:46:50 +0100 Subject: [PATCH 31/44] EgtGeomKernel : - piccola correzione. --- ChainCurves.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChainCurves.cpp b/ChainCurves.cpp index c41ff51..531cbd1 100644 --- a/ChainCurves.cpp +++ b/ChainCurves.cpp @@ -518,7 +518,7 @@ ChainCurves::GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool b INTVECTOR vIds ; Point3d ptStart = ORIG ; while ( GetChainFromNear( ptStart, false, vIds)) { - ICurveComposite* pFirstCrv = vCrv[vIds[0]] ; + ICurveComposite* pFirstCrv = vCrv[abs(vIds[0]) - 1] ; for ( int nId : vIds) { bool bInvert = false ; if( nId < 0) From d343f474e4602fb03766711b51780bec2f50495b Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 20 Jan 2026 15:21:26 +0100 Subject: [PATCH 32/44] EgtGeomKernel : - Aggiunti controlli in PolygonElevation. --- PolygonElevation.cpp | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/PolygonElevation.cpp b/PolygonElevation.cpp index 4e04206..28c72e6 100644 --- a/PolygonElevation.cpp +++ b/PolygonElevation.cpp @@ -172,9 +172,9 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl return true ; } } - else if ( ( Inters.nILTT == ILTT_VERT || Inters.nILTT == ILTT_EDGE || Inters.nILTT == ILTT_IN) && Inters.dCosDN > EPS_ZERO) + else if ( ( Inters.nILTT == ILTT_VERT || Inters.nILTT == ILTT_EDGE || Inters.nILTT == ILTT_IN) && Inters.dCosDN > EPS_ZERO) dElev = max( dElev, Inters.dU) ; - else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE) + else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE) dElev = max( dElev, Inters.dU2) ; } } @@ -206,22 +206,30 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl if ( vEdges[i].first.z < EPS_SMALL && vEdges[i].second.z < EPS_SMALL) continue ; // calcolo il segmento di linea - CurveLine clLine ; + CurveLine clLine ; if ( ! clLine.Set( vEdges[i].first, vEdges[i].second)) return false ; // l'elevazione va aggiornata con la massima Z delle eventuali intersezioni dell'edge con il loop IntersCurveCurve intLL( clLine, ccLoop) ; - IntCrvCrvInfo aInfo ; - for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) { - dElev = max( dElev, aInfo.IciA[0].ptI.z) ; - if ( aInfo.bOverlap) - dElev = max( dElev, aInfo.IciA[1].ptI.z) ; - // se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice) - if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN) - dElev = max( dElev, vEdges[i].first.z) ; - // se ultima intersezione va da esterno a interno allora devo considerare il punto finale del segmento (vertice) - else if ( j == intLL.GetIntersCount() - 1 && aInfo.IciA[ aInfo.bOverlap ? 1 : 0].nNextTy == ICCT_IN) - dElev = max( dElev, vEdges[i].second.z) ; + if ( intLL.GetIntersCount() == 0) { + Point3d ptM = Media( vEdges[i].first, vEdges[i].second) ; + ptM.z = 0 ; + if ( IsPointInsidePolyLine( ptM, PL, -EPS_SMALL)) + dElev = max( dElev, max( vEdges[i].first.z, vEdges[i].second.z)) ; + } + else { + IntCrvCrvInfo aInfo ; + for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) { + dElev = max( dElev, aInfo.IciA[0].ptI.z) ; + if ( aInfo.bOverlap) + dElev = max( dElev, aInfo.IciA[1].ptI.z) ; + // se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice) + if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN) + dElev = max( dElev, vEdges[i].first.z) ; + // se ultima intersezione va da esterno a interno allora devo considerare il punto finale del segmento (vertice) + else if ( j == intLL.GetIntersCount() - 1 && aInfo.IciA[ aInfo.bOverlap ? 1 : 0].nNextTy == ICCT_IN) + dElev = max( dElev, vEdges[i].second.z) ; + } } } From d3f2587cc25c1a476b316ec17b3e76afa10305e1 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 20 Jan 2026 17:26:28 +0100 Subject: [PATCH 33/44] EgtGeomKernel 3.1a3 : - In Trimming aggiunta una prima versione per l'analisi dei triangoli durante la ricerca di facce piane - In Trimming aggiunto l'ultilizzo delle Normali Smussate per recupero Edge mediate Estrusione - In Trimming migliorata la gestione e la creazione delle Rigate di Bezier mediante curve di sincronizzazione. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes Trimming.cpp | 805 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 652 insertions(+), 153 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index bdbb1179bc575cea3bc0ff262be029ecd0018546..245321f55d8d74e4d043c778cff34a3e31717e2a 100644 GIT binary patch delta 81 zcmdlNy)SyhH#SD&&FAG5nSs VBORDERINFO ; +enum TriaClass { OK = 0, SMALL = 1, CAP = 2, HAT = 3, FLIPPED = 4} ; + //----------------------------------------------------------------------------- static const string sCircle{ "circle"} ; @@ -1574,18 +1577,509 @@ GetSurfBorders( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace, double d return true ; } +// ---------------------------------------------------------------------------- +// Funzione per il calcolo dei bordi mediante spessore +static bool +GetBorderByExtrusion( const SurfTriMesh* pStm, double dThick, double dLinTol, double dAngTol, + vector>& vPLLoopPLExtr) +{ + // Verifico la validità della superficie + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + vPLLoopPLExtr.clear() ; + + #if DEBUG_BORDERS_BY_NORMALS + VT.emplace_back( pStm->Clone()) ; + VC.emplace_back( BLACK) ; + SaveGeoObj( VT, VC, "C:\\Temp\\ExtrLoops.nge") ; + #endif + + // Recupero tutti i Loop della superficie + POLYLINEVECTOR vPLLoop ; + if ( ! pStm->GetLoops( vPLLoop)) + return false ; + // Se Superficie Chiusa, non faccio nulla + if ( vPLLoop.empty()) + return true ; + + // Scorro i Loop + for ( PolyLine& PLLoop : vPLLoop) { + PolyLine PLLoopExtr ; + // Scorro i Segmenti + Point3d ptI, ptE ; + double dUI, dUE ; + bool bFound = PLLoop.GetFirstULine( &dUI, &ptI, &dUE, &ptE) ; + double dPar = -1 ; + bool bFirst = true ; + while ( bFound) { + // Recupero il TriangoloEx del tratto lineare corrente + Triangle3dEx Tria ; + if ( ! pStm->GetTriangle( int( dUI), Tria)) + return false ; + // Tale Triangolo contiene le normali mediate, cerco quelle riferite ai vertici + if ( bFirst) { + int nTriaP = 0 ; + for ( ; nTriaP < 3 ; ++ nTriaP) { + if ( AreSamePointApprox( Tria.GetP( nTriaP), ptI)) + break ; + } + PLLoopExtr.AddUPoint( ++ dPar, ptI - Tria.GetVertexNorm( nTriaP) * dThick) ; + #if DEBUG_BORDERS_BY_NORMALS + IGeoVector3d* _vtN = CreateGeoVector3d() ; _vtN->Set( Tria.GetVertexNorm( nTriaP), ptI) ; + VT.emplace_back( _vtN) ; + Color _myCol = Color( abs( Tria.GetVertexNorm( nTriaP).x), abs( Tria.GetVertexNorm( nTriaP).y), abs( Tria.GetVertexNorm( nTriaP).z)) ; + VC.emplace_back( _myCol) ; + CurveLine _Line ; _Line.Set( ptI, ptI - Tria.GetVertexNorm( nTriaP) * dThick) ; + VT.emplace_back( _Line.Clone()) ; + VC.emplace_back( _myCol) ; + #endif + bFirst = false ; + } + int nTriaP = 0 ; + for ( ; nTriaP < 3 ; ++ nTriaP) { + if ( AreSamePointApprox( Tria.GetP( nTriaP), ptE)) + break ; + } + PLLoopExtr.AddUPoint( ++ dPar, ptE - Tria.GetVertexNorm( nTriaP) * dThick) ; + #if DEBUG_BORDERS_BY_NORMALS + IGeoVector3d* _vtN = CreateGeoVector3d() ; _vtN->Set( Tria.GetVertexNorm( nTriaP), ptE) ; + VT.emplace_back( _vtN) ; + Color _myCol = Color( abs( Tria.GetVertexNorm( nTriaP).x), abs( Tria.GetVertexNorm( nTriaP).y), abs( Tria.GetVertexNorm( nTriaP).z)) ; + VC.emplace_back( _myCol) ; + CurveLine _Line ; _Line.Set( ptE, ptE - Tria.GetVertexNorm( nTriaP) * dThick) ; + VT.emplace_back( _Line.Clone()) ; + VC.emplace_back( _myCol) ; + #endif + bFound = PLLoop.GetNextULine( &dUI, &ptI, &dUE, &ptE) ; + } + #if DEBUG_BORDERS_BY_NORMALS + ICurveComposite* pC = CreateCurveComposite() ; + pC->FromPolyLine( PLLoopExtr) ; + VT.emplace_back( pC->Clone()) ; + VC.emplace_back( AQUA) ; + #endif + if ( PLLoopExtr.GetPointNbr() >= 4) { + // Il primo e l'ultimo punto devono coincidere + PNTULIST& lPntU = PLLoopExtr.GetUPointList() ; + Point3d ptClose = Media( lPntU.front().first, lPntU.back().first) ; + lPntU.front().first = ptClose ; + lPntU.back().first = ptClose ; + vPLLoopPLExtr.emplace_back( make_pair( PLLoop, PLLoopExtr)) ; + } + } + + #if DEBUG_BORDERS_BY_NORMALS + SaveGeoObj( VT, VC, "C:\\Temp\\ExtrLoops.nge") ; + #endif + + return true ; +} + // ---------------------------------------------------------------------------- // ---------------------------------- Analisi Adiacenze ----------------------- // ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// Funzione per individuare se un triangolo piccolo è trascurabile +static bool +CheckUnrelevantTriangle( const SurfTriMesh& Stm, int nCurrTria, int nTriaAdj, int nAdj, double dAngTol, + unordered_map& mapAdjToAvoid, INTVECTOR& vNewTria) +{ + vNewTria.clear() ; vNewTria.reserve( 2) ; + // Verifico che la TriMesh sia valida + if ( ! Stm.IsValid()) + return false ; + + // Verifico che il triangoli appartengano alla TriMesh + Triangle3d Tria, TriaAdj ; + if ( ! Stm.GetTriangle( nCurrTria, Tria) || ! Stm.GetTriangle( nTriaAdj, TriaAdj)) + return false ; + + // Verifico le sue adiacenze + int nUnrelAdjTriaIds[3] ; + if ( ! Stm.GetTriangleAdjacencies( nTriaAdj, nUnrelAdjTriaIds)) + return false ; + int nInvAdj = 0 ; + for ( int nUnrelAdj = 0 ; nUnrelAdj < 3 ; ++ nUnrelAdj) { + // Se non esiste l'adiacenza, non faccio nulla + int nUnrelTriaAdj = nUnrelAdjTriaIds[nUnrelAdj] ; + if ( nUnrelTriaAdj == SVT_NULL) + continue ; + // Se l'Adiacenza è il triangolo di partenza, va scarata + if ( nUnrelTriaAdj == nCurrTria) { + nInvAdj = nUnrelAdj ; + continue ; + } + // Recupero il triangolo adiacente + Triangle3d TriaAdjUnrel ; + if ( ! Stm.GetTriangle( nUnrelTriaAdj, TriaAdjUnrel)) + return false ; + // Se la normale è dentro alla tolleranza del triangolo di partenza, allora sarà + // fuori dalla tolleranza del triangolo di adiacenza corrente, quindi va scaratata + if ( Tria.GetN() * TriaAdjUnrel.GetN() > cos( ( dAngTol - EPS_ANG_SMALL) * DEGTORAD)) { + mapAdjToAvoid[nTriaAdj].push_back( nUnrelAdj) ; + int nIdAdjTriaId[3] ; + if ( ! Stm.GetTriangleAdjacencies( nUnrelTriaAdj, nIdAdjTriaId)) + return false ; + for ( int nMyAdj = 0 ; nMyAdj < 3 ; ++ nMyAdj) { + if ( nIdAdjTriaId[nMyAdj] == nTriaAdj) { + mapAdjToAvoid[nUnrelTriaAdj].push_back( nMyAdj) ; + vNewTria.push_back( nUnrelTriaAdj) ; + break ; + } + } + } + } + + if ( ! vNewTria.empty()) { + mapAdjToAvoid[nTriaAdj].push_back( nInvAdj) ; + mapAdjToAvoid[nCurrTria].push_back( nAdj) ; + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per analisi del singolo triangolo +static bool +AnalyzeTriangle( const Triangle3d& Tria, const Triangle3d& TriaAdj, double dAngTol, int& nTriaClass) +{ + // Verifico la validità del triangolo + if ( ! Tria.IsValid()) + return false ; + nTriaClass = TriaClass::OK ; + + // Verifico caso Small + double dArea = TriaAdj.GetArea() ; + if ( dArea < ( 70 * EPS_SMALL) * ( 70. * EPS_SMALL)) { // ~ 0.005 + nTriaClass = TriaClass::SMALL ; + return true ; + } + + bool bCap, bHat = false ; + // Verifico caso Cap + double dLen0 = Dist( TriaAdj.GetP( 0), TriaAdj.GetP( 1)) ; + double dLen1 = Dist( TriaAdj.GetP( 1), TriaAdj.GetP( 2)) ; + double dLen2 = Dist( TriaAdj.GetP( 2), TriaAdj.GetP( 0)) ; + double dLenMin = min( { dLen0, dLen1, dLen2}) ; + double dLenMax = max( { dLen0, dLen1, dLen2}) ; + double dRatio = ( dLenMin > EPS_SMALL ? dLenMax / dLenMin : INFINITO) ; + bCap = ( dRatio > 100.) ; // ~ 2 ordini di grandezza + if ( bCap) { + nTriaClass = TriaClass::CAP ; + return true ; + } + // Verifico caso Hat + double dH0 = ( dLen1 > EPS_SMALL ? ( ( 2. * dArea) / dLen1) : ( ( dLen0 + dLen2) / 2.)) ; + double dH1 = ( dLen2 > EPS_SMALL ? ( ( 2. * dArea) / dLen2) : ( ( dLen0 + dLen1) / 2.)) ; + double dH2 = ( dLen0 > EPS_SMALL ? ( ( 2. * dArea) / dLen0) : ( ( dLen1 + dLen2) / 2.)) ; + double dHMin = min( { dH0, dH1, dH2}) ; + double dAvgH = ( dH0 + dH1 + dH2) / 3. ; + double dRatioH = ( dAvgH > EPS_SMALL ? ( dHMin / dAvgH) : 0.) ; + double dAvgE = ( dLen0 + dLen1 + dLen2) / 3. ; + double dRatioE = ( dAvgE > EPS_SMALL ? ( dHMin / dAvgE) : 0.) ; + bHat = ( dRatioH < 1 / 100. || dRatioE < 1 / 100.) ; + if ( bHat) + nTriaClass = TriaClass::HAT ; + + // Caso Flip + bool bFlipped = ( ( - Tria.GetN()) * TriaAdj.GetN() > cos( ( dAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + if ( bFlipped) { + nTriaClass = TriaClass::FLIPPED ; + return true ; + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per correzione dei triangoli +static bool +AdjustClassifiedTriangles( unordered_set& setValidTria, const SurfTriMesh* pStm, + const unordered_map& mapTriaClass, TRIA3DVECTOR& vAllTria) +{ + // Se superficie non valida, errore + if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0) + return false ; + // se non ho triangoli nel set, non faccio nulla + if ( setValidTria.empty()) + return true ; + + // se non ho una Mappa di classificazione, allora i triangoli sono già tutti validi e corretti + if ( mapTriaClass.empty()) { + vAllTria.reserve( setValidTria.size()) ; + for ( auto Iter = setValidTria.begin() ; Iter != setValidTria.end() ; ++ Iter) { + Triangle3d Tria ; + if ( ! pStm->GetTriangle( *Iter, Tria)) + return false ; + vAllTria.emplace_back( Tria) ; + } + return true ; + } + + // Scorro gli elementi della Mappa + for ( auto &KeyVal : mapTriaClass) { + int nTria = KeyVal.first ; + int nTriaClass = KeyVal.second ; + // Recupero il Triangolo + Triangle3d Tria ; + if ( ! pStm->GetTriangle( nTria, Tria)) + return false ; + + // Se Triangolo Small, lo elimino + if ( nTriaClass == TriaClass::SMALL) + setValidTria.erase( nTria) ; + + // Recupero le 3 adiacenze + int nIdAdjTriaId[3] ; + if ( ! pStm->GetTriangleAdjacencies( nTria, nIdAdjTriaId)) + return false ; + // Controllo quali tra i miei triangoli devo analizzare + vector> vMyAdjTria ; vMyAdjTria.reserve( 3) ; + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + int nTriaAdj = nIdAdjTriaId[nAdj] ; + if ( nTriaAdj == SVT_NULL || + setValidTria.find( nTriaAdj) == setValidTria.end()) + continue ; + Triangle3d myAdjTria ; + if ( ! pStm->GetTriangle( nTriaAdj, myAdjTria)) + return false ; + vMyAdjTria.emplace_back( make_pair( nTriaAdj, myAdjTria)) ; + } + #if DEBUG_FACE_SEARCH_TRIA_MODIF + VT.clear() ; VC.clear() ; + VT.emplace_back( pStm->CloneTriangle( nTria)) ; + VC.emplace_back( RED) ; + for ( int i = 0 ; i < ssize( vMyAdjTria) ; ++ i) { + VT.emplace_back( pStm->CloneTriangle( vMyAdjTria[i].first)) ; + VC.emplace_back( GREEN) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\Vert0.nge") ; + #endif + + // Se Triangolo CAP + if ( nTriaClass == TriaClass::CAP) { + // Se nessuna adiacenza valida, non faccio nulla + int nAdjTria = ssize( vMyAdjTria) ; + if ( nAdjTria == 0) + continue ; + // Se una sola,non faccio nulla + else if ( nAdjTria == 1) + continue ; + // Altrimenti + else { + // Recupero l'adiacenza più corta + int nShortestAdj = 0 ; + double dMinLen = INFINITO ; + for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { + double dEdgeLen = SqDist( Tria.GetP( nAdj), Tria.GetP( ( nAdj + 1) % 3)) ; + if ( dEdgeLen < dMinLen) { + dMinLen = dEdgeLen ; + nShortestAdj = nAdj ; + } + } + // Calcolo il punto medio di tale Edge, il più corto + Point3d ptA = Tria.GetP( nShortestAdj) ; + Point3d ptB = Tria.GetP( ( nShortestAdj + 1) % 3) ; + Point3d ptMid = Media( ptA, ptB) ; + // Cerco l'indice del vertice più vicino a ptA e ptB + int nVertA = -1, nVertB = -1 ; + for ( int nV = 0 ; ( nVertA == -1 || nVertB == -1) && nV < pStm->GetVertexCount() ; ++ nV) { + Point3d ptV ; + if ( ! pStm->GetVertex( nV, ptV)) + return false ; + if ( AreSamePointEpsilon( ptV, ptA, 1e-6)) + nVertA = nV ; + if ( AreSamePointEpsilon( ptV, ptB, 1e-6)) + nVertB = nV ; + } + if ( nVertA == -1 || nVertB == -1) + continue ; + + #if DEBUG_FACE_SEARCH_TRIA_MODIF + IGeoPoint3d* _ptA = CreateGeoPoint3d() ; _ptA->Set( ptA) ; + IGeoPoint3d* _ptB = CreateGeoPoint3d() ; _ptB->Set( ptB) ; + IGeoPoint3d* _ptM = CreateGeoPoint3d() ; _ptM->Set( ptMid) ; + VT.emplace_back( _ptA) ; VT.emplace_back( _ptB) ; VT.emplace_back( _ptM) ; + VC.emplace_back( FUCHSIA) ; VC.emplace_back( FUCHSIA) ; VC.emplace_back( FUCHSIA) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Vert1.nge") ; + #endif + + // Elimino il triangolo CAP + setValidTria.erase( nTria) ; + // Modifico tutti i triangoli attorno al Vertice A e B + INTVECTOR vTA, vTB ; + bool bCirc ; + if ( ! pStm->GetAllTriaAroundVertex( nVertA, vTA, bCirc) || + ! pStm->GetAllTriaAroundVertex( nVertB, vTB, bCirc)) + return false ; + for ( const int& nVertTria : vTA) { + if ( nVertTria == SVT_NULL || + setValidTria.find( nVertTria) == setValidTria.end()) + continue ; + #if DEBUG_FACE_SEARCH_TRIA_MODIF + VT.emplace_back( pStm->CloneTriangle( nVertTria)) ; + VC.emplace_back( LIME) ; + #endif + Triangle3d newTria ; + if ( ! pStm->GetTriangle( nVertTria, newTria)) + return false ; + for ( int j = 0 ; j < 3 ; ++ j) { + if ( AreSamePointApprox( newTria.GetP( j), ptA) || + AreSamePointApprox( newTria.GetP( j), ptB)) { + newTria.SetP( j, ptMid) ; + break ; + } + } + setValidTria.erase( nVertTria) ; + vAllTria.emplace_back( newTria) ; + } + for ( const int& nVertTria : vTB) { + if ( nVertTria == SVT_NULL || + setValidTria.find( nVertTria) == setValidTria.end()) + continue ; + #if DEBUG_FACE_SEARCH_TRIA_MODIF + VT.emplace_back( pStm->CloneTriangle( nVertTria)) ; + VC.emplace_back( LIME) ; + #endif + Triangle3d newTria ; + if ( ! pStm->GetTriangle( nVertTria, newTria)) + return false ; + for ( int j = 0 ; j < 3 ; ++ j) { + if ( AreSamePointApprox( newTria.GetP( j), ptA) || + AreSamePointApprox( newTria.GetP( j), ptB)) { + newTria.SetP( j, ptMid) ; + break ; + } + } + setValidTria.erase( nVertTria) ; + vAllTria.emplace_back( newTria) ; + } + #if DEBUG_FACE_SEARCH_TRIA_MODIF + SaveGeoObj( VT, VC, "C:\\Temp\\Vert2.nge") ; + #endif + } + } + // Se triangolo di tipo HAT + else if ( nTriaClass == TriaClass::HAT) { + // TODO ... + } + // Se Triangolo Invertito + else if ( nTriaClass == TriaClass::FLIPPED) { // TODO : Testare se capita + // 2 Possibilità : + // a) Triangolo Invertito senza altre intersezioni + // b) Triangolo Invertito senza altre intersezioni + + // Se nessuna adiacenza valida, non faccio nulla + int nAdjTria = ssize( vMyAdjTria) ; + if ( nAdjTria == 0) + continue ; + // Altrimenti + else { + // Cerco il triangolo in cui cade il punto centrale + bool bPointIn = false ; + for ( int i = 0 ; ! bPointIn && i < nAdjTria ; ++ i) { + Triangle3d& TriaAdj = vMyAdjTria[i].second ; + Plane3d plAdjTria ; plAdjTria.Set( TriaAdj.GetP( 0), TriaAdj.GetN()) ; + for ( int nP = 0 ; nP < 3 ; ++ nP) { + Point3d ptTest = ProjectPointOnPlane( Tria.GetP( nP), plAdjTria) ; + if ( IsPointInsideTriangle( ptTest, TriaAdj, TriangleType::OPEN)) { + #if DEBUG_FACE_SEARCH_TRIA_MODIF + IGeoPoint3d* _pt = CreateGeoPoint3d() ; + _pt->Set( ptTest) ; + VT.emplace_back( _pt) ; + VC.emplace_back( YELLOW) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Vert1.nge") ; + #endif + // Recupro il vertice più distante + Point3d ptA = Tria.GetP( ( nP + 1) % 3) ; + Point3d ptB = Tria.GetP( ( nP + 2) % 3) ; + for ( int nAdjP = 0 ; nAdjP < 3 ; ++ nAdjP) { + if ( ! AreSamePointApprox( TriaAdj.GetP( nAdjP), ptA) && + ! AreSamePointApprox( TriaAdj.GetP( nAdjP), ptB)) { + Triangle3d TriaA, TriaB ; + TriaA.Set( TriaAdj.GetP( nAdjP), TriaAdj.GetP( ( nAdjP + 1) % 3), ptTest) ; + TriaB.Set( TriaAdj.GetP( ( nAdjP + 2) % 3), TriaAdj.GetP( nAdjP), ptTest) ; + #if DEBUG_FACE_SEARCH_TRIA_MODIF + CurveComposite CompoA ; + CompoA.AddPoint( TriaA.GetP( 0)) ; + CompoA.AddLine( TriaA.GetP( 1)) ; + CompoA.AddLine( TriaA.GetP( 2)) ; + CompoA.Close() ; + CurveComposite CompoB ; + CompoB.AddPoint( TriaB.GetP( 0)) ; + CompoB.AddLine( TriaB.GetP( 1)) ; + CompoB.AddLine( TriaB.GetP( 2)) ; + CompoB.Close() ; + VT.emplace_back( CompoA.Clone()) ; + VC.emplace_back( FUCHSIA) ; + VT.emplace_back( CompoB.Clone()) ; + VC.emplace_back( FUCHSIA) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Vert2.nge") ; + #endif + vAllTria.emplace_back( TriaA) ; + vAllTria.emplace_back( TriaB) ; + setValidTria.erase( nTria) ; + setValidTria.erase( nAdjTria) ; + // Se il triangolo diviso è l'unico di adiacenza + if ( nAdjTria == 1) { + // Inverto il triangolo corrente e aggiungo + Triangle3d TriaFlipped ; + TriaFlipped.Set( Tria.GetP( 0), Tria.GetP( 2), Tria.GetP( 1)) ; + vAllTria.emplace_back( TriaFlipped) ; + } + else { + for ( i = 0 ; i < nAdjTria ; ++ i) { + for ( int j = 0 ; j < 3 ; ++ j) { + if ( AreSamePointApprox( TriaAdj.GetP( j), Tria.GetP( nP))) { + TriaAdj.SetP( j, ptTest) ; + break ; + } + } + } + break ; + } + } + } + break ; + } + } + } + // Se non esiste un triangolo che contiene la proiezione del punto, inverto + if ( ! bPointIn) { + Tria.Set( Tria.GetP( 0), Tria.GetP( 2), Tria.GetP( 1)) ; + vAllTria.emplace_back( Tria) ; + setValidTria.erase( nTria) ; + } + } + } + } + + // Nel vettore dei triangoli nuovi, inserisco tutti i triangoli non scartati + for ( auto Iter = setValidTria.begin() ; Iter != setValidTria.end() ; ++ Iter) { + Triangle3d Tria ; + if ( ! pStm->GetTriangle( *Iter, Tria)) + return false ; + vAllTria.emplace_back( Tria) ; + } + + return true ; +} + +// ---------------------------------------------------------------------------- +// Funzione per classificare i triangoli all'interno di un Box static bool ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTria, double dAngTol, - unordered_set& setAvoidTria, unordered_set& setNewTria) + unordered_set& setAvoidTria, unordered_set& setNewTria, + unordered_map& mapTriaClass) { // Collezione di triangoli già visitati unordered_set setTria ; setTria.reserve( vTBox.size()) ; // Collezioni di triangoli da analizzare INTVECTOR vTria ; vTria.reserve( int( vTBox.size()) + 1) ; vTria.push_back( nFirstTria) ; + // Collezioni di adiacenze da non riguardare + unordered_map mapAdjToAvoid ; mapAdjToAvoid.reserve( int( vTBox.size() + 1)) ; // Finchè ho triangoli da visitare while ( ! vTria.empty()) { @@ -1621,6 +2115,18 @@ ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTri for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { // Recupero l'indice del triangolo corrente int nTriaAdj = nIdAdjTriaId[nAdj] ; + // Se adiacenza da scartare, la salto + auto mapIter = mapAdjToAvoid.find( nCurrTria) ; + if ( mapIter != mapAdjToAvoid.end()) { + bool bSkip = false ; + for ( int nAvoidAdj = 0 ; ! bSkip && nAvoidAdj < ssize( mapIter->second) ; ++ nAvoidAdj) + bSkip = ( mapIter->second[nAvoidAdj] == nAdj) ; + if ( bSkip) { + // Se presente, lo inserisco + vTria.push_back( nTriaAdj) ; + continue ; + } + } // Se non ho adiacenza, non faccio nulla if ( nTriaAdj == SVT_NULL) continue ; @@ -1633,6 +2139,27 @@ ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTri setTria.insert( nTriaAdj) ; // Se la normale è fuori dalla tolleranza if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dAngTol + EPS_ANG_SMALL) * DEGTORAD)) { + // Classifico il triangolo + int nTriaClass = TriaClass::OK ; + if ( ! AnalyzeTriangle( Tria, TriaAdj, dAngTol, nTriaClass)) + return false ; + bool bUnrelTria = ( nTriaClass == TriaClass::FLIPPED || + nTriaClass == TriaClass::CAP) ; + if ( bUnrelTria) { + INTVECTOR vNewTria ; vNewTria.reserve( 2) ; + if ( ! CheckUnrelevantTriangle( Stm, nCurrTria, nTriaAdj, nAdj, dAngTol, mapAdjToAvoid, vNewTria)) + return false ; + // Se triangolo irrilevante, memorizzo tale informazione + if ( ! vNewTria.empty()) { + mapTriaClass[nTriaAdj] = nTriaClass ; + vTria.push_back( nTriaAdj) ; + vTria.push_back( vNewTria[0]) ; + if ( ssize( vNewTria) == 2) + vTria.push_back( vNewTria[1]) ; + continue ; + } + } + // Se tale non è già stato scartato if ( find( setAvoidTria.begin(), setAvoidTria.end(), nTriaAdj) == setAvoidTria.end()) { // Azzero i triangoli correnti e ricomincio l'algoritmo @@ -1640,8 +2167,13 @@ ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTri vTria.clear() ; vTria.push_back( nFirstTria) ; setTria.clear() ; + mapAdjToAvoid.clear() ; + #if DEBUG_FACE_SEARCH + VT.clear() ; VC.clear() ; + #endif break ; } + continue ; } // Inserisco il triangolo per la ricerca futura @@ -1658,7 +2190,7 @@ ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTri VT.emplace_back( Stm.CloneTriangle( *Iter)) ; VC.emplace_back( ORANGE) ; } - //SaveGeoObj( VT, VC, "C:\\Temp\\2.nge") ; + SaveGeoObj( VT, VC, "C:\\Temp\\2.nge") ; #endif return true ; @@ -2366,7 +2898,8 @@ CheckBordersInBox( CurveComposite& CompoA, CurveComposite& CompoB, } unordered_set MysetAvoidTria( setAvoidTria) ; unordered_set MysetNewTria ; - if ( ! ClassifyTriangles( Stm, vTBox, nTria, dAngTol, MysetAvoidTria, MysetNewTria)) + unordered_map MymapTriaClass ; + if ( ! ClassifyTriangles( Stm, vTBox, nTria, dAngTol, MysetAvoidTria, MysetNewTria, MymapTriaClass)) return false ; COMPOVECTOR vCompoChain ; if ( ! GetBordersByTriaInBox( Stm, BBoxCheck, dLinTol, MysetNewTria, vCompoChain, bBreak)) @@ -2409,8 +2942,8 @@ static bool GetBordersInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, int nFirstTria, const Point3d& ptSel, double dSize, double dSizeTol, bool bAbsFirst, bool bRelFirst, double dAngTol, double dLinTol, unordered_set& setAvoidTria, unordered_set& setNewTria, - CurveComposite& CompoA, CurveComposite& CompoB, Point3d& ptMid, Point3d& ptMid1, - int& nTria, int& nTria1, bool& bBreak, bool& bStop) + unordered_map& mapTriaClass, CurveComposite& CompoA, CurveComposite& CompoB, + Point3d& ptMid, Point3d& ptMid1, int& nTria, int& nTria1, bool& bBreak, bool& bStop) { // Controllo dei parametri if ( ! Stm.IsValid()) @@ -2444,12 +2977,12 @@ GetBordersInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, int nFirstTria, IGeoPoint3d* _ptSel = CreateGeoPoint3d() ; _ptSel->Set( ptSel) ; VT.emplace_back( _ptSel) ; VC.emplace_back( RED) ; - //if ( bAbsFirst) - //SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ; + if ( bAbsFirst) + SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ; #endif // Classifico i triangoli - if ( ! ClassifyTriangles( Stm, vTBox, nFirstTria, dAngTol, setAvoidTria, setNewTria)) + if ( ! ClassifyTriangles( Stm, vTBox, nFirstTria, dAngTol, setAvoidTria, setNewTria, mapTriaClass)) return false ; // Recupero solo i bordi validi interni al Box dai triangoli classificati @@ -2595,8 +3128,9 @@ GetBordersInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, int nFirstTria, static bool MarchAlongPath( const BBox3d& BBoxCurr, const SurfTriMesh& Stm, unordered_set& setAvoidTria, unordered_set& setValidTria, - bool bFollowA, const Point3d& ptMid, int nTria, double dSize, double dSizeTol, - double dAngTol, bool& bRelFirst, CurveComposite& CompoA, CurveComposite& CompoB, bool& bStop) + unordered_map& mapTriaClass, bool bFollowA, const Point3d& ptMid, int nTria, + double dSize, double dSizeTol, double dAngTol, bool& bRelFirst, + CurveComposite& CompoA, CurveComposite& CompoB, bool& bStop) { // Variabili di controllo per la ricerca BBox3d BBoxLast = BBoxCurr ; @@ -2621,7 +3155,7 @@ MarchAlongPath( const BBox3d& BBoxCurr, const SurfTriMesh& Stm, Point3d myPtMid, myPtMid1 ; int nMyTria = 0, nMyTria1 = 0 ; if ( ! GetBordersInBox( Stm, MyBBoxCurr, nTriaRef, ptRef, dSize, dSizeTol, false, bRelFirst, - dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB, + dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, mapTriaClass, CompoA, CompoB, myPtMid, myPtMid1, nMyTria, nMyTria1, bBreak, bStop)) return false ; bRelFirst = false ; @@ -3047,8 +3581,8 @@ GetTrimmingFinalBorders( ICRVCOMPOPOVECTOR& vCompoBezierEdges, double dLinTol, d // Funzione per ricavare i bordi a partire da un insieme di superfici; questi vengono // calcolati mediante analisi delle normali lungo il bordo delle Patches di Surfs bool -GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dLinTol, double dAngTol, double dThick, - ICRVCOMPOPOVECTOR& vCompoBezierEdges) +GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dLinTol, + double dAngTol, double dThick, ICRVCOMPOPOVECTOR& vCompoBezierEdges) { // Pulizia dei parametri di ritorno vCompoBezierEdges.clear() ; @@ -3070,7 +3604,7 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou // Controllo sulla tolleranza angolare double dMyAngTol = Clamp( dAngTol, 1., 45.) ; - // Recupero la superficie TriMesh di cui fare l'Offset + // Recupero la superficie TriMesh complessiva [migliorabile] PtrOwner pStm( nullptr) ; if ( int( vpSurf.size()) == 1) { const ISurf* pSurf = vpSurf[0] ; @@ -3086,7 +3620,6 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou } } else { - // [ Soluzione temporanea ] StmFromTriangleSoup mySoup ; mySoup.Start() ; for ( const ISurf* pSurf : vpSurf) { if ( pSurf == nullptr) @@ -3109,108 +3642,40 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou if ( IsNull( pStm) || ! pStm->IsValid() || pStm->IsClosed()) return false ; - // Eseguo l'Offset in negativo della superficie passando per lo ZMap - double dPrec = max( min( dThick / 4., 10. * max( dMyLinTol, EPS_SMALL)), 0.5) ; - PtrOwner pStmOffs( CreateSurfTriMeshesOffset( { pStm}, - dThick, dPrec)) ; - if ( IsNull( pStmOffs) || ! pStmOffs->IsValid()) + // Calcolo il Bordo mediante estrusione + vector> vPLLoopPLExtr ; + if ( ! GetBorderByExtrusion( pStm, dThick, dMyLinTol, dMyAngTol, vPLLoopPLExtr)) return false ; - // Recupero i Loop dalla superficie originaria e i Loop della superficie di Offset - POLYLINEVECTOR vPL, vPLOffs ; - if ( ! pStm->GetLoops( vPL) || ! pStmOffs->GetLoops( vPLOffs)) - return false ; - - #if DEBUG_BORDERS_BY_NORMALS - for ( const ISurf* _pSurf : vpSurf) { - VT.emplace_back( _pSurf->Clone()) ; - VC.emplace_back( LIME) ; - } - VT.emplace_back( pStmOffs->Clone()) ; - VC.emplace_back( ORANGE) ; - SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ; - #endif - - // Trasformo ogni Loop in curva composita - ICRVCOMPOPOVECTOR vCompoLoops ; vCompoLoops.reserve( vPL.size()) ; - for ( const PolyLine& PL : vPL) { - if ( PL.IsClosed()) { - if ( ! vCompoLoops.emplace_back( CreateBasicCurveComposite()) || - ! vCompoLoops.back()->FromPolyLine( PL) || - ! vCompoLoops.back()->IsValid()) - return false ; - } - } - ICRVCOMPOPOVECTOR vCompoOffsLoops ; vCompoOffsLoops.reserve( vPLOffs.size()) ; - for ( const PolyLine& PLOffs : vPLOffs) { - if ( PLOffs.IsClosed()) { - if ( ! vCompoOffsLoops.emplace_back( CreateCurveComposite()) || - ! vCompoOffsLoops.back()->FromPolyLine( PLOffs) || - ! vCompoOffsLoops.back()->IsValid()) - return false ; - } - } - - #if DEBUG_BORDERS_BY_NORMALS - for ( ICurveComposite* pCompo : vCompoLoops) { - VT.emplace_back( pCompo->Clone()) ; - VC.emplace_back( GREEN) ; - } - for ( ICurveComposite* pCompoOffs : vCompoOffsLoops) { - VT.emplace_back( pCompoOffs->Clone()) ; - VC.emplace_back( BLUE) ; - } - SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ; - #endif - - // Per ogni curva della superficie originale cerco la sua associata - BOOLVECTOR vIndMatched( vCompoOffsLoops.size(), false) ; - for ( const ICurveComposite* pCompoLoop : vCompoLoops) { - // sposto il punto iniziale della curva nel tratto più lungo - double dMaxLen = - INFINITO ; - int nIndCrv = 0 ; - for ( int nCrv = 0 ; nCrv < pCompoLoop->GetCurveCount() ; ++ nCrv) { - const ICurve* pCurve = pCompoLoop->GetCurve( nCrv) ; - if ( pCurve != nullptr && pCurve->IsValid()) { - double dCurrLen = 0. ; - pCurve->GetLength( dCurrLen) ; - if ( dCurrLen > dMaxLen) { - dMaxLen = dCurrLen ; - nIndCrv = nCrv ; - } - } - } - Point3d ptRef ; - pCompoLoop->GetPointD1D2( nIndCrv + 0.5, ICurve::FROM_MINUS, ptRef) ; - // dalle altre curve derivanti dalla superficie di Offset cerco quella più vicina al punto inziale - double dMinSqDist = INFINITO ; - int nIndOffsCrv = -1 ; - for ( int nOffsCrv = 0 ; nOffsCrv < int( vCompoOffsLoops.size()) ; ++ nOffsCrv) { - if ( vIndMatched[nOffsCrv]) - continue ; - // recupero la curva e calcolo la distanza - const ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nOffsCrv] ; - int nFlag = 0 ; - Point3d ptCurrMinDist ; - if ( DistPointCurve( ptRef, *pCompoOffsLoop).GetMinDistPoint( 0., ptCurrMinDist, nFlag)) { - double dCurrSqDist = SqDist( ptRef, ptCurrMinDist) ; - if ( dCurrSqDist < dMinSqDist) { - dMinSqDist = dCurrSqDist ; - nIndOffsCrv = nOffsCrv ; - } - } - } - if ( nIndOffsCrv == -1) - return false ; - vIndMatched[ nIndOffsCrv] = true ; - // associo le due curve ( quindi consecutive nel vettore delle curve risultanti) - vCompoBezierEdges.emplace_back( CloneCurveComposite( pCompoLoop)) ; + // Trasformo ogni PolyLine in Curva Composita + for ( int i = 0 ; i < ssize( vPLLoopPLExtr) ; ++ i) { + PolyLine& PLLoop = vPLLoopPLExtr[i].first ; + PtrOwner pCompoLoop( CreateCurveComposite()) ; + if ( IsNull( pCompoLoop) || + ! pCompoLoop->FromPolyLine( PLLoop) || + ! pCompoLoop->MergeCurves( dMyLinTol, dMyAngTol)) + continue ; + PolyLine& PLLoopExtr = vPLLoopPLExtr[i].second ; + PtrOwner pCompoLoopExtr( CreateCurveComposite()) ; + if ( IsNull( pCompoLoopExtr) || + ! pCompoLoopExtr->FromPolyLine( PLLoopExtr) || + ! pCompoLoopExtr->MergeCurves( dMyLinTol, dMyAngTol)) + continue ; + vCompoBezierEdges.emplace_back( Release( pCompoLoop)) ; if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) return false ; - vCompoBezierEdges.emplace_back( CloneCurveComposite( vCompoOffsLoops[nIndOffsCrv])) ; + vCompoBezierEdges.emplace_back( Release( pCompoLoopExtr)) ; if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) return false ; } + // Restituisco le curve orientate correttamente per la creazione della superficie di Bezier + erase_if( vCompoBezierEdges, []( ICurveComposite* pBezierEdge) { + return ( pBezierEdge == nullptr || ! pBezierEdge->IsValid() || pBezierEdge->GetCurveCount() == 0) ; + }) ; + for ( int i = 0 ; i < ssize( vCompoBezierEdges) - 1 ; i += 2) + ManageRuledBorders( vCompoBezierEdges[i], vCompoBezierEdges[i+1]) ; + return true ; } @@ -3248,10 +3713,17 @@ GetTrimmingBezierEdges( ICRVCOMPOPOVECTOR& vCompoRawEdges, double dLinTol, doubl } } + // Restituisco le curve orientate correttamente per la creazione della superficie di Bezier + erase_if( vBezierEdges, []( ICurveComposite* pBezierEdge) { + return ( pBezierEdge == nullptr || ! pBezierEdge->IsValid() || pBezierEdge->GetCurveCount() == 0) ; + }) ; + for ( int i = 0 ; i < ssize( vBezierEdges) - 1 ; i += 2) + ManageRuledBorders( vBezierEdges[i], vBezierEdges[i+1]) ; + #if DEBUG_EDGES VC.clear() ; VT.clear() ; - for ( int _i = 0 ; _i < int( vCompoTmpEdges.size()) ; ++ _i) { - VT.emplace_back( vCompoTmpEdges[_i]->Clone()) ; + for ( int _i = 0 ; _i < int( vBezierEdges.size()) ; ++ _i) { + VT.emplace_back( vBezierEdges[_i]->Clone()) ; VC.emplace_back( ORANGE) ; } SaveGeoObj( VT, VC, "C:\\Temp\\ApproxBorder.nge") ; @@ -3326,9 +3798,11 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, ISurfBezier* GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints, - const INTVECTOR& vIndPriority, const INTVECTOR& vIndVisible) + const INTVECTOR& vnShown, const INTVECTOR& vnEdited, const INTVECTOR& vnNew) { // Verifica validità delle curve per la creazione della Bezier rigata + if ( pCrvEdge1 == nullptr || pCrvEdge2 == nullptr) + return nullptr ; PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) @@ -3343,7 +3817,7 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, VC_Glob.emplace_back( AQUA) ; #endif - // Creo la superficie di Bezier + // Inzializzo la superficie di Bezier PtrOwner pSurfBz( CreateSurfBezier()) ; if ( IsNull( pSurfBz)) return nullptr ; @@ -3358,26 +3832,29 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, } // Se ho punti di controllo forzati else { - // Recupero i tratti lineari di sincronizzazione - ICURVEPOVECTOR vCrv ; vCrv.reserve( vSyncPoints.size()) ; - for ( const BIPOINT& PtSPtE : vSyncPoints) { - PtrOwner pLine( CreateCurveLine()) ; - if ( IsNull( pLine) || ! pLine->Set( PtSPtE.first, PtSPtE.second)) - return nullptr ; - vCrv.emplace_back( Release( pLine)) ; - } #if DEBUG_BEZIER_RULED - for ( int _i = 0 ; _i < int( vCrv.size()) ; ++ _i) { - VT_Glob.emplace_back( vCrv[_i]) ; - VC_Glob.emplace_back( LIME) ; + for ( int i = 0 ; i < ssize( vSyncPoints) ; ++ i) { + const Point3d& ptS = vSyncPoints[i].first ; + const Point3d& ptE = vSyncPoints[i].second ; + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine) || ! pLine->Set( ptS, ptE)) + return nullptr ; + VT_Glob.emplace_back( pLine->Clone()) ; + if ( find( vnShown.begin(), vnShown.end(), i) != vnShown.end()) { + if ( find( vnEdited.begin(), vnEdited.end(), i) != vnEdited.end()) + VC_Glob.emplace_back( GREEN) ; + else if ( find( vnNew.begin(), vnNew.end(), i) != vnNew.end()) + VC_Glob.emplace_back( ORANGE) ; + else + VC_Glob.emplace_back( LIME) ; + } + else + VC_Glob.emplace_back( GRAY) ; } + SaveGeoObj( VT_Glob, VC_Glob, "C:\\Temp\\TestBz.nge") ; #endif // Definisco la superficie - BIPNTVECTOR vGuides ; - INTVECTOR vShown ; - INTVECTOR vEdited ; - INTVECTOR vNew ; - pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vGuides, vShown, vEdited, vNew, dMyLinTol)) ; + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vSyncPoints, vnShown, vnEdited, vnNew, dMyLinTol)) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; return nullptr ; @@ -3386,7 +3863,7 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, #if DEBUG_BEZIER_RULED VT_Glob.emplace_back( pSurfBz->Clone()) ; - VC_Glob.emplace_back( LIME) ; + VC_Glob.emplace_back( BLACK) ; SaveGeoObj( VT_Glob, VC_Glob, "C:\\Temp\\TestBz.nge") ; #endif @@ -3429,8 +3906,12 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, // di ulteriori adiacenze. bool GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const PNTVECTOR& vPts, - double dAngTol, double dSize, double dSizeTol, INTVECTOR& vOtherTria) + double dAngTol, double dSize, double dSizeTol, ISurfTriMesh* pStmAdjTria) { + // La superfcicie deve essere inizializzata + if ( pStmAdjTria == nullptr) + return false ; + // Verifico la validità della superficie TriMesh e l'esistenza di triangoli di riferimento if ( ! pStm->IsValid() || vTria.empty()) return false ; @@ -3453,14 +3934,16 @@ GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const P // Recupero i triangoli validi all'interno del Box e definisco i primi due tratti lineari // per le curve di Bordo bool bBreak = false, bStop = false ; + INTVECTOR vOtherTria ; vOtherTria.reserve( pStmBasic->GetTriangleCount()) ; unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ; unordered_set setValidTria ; setValidTria.reserve( pStmBasic->GetTriangleCount()) ; unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ; + unordered_map mapTriaClass ; mapTriaClass.reserve( pStmBasic->GetTriangleCount()) ; Point3d ptMid, ptMid1 ; int nTria = 0, nTria1 = 0 ; CurveComposite CompoA, CompoB ; if ( ! GetBordersInBox( *pStmBasic, BBoxCurr, vTria[0], vPts[0], dSize, dSizeTol, true, true, - dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB, + dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, mapTriaClass, CompoA, CompoB, ptMid, ptMid1, nTria, nTria1, bBreak, bStop)) return false ; @@ -3472,30 +3955,46 @@ GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const P else if ( bStop) { for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) vOtherTria.push_back( *Iter) ; - return true ; + } + // Altrimenti ricerco gli altri triangoli validi + else { + // I nuovi triangoli della striscia vengono memorizzati + for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) + setValidTria.insert( *Iter) ; + + // Ricerco nella direzione di ptMid1 + bool bRelFirst = true ; + if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, mapTriaClass, true, + ptMid1, nTria1, dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + return false ; + + // Se Non ho ricavato un'intera striscia chiusa, allora avvio la ricerca in direzione di ptMid + if ( ! bStop) { + if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, mapTriaClass, false, + ptMid, nTria, dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + return false ; + } } - // I nuovi triangoli della striscia vengono memorizzati - for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) - setValidTria.insert( *Iter) ; - - // Ricerco nella direzione di ptMid1 - bool bRelFirst = true ; - if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, true, ptMid1, nTria1, - dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + // Aggiusto i Triangoli in base alla loro classificazione ( modificandoli se necessario) + TRIA3DVECTOR vAllTria ; vAllTria.reserve( pStmBasic->GetTriangleCount()) ; + if ( ! AdjustClassifiedTriangles( setValidTria, pStmBasic, mapTriaClass, vAllTria)) return false ; - // Se Non ho ricavato un'intera striscia chiusa, allora avvio la ricerca in direzione di ptMid - if ( ! bStop) { - if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, false, ptMid, nTria, - dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop)) + // Creo la superficie TriMesh dai triangoli ricavati + StmFromTriangleSoup TriaSoup ; + TriaSoup.Start() ; + for ( const Triangle3d& Tria : vAllTria) { + if ( ! TriaSoup.AddTriangle( Tria)) return false ; } + TriaSoup.End() ; + PtrOwner pStmTria( TriaSoup.GetSurf()) ; - // Per ogni triangolo recuperato, cerco le facce a cui appartiene - unordered_set setValidFace ; - for ( auto Iter = setValidTria.begin() ; Iter != setValidTria.end() ; ++ Iter) - vOtherTria.push_back( *Iter) ; + if ( IsNull( pStmTria) || ! pStmTria->IsValid() || pStmTria->GetTriangleCount() == 0) + return false ; + else + return ( pStmAdjTria->CopyFrom( pStmTria)) ; return true ; } @@ -3761,7 +4260,7 @@ GetTrimmingAutoEntities( const CISURFPVECTOR& vSurf, double dShapeLinTol, double if ( ! GetTrimmingBezierEdges( matCompoBordersTmp[i], dLinTol, dAngTol, matCompoBorders.back())) return false ; vSurfBz.emplace_back( GetTrimmingRuledBezier( vSurf, matCompoBorders.back()[0], matCompoBorders.back()[1], - dMyLinTol, BIPNTVECTOR{}, INTVECTOR{}, INTVECTOR{})) ; + dMyLinTol, BIPNTVECTOR{}, INTVECTOR{}, INTVECTOR{}, INTVECTOR{})) ; } return true ; From cdef3931be6d8e6ef249b0252415942398341b1f Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Wed, 21 Jan 2026 10:05:54 +0100 Subject: [PATCH 34/44] EgtGeomKernel : - spostata la funzione GetChainedCurves. --- ChainCurves.cpp | 43 ------------------------------------------- CurveAux.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ CurveAux.h | 1 + 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/ChainCurves.cpp b/ChainCurves.cpp index 531cbd1..280cc27 100644 --- a/ChainCurves.cpp +++ b/ChainCurves.cpp @@ -497,46 +497,3 @@ ChainCurves::GetForkPoint( const Point3d& ptP) return ( find_if( m_vForkData.begin(), m_vForkData.end(), [&]( const ForkData& frkData) { return AreSamePointEpsilon( frkData.ptFork, ptP, m_dToler) ; })) ; } - -//---------------------------------------------------------------------------- -bool -ChainCurves::GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert) -{ - if( ssize( vCrv) == 1) - return true ; - // modifico direttamente le curve passate in input - Init( bAllowInvert, dChainTol, ssize( vCrv)) ; - for ( int c = 0 ; c < ssize( vCrv) ; ++c) { - Point3d ptStart, ptEnd ; - Vector3d vtStart, vtEnd ; - vCrv[c]->GetStartPoint( ptStart) ; - vCrv[c]->GetEndPoint( ptEnd) ; - vCrv[c]->GetStartDir( vtStart) ; - vCrv[c]->GetEndDir( vtEnd) ; - AddCurve( 1 + c, ptStart, vtStart, ptEnd, vtEnd) ; - } - INTVECTOR vIds ; - Point3d ptStart = ORIG ; - while ( GetChainFromNear( ptStart, false, vIds)) { - ICurveComposite* pFirstCrv = vCrv[abs(vIds[0]) - 1] ; - for ( int nId : vIds) { - bool bInvert = false ; - if( nId < 0) - bInvert = true ; - nId = abs( nId) - 1 ; - if( bInvert) - vCrv[nId]->Invert() ; - if( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol)) - return false ; - } - pFirstCrv->GetEndPoint( ptStart) ; - } - // elimino gli elementi del vettore che non contengono più curve - int c = ssize( vCrv) ; - while( c > -1) { - if( IsNull( vCrv[c])) - vCrv.erase( vCrv.begin() + c) ; - --c ; - } - return true ; -} diff --git a/CurveAux.cpp b/CurveAux.cpp index d75372b..5f4c1c3 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -26,6 +26,7 @@ #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EGkCurveByInterp.h" +#include "/EgtDev/Include/EGkChainCurves.h" #define EIGEN_NO_IO #include "/EgtDev/Extern/Eigen/Dense" @@ -2326,3 +2327,47 @@ ResetCurveVoronoi( const ICurve& crvC) break ; } } + +//---------------------------------------------------------------------------- +bool +GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert) +{ + if( ssize( vCrv) == 1) + return true ; + ChainCurves chainCrv ; + // modifico direttamente le curve passate in input + chainCrv.Init( bAllowInvert, dChainTol, ssize( vCrv)) ; + for ( int c = 0 ; c < ssize( vCrv) ; ++c) { + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + vCrv[c]->GetStartPoint( ptStart) ; + vCrv[c]->GetEndPoint( ptEnd) ; + vCrv[c]->GetStartDir( vtStart) ; + vCrv[c]->GetEndDir( vtEnd) ; + chainCrv.AddCurve( 1 + c, ptStart, vtStart, ptEnd, vtEnd) ; + } + INTVECTOR vIds ; + Point3d ptStart = ORIG ; + while ( chainCrv.GetChainFromNear( ptStart, false, vIds)) { + ICurveComposite* pFirstCrv = vCrv[abs(vIds[0]) - 1] ; + for ( int nId : vIds) { + bool bInvert = false ; + if( nId < 0) + bInvert = true ; + nId = abs( nId) - 1 ; + if( bInvert) + vCrv[nId]->Invert() ; + if( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol)) + return false ; + } + pFirstCrv->GetEndPoint( ptStart) ; + } + // elimino gli elementi del vettore che non contengono più curve + int c = ssize( vCrv) ; + while( c > -1) { + if( IsNull( vCrv[c])) + vCrv.erase( vCrv.begin() + c) ; + --c ; + } + return true ; +} \ No newline at end of file diff --git a/CurveAux.h b/CurveAux.h index 4b2cf62..58bfae4 100644 --- a/CurveAux.h +++ b/CurveAux.h @@ -35,3 +35,4 @@ bool CopyExtrusion( const ICurve* pSouCrv, ICurve* pDestCrv) ; bool CopyThickness( const ICurve* pSouCrv, ICurve* pDestCrv) ; ICurveBezier* ApproxCurveBezierWithSingleCubic( const ICurve* pCrv) ; Voronoi* GetCurveVoronoi( const ICurve& crvC) ; +bool GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert) ; From a7b36280f3fc2b865820bfd8469ab3300d2e00c1 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 21 Jan 2026 18:27:28 +0100 Subject: [PATCH 35/44] EgtGeomKernel : - in Trimming semplificazione delle funzioni per le curve di sincronizzazione. --- Trimming.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Trimming.cpp b/Trimming.cpp index 3665d6f..7745054 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -37,6 +37,7 @@ #include "/EgtDev/Include/EgtNumUtils.h" #include #include +#include // -------------------------- Debug -------------------------------------------- #define DEBUG 0 @@ -3797,8 +3798,7 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, // alla superficie nei pressi dei tratti lineari di sincronizzazione prioritari ISurfBezier* GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, - const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints, - const INTVECTOR& vnShown, const INTVECTOR& vnEdited, const INTVECTOR& vnNew) + const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints) { // Verifica validità delle curve per la creazione della Bezier rigata if ( pCrvEdge1 == nullptr || pCrvEdge2 == nullptr) @@ -3854,7 +3854,9 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, SaveGeoObj( VT_Glob, VC_Glob, "C:\\Temp\\TestBz.nge") ; #endif // Definisco la superficie - pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vSyncPoints, vnShown, vnEdited, vnNew, dMyLinTol)) ; + INTVECTOR vInd( ssize( vSyncPoints)) ; iota( vInd.begin(), vInd.end(), 0) ; + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vSyncPoints, vInd, + INTVECTOR{}, INTVECTOR{}, dMyLinTol)) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; return nullptr ; @@ -4260,7 +4262,7 @@ GetTrimmingAutoEntities( const CISURFPVECTOR& vSurf, double dShapeLinTol, double if ( ! GetTrimmingBezierEdges( matCompoBordersTmp[i], dLinTol, dAngTol, matCompoBorders.back())) return false ; vSurfBz.emplace_back( GetTrimmingRuledBezier( vSurf, matCompoBorders.back()[0], matCompoBorders.back()[1], - dMyLinTol, BIPNTVECTOR{}, INTVECTOR{}, INTVECTOR{}, INTVECTOR{})) ; + dMyLinTol, BIPNTVECTOR{})) ; } return true ; From 42fcb1847bca4340cf9cd283d095a6d5276cd86e Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 22 Jan 2026 11:23:58 +0100 Subject: [PATCH 36/44] EgtGeomKernel : - GetSurfBezierRuledGuided. --- SbzFromCurves.cpp | 5 ++-- SurfBezier.cpp | 66 ++++++++++------------------------------------- SurfBezier.h | 2 +- Trimming.cpp | 3 +-- 4 files changed, 18 insertions(+), 58 deletions(-) diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp index 0fa537b..af0d46e 100644 --- a/SbzFromCurves.cpp +++ b/SbzFromCurves.cpp @@ -735,8 +735,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou //------------------------------------------------------------------------------- ISurfBezier* -GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const BIPNTVECTOR& vCrv, - const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew, double dLinTol) +GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const BIPNTVECTOR& vCrv, double dLinTol) { // verifica parametri if ( pCurve1 == nullptr || pCurve2 == nullptr) @@ -763,7 +762,7 @@ GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const BI // creo e setto la superficie trimesh PtrOwner pSbz( CreateBasicSurfBezier()) ; - if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv, vShown, vEdited, vNew)) + if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv)) return nullptr ; // restituisco la superficie diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 65982c5..7b6cd02 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -5653,10 +5653,8 @@ struct IsoParam { int nCrv ; double dParam0 ; double dParam1 ; - bool bNew ; // new or edited - bool bShown ; - IsoParam( int _nCrv, double _dParam0, double _dParam1, bool _bNew = false, bool _bShown = false) : - nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1), bNew( _bNew), bShown( _bShown){ } ; + IsoParam( int _nCrv, double _dParam0, double _dParam1) : + nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1){ } ; bool operator < ( IsoParam& b) { return ( abs(dParam0 - b.dParam0) > EPS_SMALL ? dParam0 < b.dParam0 : dParam1 < b.dParam1) ; @@ -5667,12 +5665,13 @@ typedef vector ISOPARVECT ; //---------------------------------------------------------------------------- bool -SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv, const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew) +SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv) { - // vCrv è il vettore delle isocurve (nel parametro V) di una surf ( creata come rigata) che si vuole modificare ( già ordinato) - // vNewCrv è il vettore delle isocurve mostrate durante l'editing, che comprende le curve editate e le curve nuove - // vShown indica gli indici delle curve in vCrv che sono mostrate in vCrv - // vNewOrEdited indica la coppia di indici (nId1, nId2) (in vCrv, in vNewCrv) per le curve editate e una coppia (-1, nId) per le curve aggiunte + // vCrv è il vettore delle isocurve (nel parametro V) che si vogliono forzare per la creazione della rigata tra Curve0 e Curve1 + + //controllo che siano entrambe chiuse o entrambe aperte + if( pCurve0->IsClosed() ^ pCurve1->IsClosed()) + return false ; // converto in bezier la curva iniziale CurveComposite CrvU0 ; CrvU0.AddCurve( CurveToBezierCurve(pCurve0)) ; @@ -5711,63 +5710,24 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c // costruisco il vettore delle nuove curve isoparamtriche per la nuova superficie ISOPARVECT vIso ; - int nNewCounter = 0 ; - int nShowCounter = 0 ; - int nEditCounter = 0 ; for ( int i = 0 ; i < ssize( vCrv) ; ++i) { Point3d ptU0 = vCrv[i].first ; Point3d ptU1 = vCrv[i].second ; double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; - if ( nEditCounter < ssize( vEdited) && i == vEdited[nEditCounter]) { - vIso.emplace_back( i, dParam0, dParam1, true, true) ; - ++ nEditCounter ; - ++ nShowCounter ; - } - else if ( nNewCounter < ssize( vNew) && i == vNew[nNewCounter]) { - vIso.emplace_back( i, dParam0, dParam1, true) ; - ++ nNewCounter ; - } - else if ( nShowCounter < ssize( vShown) && i == vShown[nShowCounter]) { - vIso.emplace_back( i, dParam0, dParam1, false, true) ; - ++ nShowCounter ; - } - else - vIso.emplace_back( i, dParam0, dParam1) ; + vIso.emplace_back( i, dParam0, dParam1) ; } sort( vIso.begin(), vIso.end()) ; - // scorro vIso per eliminare le isocurve non più necessarie + // scorro vIso per verificare che non ci siano curve che si intersecano int c = 0 ; dLastParam0 = vIso[c].dParam0 ; dLastParam1 = vIso[c].dParam1 ; ++c ; while ( c < ssize( vIso)) { - if ( vIso[c].dParam1 >= dLastParam1 && ! vIso[c].bNew) - ; // non devo fare nulla - else { - dLastParam0 = vIso[c].dParam0 ; - dLastParam1 = vIso[c].dParam1 ; - // cancello tutte le curve avanti e indietro finché incontro una show che non viene intersecata - int c_temp = c + 1 ; - while ( c_temp < ssize( vIso) && ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 >= dLastParam0 && vIso[c_temp].dParam1 >= dLastParam1)) { - if ( vIso[c_temp].bNew) - ++c_temp ; - else - vIso.erase(vIso.begin() + c_temp) ; - } - c_temp = c - 1 ; - while ( c_temp > 0 && ! ( vIso[c_temp].bShown && vIso[c_temp].dParam0 <= dLastParam0 && vIso[c_temp].dParam1 <= dLastParam1)) { - if ( vIso[c_temp].bNew) - --c_temp ; - else { - vIso.erase(vIso.begin() + c_temp) ; - --c_temp ; - --c ; - } - } - } + if ( vIso[c].dParam0 < dLastParam0 || vIso[c].dParam1 < dLastParam1) + return false ; dLastParam0 = vIso[c].dParam0 ; dLastParam1 = vIso[c].dParam1 ; ++c ; @@ -5775,6 +5735,8 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c dLastParam0 = 0 ; dLastParam1 = 0 ; + if( vIso[0].dParam0 > 0 || vIso[0].dParam1 > 1) + vPairs.emplace_back( 0, 0) ; for ( int i = 0 ; i < ssize( vIso) ; ++i) { const BIPOINT& pCrv = vCrv[vIso[i].nCrv] ; Point3d ptU0 = pCrv.first ; diff --git a/SurfBezier.h b/SurfBezier.h index 32e7d97..80c4286 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -150,7 +150,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3) override ; PNTVECTOR GetAllControlPoints( void) const ; bool GetAllPatchesIsocurves( bool bUorV, ICURVEPOVECTOR& vCrv) const ; - bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv, const INTVECTOR& vShown, const INTVECTOR& vEdited, const INTVECTOR& vNew) ; + bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv) ; bool RemoveCollapsedSpans() override ; bool SwapParameters() ; diff --git a/Trimming.cpp b/Trimming.cpp index 7745054..252353d 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -3855,8 +3855,7 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, #endif // Definisco la superficie INTVECTOR vInd( ssize( vSyncPoints)) ; iota( vInd.begin(), vInd.end(), 0) ; - pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vSyncPoints, vInd, - INTVECTOR{}, INTVECTOR{}, dMyLinTol)) ; + pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vSyncPoints, dMyLinTol)) ; if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ; return nullptr ; From f72c949563e4e42a1e4f448385255db1b85f6081 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Fri, 23 Jan 2026 10:18:30 +0100 Subject: [PATCH 37/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20In=20TestSurfTmSu?= =?UTF-8?q?rfTm=20aggiunto=20flag=20per=20segnalare=20collisione=20anche?= =?UTF-8?q?=20quando=20una=20delle=20due=20=C3=A8=20chiusa=20e=20contiene?= =?UTF-8?q?=20l'altra.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CDeClosedSurfTmClosedSurfTm.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/CDeClosedSurfTmClosedSurfTm.cpp b/CDeClosedSurfTmClosedSurfTm.cpp index dad76de..36918e7 100644 --- a/CDeClosedSurfTmClosedSurfTm.cpp +++ b/CDeClosedSurfTmClosedSurfTm.cpp @@ -1,12 +1,13 @@ //---------------------------------------------------------------------------- -// EgalTech 2020-2024 +// EgalTech 2020-2026 //---------------------------------------------------------------------------- -// File : CDeClosedSurfTmClosedSurfTm.h Data : 24.03.24 Versione : 2.6c2 +// File : CDeClosedSurfTmClosedSurfTm.h Data : 23.01.26 Versione : 3.1a3 // Contenuto : Implementazione funzione verifica collisione tra // SurfTm e SurfTm. // // Modifiche : 13.11.20 LM Creazione modulo. // 24.03.24 DS Aggiunta TestSurfTmSurfTm. +// 23.01.26 DS In TestSurfTmSurfTm aggiunto flag per collisione quando una delle due è chiusa e contiene l'altra. // //---------------------------------------------------------------------------- @@ -127,7 +128,7 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf // Verifica l'interferenza tra le due superfici : restituisce true in caso di interferenza. //---------------------------------------------------------------------------- bool -TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double dSafeDist) +TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double dSafeDist, bool bTestEnclosion) { // Recupero le superfici base const SurfTriMesh* pSrfA = GetBasicSurfTriMesh( &SurfA) ; @@ -205,6 +206,25 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d pSrfB->SetTempInt( nTB, 1) ; } } + // Se non richiesto test di inclusione, non c'è interferenza + if ( ! bTestEnclosion) + return false ; + // Se la prima superficie è chiusa, verifico se include totalmente la seconda + if ( pSrfA->IsClosed() && b3BoxA.Encloses( b3BoxB)) { + Point3d ptPointB ; + pSrfB->GetFirstVertex( ptPointB) ; + DistPointSurfTm DistPoinBSrfA( ptPointB, *pSrfA) ; + if ( DistPoinBSrfA.IsPointInside()) + return true ; + } + // Se la seconda superficie è chiusa, verifico se include totalmente la prima + if ( pSrfB->IsClosed() && b3BoxB.Encloses( b3BoxA)) { + Point3d ptPointA ; + pSrfA->GetFirstVertex( ptPointA) ; + DistPointSurfTm DistPoinASrfB( ptPointA, *pSrfB) ; + if ( DistPoinASrfB.IsPointInside()) + return true ; + } // Non c'è interferenza return false ; } From c2a79b26655b7075b113ca12237970194482da2a Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 23 Jan 2026 12:38:16 +0100 Subject: [PATCH 38/44] =?UTF-8?q?EgtGeomKernel=20:=20-=20InTestSurfTmSurfT?= =?UTF-8?q?m=20affinato=20il=20controllo=20collisione=20quando=20una=20del?= =?UTF-8?q?le=20due=20superfici=20=C3=A8=20chiusa=20e=20contiene=20l'altra?= =?UTF-8?q?.=20In=20CalcPocketing=20aggiunta=20piccola=20miglioria.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CDeClosedSurfTmClosedSurfTm.cpp | 46 ++++++++++++++++----------------- CalcPocketing.cpp | 6 +++++ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/CDeClosedSurfTmClosedSurfTm.cpp b/CDeClosedSurfTmClosedSurfTm.cpp index 36918e7..c7ca9ac 100644 --- a/CDeClosedSurfTmClosedSurfTm.cpp +++ b/CDeClosedSurfTmClosedSurfTm.cpp @@ -7,7 +7,7 @@ // // Modifiche : 13.11.20 LM Creazione modulo. // 24.03.24 DS Aggiunta TestSurfTmSurfTm. -// 23.01.26 DS In TestSurfTmSurfTm aggiunto flag per collisione quando una delle due è chiusa e contiene l'altra. +// 23.01.26 DS In TestSurfTmSurfTm aggiunto flag per collisione quando una delle due è chiusa e contiene l'altra. // //---------------------------------------------------------------------------- @@ -46,10 +46,10 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf BBox3d b3BoxA, b3BoxB ; pSrfA->GetLocalBBox( b3BoxA) ; pSrfB->GetLocalBBox( b3BoxB) ; - // Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza. + // Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza. if ( dSafeDist > EPS_SMALL) b3BoxB.Expand( dSafeDist) ; - // Se i box non si sovrappongono, non c'è collisione. Ho finito. + // Se i box non si sovrappongono, non c'è collisione. Ho finito. if ( ! b3BoxA.Overlaps( b3BoxB)) return false ; // Recupero i triangoli di A che interferiscono col box di B @@ -62,13 +62,13 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf continue ; BBox3d b3BoxTriaA ; trTriaA.GetLocalBBox( b3BoxTriaA) ; - // Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza. + // Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza. if ( dSafeDist > EPS_SMALL) b3BoxTriaA.Expand( dSafeDist) ; // Recupero i triangoli di B che interferiscono col box del triangolo di A INTVECTOR vNearTria ; pSrfB->GetAllTriaOverlapBox( b3BoxTriaA, vNearTria) ; - // Settare tutti i triangoli come già processati. + // Settare tutti i triangoli come già processati. // Al termine della chiamata i TempInt dei triangoli valgono 0. pSrfB->ResetTempInts() ; // Ciclo sui triangoli della superficie B che cadono nel box del triangolo corrente della Superficie A. @@ -85,14 +85,14 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf // Ciclo sui vertici del triangolo. for ( int nVB = 0 ; nVB < 3 ; ++ nVB) { // Se il triangolo adiacente al triangolo corrente su questo edge - // non è stato processato, processo il vertice e l'edge. + // non è stato processato, processo il vertice e l'edge. int nAdjTriaTempFlag ; if ( ! ( pSrfB->GetTempInt( nAdjTriaId[nVB], nAdjTriaTempFlag) || nAdjTriaTempFlag == 0)) continue ; - // Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito. + // Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito. if ( CDeSimpleSpheTria( trTriaB.GetP( nVB), dSafeDist, trTriaA)) return true ; - // Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito. + // Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito. Vector3d vtEdgeV = trTriaB.GetP( ( nVB + 1) % 3) - trTriaB.GetP( nVB) ; double dEdgeLen = vtEdgeV.Len() ; vtEdgeV /= dEdgeLen ; @@ -112,10 +112,10 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf } } // Non ho trovato collisioni fra triangoli delle superfici. - // Se il BBox della prima superficie non è interno a quello della seconda e viceversa, non c'è collisione + // Se il BBox della prima superficie non è interno a quello della seconda e viceversa, non c'è collisione if ( ! b3BoxA.Encloses( b3BoxB) && ! b3BoxB.Encloses( b3BoxA)) return false ; - // La collisione c'è se una superficie è dentro l'altra. + // La collisione c'è se una superficie è dentro l'altra. Point3d ptPointA, ptPointB ; pSrfA->GetFirstVertex( ptPointA) ; pSrfB->GetFirstVertex( ptPointB) ; @@ -141,10 +141,10 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d BBox3d b3BoxA, b3BoxB ; pSrfA->GetLocalBBox( b3BoxA) ; pSrfB->GetLocalBBox( b3BoxB) ; - // Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza. + // Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza. if ( dSafeDist > EPS_SMALL) b3BoxB.Expand( dSafeDist) ; - // Se i box non si sovrappongono, non c'è collisione. Ho finito. + // Se i box non si sovrappongono, non c'è collisione. Ho finito. if ( ! b3BoxA.Overlaps( b3BoxB)) return false ; // Recupero i triangoli di A che interferiscono col box di B @@ -157,13 +157,13 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d continue ; BBox3d b3BoxTriaA ; trTriaA.GetLocalBBox( b3BoxTriaA) ; - // Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza. + // Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza. if ( dSafeDist > EPS_SMALL) b3BoxTriaA.Expand( dSafeDist) ; // Recupero i triangoli di B che interferiscono col box del triangolo di A INTVECTOR vNearTria ; pSrfB->GetAllTriaOverlapBox( b3BoxTriaA, vNearTria) ; - // Settare tutti i triangoli come già processati. + // Settare tutti i triangoli come già processati. // Al termine della chiamata i TempInt dei triangoli valgono 0. pSrfB->ResetTempInts() ; // Ciclo sui triangoli della superficie B che cadono nel box del triangolo corrente della Superficie A. @@ -180,14 +180,14 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d // Ciclo sui vertici del triangolo. for ( int nVB = 0 ; nVB < 3 ; ++ nVB) { // Se il triangolo adiacente al triangolo corrente su questo edge - // non è stato processato, processo il vertice e l'edge. + // non è stato processato, processo il vertice e l'edge. int nAdjTriaTempFlag ; if ( ! ( pSrfB->GetTempInt( nAdjTriaId[nVB], nAdjTriaTempFlag) || nAdjTriaTempFlag == 0)) continue ; - // Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito. + // Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito. if ( CDeSimpleSpheTria( trTriaB.GetP( nVB), dSafeDist, trTriaA)) return true ; - // Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito. + // Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito. Vector3d vtEdgeV = trTriaB.GetP( ( nVB + 1) % 3) - trTriaB.GetP( nVB) ; double dEdgeLen = vtEdgeV.Len() ; vtEdgeV /= dEdgeLen ; @@ -206,25 +206,25 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d pSrfB->SetTempInt( nTB, 1) ; } } - // Se non richiesto test di inclusione, non c'è interferenza + // Se non richiesto test di inclusione, non c'è interferenza if ( ! bTestEnclosion) return false ; - // Se la prima superficie è chiusa, verifico se include totalmente la seconda + // Se la prima superficie è chiusa, verifico se include totalmente la seconda if ( pSrfA->IsClosed() && b3BoxA.Encloses( b3BoxB)) { Point3d ptPointB ; pSrfB->GetFirstVertex( ptPointB) ; DistPointSurfTm DistPoinBSrfA( ptPointB, *pSrfA) ; - if ( DistPoinBSrfA.IsPointInside()) + if ( DistPoinBSrfA.IsPointInside() || DistPoinBSrfA.IsEpsilon( dSafeDist)) return true ; } - // Se la seconda superficie è chiusa, verifico se include totalmente la prima + // Se la seconda superficie è chiusa, verifico se include totalmente la prima if ( pSrfB->IsClosed() && b3BoxB.Encloses( b3BoxA)) { Point3d ptPointA ; pSrfA->GetFirstVertex( ptPointA) ; DistPointSurfTm DistPoinASrfB( ptPointA, *pSrfB) ; - if ( DistPoinASrfB.IsPointInside()) + if ( DistPoinASrfB.IsPointInside() || DistPoinASrfB.IsEpsilon( dSafeDist)) return true ; } - // Non c'è interferenza + // Non c'è interferenza return false ; } diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 80033b3..36cb139 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -6053,6 +6053,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // ricavo le regioni progressive double dOffsPrec = 0. ; int nCrvFirstOffs = 0 ; + bool bLastNotValid = false ; while ( nIter < MAX_ITER) { // Offset della regione attuale PtrOwner pSfrOffsVR( pSrfAct->CreateOffsetSurf( - dOffs, ICurve::OFF_FILLET)) ; @@ -6063,6 +6064,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co pSfrOffsVR.Set( pSrfAct->CreateOffsetSurf( - dOffs + 5 * EPS_SMALL, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffsVR)) return false ; + bLastNotValid = true ; } // se primo Offset @@ -6094,6 +6096,10 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co bool bInsert = true ; if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert)) return false ; + // per evitare di allacciare una curva di regione non svuotata alla prima curva di Offset + // ( quindi avere un entrata nel pieno del grezzo) controllo di non eliminare il secondo Offset + if ( ! bInsert && nChunks == 1 && bLastNotValid) + bInsert = true ; if ( bInsert) { // imposto come secondo TempParam il Side di classificazione pCrvCompoBorder->SetTempParam( j == 0 ? MDS_RIGHT : MDS_LEFT, 1) ; From 552ce702313ddad1a8ff65c46071aa93c1b8cbf7 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 23 Jan 2026 17:57:18 +0100 Subject: [PATCH 39/44] EgtGeomKernel : - in Trimming introdotta una prima approssimazione delle curve di bordo. --- Trimming.cpp | 140 +++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/Trimming.cpp b/Trimming.cpp index 252353d..ea7dd6a 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -292,88 +292,78 @@ GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL) // Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante // Patches di curve di Bezier static bool -ApproxCurveWithBezier( ICurveComposite* pCrvCompo, double dLinTol, double dAngTol) +ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) { // Controllo dei parametri - if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) + if ( ! CrvCompo.IsValid()) return false ; - // Recupero la PolyLine associata ( senza alcuna approssimazione) - PolyLine myPL ; - if ( ! pCrvCompo->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL)) - return false ; - - // Approssimo la curva mediante Set di punti considerando la tolleranza angolare - POLYLINEVECTOR vPL ; - if ( ! GetPointSetByAngTol( myPL, dAngTol, vPL)) - return false ; #if DEBUG_BEZIER_INTERP - VT.clear() ; VC.clear() ; - VT.emplace_back( pCrvCompo->Clone()) ; + VT.emplace_back( CrvCompo.Clone()) ; VC.emplace_back( RED) ; - for ( PolyLine& PL : vPL) { - if ( PL.GetPointNbr() > 1) { - Point3d ptCurr ; PL.GetFirstPoint( ptCurr) ; - IGeoPoint3d* pt = CreateGeoPoint3d() ; - pt->Set( ptCurr) ; - VT.emplace_back( pt) ; - VC.emplace_back( AQUA) ; - PL.GetLastPoint( ptCurr) ; - pt->Set( ptCurr) ; - VT.emplace_back( pt) ; - VC.emplace_back( AQUA) ; - } - } - SaveGeoObj( VT, VC, "C:\\Temp\\AngBorderApprox.nge") ; - VT.clear() ; VC.clear() ; + SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; #endif - // Pulisco la curva originale - pCrvCompo->Clear() ; + // Dalla Curva Grezza, analizzo i suoi estremi e calcolo le Patch + PolyLine PL ; + if ( ! CrvCompo.ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PL)) + return false ; + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( PL, dAngTol, vPL)) + return false ; - // Ogni PolyLine ricavata viene approssimata con un tratto di Bezier - const double MAXLEN = 1.5 ; - for ( const PolyLine& PL : vPL) { - // Se meno di due punti, non la considero ( non dovrebbe mai capitare ) - if ( PL.GetPointNbr() < 2) - continue ; - // Recupero i punti - PNTVECTOR vPoints ; - Point3d ptCurr ; - bool bFound = PL.GetFirstPoint( ptCurr) ; - while ( bFound) { - vPoints.emplace_back( ptCurr) ; - bFound = PL.GetNextPoint( ptCurr) ; + #if DEBUG_BEZIER_INTERP + vector vColor ; vColor.reserve( vPL.size()) ; + for ( const PolyLine& PL : vPL) { + CurveComposite CCTemp ; CCTemp.FromPolyLine( PL) ; + VT.emplace_back( CCTemp.Clone()) ; + vColor.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ; + VC.emplace_back( vColor.back()) ; } + int nIndCol = -1 ; + SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; + #endif + + // Approssimo le Patch mediante Archi + CurveComposite CCApprox ; + for ( const PolyLine& PL : vPL) { + // Recupero la Patch Grezza + CurveComposite CCPatch ; CCPatch.FromPolyLine( PL) ; + // Creo la Patch Approssimata con Archi + PolyArc PA ; + CCPatch.ApproxWithArcs( dLinTol, dAngTol, PA) ; + CurveComposite CCPatchApprox ; CCPatchApprox.FromPolyArc( PA) ; + // Rimozione delle Imperfezioni + CCPatchApprox.RemoveSmallDefects( dLinTol, dAngTol) ; + // Merge complessivo + CCPatchApprox.MergeCurves( dLinTol, dAngTol) ; #if DEBUG_BEZIER_INTERP - Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; - for ( int i = 0 ; i < int( vPoints.size()) ; ++ i) { - IGeoPoint3d* pt = CreateGeoPoint3d() ; - pt->Set( vPoints[i]) ; - VT.emplace_back( pt) ; - VC.emplace_back( myCol) ; - } + VT.emplace_back( CCPatchApprox.Clone()) ; + VC.emplace_back( vColor[ ++ nIndCol]) ; #endif - // Approssimo con una Bezier - PtrOwner pCrvBz( InterpolatePointSetWithBezier( vPoints, dLinTol, MAXLEN)) ; - if ( IsNull( pCrvBz) || ! pCrvBz->IsValid()) { + // Approssimo tale curva con una Bezier + PtrOwner pCrvPatchBZ( ApproxCurveWithBezier( &CCPatchApprox, dLinTol, 123456)) ; + if ( IsNull( pCrvPatchBZ) || ! pCrvPatchBZ->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error : Interpolating points to bezier curve failed") ; return false ; } #if DEBUG_BEZIER_INTERP - VT.emplace_back( pCrvBz->Clone()) ; - myCol.Set( myCol.GetRed() * .95, myCol.GetGreen() * .95, myCol.GetBlue() * .95) ; - VC.emplace_back( myCol) ; + VT.emplace_back( pCrvPatchBZ->Clone()) ; + VC.emplace_back( vColor[nIndCol]) ; #endif - // Aggiungo il tratto approssimato alla curva finale complessiva - if ( ! pCrvCompo->AddCurve( Release( pCrvBz))) + // Aggiungo alla Curva complessiva Approssimata + if ( ! CCApprox.AddCurve( Release( pCrvPatchBZ))) return false ; } #if DEBUG_BEZIER_INTERP - SaveGeoObj( VT, VC, "C:\\Temp\\InterpolationCurveBezier.nge") ; + VT.emplace_back( CCApprox.Clone()) ; + VC.emplace_back( RED) ; + SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; #endif + if ( CCApprox.IsValid()) + CrvCompo.CopyFrom( CCApprox.Clone()) ; - return ( pCrvCompo->IsValid()) ; + return true ; } //----------------------------------------------------------------------------- @@ -3652,21 +3642,17 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou for ( int i = 0 ; i < ssize( vPLLoopPLExtr) ; ++ i) { PolyLine& PLLoop = vPLLoopPLExtr[i].first ; PtrOwner pCompoLoop( CreateCurveComposite()) ; - if ( IsNull( pCompoLoop) || - ! pCompoLoop->FromPolyLine( PLLoop) || - ! pCompoLoop->MergeCurves( dMyLinTol, dMyAngTol)) + if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( PLLoop)) continue ; PolyLine& PLLoopExtr = vPLLoopPLExtr[i].second ; PtrOwner pCompoLoopExtr( CreateCurveComposite()) ; - if ( IsNull( pCompoLoopExtr) || - ! pCompoLoopExtr->FromPolyLine( PLLoopExtr) || - ! pCompoLoopExtr->MergeCurves( dMyLinTol, dMyAngTol)) + if ( IsNull( pCompoLoopExtr) || ! pCompoLoopExtr->FromPolyLine( PLLoopExtr)) continue ; vCompoBezierEdges.emplace_back( Release( pCompoLoop)) ; - if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + if ( ! ApproxBorder( *vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) return false ; vCompoBezierEdges.emplace_back( Release( pCompoLoopExtr)) ; - if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + if ( ! ApproxBorder( *vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) return false ; } @@ -3706,8 +3692,8 @@ GetTrimmingBezierEdges( ICRVCOMPOPOVECTOR& vCompoRawEdges, double dLinTol, doubl vBezierEdges.reserve( vCompoRawEdges.size()) ; for ( int i = 0 ; i < int( vCompoRawEdges.size()) ; ++ i) { PtrOwner pCompoTmp( CloneCurveComposite( vCompoRawEdges[i])) ; - if ( IsNull( pCompoTmp) || - ! ApproxCurveWithBezier( pCompoTmp, dMyLinTol, dMyAngTol) || + if ( IsNull( pCompoTmp) || + ! ApproxBorder( *pCompoTmp, dMyLinTol, dMyAngTol) || ! vBezierEdges.emplace_back( Release( pCompoTmp))) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Approxing edge failed") ; return false ; @@ -3801,12 +3787,22 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints) { // Verifica validità delle curve per la creazione della Bezier rigata - if ( pCrvEdge1 == nullptr || pCrvEdge2 == nullptr) + if ( pCrvEdge1 == nullptr || pCrvEdge2 == nullptr || + ! pCrvEdge1->IsValid() || ! pCrvEdge2->IsValid()) return nullptr ; + // Se una chiusa e una aperta, errore + if ( pCrvEdge1->IsClosed() != pCrvEdge2->IsClosed()) + return nullptr ; + PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; - if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) + if ( IsNull( pCompoEdge1) || IsNull( pCompoEdge2)) return nullptr ; + // Se entrambe aperte potrei doverle invertire, altrimenti non le modifico + if ( ! pCrvEdge1->IsClosed() && ! pCrvEdge2->IsClosed()) { + if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) + return nullptr ; + } // Controllo sulla tolleranza lineare double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; From 3178bb5f27eab5b147b76feb96a07d34bb891585 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 26 Jan 2026 12:34:32 +0100 Subject: [PATCH 40/44] EgtGeomKernel : - miglioramento della Bezier ruled - miglioramento della Nezier ruled guided. --- SurfBezier.cpp | 271 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 260 insertions(+), 11 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 7b6cd02..138a4d8 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -46,7 +46,9 @@ #define SAVEFAILEDTRIANGULATION 0 #define SAVEISO 0 -#if SAVEFAILEDTRIANGULATION || SAVEISO +#define SAVERULEDISO 1 +#define SAVERULEDGUIDEDISO 1 +#if SAVEFAILEDTRIANGULATION || SAVEISO || SAVERULEDISO || SAVERULEDGUIDEDISO #include "/EgtDev/Include/EGkGeoObjSave.h" #endif @@ -5058,8 +5060,8 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int bool bAdvance0 = dParam0 < j + 1 + EPS_SMALL ; bool bAdvance1 = dParam1 < c + 1 + EPS_SMALL ; // controllo se ho un match biunivoco - bool bPerfectMatch = dParam0 - int( dParam0) < EPS_SMALL && int( dParam0) == j + 1 && - dParam1 - int( dParam1) < EPS_SMALL && int( dParam1) == c + 1 ; + bool bPerfectMatch = abs( dParam0 - round( dParam0)) < EPS_SMALL && round( dParam0) == j + 1 && + abs( dParam1 - round( dParam1)) < EPS_SMALL && round( dParam1) == c + 1 ; int nSplit1 = vdSplit1.size() ; int nSplit0 = vdSplit0.size() ; // se con una polyline sono arrivato alla fine non posso più avanzare @@ -5068,7 +5070,14 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int if ( j == vMatch1.size()) bAdvance1 = false ; // se trovo che ho uno spigolo allora procedo con la gestione spigoli - if ( vEdgeSplit0[c+1] || vEdgeSplit1[j+1]) { + if( vEdgeSplit0[c+1] && vEdgeSplit1[j+1]) { + // se ho uno spigolo su entrambe le curve forzo l'accoppiamento + bAdvance0 = true ; + bPerfectMatch = true ; + dParam0 = round( dParam0) ; + dParam1 = round( dParam1) ; + } + else if ( (vEdgeSplit0[c+1] && ! bAdvance1) || (vEdgeSplit1[j+1] && ! bAdvance0)) { bAdvance0 = false ; bAdvance1 = false ; } @@ -5152,7 +5161,7 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int bool bEdgeFoundOnSecond = false ; if ( vEdgeSplit0[c+1] && vEdgeSplit1[j+1]) { // questo caso non è previsto !!!!! e non mi aspetto che avvenga - LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found") ; + LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 0") ; } if ( vEdgeSplit0[c+1]) { ++c ; @@ -5177,6 +5186,9 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int dLastParamMatch0 = j - 1 ; ptLastPointMatch0 = vPnt1[j] ; } + else { + LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 1") ; + } } else if ( vEdgeSplit1[j+1]) { ++c ; @@ -5201,10 +5213,12 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int dLastParamMatch1 = c - 1 ; ptLastPointMatch1 = vPnt0[c] ; } + else { + LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 2") ; + } } else { - // potrei avere un mismatch, senza però avere degli spigoli.. - // gestisco comunque con un'accoppiamento + /////////OLD VRESION ++c ; ++j ; vPairs.emplace_back( c + nSplit0, j + nSplit1) ; @@ -5212,12 +5226,187 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int ptLastPointMatch1 = vPnt0[c] ; dLastParamMatch0 = j ; ptLastPointMatch0 = vPnt1[j] ; + + + + ////// potrei avere un mismatch, senza però avere degli spigoli.. + + // // identifico la zona in cui ho il mismatch e parametrizzo localmente + + // //conto quanti punti ho nel mezzo + // int c_temp = c, j_temp = j ; + // bAdvance0 = true ; + // bAdvance1 = true ; + // int nParam0, nParam1 ; + // while( bAdvance0) { + // dParam0 = vMatch0[c_temp].second ; + // nParam0 = int( round( dParam0)) ; + // dParam1 = vMatch1[nParam0].second ; + // nParam1 = int( round( dParam1)) ; + // if( abs( nParam1 - c_temp) <= 2) + // bAdvance0 = false ; + // else + // ++ c_temp ; + // } + // while( bAdvance1) { + // dParam1 = vMatch1[j_temp].second ; + // nParam1 = int( round( dParam1)) ; + // dParam0 = vMatch0[nParam1].second ; + // nParam0 = int( round( dParam0)) ; + // if( abs( nParam0 - j_temp) <= 2) + // bAdvance1 = false ; + // else + // ++ j_temp ; + // } + // // se non sono avanzato, allora mi basta accoppiare i due punti in questione + // if( c_temp == c || j_temp == j) { + // ++c ; + // ++j ; + // vPairs.emplace_back( c + nSplit0, j + nSplit1) ; + // dLastParamMatch1 = c ; + // ptLastPointMatch1 = vPnt0[c] ; + // dLastParamMatch0 = j ; + // ptLastPointMatch0 = vPnt1[j] ; + // } + // // se sono dovuto avanzare per trovare delle coppie che tornano a matchare allora ho effettivamente trovato una zona di mismatch + // else { + // // determino quale delle due coppie è il confine effettivo con la zona di mismatch e quale sarà la prima dopo il mismamtch + // dParam0 = vMatch0[c_temp].second ; + // dParam1 = vMatch1[j_temp].second ; + // bool bIntParam0 = false ; + // bool bIntParam1 = false ; + // if ( abs( dParam0 - round( dParam0)) < EPS_SMALL) { + // dParam0 = round( dParam0) ; + // bIntParam0 = true ; + // } + // if ( abs( dParam1 - round( dParam1)) < EPS_SMALL) { + // dParam1 = round( dParam1) ; + // bIntParam1 = true ; + // } + // bAdvance0 = dParam0 < j_temp + 1 + EPS_SMALL ; + // bAdvance1 = dParam1 < c_temp + 1 + EPS_SMALL ; + // PtrOwner pCC0 ; + // PtrOwner pCC1 ; + // int nPointsBetween0 = 0 ; + // int nPointsBetween1 = 0 ; + // if( bAdvance0 && bAdvance1) { + // pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, c_temp + 1)) ; + // pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, j_temp + 1)) ; + // nPointsBetween0 = c_temp - c ; + // nPointsBetween1 = j_temp - j ; + // } + // else if( bAdvance0){ + // pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, c_temp + 1)) ; + // pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, dParam0)) ; + // nPointsBetween0 = c_temp - c ; + // nPointsBetween1 = int( dParam0) - ( j + 1) ; + // if ( bIntParam0) + // nPointsBetween1 -= 1 ; + // } + // else if( bAdvance1){ + // pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, dParam1)) ; + // pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, j_temp + 1)) ; + // nPointsBetween0 = int( dParam1) - ( c + 1) ; + // nPointsBetween1 = j_temp - j ; + // if ( bIntParam1) + // nPointsBetween0 -= 1 ; + // } + // + // double dLen0 ; pCC0->GetLength( dLen0) ; + // double dLen1 ; pCC1->GetLength( dLen1) ; + // DBLVECTOR vdParamPos0 ; vdParamPos0.reserve( nPointsBetween0) ; + // DBLVECTOR vdParamPos1 ; vdParamPos1.reserve( nPointsBetween1) ; + // for ( int k = 0 ; k <= nPointsBetween0 ; ++k) { + // double dLen = 0 ; pCC0->GetLengthAtParam( k, dLen) ; + // vdParamPos0.push_back( dLen / dLen0) ; + // } + // vdParamPos0.push_back( 1) ; + // for ( int k = 0 ; k <= nPointsBetween1 ; ++k) { + // double dLen = 0 ; pCC1->GetLengthAtParam( k, dLen) ; + // vdParamPos1.push_back( dLen / dLen1) ; + // } + // vdParamPos1.push_back( 1) ; + + // bool bSplitToAdd = true ; + // int c0 = 1, c1 = 1 ; + // //debug + // int nCBerfore = c ; + // int nJBefore = j ; + // //debug + // while ( bSplitToAdd) { + // if ( c0 > ssize( vdParamPos0) - 1 && c1 > ssize( vdParamPos1) - 1) { + // LOG_DBG_ERR( GetEGkLogger(), "Surf Bez Ruled Guided: error 1 while reparametrizing some section") ; + // return false ; + // } + // // se ho una corrispondenza tra punti ( e non sono alla fine del tratto) allora non aggiungo split + // if ( abs( vdParamPos0[c0] - vdParamPos1[c1]) < EPS_PARAM && vdParamPos0[c0] < 1) { + // ++c0 ; + // ++c1 ; + // ++c ; + // ++j ; + // vPairs.emplace_back( c + nSplit0, j + nSplit1) ; + // } + // // se non ho corrispondenza allora aggiungo uno split sulla curva a cui manca il punto corrispondente + // else if ( vdParamPos0[c0] < vdParamPos1[c1]) { + // double dPar ; CrvU1.GetParamAtLength( dLen1 * vdParamPos0[c0], dPar) ; + // if ( abs( dPar - round( dPar)) > EPS_SMALL) { + // vdSplit1.push_back( dPar + dLastParamMatch0) ; + // nSplit1 = vdSplit1.size() ; + // } + // else if ( dPar = round( dPar) ; dPar > j){ + // ++ j ; + // } + // ++c ; + // vPairs.emplace_back( c + nSplit0, j + nSplit1) ; + // ++c0 ; + // } + // else if ( vdParamPos0[c0] > vdParamPos1[c1]) { + // double dPar ; CrvU0.GetParamAtLength( dLen0 * vdParamPos1[c1], dPar) ; + // // se lo split non è in prossimità di una joint già esistente allora lo aggiungo + // if ( abs( dPar - round( dPar)) > EPS_SMALL) { + // vdSplit0.push_back( dPar + dLastParamMatch1) ; + // nSplit0 = vdSplit0.size() ; + // } + // else if ( dPar = round( dPar) ; dPar > c){ + // ++ c ; + // } + // ++j ; + // vPairs.emplace_back( c + nSplit0, j + nSplit1) ; + // ++c1 ; + // } + // else { + // LOG_DBG_ERR( GetEGkLogger(), "Surf Bez Ruled Guided: error 2 while reparametrizing some section") ; + // return false ; + // } + // bSplitToAdd = ! ( c0 == ssize( vdParamPos0) - 1 && c1 == ssize( vdParamPos1) - 1) ; + // } + // // aggiorno i dati dell'ultima aggiunta + // if( bAdvance0 && ! bAdvance1) { + // ptLastPointMatch0 = vMatch0[c_temp].first ; + // dLastParamMatch0 = vMatch0[c_temp].second ; + // ptLastPointMatch1 = vPnt0[c_temp] ; + // dLastParamMatch0 = c_temp ; + // } + // else if( ! bAdvance0 && bAdvance1) { + // ptLastPointMatch0 = vPnt1[j_temp] ; + // dLastParamMatch0 = j_temp ; + // ptLastPointMatch1 = vMatch1[j_temp].first ; + // dLastParamMatch0 = vMatch1[j_temp].second ; + // } + // else { + // ptLastPointMatch0 = vPnt1[j_temp] ; + // dLastParamMatch0 = j_temp ; + // ptLastPointMatch1 = vPnt0[c_temp] ; + // dLastParamMatch0 = c_temp ; + // } + // vPairs.emplace_back( c + nSplit0, j + nSplit1) ; + // } } } bAdvance = ! (c >= int(vMatch0.size()) - 1 && j >= int(vMatch1.size()) - 1) ; } - // applico effettivamente gli split e aggiungo gli elementi ai vettori vbRep + // applico effettivamente gli split int nUnit = 0 ; if ( ! vdSplit1.empty()) nUnit = int( vdSplit1.back()) ; @@ -5304,6 +5493,28 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int ++ nAddedSpan ; } +#if SAVERULEDISO + //debug + vector vGeo ; + ICURVEPOVECTOR vCrv ; + GetAllPatchesIsocurves( false, vCrv) ; + for( int i = 0 ; i < ssize( vCrv) ; ++i) { + vGeo.push_back( vCrv[i]->Clone()) ; + } + vector vCol( ssize( vCrv)) ; + fill( vCol.begin(), vCol.end(), Color( 255,0,128)) ; + SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/isoCurves.nge") ; + //debug + + vGeo.clear() ; + vGeo.push_back( CrvU0.Clone()) ; + vGeo.push_back( CrvU1.Clone()) ; + vCol.clear() ; + vCol.push_back(Color(0,64,128)) ; + vCol.push_back(Color(128,64,0)) ; + SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/NewCurves.nge") ; +#endif + return bOk ; } else if ( RLT_B_LENPAR ) { @@ -5672,6 +5883,8 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c //controllo che siano entrambe chiuse o entrambe aperte if( pCurve0->IsClosed() ^ pCurve1->IsClosed()) return false ; + + bool bClosed = pCurve0->IsClosed() ; // converto in bezier la curva iniziale CurveComposite CrvU0 ; CrvU0.AddCurve( CurveToBezierCurve(pCurve0)) ; @@ -5709,12 +5922,26 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c double dLenPrev0 = 0 ,dLenPrev1 = 0 ; // costruisco il vettore delle nuove curve isoparamtriche per la nuova superficie + bool bFirstAdded = false ; + int nSpanU0 = CrvU0.GetCurveCount() ; + int nSpanU1 = CrvU1.GetCurveCount() ; ISOPARVECT vIso ; for ( int i = 0 ; i < ssize( vCrv) ; ++i) { Point3d ptU0 = vCrv[i].first ; Point3d ptU1 = vCrv[i].second ; double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ; double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ; + if( bClosed && (dParam0 < EPS_SMALL || nSpanU0 - dParam0 < EPS_SMALL) && (dParam1 < EPS_SMALL || nSpanU1 - dParam1 < EPS_SMALL)) { + if( ! bFirstAdded) { + dParam0 = 0 ; + dParam1 = 0 ; + bFirstAdded = true ; + } + else { + dParam0 = nSpanU0 ; + dParam1 = nSpanU1 ; + } + } vIso.emplace_back( i, dParam0, dParam1) ; } @@ -5735,7 +5962,7 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c dLastParam0 = 0 ; dLastParam1 = 0 ; - if( vIso[0].dParam0 > 0 || vIso[0].dParam1 > 1) + if( vIso[0].dParam0 > 0 || vIso[0].dParam1 > 0) vPairs.emplace_back( 0, 0) ; for ( int i = 0 ; i < ssize( vIso) ; ++i) { const BIPOINT& pCrv = vCrv[vIso[i].nCrv] ; @@ -5893,8 +6120,8 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c CrvU0.AddJoint( dSplit) ; } - int nSpanU0 = CrvU0.GetCurveCount() ; - int nSpanU1 = CrvU1.GetCurveCount() ; + nSpanU0 = CrvU0.GetCurveCount() ; + nSpanU1 = CrvU1.GetCurveCount() ; // aggiungo l'ultima coppia vPairs.emplace_back( nSpanU0, nSpanU1) ; @@ -5951,6 +6178,28 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c ++ nAddedSpan ; } + #if SAVERULEDGUIDEDISO + //debug + vector vGeo ; + ICURVEPOVECTOR vCrvIso ; + GetAllPatchesIsocurves( false, vCrvIso) ; + for( int i = 0 ; i < ssize( vCrvIso) ; ++i) { + vGeo.push_back( vCrvIso[i]->Clone()) ; + } + vector vCol( ssize( vCrvIso)) ; + fill( vCol.begin(), vCol.end(), Color( 255,0,128)) ; + SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/isoCurves.nge") ; + //debug + + vGeo.clear() ; + vGeo.push_back( CrvU0.Clone()) ; + vGeo.push_back( CrvU1.Clone()) ; + vCol.clear() ; + vCol.push_back(Color(0,64,128)) ; + vCol.push_back(Color(128,64,0)) ; + SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/NewCurves.nge") ; +#endif + return true ; } From f4b3312672da3fa6ee3291fae6937c0064cc1a18 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 26 Jan 2026 13:08:47 +0100 Subject: [PATCH 41/44] EgtGeomKernel : - disattivati salvataggi debug. --- SurfBezier.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 138a4d8..259f0e4 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -46,8 +46,8 @@ #define SAVEFAILEDTRIANGULATION 0 #define SAVEISO 0 -#define SAVERULEDISO 1 -#define SAVERULEDGUIDEDISO 1 +#define SAVERULEDISO 0 +#define SAVERULEDGUIDEDISO 0 #if SAVEFAILEDTRIANGULATION || SAVEISO || SAVERULEDISO || SAVERULEDGUIDEDISO #include "/EgtDev/Include/EGkGeoObjSave.h" #endif From 736353bbac1272a7cdc065e07105dd1706fd1eee Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 26 Jan 2026 18:02:59 +0100 Subject: [PATCH 42/44] EgtGeomKernel : - in Trimming piccole correzioni e migliorie. --- Trimming.cpp | 73 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/Trimming.cpp b/Trimming.cpp index ea7dd6a..f8c0f99 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -304,9 +304,9 @@ ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; #endif - // Dalla Curva Grezza, analizzo i suoi estremi e calcolo le Patch + // Dalla Curva Grezza, recupero i suoi punti grezzi e le sue Patch PolyLine PL ; - if ( ! CrvCompo.ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PL)) + if ( ! CrvCompo.ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL)) return false ; POLYLINEVECTOR vPL ; if ( ! GetPointSetByAngTol( PL, dAngTol, vPL)) @@ -371,7 +371,7 @@ ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) //----------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -// Funzione per controllare e sistemare le curve di bordo di una riagata Bezier +// Funzione per controllare e sistemare le curve di bordo di una rigata Bezier static bool ManageRuledBorders( ICurveComposite* pCompoEdge1, ICurveComposite* pCompoEdge2) { @@ -3572,8 +3572,9 @@ GetTrimmingFinalBorders( ICRVCOMPOPOVECTOR& vCompoBezierEdges, double dLinTol, d // Funzione per ricavare i bordi a partire da un insieme di superfici; questi vengono // calcolati mediante analisi delle normali lungo il bordo delle Patches di Surfs bool -GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dLinTol, - double dAngTol, double dThick, ICRVCOMPOPOVECTOR& vCompoBezierEdges) +GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dSurfLinTol, + double dSurfAngTol, double dLinTol, double dAngTol, double dThick, + ICRVCOMPOPOVECTOR& vCompoBezierEdges) { // Pulizia dei parametri di ritorno vCompoBezierEdges.clear() ; @@ -3595,7 +3596,7 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou // Controllo sulla tolleranza angolare double dMyAngTol = Clamp( dAngTol, 1., 45.) ; - // Recupero la superficie TriMesh complessiva [migliorabile] + // Recupero la superficie TriMesh complessiva PtrOwner pStm( nullptr) ; if ( int( vpSurf.size()) == 1) { const ISurf* pSurf = vpSurf[0] ; @@ -3607,7 +3608,7 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou else if ( nType == SRF_BEZIER) { const ISurfBezier* pSurfBz = GetSurfBezier( pSurf) ; if ( pSurfBz != nullptr) - pStm.Set( CloneBasicSurfTriMesh( pSurfBz->GetApproxSurf( dMyLinTol))) ; + pStm.Set( CloneBasicSurfTriMesh( pSurfBz->GetApproxSurf( dSurfLinTol))) ; } } else { @@ -3622,7 +3623,7 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou const ISurfBezier* pSrfBz = GetSurfBezier( pSurf) ; if ( pSrfBz == nullptr) return false ; - PtrOwner pStmTmp( pSrfBz->GetApproxSurf( dMyLinTol)) ; + PtrOwner pStmTmp( pSrfBz->GetApproxSurf( dSurfLinTol)) ; if ( ! IsNull( pStmTmp) && pStmTmp->IsValid()) mySoup.AddSurfTriMesh( *pStmTmp) ; } @@ -3660,8 +3661,12 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou erase_if( vCompoBezierEdges, []( ICurveComposite* pBezierEdge) { return ( pBezierEdge == nullptr || ! pBezierEdge->IsValid() || pBezierEdge->GetCurveCount() == 0) ; }) ; - for ( int i = 0 ; i < ssize( vCompoBezierEdges) - 1 ; i += 2) + for ( int i = 0 ; i < ssize( vCompoBezierEdges) - 1 ; i += 2) { ManageRuledBorders( vCompoBezierEdges[i], vCompoBezierEdges[i+1]) ; + // Essendo l'Offset fatto in negativo, entrambe le curve vanno invertite + vCompoBezierEdges[i]->Invert() ; + vCompoBezierEdges[i+1]->Invert() ; + } return true ; } @@ -3729,8 +3734,6 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, // Verifica validità delle curve per la creazione della Bezier rigata PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ; PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ; - if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2)) - return false ; vSyncPoints.clear() ; // Controllo sulla tolleranza lineare @@ -4152,25 +4155,41 @@ GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf BIPNTVECTOR vPtAPtB ; vPtAPtB.reserve( MAX_POINTS + 1) ; CurveComposite& currCompoPatch = vSurfPatches[nSurf].CompoPathces[nCurrPatch] ; CurveComposite& otherCompoPatch = vSurfPatches[nOtherSurf].CompoPathces[nOtherPatch] ; - double dLen = 0.; - currCompoPatch.GetLength( dLen) ; - for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) { - double dU = 0. ; - currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ; - Point3d ptCurr ; - currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ; - Point3d ptOther ; - int nFlag = 0 ; - DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag) ; - // Recupero le due normali sulle curva patch campionate - Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ; - if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) || - ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther)) - return false ; - bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + bTangent = ( currCompoPatch.IsValid() && otherCompoPatch.IsValid()) ; + if ( bTangent) { + double dLen = 0.; + currCompoPatch.GetLength( dLen) ; + for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) { + double dU = 0. ; + currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ; + Point3d ptCurr ; + currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ; + Point3d ptOther ; + int nFlag = 0 ; + if ( ! DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag)) + bTangent = false ; + // Recupero le due normali sulle curva patch campionate + Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ; + if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) || + ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther)) + return false ; + bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + } } // Se superficie in tangenza, aggiorno i parametri if ( bTangent) { + #if DEBUG_SIMPLE_PATCHES + VC.clear() ; VT.clear() ; + VT.emplace_back( pCurrSurf->Clone()) ; + VC.emplace_back( LIME) ; + VT.emplace_back( pOtherSurf->Clone()) ; + VC.emplace_back( GREEN) ; + VT.emplace_back( currCompoPatch.Clone()) ; + VC.emplace_back( RED) ; + VT.emplace_back( otherCompoPatch.Clone()) ; + VC.emplace_back( BLUE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Test.nge") ; + #endif vSurfToCheck.emplace_back( nOtherSurf) ; nextPatch.bErase = true ; if ( nOtherSurf >= int( vSurf.size()) && From 06cfe1bb9696a84fed2c082fd15ee6a26e2a4b8b Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 27 Jan 2026 10:21:51 +0100 Subject: [PATCH 43/44] EgtGeomKernel : - correzione alle bezier ruled per il match degli edge. --- SurfBezier.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 259f0e4..8be2b0d 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -5074,8 +5074,10 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int // se ho uno spigolo su entrambe le curve forzo l'accoppiamento bAdvance0 = true ; bPerfectMatch = true ; - dParam0 = round( dParam0) ; - dParam1 = round( dParam1) ; + dParam0 = j + 1 ; + dParam1 = c + 1 ; + ptJoint0 = vPnt1[j+1] ; + ptJoint1 = vPnt0[c+1] ; } else if ( (vEdgeSplit0[c+1] && ! bAdvance1) || (vEdgeSplit1[j+1] && ! bAdvance0)) { bAdvance0 = false ; From f02f29c543d3d26b57fdeb480dee1fd28a6a3d5b Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 27 Jan 2026 13:36:42 +0100 Subject: [PATCH 44/44] EgtGeomKernel 3.1a4 : - correzione all'intersezione LineLine - correzione all'intersezione CompoCompo - cambio versione. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes IntersCrvCompoCrvCompo.cpp | 6 +++++- IntersLineLine.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 245321f55d8d74e4d043c778cff34a3e31717e2a..5ff8fcbaacafb63d0892e3ed26b696523ac19e8c 100644 GIT binary patch delta 81 zcmdlNy)SyhH#SC-&FAG5nSs m_Info[j].IciB[kj].dU + EPS_PARAM) + m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) EraseCurrentInfo( i, j) ; } // caso NULL-NULL per precedente di prima curva else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL) { - m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ; + m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ; + if ( m_Info[j].IciB[kj].dU < m_Info[i].IciB[ki].dU - EPS_PARAM) + m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ; // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) EraseOtherInfo( i, j) ; } diff --git a/IntersLineLine.cpp b/IntersLineLine.cpp index 12e0ce7..9d06ec4 100644 --- a/IntersLineLine.cpp +++ b/IntersLineLine.cpp @@ -180,10 +180,10 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line } // estremità sovrapposte di poco if ( ! bParallel && abs( dCrossXY) < ( 0.1 * DEGTORAD) * ( dLen1XY * dLen2XY)) { - if (( nS1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) || - ( nS1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) || - ( nE1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptE1, ptS2, 2 * EPS_SMALL)) || - ( nE1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptE1, ptE2, 2 * EPS_SMALL))) { + if (( nS1Side == 0 && nS2Side == 0 && ScalarXY( vtDir1, vtDir2) < 0 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) || + ( nS1Side == 0 && nE2Side == 0 && ScalarXY( vtDir1, vtDir2) > 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) || + ( nE1Side == 0 && nS2Side == 0 && ScalarXY( vtDir1, vtDir2) > 0 && ! AreSamePointXYEpsilon( ptE1, ptS2, 2 * EPS_SMALL)) || + ( nE1Side == 0 && nE2Side == 0 && ScalarXY( vtDir1, vtDir2) < 0 && ! AreSamePointXYEpsilon( ptE1, ptE2, 2 * EPS_SMALL))) { bParallel = true ; bFarEnds = false ; }