EgtGeomKernel : notevoli migliorie al calcolo lunghezza delle curve di Bezier.
This commit is contained in:
+137
-42
@@ -507,15 +507,70 @@ CurveBezier::GetLength( double& dLen) const
|
||||
return ( GetLengthAtParam( 1, dLen) && dLen > EPS_SMALL) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
double
|
||||
CurveBezier::GetSegmentLength( int nLev, double dU0, double dU1, double dU2,
|
||||
const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) const
|
||||
{
|
||||
const int MAX_LEV = 5 ;
|
||||
const double MAX_ARC = 1.05 ;
|
||||
const double LEN_RATIO = 1.2 ;
|
||||
double dD1 ;
|
||||
double dDa ;
|
||||
double dDb ;
|
||||
double dD2 ;
|
||||
|
||||
|
||||
// algoritmo dell'approssimazione con arco per tre punti di S. Vincent e D. Forsey
|
||||
|
||||
// calcolo delle distanze
|
||||
dD1 = Dist( ptP0, ptP2) ;
|
||||
dDa = Dist( ptP0, ptP1) ;
|
||||
dDb = Dist( ptP1, ptP2) ;
|
||||
dD2 = dDa + dDb ;
|
||||
|
||||
// distanza piccola o massimo livello di recursione, approx arco ok
|
||||
if ( dD2 < EPS_SMALL || nLev == MAX_LEV)
|
||||
return ( dD2 + ( dD2 - dD1) / 3) ;
|
||||
|
||||
// se ci sono anomalie si suddivide
|
||||
if ( dD1 < EPS_SMALL || dD2 / dD1 > MAX_ARC ||
|
||||
dDa < 0.1 * EPS_SMALL || dDb / dDa > LEN_RATIO ||
|
||||
dDb < 0.1 * EPS_SMALL || dDa / dDb > LEN_RATIO) {
|
||||
|
||||
double dUMid ;
|
||||
Point3d ptMid ;
|
||||
|
||||
// prima metà
|
||||
dUMid = 0.5 * ( dU0 + dU1) ;
|
||||
GetPoint( dUMid, ptMid) ;
|
||||
double dD3 = GetSegmentLength( nLev +1, dU0, dUMid, dU1,
|
||||
ptP0, ptMid, ptP1) ;
|
||||
// seconda metà
|
||||
dUMid = 0.5 * ( dU1 + dU2) ;
|
||||
GetPoint( dUMid, ptMid) ;
|
||||
double dD4 = GetSegmentLength( nLev + 1, dU1, dUMid, dU2,
|
||||
ptP1, ptMid, ptP2) ;
|
||||
|
||||
// la lunghezza è la somma delle due
|
||||
return ( dD3 + dD4) ;
|
||||
}
|
||||
|
||||
// caso normale
|
||||
return ( dD2 + ( dD2 - dD1) / 3) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
CurveBezier::GetLengthAtParam( double dU, double& dLen) const
|
||||
{
|
||||
const int NUM_SEG = 50 ;
|
||||
const int NUM_SEG = 16 ;
|
||||
int i ;
|
||||
double dPar ;
|
||||
double dSegLen ;
|
||||
double dUIni ;
|
||||
double dUMid ;
|
||||
double dUFin ;
|
||||
Point3d ptIni ;
|
||||
Point3d ptMid ;
|
||||
Point3d ptFin ;
|
||||
|
||||
|
||||
@@ -535,39 +590,88 @@ CurveBezier::GetLengthAtParam( double dU, double& dLen) const
|
||||
return true ;
|
||||
}
|
||||
|
||||
// approssimo la curva con un numero fisso di segmenti !!! DA MIGLIORARE !!!
|
||||
// parto con un numero fisso di punti e poi affino dove serve
|
||||
dLen = 0 ;
|
||||
for ( i = 0 ; i <= NUM_SEG ; ++ i) {
|
||||
dUIni = PAR_START ;
|
||||
GetPoint( PAR_START, ptIni) ;
|
||||
for ( i = 1 ; i <= NUM_SEG ; ++ i) {
|
||||
// ricavo il punto
|
||||
dPar = i / (double) NUM_SEG ;
|
||||
GetPoint( dPar, ptFin) ;
|
||||
// dal secondo posso calcolare la lunghezza
|
||||
if ( i > 0) {
|
||||
dSegLen = Dist( ptIni, ptFin) ;
|
||||
dLen += dSegLen ;
|
||||
if ( dPar >= dU) {
|
||||
dLen += ( dU - dPar) * NUM_SEG * dSegLen ;
|
||||
break ;
|
||||
}
|
||||
dUFin = i / (double) NUM_SEG * dU ;
|
||||
GetPoint( dUFin, ptFin) ;
|
||||
// se punto dispari
|
||||
if ( ( i % 2) == 1) {
|
||||
// assegno nuovo medio
|
||||
dUMid = dUFin ;
|
||||
ptMid = ptFin ;
|
||||
}
|
||||
// se punto pari, calcolo la lunghezza
|
||||
else {
|
||||
dLen += GetSegmentLength( 0, dUIni, dUMid, dUFin, ptIni, ptMid, ptFin) ;
|
||||
// nuovo iniziale prende i valori del finale
|
||||
dUIni = dUFin ;
|
||||
ptIni = ptFin ;
|
||||
}
|
||||
// nuovo iniziale prende i valori del finale
|
||||
ptIni = ptFin ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
CurveBezier::GetSegmentParam( double dLen, double& dCurrLen, double& dSegLen,
|
||||
double& dUIni, double& dUFin) const
|
||||
{
|
||||
const int NUM_SEG = 16 ;
|
||||
int i ;
|
||||
double dUStart ;
|
||||
double dUEnd ;
|
||||
double dUMid ;
|
||||
Point3d ptIni ;
|
||||
Point3d ptMid ;
|
||||
Point3d ptFin ;
|
||||
|
||||
|
||||
dUStart = dUIni ;
|
||||
dUEnd = dUFin ;
|
||||
GetPoint( dUIni, ptIni) ;
|
||||
for ( i = 1 ; i <= NUM_SEG ; ++ i) {
|
||||
// ricavo il punto
|
||||
dUFin = dUStart + i / (double) NUM_SEG * ( dUEnd - dUStart) ;
|
||||
GetPoint( dUFin, ptFin) ;
|
||||
// se punto dispari
|
||||
if ( ( i % 2) == 1) {
|
||||
// assegno nuovo medio
|
||||
dUMid = dUFin ;
|
||||
ptMid = ptFin ;
|
||||
}
|
||||
// se punto pari, calcolo la lunghezza
|
||||
else {
|
||||
dSegLen = GetSegmentLength( 0, dUIni, dUMid, dUFin, ptIni, ptMid, ptFin) ;
|
||||
if ( ( dCurrLen + dSegLen) >= dLen) {
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
dCurrLen += dSegLen ;
|
||||
// nuovo iniziale prende i valori del finale
|
||||
dUIni = dUFin ;
|
||||
ptIni = ptFin ;
|
||||
}
|
||||
}
|
||||
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
CurveBezier::GetParamAtLength( double dLen, double& dU) const
|
||||
{
|
||||
const int NUM_SEG = 50 ;
|
||||
int i ;
|
||||
double dPar ;
|
||||
double dSegLen ;
|
||||
double dCurrLen ;
|
||||
Point3d ptIni ;
|
||||
Point3d ptFin ;
|
||||
const int NUM_SEG = 16 ;
|
||||
const double MAX_SEG_LEN = 0.2 ;
|
||||
bool bOk ;
|
||||
double dCurrLen ;
|
||||
double dSegLen ;
|
||||
double dUIni ;
|
||||
double dUFin ;
|
||||
|
||||
|
||||
// la curva deve essere validata
|
||||
@@ -580,26 +684,17 @@ CurveBezier::GetParamAtLength( double dLen, double& dU) const
|
||||
return true ;
|
||||
}
|
||||
|
||||
// approssimo la curva con un numero fisso di segmenti !!! DA MIGLIORARE !!!
|
||||
// approfondisco nell'intervallo diinteresse
|
||||
dCurrLen = 0 ;
|
||||
for ( i = 0 ; i <= NUM_SEG ; ++ i) {
|
||||
// ricavo il punto
|
||||
dPar = i / (double) NUM_SEG ;
|
||||
GetPoint( dPar, ptFin) ;
|
||||
// dal secondo posso calcolare la lunghezza
|
||||
if ( i > 0) {
|
||||
dSegLen = Dist( ptIni, ptFin) ;
|
||||
dCurrLen += dSegLen ;
|
||||
if ( dCurrLen >= dLen) {
|
||||
dU = dPar - ( dCurrLen - dLen) / ( dSegLen * NUM_SEG) ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
// nuovo iniziale prende i valori del finale
|
||||
ptIni = ptFin ;
|
||||
}
|
||||
dUIni = PAR_START ;
|
||||
dUFin = PAR_END ;
|
||||
while ( ( bOk = GetSegmentParam( dLen, dCurrLen, dSegLen, dUIni, dUFin)) && dSegLen > MAX_SEG_LEN)
|
||||
;
|
||||
// aggiustamento finale parametro
|
||||
if ( bOk)
|
||||
dU = dUIni + ( dLen - dCurrLen) / dSegLen * ( dUFin - dUIni) ;
|
||||
|
||||
return true ;
|
||||
return bOk ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -86,6 +86,10 @@ class CurveBezier : public ICurveBezier
|
||||
private :
|
||||
bool Validate( void) ;
|
||||
void IncreaseBernsteinOneDegree( double dU, int nDeg, double dBern[]) const ;
|
||||
double GetSegmentLength( int nLev, double dU0, double dU1, double dU2,
|
||||
const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) const ;
|
||||
bool GetSegmentParam( double dLen, double& dCurrLen, double& dSegLen,
|
||||
double& dUIni, double& dUFin) const ;
|
||||
|
||||
private :
|
||||
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;
|
||||
|
||||
Reference in New Issue
Block a user