EgtGeomKernel :

- aggiunta la funzione per l'approssimazione di una curva generica con una serie di bezier.
- piccole modifiche.
This commit is contained in:
Daniele Bariletti
2025-10-17 15:36:32 +02:00
parent 717d7a3fe3
commit fb235bf985
2 changed files with 78 additions and 70 deletions
+77 -69
View File
@@ -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<ICurveComposite> 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<ICurveComposite> 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<ICurve> 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<ICurveComposite> 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) ;
+1 -1
View File
@@ -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