From 4050aa11c58863567adaca02d6d6381c5f7ebbf5 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Mon, 2 Sep 2024 09:47:45 +0200 Subject: [PATCH] EgtGeomKernel : - aggiunto un limite di iterazioni per l'approssimazione con bezier cubiche - correzione alla MakeNonRational. --- CurveAux.cpp | 26 ++++++++------ CurveBezier.cpp | 95 +++++++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 861ef2b..dec95b4 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -895,7 +895,8 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol) PtrOwner pCC( CreateBasicCurveComposite()) ; // approssimo l'ultimo tratto - while ( dErr > dTol) { + int nCount = 0 ; + while ( dErr > dTol && nCount < 100) { PtrOwner pCrvPart( pCrvBezier->Clone()) ; pCrvPart->TrimStartEndAtParam( double( nParts - 1) / nParts, 1) ; PtrOwner pCrvCubic ; @@ -920,18 +921,23 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol) if( bOneIsEnough) break ; } + ++ nCount ; } - // approssimo annche tutti gli altri tratti con una cubica - for ( int i = nParts - 1 ; i > 0 ; --i) { - PtrOwner pCrvPart( pCrvBezier->Clone()) ; - pCrvPart->TrimStartEndAtParam( double( i - 1) / nParts, double(i) / nParts) ; - PtrOwner pCrvCubic( ApproxCurveBezierWithSingleCubic( pCrvPart)) ; - if ( ! pCC->AddCurve( Release( pCrvCubic), false)) - return nullptr ; - } + if( nCount < 100) { + // approssimo annche tutti gli altri tratti con una cubica + for ( int i = nParts - 1 ; i > 0 ; --i) { + PtrOwner pCrvPart( pCrvBezier->Clone()) ; + pCrvPart->TrimStartEndAtParam( double( i - 1) / nParts, double(i) / nParts) ; + PtrOwner pCrvCubic( ApproxCurveBezierWithSingleCubic( pCrvPart)) ; + if ( ! pCC->AddCurve( Release( pCrvCubic), false)) + return nullptr ; + } - return Release( pCC) ; + return Release( pCC) ; + } + else + return nullptr ; } //---------------------------------------------------------------------------- diff --git a/CurveBezier.cpp b/CurveBezier.cpp index 570858f..c54c194 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -2297,12 +2297,16 @@ CurveBezier::MakeNonRational( double dTol) return true ; // controllo se i pesi sono tutti == 1 allora รจ una finta razionale e mi basta fare una copia dei punti di controllo - bool bIsActualRat = true ; - for ( int i = 0 ; i < m_nDeg && bIsActualRat ; ++i) - bIsActualRat = bIsActualRat && abs(m_vWeCtrl[i] - 1) > EPS_SMALL ; + bool bIsActualRat = false ; + for ( int i = 0 ; i < m_nDeg ; ++i) { + if ( abs(m_vWeCtrl[i] - 1) > EPS_SMALL) { + bIsActualRat = true ; + break ; + } + } bool bOk = true ; - if ( ! bIsActualRat ) { + if ( ! bIsActualRat) { PtrOwner pNewBez( CreateBasicCurveBezier()) ; for ( int p = 0 ; p < m_nDeg ; ++p) { Point3d pt = GetControlPoint( p) ; @@ -2311,49 +2315,54 @@ CurveBezier::MakeNonRational( double dTol) } else { // provo ad approssimare la curva di bezier con una controparte non razionale - PtrOwner pNewBez( CreateBasicCurveBezier()) ; - int nDeg = m_nDeg + 2 ; - pNewBez->Init( nDeg, false) ; - PNTVECTOR vPntCtrl ; - PNTVECTOR vPntSampling ; - for ( int p = 0 ; p < nDeg + 1; ++p) { - Point3d pt ; GetPointD1D2( double(p) / nDeg, pt) ; - pNewBez->SetControlPoint( p, pt) ; - vPntCtrl.push_back( pt) ; - } - vPntSampling = vPntCtrl ; - int c = 0 ; - double dErr = INFINITO ; - while ( dErr > dTol && c < 100) { - double dErrMax = 0 ; - // calcolo le differenze tra i punti di sampling sulla nuova curva e quelli sulla curva originale + int nDeg = m_nDeg ; + // punto di rientro in caso fallisca il primo tentativo + retry : + nDeg += 2 ; + PtrOwner pNewBez( CreateBasicCurveBezier()) ; + pNewBez->Init( nDeg, false) ; + PNTVECTOR vPntCtrl ; + PNTVECTOR vPntSampling ; for ( int p = 0 ; p < nDeg + 1; ++p) { - Point3d pt ; pNewBez->GetPointD1D2( double(p) / nDeg, pt) ; - Vector3d vDiff = vPntSampling[p] - pt ; - double dErrLoc = vDiff.Len() ; - if( dErrLoc > dErrMax) - dErrMax = dErrLoc ; - // aggiorno il vettore dei punti di controllo della nuova curva - vPntCtrl[p] += vDiff ; + Point3d pt ; GetPointD1D2( double(p) / nDeg, pt) ; + pNewBez->SetControlPoint( p, pt) ; + vPntCtrl.push_back( pt) ; + } + vPntSampling = vPntCtrl ; + int c = 0 ; + double dErr = INFINITO ; + while ( dErr > dTol && c < 100) { + double dErrMax = 0 ; + // calcolo le differenze tra i punti di sampling sulla nuova curva e quelli sulla curva originale + for ( int p = 0 ; p < nDeg + 1; ++p) { + Point3d pt ; pNewBez->GetPointD1D2( double(p) / nDeg, pt) ; + Vector3d vDiff = vPntSampling[p] - pt ; + double dErrLoc = vDiff.Len() ; + if( dErrLoc > dErrMax) + dErrMax = dErrLoc ; + // aggiorno il vettore dei punti di controllo della nuova curva + vPntCtrl[p] += vDiff ; + } + dErr = dErrMax ; + // aggiorno i punti di controllo della nuova curva + for ( int i = 0 ; i < nDeg + 1 ; ++i) + pNewBez->SetControlPoint( i, vPntCtrl[i]) ; + ++c ; } - dErr = dErrMax ; - // aggiorno i punti di controllo della nuova curva - for ( int i = 0 ; i < nDeg + 1 ; ++i) - pNewBez->SetControlPoint( i, vPntCtrl[i]) ; - ++c ; - } - // calcolo l'errore di approssimazione sulla curva - CalcBezierApproxError( this, pNewBez, dErr) ; - bOk = dErr < dTol ; - if( bOk) { - // aggiorno la curva di bezier originale con quella approssimata - Init( nDeg, false) ; - for( int i = 0 ; i < nDeg + 1 ; ++i) { - SetControlPoint( i, pNewBez->GetControlPoint( i)) ; - SetControlWeight( i, pNewBez->GetControlWeight( i)) ; + // calcolo l'errore di approssimazione sulla curva + CalcBezierApproxError( this, pNewBez, dErr) ; + bOk = dErr < dTol ; + if( bOk) { + // aggiorno la curva di bezier originale con quella approssimata + Init( nDeg, false) ; + for( int i = 0 ; i < nDeg + 1 ; ++i) { + SetControlPoint( i, pNewBez->GetControlPoint( i)) ; + SetControlWeight( i, pNewBez->GetControlWeight( i)) ; + } } - } + else if( nDeg < m_nDeg + 4) + goto retry ; } return bOk ;