Files
EgtGeomKernel/CurveBezier.cpp
T
2013-12-24 22:09:55 +00:00

1082 lines
29 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2013
//----------------------------------------------------------------------------
// File : CurveBezier.cpp Data : 22.11.13 Versione : 1.3a1
// Contenuto : Implementazione della classe Curva di Bezier.
//
//
//
// Modifiche : 28.12.12 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "DllMain.h"
#include "CurveBezier.h"
#include "GeoObjFactory.h"
#include "\EgtDev\Include\EGnStringUtils.h"
#include "\EgtDev\Include\EGkCurveArc.h"
#include "\EgtDev\Include\EGkDistPointLine.h"
#include <new>
using namespace std ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( CRV_BEZ, "C_BEZ", CurveBezier) ;
//----------------------------------------------------------------------------
const double CurveBezier::PAR_START = 0 ;
const double CurveBezier::PAR_END = 1 ;
//----------------------------------------------------------------------------
CurveBezier::CurveBezier( void)
{
m_nDeg = 0 ;
m_bRat = false ;
m_nDimArr = 0 ;
m_aPtCtrl = nullptr ;
m_aWeCtrl = nullptr ;
m_nStatus = TO_VERIFY ;
}
//----------------------------------------------------------------------------
CurveBezier::~CurveBezier( void)
{
if ( m_nDimArr > 0) {
delete [] m_aPtCtrl ;
delete [] m_aWeCtrl ;
}
m_nDimArr = 0 ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Init( int nDeg, bool bIsRational)
{
const int MINDIM = 4 ;
// verifico validità grado
if ( nDeg < 1 || nDeg > MAXDEG)
return false ;
// se spazio dinamico sufficiente
if ( ( nDeg + 1) <= m_nDimArr)
;
// se altrimenti spazio statico sufficiente
else if ( ( nDeg + 1) <= ST_PTC) {
m_aPtCtrl = m_aStPtCtrl ;
if ( bIsRational)
m_aWeCtrl = m_aStWeCtrl ;
}
// altrimenti
else {
// se necessaria, pulizia
if ( m_nDimArr > 0) {
delete [] m_aPtCtrl ;
delete [] m_aWeCtrl ;
}
// alloco punti
m_aPtCtrl = new Point3d [ nDeg + 1] ;
if ( m_aPtCtrl == nullptr)
return false ;
// se razionale, alloco pesi
if ( bIsRational) {
m_aWeCtrl = new double [ nDeg + 1] ;
if ( m_aWeCtrl == nullptr) {
delete [] m_aPtCtrl ;
return false ;
}
}
// salvo dimensione array allocati
m_nDimArr = nDeg + 1 ;
}
// salvo il grado
m_nDeg = nDeg ;
// salvo flag di razionale
m_bRat = bIsRational ;
// pulisco, assegnando 0 ai punti e 1 ai pesi
memset( m_aPtCtrl, 0, sizeof( Point3d) * ( m_nDeg + 1)) ;
if ( m_bRat) {
for ( int i = 0 ; i <= m_nDeg ; ++ i)
m_aWeCtrl[i] = 1 ;
}
m_nStatus = TO_VERIFY ;
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl)
{
// verifico validità indice
if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd > m_nDeg)
return false ;
// assegno il valore
m_aPtCtrl[nInd] = ptCtrl ;
// se razionale, metto il peso a 1
if ( m_bRat)
m_aWeCtrl[nInd] = 1 ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW)
{
// verifico validità, razionalità e indice
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg)
return false ;
// verifico che il peso non sia nullo o negativo
if ( dW < EPS_SMALL)
return false ;
// assegno il valore e il peso
m_aPtCtrl[nInd] = ptCtrl ;
m_aWeCtrl[nInd] = dW ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::SetFromArc( const ICurveArc& crArc)
{
double dAngCen ;
double dCosAhalf ;
Point3d ptStart ;
Point3d ptEnd ;
Point3d ptMed ;
Point3d ptNew ;
Vector3d vtDir ;
if ( ! crArc.IsValid())
return false ;
dAngCen = crArc.GetAngCenter() ;
if ( fabs( dAngCen) > 120.0)
return false ;
dCosAhalf = cos( 0.5 * dAngCen * DEGTORAD) ;
crArc.GetStartPoint( ptStart) ;
crArc.GetEndPoint( ptEnd) ;
ptMed = Media( ptStart, ptEnd, 0.5) ;
vtDir = ptMed - crArc.GetCenter() ;
ptNew = crArc.GetCenter() + vtDir / ( dCosAhalf * dCosAhalf) ;
Init( 2, true ) ;
SetControlPoint( 0, ptStart, 1) ;
SetControlPoint( 1, ptNew, dCosAhalf) ;
SetControlPoint( 2, ptEnd, 1) ;
return true ;
}
//----------------------------------------------------------------------------
const Point3d&
CurveBezier::GetControlPoint( int nInd, bool* pbOk) const
{
// verifico validità e indice
if ( m_nStatus != OK || nInd < 0 || nInd > m_nDeg) {
if ( pbOk != NULL)
*pbOk = false ;
return ORIG ;
}
// ritorno i dati
if ( pbOk != NULL)
*pbOk = true ;
return m_aPtCtrl[nInd] ;
}
//----------------------------------------------------------------------------
double
CurveBezier::GetControlWeight( int nInd, bool* pbOk) const
{
// verifico validità, razionalità e indice
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg) {
if ( pbOk != NULL)
*pbOk = false ;
return 0 ;
}
// ritorno i dati
if ( pbOk != NULL)
*pbOk = true ;
return m_aWeCtrl[nInd] ;
}
//----------------------------------------------------------------------------
CurveBezier*
CurveBezier::Clone( void) const
{
CurveBezier* pCrv ;
// alloco oggetto
pCrv = new(nothrow) CurveBezier ;
if ( pCrv != nullptr)
*pCrv = *(const_cast<CurveBezier*>(this)) ;
return pCrv ;
}
//----------------------------------------------------------------------------
const string&
CurveBezier::GetKey( void) const
{
return GEOOBJ_GETKEY( CurveBezier) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Save( ostream& osOut) const
{
int i ;
// flag razionale
osOut << m_bRat ;
// dati della curva di bezier
osOut << ";" << ToString( m_nDeg) ;
// ciclo sui punti di controllo ( con pesi se razionale)
for ( i = 0 ; i <= m_nDeg ; ++ i) {
osOut << ";" << ToString( m_aPtCtrl[i]) ;
if ( m_bRat) {
osOut << "," << ToString( m_aWeCtrl[i]) ;
}
}
// terminazione
osOut << ";" << endl ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Load( Scanner& TheScanner)
{
string sLine ;
STRVECTOR vsParams ;
bool bIsRat ;
int nDeg ;
Point3d ptP ;
double dW ;
int i ;
// leggo la prossima linea
if ( ! TheScanner.GetLine( sLine))
return false ;
// la divido in parametri
Tokenize( sLine, ";", vsParams) ;
// almeno 2 parametri : flag razionale e grado
if ( vsParams.size() < 2)
return false ;
// recupero il flag
if ( ! FromString( vsParams[0], bIsRat))
return false ;
// recupero il grado
if ( ! FromString( vsParams[1], nDeg))
return false ;
// ri-controllo il numero dei parametri
if ( vsParams.size() != ( 2 + ( nDeg + 1)))
return false ;
// inizializzo la curva di Bezier
if ( ! Init( nDeg, bIsRat))
return false ;
// se integrale
if ( ! bIsRat) {
// recupero e setto punti di controllo
for ( i = 0 ; i <= nDeg ; ++ i) {
if ( ! FromString( vsParams[i+2], ptP) ||
! SetControlPoint( i, ptP))
return false ;
}
}
// altrimenti razionale
else {
// recupero e setto punti di controllo
for ( i = 0 ; i <= nDeg ; ++ i) {
if ( ! FromString( vsParams[i+2], ptP, dW) ||
! SetControlPoint( i, ptP, dW))
return false ;
}
}
// eseguo validazione
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Validate( void)
{
if ( m_nStatus == TO_VERIFY)
m_nStatus = ( ( m_nDeg > 0 && m_aPtCtrl != nullptr) ? OK : ERR) ;
return ( m_nStatus == OK) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetStartPoint( Point3d& ptStart) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptStart = m_aPtCtrl[0] ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetEndPoint( Point3d& ptEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptEnd = m_aPtCtrl[m_nDeg] ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetDomain( double& dStart, double& dEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno gli estremi del dominio
dStart = PAR_START ;
dEnd = PAR_END ;
return true ;
}
//----------------------------------------------------------------------------
// Calcolo i polinomi di Bernstein e da questi il punto ( vedi Piegl-Tiller)
//----------------------------------------------------------------------------
bool
CurveBezier::GetPointD1D2( double dU, Point3d& ptPos, Vector3d& vtDer1, Vector3d& vtDer2) const
{
int i ;
double dBern[MAXDEG] ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// il parametro U deve essere compreso tra 0 e 1
if ( dU < PAR_START)
dU = PAR_START ;
else if ( dU > PAR_END)
dU = PAR_END ;
// se forma polinomiale (o integrale)
if ( ! m_bRat) {
// calcolo dei polinomi di Bernstein di grado opportuno
dBern[0] = 1 ;
for ( i = 1 ; i <= m_nDeg - 2 ; ++ i)
IncreaseBernsteinOneDegree( dU, i, dBern) ;
// calcolo della derivata seconda
vtDer2.Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg - 2 ; ++ i) {
vtDer2 = vtDer2 + dBern[i] * ( m_aPtCtrl[i+2] + m_aPtCtrl[i] - 2 * m_aPtCtrl[i+1]) ;
}
vtDer2 = m_nDeg * ( m_nDeg - 1) * vtDer2 ;
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg - 1, dBern) ;
// calcolo della derivata prima
vtDer1.Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg - 1 ; ++ i) {
vtDer1 = vtDer1 + dBern[i] * ( m_aPtCtrl[i+1] - m_aPtCtrl[i]) ;
}
vtDer1 = m_nDeg * vtDer1 ;
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg, dBern) ;
// calcolo del punto
ptPos.Set( 0, 0, 0) ;
for ( i = 0 ; i <= m_nDeg ; ++ i)
ptPos = ptPos + dBern[i] * m_aPtCtrl[i] ;
}
// altrimenti forma razionale
else {
double dW ;
double dW1 ;
double dW2 ;
double dInvW ;
Point3d aPtWCtrl[MAXDEG] ;
Vector3d vtPos ;
// porto i punti in forma omogenea moltiplicandoli per i pesi
for ( i = 0 ; i <= m_nDeg ; ++ i)
aPtWCtrl[i] = m_aWeCtrl[i] * m_aPtCtrl[i] ;
// calcolo dei polinomi di Bernstein di grado opportuno
dBern[0] = 1 ;
for ( i = 1 ; i <= m_nDeg - 2 ; ++ i)
IncreaseBernsteinOneDegree( dU, i, dBern) ;
// calcolo della derivata seconda
vtDer2.Set( 0, 0, 0) ; dW2 = 0 ;
for ( i = 0 ; i <= m_nDeg - 2 ; ++ i) {
vtDer2 = vtDer2 + dBern[i] * ( aPtWCtrl[i+2] + aPtWCtrl[i] - 2 * aPtWCtrl[i+1]) ;
dW2 = dW2 + dBern[i] * ( m_aWeCtrl[i+2] + m_aWeCtrl[i] - 2 * m_aWeCtrl[i+1]) ;
}
vtDer2 = m_nDeg * ( m_nDeg - 1) * vtDer2 ;
dW2 = m_nDeg * ( m_nDeg - 1) * dW2 ;
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg - 1, dBern) ;
// calcolo della derivata prima
vtDer1.Set( 0, 0, 0) ; dW1 = 0 ;
for ( i = 0 ; i <= m_nDeg - 1 ; ++ i) {
vtDer1 = vtDer1 + dBern[i] * ( aPtWCtrl[i+1] - aPtWCtrl[i]) ;
dW1 = dW1 + dBern[i] * ( m_aWeCtrl[i+1] - m_aWeCtrl[i]) ;
}
vtDer1 = m_nDeg * vtDer1 ;
dW1 = m_nDeg * dW1 ;
// aumento il grado
IncreaseBernsteinOneDegree( dU, m_nDeg, dBern) ;
// calcolo del punto
ptPos.Set( 0, 0, 0) ; dW = 0 ;
for ( i = 0 ; i <= m_nDeg ; ++ i) {
ptPos = ptPos + dBern[i] * aPtWCtrl[i] ;
dW = dW + dBern[i] * m_aWeCtrl[i] ;
}
// ritrasformo da forma omogenea a forma standard
dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
ptPos = ptPos * dInvW ;
vtPos.Set( ptPos.x, ptPos.y, ptPos.z) ;
vtDer1 = ( vtDer1 - dW1 * vtPos) * dInvW ;
vtDer2 = ( vtDer2 - 2 * dW1 * vtDer1 - dW2 * vtPos) * dInvW ;
}
return true ;
}
//----------------------------------------------------------------------------
void
CurveBezier::IncreaseBernsteinOneDegree( double dU, int nDeg, double dBern[]) const
{
int j ;
double dU1 ;
double dTot ;
double dTmp ;
dU1 = 1 - dU ;
dTot = 0 ;
for ( j = 0 ; j < nDeg ; ++ j) {
dTmp = dBern[j] ;
dBern[j] = dTot + dU1 * dTmp ;
dTot = dU * dTmp ;
}
dBern[nDeg] = ( nDeg > 0 ? dTot : 1) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::GetControlPolygonLength( double& dLen) const
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// ciclo sui punti di controllo
dLen = 0 ;
for ( i = 1 ; i <= m_nDeg ; ++ i)
dLen += Dist( m_aPtCtrl[i], m_aPtCtrl[i-1]) ;
return true ;
}
//----------------------------------------------------------------------------
bool
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 = 10 ;
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
// verifica superamento del massimo livello di recursione per debug
if ( nLev >= MAX_LEV)
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
// 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 = 16 ;
int i ;
double dUIni ;
double dUMid ;
double dUFin ;
Point3d ptIni ;
Point3d ptMid ;
Point3d ptFin ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// fuori dominio del parametro -> errore
if ( dU < PAR_START - EPS_ZERO)
return false ;
if ( dU > ( PAR_END + EPS_ZERO))
return false ;
// inizio
if ( dU < PAR_START + EPS_ZERO) {
dLen = 0 ;
return true ;
}
// parto con un numero fisso di punti e poi affino dove serve
dLen = 0 ;
dUIni = PAR_START ;
GetPoint( PAR_START, ptIni) ;
for ( i = 1 ; i <= NUM_SEG ; ++ i) {
// ricavo il punto
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 ;
}
}
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 = 16 ;
const double MAX_SEG_LEN = 0.2 ;
bool bOk ;
double dCurrLen ;
double dSegLen ;
double dUIni ;
double dUFin ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// inizio
if ( dLen < EPS_SMALL) {
dU = PAR_START ;
return true ;
}
// approfondisco nell'intervallo diinteresse
dCurrLen = 0 ;
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 bOk ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart, double dParEnd,
double dLinTol, double dAngTolDeg, PolyLine& PL) const
{
const int MAX_LEV = 10 ;
int i ;
double dMaxSqDist ;
double dSqDist ;
double dAngDeg ;
double dPolLen ;
Point3d ptLast ;
Vector3d vtDirI ;
Vector3d vtDirF ;
DistPointLine dstPL ;
// se raggiunto il massimo livello di recursione ...
if ( nLev >= MAX_LEV) {
// segnalo situazione per debug
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
// considero la curva piatta (inserisco il punto se abbastanza lontano dal precedente) ed esco
PL.GetLastPoint( ptLast) ;
if ( SqDist( ptLast, crvBez.m_aPtCtrl[m_nDeg]) > ( dLinTol * dLinTol))
PL.AddUPoint( dParEnd, crvBez.m_aPtCtrl[m_nDeg]) ;
return true ;
}
// massima distanza al quadrato dei punti di controllo intermedi dalla linea tra primo e ultimo
dMaxSqDist = 0 ;
dstPL.SetLine( crvBez.m_aPtCtrl[0], crvBez.m_aPtCtrl[m_nDeg], true) ;
for ( i = 1 ; i < m_nDeg ; i ++) {
dstPL.SetPoint( crvBez.m_aPtCtrl[i]) ;
dSqDist = dstPL.GetSqDist() ;
if ( dSqDist > dMaxSqDist)
dMaxSqDist = dSqDist ;
}
// se distanza entro tolleranza
if ( dMaxSqDist <= ( dLinTol * dLinTol)) {
// deviazione angolare tra primo e ultimo tratto del poligono di controllo (grado >= 1)
vtDirI = crvBez.m_aPtCtrl[1] - crvBez.m_aPtCtrl[0] ;
vtDirF = crvBez.m_aPtCtrl[m_nDeg] - crvBez.m_aPtCtrl[m_nDeg-1] ;
vtDirI.GetAngle( vtDirF, dAngDeg) ;
// se deviazione angolare entro tolleranza oppure lunghezza poligono controllo entro tolleranza
if ( fabs( dAngDeg) <= dAngTolDeg ||
( crvBez.GetControlPolygonLength( dPolLen) && dPolLen <= dLinTol)) {
// considero la curva piatta (inserisco il punto se abbastanza lontano dal precedente) ed esco
PL.GetLastPoint( ptLast) ;
if ( SqDist( ptLast, crvBez.m_aPtCtrl[m_nDeg]) > ( dLinTol * dLinTol))
PL.AddUPoint( dParEnd, crvBez.m_aPtCtrl[m_nDeg]) ;
return true ;
}
}
// curva da dividere
{
double dParMid ;
CurveBezier crvBez1 ;
// parametro a metà
dParMid = 0.5 * ( dParStart + dParEnd) ;
// prima metà
crvBez1 = crvBez ;
crvBez1.TrimEndAtParam( 0.5) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParStart, dParMid, dLinTol, dAngTolDeg, PL))
return false ;
// seconda metà
crvBez1 = crvBez ;
crvBez1.TrimStartAtParam( 0.5) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParMid, dParEnd, dLinTol, dAngTolDeg, PL))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const
{
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// se di primo grado, basta inserire gli estremi
if ( m_nDeg == 1) {
PL.AddUPoint( 0, m_aPtCtrl[0]) ;
PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ;
return true ;
}
// limiti minimi su tolleranza e deviazione angolare
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
// inserisco il punto iniziale
PL.AddUPoint( 0, m_aPtCtrl[0]) ;
// verifico se va divisa
FlatOrSplit( 0, *this, PAR_START, PAR_END, dLinTol, dAngTolDeg, PL) ;
// se è stato inserito un solo punto, aggiungo il finale
if ( PL.GetPointNbr() == 1)
PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Reverse( void)
{
int i ;
int nMid ;
Point3d ptTemp ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// inverto i punti di controllo
nMid = ( m_nDeg + 1) / 2 ;
for ( i = 0 ; i < nMid ; ++ i) {
ptTemp = m_aPtCtrl[i] ;
m_aPtCtrl[i] = m_aPtCtrl[m_nDeg-i] ;
m_aPtCtrl[m_nDeg-i] = ptTemp ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimStartAtParam( double dUTrim)
{
int i ;
int k ;
// se devo togliere dall'inizio o prima non tolgo niente
if ( dUTrim <= PAR_START)
return true ;
// se devo togliere a partire dalla fine o dopo non rimane niente
if ( dUTrim >= PAR_END)
return false ;
// eseguo il trim (algoritmo di de Casteljau)
for ( k = 1 ; k <= m_nDeg ; k ++) {
for ( i = 0 ; i <= m_nDeg - k ; i ++) {
if ( ! m_bRat) {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i] + dUTrim * m_aPtCtrl[i+1] ;
}
else {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i] * m_aWeCtrl[i] + dUTrim * m_aPtCtrl[i+1] * m_aWeCtrl[i+1] ;
m_aWeCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i] + dUTrim * m_aWeCtrl[i+1] ;
m_aPtCtrl[i] = m_aPtCtrl[i] * ( 1 / m_aWeCtrl[i]) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimEndAtParam( double dUTrim)
{
int i ;
int k ;
// se devo togliere a partire dall'inizio o prima non rimane niente
if ( dUTrim <= PAR_START)
return false ;
// se devo togliere dalla fine o dopo non tolgo niente
if ( dUTrim >= PAR_END)
return true ;
// eseguo il trim (algoritmo di de Casteljau)
for ( k = 1 ; k <= m_nDeg ; k ++) {
for ( i = m_nDeg ; i >= k ; i --) {
if ( ! m_bRat) {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i-1] + dUTrim * m_aPtCtrl[ i] ;
}
else {
m_aPtCtrl[i] = ( 1 - dUTrim) * m_aPtCtrl[i-1] * m_aWeCtrl[i-1] + dUTrim * m_aPtCtrl[ i] * m_aWeCtrl[ i] ;
m_aWeCtrl[i] = ( 1 - dUTrim) * m_aWeCtrl[i-1] + dUTrim * m_aWeCtrl[ i] ;
m_aPtCtrl[i] = m_aPtCtrl[i] * ( 1 / m_aWeCtrl[i]) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimStartAtLen( double dLenTrim)
{
double dUTrim ;
// lunghezze negative vengono considerate nulle
dLenTrim = __max( dLenTrim, 0) ;
// converto le lunghezze in valori parametrici
if ( ! GetParamAtLength( dLenTrim, dUTrim))
return false ;
// utilizzo il trim sui parametri
return TrimStartAtParam( dUTrim) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::TrimEndAtLen( double dLenTrim)
{
double dUTrim ;
// lunghezze negative vengono considerate nulle
dLenTrim = __max( dLenTrim, 0) ;
// converto le lunghezze in valori parametrici
if ( ! GetParamAtLength( dLenTrim, dUTrim))
return false ;
// utilizzo il trim sui parametri
return TrimEndAtParam( dUTrim) ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Translate( const Vector3d& vtMove)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// traslo i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Translate( vtMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// ruoto i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Scale( const Point3d& ptCen, double dCoeffX, double dCoeffY, double dCoeffZ)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico non sia nulla
if ( fabs( dCoeffX) < EPS_ZERO && fabs( dCoeffY) < EPS_ZERO && fabs( dCoeffZ) < EPS_ZERO)
return false ;
// scalo i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Scale( ptCen, dCoeffX, dCoeffY, dCoeffZ) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// specchio i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].Mirror( ptOn, vtNorm) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ToGlob( const Frame3d& frRef)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].ToGlob( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ToLoc( const Frame3d& frRef)
{
int i ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo i punti di controllo
for ( i = 0 ; i <= m_nDeg ; ++ i)
m_aPtCtrl[i].ToLoc( frRef) ;
return true ;
}