diff --git a/CurveAux.cpp b/CurveAux.cpp index 8cc9cdf..fb13974 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -899,7 +899,7 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol) } // se l'approssimazione dà un errore troppo alto allora annullo tutto // ricalcolo l'errore a mano, per avere un valore più attendibile - CalcBezierApproxError( pCrvBezier, pNewBezier, dErr) ; + CalcApproxError( pCrvBezier, pNewBezier, dErr) ; if ( dErr > dTol) return nullptr ; @@ -1005,7 +1005,7 @@ ApproxBezierWithCubics(const ICurve* pCrv, double dTol) pCrvCubic.Set( ApproxCurveBezierWithSingleCubic( pCrvPart)) ; } } - CalcBezierApproxError( pCrvPart, pCrvCubic, dErr) ; + CalcApproxError( pCrvPart, pCrvCubic, dErr) ; if ( dErr > dTol && ! bOneIsEnough) nParts += 2 ; else { @@ -1125,25 +1125,63 @@ ApproxArcCurveBezierWithSingleCubic( const ICurve* pCrv, const Point3d& ptCen, c } //---------------------------------------------------------------------------- -ICurve* -ApproxCurveWithBezier( const ICurve*, double dTol) +static bool +FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan) { - // campiono punti lungo la curva e poi li interpolo - - PtrOwner pCC( CreateBasicCurveComposite()) ; - return Release( pCC) ; + if ( dU < 0) + return false ; + else if ( dU < EPS_ZERO) { + nSpan = nDeg - 1 ; + return true ; + } + // trovo a quale span appartiene il parametro dU + int nKnots = int( vKnots.size()) ; + if ( abs( dU - vKnots[nKnots-1]) < EPS_SMALL) { + nSpan = nKnots - 1 ; + return true ; + } + int nLow = nDeg - 1 ; + int nHigh = nKnots - 1 ; + int nMid = ( nLow + nHigh) / 2 ; + while ( dU < vKnots[nMid] || dU >= vKnots[nMid + 1] ) { + if ( dU < vKnots[nMid]) + nHigh = nMid ; + else + nLow = nMid ; + nMid = ( nLow + nHigh) / 2 ; + if( nMid == nDeg - 1) + break ; + } + nSpan = nMid ; + return true ; } //---------------------------------------------------------------------------- -ICurve* -ApproxPointSetWithBezier( const ICurve*, double dTol) +static bool +CalcBasisFunc( double dU, int nSpan, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) { - // campiono punti lungo la curva e poi li interpolo + // mi aspetto che il vettore vBasis sia di lunghezza nDeg + 1 + if ( vBasis.size() != nDeg + 1) + return false ; - // oppure faccio la fat curve e poi calcolo una bezier che stia all'interno di quella regione - - PtrOwner pCC( CreateBasicCurveComposite()) ; - return Release( pCC) ; + vBasis[0] = 1 ; + DBLVECTOR vLeft ; vLeft.resize( nDeg + 1) ; + DBLVECTOR vRight ; vRight.resize( nDeg + 1) ; + for ( int j = 1 ; j <= nDeg ; ++j) { + vLeft[j] = dU - vKnots[nSpan + 1 -j] ; + vRight[j] = vKnots[nSpan + j] - dU ; + double dSaved = 0 ; + for ( int r = 0 ; r < j ; ++r) { + double dSum = vRight[r+1] + vLeft[j-r] ; + double dTemp = 0 ; + if( dSum > EPS_SMALL) + dTemp = vBasis[r] / dSum ; + vBasis[r] = dSaved + vRight[r+1] * dTemp ; + dSaved = vLeft[j-r] * dTemp ; + } + vBasis[j] = dSaved ; + } + return true ; } //---------------------------------------------------------------------------- @@ -1251,72 +1289,42 @@ InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol) } //---------------------------------------------------------------------------- -static bool -FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan) +ICurve* +ApproxCurveWithBezier( const ICurve* pCrv , double dTol, int nType) { - if ( dU < 0) - return false ; - else if ( dU < EPS_ZERO) { - nSpan = nDeg - 1 ; - return true ; - } - // trovo a quale span appartiene il parametro dU - int nKnots = int( vKnots.size()) ; - if ( abs( dU - vKnots[nKnots-1]) < EPS_SMALL) { - nSpan = nKnots - 1 ; - return true ; - } - int nLow = nDeg - 1 ; - int nHigh = nKnots - 1 ; - int nMid = ( nLow + nHigh) / 2 ; - while ( dU < vKnots[nMid] || dU >= vKnots[nMid + 1] ) { - if ( dU < vKnots[nMid]) - nHigh = nMid ; + PolyLine plApprox ; + double dAngTolFine = 2 ; + pCrv->ApproxWithLines( dTol, dAngTolFine, ICurve::APL_STD, plApprox) ; + + PNTVECTOR vPnt ; + Point3d pt ; plApprox.GetFirstPoint( pt) ; + do { + vPnt.push_back( pt) ; + }while( plApprox.GetNextPoint( pt)) ; + + // campiono punti lungo la curva e poi li interpolo + + PtrOwner pCC( InterpolatePointSetWithBezier( vPnt, dTol)) ; + if( ! IsNull( pCC) && pCC->IsValid()) + return Release( pCC) ; else - nLow = nMid ; - nMid = ( nLow + nHigh) / 2 ; - if( nMid == nDeg - 1) - break ; - } - nSpan = nMid ; - return true ; + return nullptr ; } //---------------------------------------------------------------------------- -static bool -CalcBasisFunc( double dU, int nSpan, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) +ICurve* +ApproxPointSetWithBezier( const ICurve* pCrv, double dTol) { - // mi aspetto che il vettore vBasis sia di lunghezza nDeg + 1 - if ( vBasis.size() != nDeg + 1) - return false ; + // campiono punti lungo la curva e poi li interpolo - vBasis[0] = 1 ; - DBLVECTOR vLeft ; vLeft.resize( nDeg + 1) ; - DBLVECTOR vRight ; vRight.resize( nDeg + 1) ; - for ( int j = 1 ; j <= nDeg ; ++j) { - vLeft[j] = dU - vKnots[nSpan + 1 -j] ; - vRight[j] = vKnots[nSpan + j] - dU ; - double dSaved = 0 ; - for ( int r = 0 ; r < j ; ++r) { - double dSum = vRight[r+1] + vLeft[j-r] ; - double dTemp = 0 ; - if( dSum > EPS_SMALL) - dTemp = vBasis[r] / dSum ; - vBasis[r] = dSaved + vRight[r+1] * dTemp ; - dSaved = vLeft[j-r] * dTemp ; - } - vBasis[j] = dSaved ; - } - return true ; + PtrOwner pCC( CreateBasicCurveComposite()) ; + return Release( pCC) ; } //---------------------------------------------------------------------------- bool -CalcBezierApproxError( const ICurveBezier* pCrvOri, const ICurveBezier* pCrvNew, double& dErr, int nPoints) +CalcApproxError( const ICurve* pCrvOri, const ICurve* pCrvNew, double& dErr, int nPoints) { - if ( pCrvOri->GetType() != CRV_BEZIER || pCrvNew->GetType() != CRV_BEZIER) - return false ; - // controllo l'errore effettivo campionando più finemente double dLenOri = 0 ; pCrvOri->GetLength( dLenOri) ; double dLenNew = 0 ; pCrvNew->GetLength( dLenNew) ; diff --git a/CurveBezier.cpp b/CurveBezier.cpp index f70d478..ccdd6c7 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -2396,7 +2396,7 @@ CurveBezier::MakeNonRational( double dTol) } // calcolo l'errore di approssimazione sulla curva - CalcBezierApproxError( this, pNewBez, dErr) ; + CalcApproxError( this, pNewBez, dErr) ; bOk = dErr < dTol ; if ( bOk) { // aggiorno la curva di bezier originale con quella approssimata