//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : CurveComposite.cpp Data : 23.11.13 Versione : 1.3a1 // Contenuto : Implementazione della classe CCurveComposite. // // // // Modifiche : 26.04.13 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveComposite.h" #include "GeoObjFactory.h" #include "\EgtDev\Include\EGnStringUtils.h" #include using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( CRV_COMPO, "C_CMP", CurveComposite) ; //---------------------------------------------------------------------------- CurveComposite::CurveComposite( void) : m_nStatus( TO_VERIFY), m_nCounter( 0), m_bClosed( false) { } //---------------------------------------------------------------------------- CurveComposite::~CurveComposite( void) { Clear() ; } //---------------------------------------------------------------------------- bool CurveComposite::Clear( void) { PCRVSMPL_LIST::iterator Iter ; // ciclo di pulizia for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) delete (*Iter) ; m_CrvSmplS.clear() ; m_nCounter = 0 ; m_bClosed = false ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddCurve( const ICurve& cCrv) { // se curva semplice if ( cCrv.IsSimple()) { // creo una copia della curva ICurve* pSmplCrv = GetCurve( cCrv.Clone()) ; if ( pSmplCrv == nullptr) return false ; // inserisco la curva if ( ! AddSimpleCurve( pSmplCrv)) { delete pSmplCrv ; return false ; } } // altrimenti curva composta, devo aggiungere le singole curve semplici else { const ICurveComposite* pCrvCompo ; const ICurve* pCrvOri ; ICurve* pSmplCrv ; // recupero le curve componenti e le inserisco nella lista pCrvCompo = GetCurveComposite( &cCrv) ; if ( pCrvCompo == nullptr) return false ; pCrvOri = pCrvCompo->GetFirstCurve() ; while ( pCrvOri != nullptr) { // creo una copia della curva pSmplCrv = GetCurve( pCrvOri->Clone()) ; if ( pSmplCrv == nullptr) return false ; // inserisco la curva if ( ! AddSimpleCurve( pSmplCrv)) { delete pSmplCrv ; return false ; } // passo alla prossima curva componente pCrvOri = pCrvCompo->GetNextCurve() ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddSimpleCurve( ICurve* pSmplCrv) { Point3d ptStart ; Point3d ptEnd ; // verifico lo stato if ( m_nStatus != OK && ! ( m_nCounter == 0 && m_nStatus == TO_VERIFY)) return false ; // verifico che il parametro sia una curva semplice if ( ! pSmplCrv->IsSimple()) return false ; // recupero i punti iniziali e finali della curva if ( ! pSmplCrv->GetStartPoint( ptStart) || ! pSmplCrv->GetEndPoint( ptEnd)) return false ; // se non č la prima, verifico sia in continuitā con il finale corrente if ( m_nCounter > 0 && ! AreSamePointNear( ptStart, m_PtEnd)) return false ; // se prima curva, assegno il punto iniziale if ( m_nCounter == 0) m_PtStart = ptStart ; // inserisco la curva nella lista m_CrvSmplS.push_back( pSmplCrv) ; m_nCounter ++ ; // assegno il punto finale m_PtEnd = ptEnd ; // aggiorno il flag di curva chiusa m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; // aggiorno lo stato m_nStatus = OK ; return true ; } //---------------------------------------------------------------------------- CurveComposite* CurveComposite::Clone( void) const { CurveComposite* pCrv ; // alloco oggetto pCrv = new(nothrow) CurveComposite ; if ( pCrv != nullptr) *pCrv = *(const_cast(this)) ; return pCrv ; } //---------------------------------------------------------------------------- const string& CurveComposite::GetKey( void) const { return GEOOBJ_GETKEY( CurveComposite) ; } //---------------------------------------------------------------------------- bool CurveComposite::Save( ostream& osOut) const { int i ; string sCrvName ; const ICurve* pCrvSmpl ; // numero di curve osOut << ToString( m_nCounter) << endl ; // ciclo sulle curve componenti i = 0 ; pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { // emetto tipo della curva semplice osOut << pCrvSmpl->GetKey() << endl ; // assegno ed emetto nome della curva semplice sCrvName = "#" + ToString( ++i) ; osOut << sCrvName << endl ; // salvataggio della curva semplice if ( ! pCrvSmpl->Save( osOut)) return false ; // passo alla successiva pCrvSmpl = GetNextCurve() ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Load( Scanner& TheScanner) { int nType ; string sLine ; STRVECTOR vsParams ; bool bOk ; int i ; int nCounter ; IGeoObj* pGeoO ; ICurve* pCrv ; // leggo la prossima linea if ( ! TheScanner.GetLine( sLine)) return false ; // la divido in parametri Tokenize( sLine, ",", vsParams) ; // 1 parametro : numero di curve componenti if ( vsParams.size() != 1) return false ; // recupero il numero di curve componenti if ( ! FromString( vsParams[0], nCounter)) return false ; // leggo le curve componenti for ( i = 0 ; i < nCounter ; ++ i) { // recupero la prossima linea (con il tipo di oggetto) if ( ! TheScanner.GetLine( sLine)) return false ; // creo l'oggetto nType = GEOOBJ_KEYTOTYPE( sLine) ; pGeoO = GEOOBJ_CREATE( nType) ; if ( pGeoO == nullptr) return false ; // recupero la linea con il nome bOk = TheScanner.GetLine( sLine) ; // ne leggo i dati bOk = bOk && pGeoO->Load( TheScanner) ; // verifico sia una curva pCrv = ::GetCurve( pGeoO) ; bOk = bOk && ( pCrv != nullptr && pCrv->IsSimple()) ; // aggiungo questa curva (sicuramente semplice) bOk = bOk && AddSimpleCurve( pCrv) ; // se errore if ( ! bOk) { delete pGeoO ; return false ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetLocalBBox( BBox3d& b3Loc) const { // verifico lo stato if ( m_nStatus != OK) return false ; // inizializzo il box b3Loc.Reset() ; // ciclo sulle curve componenti const ICurve* pCrvSmpl ; pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { BBox3d b3Crv ; // recupero il box della curva pCrvSmpl->GetLocalBBox( b3Crv) ; // aggiorno il box b3Loc.Add( b3Crv) ; // passo alla curva successiva pCrvSmpl = GetNextCurve() ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetBBox( const Frame3d& frRef, BBox3d& b3Ref) const { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validitā del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // inizializzo il box b3Ref.Reset() ; // ciclo sulle curve componenti const ICurve* pCrvSmpl ; pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { BBox3d b3Crv ; // recupero il box della curva pCrvSmpl->GetBBox( frRef, b3Crv) ; // aggiorno il box b3Ref.Add( b3Crv) ; // passo alla curva successiva pCrvSmpl = GetNextCurve() ; } return true ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Validate( void) { if ( m_nStatus == TO_VERIFY) { int nCount ; Point3d ptPrevEnd ; Point3d ptStart ; PCRVSMPL_LIST::const_iterator Iter ; // ciclo su tutte le curve nCount = 0 ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // verifico validitā della curva e sua semplicitā if ( ! (*Iter)->IsValid() || (*Iter)->GetType() == CRV_COMPO) { m_nStatus = ERR ; return false ; } // incremento contatore ++ nCount ; // verifico continuitā con la precedente (se non č la prima) if ( nCount > 1) { (*Iter)->GetStartPoint( ptStart) ; if ( ! AreSamePointNear( ptPrevEnd, ptStart)) { m_nStatus = ERR ; return false ; } } // recupero il punto finale (*Iter)->GetEndPoint( ptPrevEnd) ; } // aggiorno m_nStatus = OK ; m_nCounter = nCount ; m_CrvSmplS.front()->GetStartPoint( m_PtStart) ; m_CrvSmplS.back()->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; } return ( m_nStatus == OK) ; } //---------------------------------------------------------------------------- bool CurveComposite::GetStartPoint( Point3d& ptStart) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno il punto ptStart = m_PtStart ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetEndPoint( Point3d& ptEnd) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno il punto ptEnd = m_PtEnd ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetDomain( double& dStart, double& dEnd) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno gli estremi del dominio dStart = 0 ; dEnd = m_nCounter ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const { PCRVSMPL_LIST::const_iterator Iter ; // il parametro U deve essere compreso tra 0 e m_nCounter if ( dU < ( 0 + EPS_ZERO)) { dU = 0 ; nS = ICurve::FROM_PLUS ; } else if ( dU > ( m_nCounter - EPS_ZERO)) { dU = m_nCounter ; nS = ICurve::FROM_MINUS ; } // determino la curva di appartenenza e faccio eseguire il calcolo for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // ogni curva semplice ha parametro compreso tra 0 e 1 // se nella parametrizzazione della curva semplice, oppure all'estremo superiore e dal basso if ( dU < ( 1 - EPS_ZERO) || ( fabs( dU - 1) < EPS_ZERO && nS == ICurve::FROM_MINUS)) return (*Iter)->GetPointD1D2( dU, ICurve::FROM_MINUS, ptPos, pvtDer1, pvtDer2) ; else dU -= 1 ; } return false ; } //---------------------------------------------------------------------------- bool CurveComposite::GetLength( double& dLen) const { double dLenCrvSmpl ; PCRVSMPL_LIST::const_iterator Iter ; // ciclo di calcolo dLen = 0 ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { if ( (*Iter)->GetLength( dLenCrvSmpl)) dLen += dLenCrvSmpl ; else return false ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { bool bFirst ; double dStartPar ; Point3d ptP ; PolyLine PLSmpl ; PCRVSMPL_LIST::const_iterator Iter ; bFirst = true ; dStartPar = 0 ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // recupero approssimazione per curva semplice if ( ! (*Iter)->ApproxWithLines( dLinTol, dAngTolDeg, PLSmpl)) return false ; // la accodo opportunamente a quella della curva composita if ( bFirst) { PL.Splice( PLSmpl) ; bFirst = false ; } else { PLSmpl.EraseFirstUPoint() ; PLSmpl.AddOffsetToU( dStartPar) ; PL.Splice( PLSmpl) ; } // incremento inizio parametro per prossima curva semplice dStartPar += 1 ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Invert( void) { PCRVSMPL_LIST::iterator Iter ; // inverto le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Invert() ; // inverto l'ordine della lista m_CrvSmplS.reverse() ; // scambio punti iniziale e finale swap( m_PtStart, m_PtEnd) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimStartAtParam( double dUTrim) { double dParStart ; double dParEnd ; double dUToTrim ; PCRVSMPL_LIST::iterator Iter ; // ciclo sulle diverse curve dall'inizio dUToTrim = dUTrim ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // dominio parametrico della curva semplice (*Iter)->GetDomain( dParStart, dParEnd) ; // lunghezza parametrica progressiva dUToTrim -= ( dParEnd - dParStart) ; // se lunghezza ancora da tagliare non nulla if ( dUToTrim > EPS_ZERO) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; } // se lunghezza ancora da tagliare nulla (entro la tolleranza) else if ( dUToTrim > - EPS_ZERO) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; if ( m_nCounter == 0) return false ; (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; break ; } // altrimenti superata lunghezza ancora da tagliare else { if ( ! (*Iter)->TrimStartAtParam( 1 + dUToTrim)) { m_nStatus = ERR ; return false ; } (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; break ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimEndAtParam( double dUTrim) { bool bToErase ; double dParStart ; double dParEnd ; double dUToTrim ; PCRVSMPL_LIST::iterator Iter ; // ciclo sulle diverse curve dalla fine bToErase = false ; dUToTrim = dUTrim ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // dominio parametrico della curva semplice (*Iter)->GetDomain( dParStart, dParEnd) ; // lunghezza parametrica progressiva dUToTrim -= ( dParEnd - dParStart) ; // se da cancellare if ( bToErase) { // cancello l'entitā, la tolgo dalla lista e passo alla successiva delete (*Iter) ; Iter = m_CrvSmplS.erase( Iter) ; // decremento il numero di entitā m_nCounter -- ; } // se lunghezza parametrica ancora da tagliare non nulla else if ( dUToTrim > EPS_ZERO) { Iter ++ ; } // se lunghezza parametrica ancora da tagliare nulla (entro la tolleranza) else if ( dUToTrim > - EPS_ZERO) { // imposto punto finale e verifico curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; // passo alla entitā successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } // altrimenti superata lunghezza parametrica ancora da tagliare else { // trimmo la curva semplice if ( ! (*Iter)->TrimEndAtParam( 1 + dUToTrim)) { m_nStatus = ERR ; return false ; } // imposto punto finale e verifica curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; // passo alla entitā successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimStartAtLen( double dLenTrim) { double dLenToTrim ; double dCrvLen ; PCRVSMPL_LIST::iterator Iter ; // ciclo sulle diverse curve dall'inizio dLenToTrim = dLenTrim ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // lunghezza della curva if ( ! (*Iter)->GetLength( dCrvLen)) return false ; // lunghezza progressiva dLenToTrim -= dCrvLen ; // se lunghezza ancora da tagliare non nulla if ( dLenToTrim > EPS_SMALL) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; } // se lunghezza ancora da tagliare nulla (entro la tolleranza) else if ( dLenToTrim > - EPS_SMALL) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; if ( m_nCounter == 0) return false ; (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; break ; } // altrimenti superata lunghezza ancora da tagliare else { if ( ! (*Iter)->TrimStartAtLen( dCrvLen + dLenToTrim)) { m_nStatus = ERR ; return false ; } (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; break ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimEndAtLen( double dLenTrim) { bool bToErase ; double dLenToTrim ; double dCrvLen ; PCRVSMPL_LIST::iterator Iter ; // ciclo sulle diverse curve dalla fine bToErase = false ; dLenToTrim = dLenTrim ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // se non sono giā nella zona da cancellare, aggiorno lunghezze if ( ! bToErase) { // lunghezza della curva if ( ! (*Iter)->GetLength( dCrvLen)) return false ; // lunghezza progressiva dLenToTrim -= dCrvLen ; } // se da cancellare if ( bToErase) { // cancello l'entitā, la tolgo dalla lista e passo alla successiva delete (*Iter) ; Iter = m_CrvSmplS.erase( Iter) ; // decremento il numero di entitā m_nCounter -- ; } // se lunghezza ancora da tagliare non nulla else if ( dLenToTrim > EPS_SMALL) { // passo alla entitā successiva ++ Iter ; } // se lunghezza ancora da tagliare nulla (entro la tolleranza) else if ( dLenToTrim > - EPS_SMALL) { // imposto punto finale e verifica curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; // passo alla entitā successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } // altrimenti superata lunghezza ancora da tagliare else { // trimmo la curva semplice if ( ! (*Iter)->TrimEndAtLen( dCrvLen + dLenToTrim)) { m_nStatus = ERR ; return false ; } // imposto punto finale e verifica curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ; // passo alla entitā successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Translate( const Vector3d& vtMove) { PCRVSMPL_LIST::iterator Iter ; // traslo le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Translate( vtMove) ; // traslo i punti estremi m_PtStart.Translate( vtMove) ; m_PtEnd.Translate( vtMove) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { PCRVSMPL_LIST::iterator Iter ; // verifico validitā dell'asse di rotazione if ( vtAx.IsSmall()) return false ; // ruoto le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Rotate( ptAx, vtAx, dCosAng, dSinAng) ; // ruoto i punti estremi m_PtStart.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; m_PtEnd.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Scale( const Point3d& ptCen, double dCoeffX, double dCoeffY, double dCoeffZ) { PCRVSMPL_LIST::iterator Iter ; // ammessa solo scalatura uniforme (per la presenza di archi) if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( dCoeffX - dCoeffZ) > EPS_SMALL) return false ; // verifico non sia nulla if ( fabs( dCoeffX) < EPS_ZERO) return false ; // scalo le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ; // scalo i punti estremi m_PtStart.Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ; m_PtEnd.Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveComposite::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { PCRVSMPL_LIST::iterator Iter ; // verifico validitā del piano di specchiatura if ( vtNorm.IsSmall()) return false ; // specchio le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Mirror( ptOn, vtNorm) ; // specchio i punti estremi m_PtStart.Mirror( ptOn, vtNorm) ; m_PtEnd.Mirror( ptOn, vtNorm) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ToGlob( const Frame3d& frRef) { PCRVSMPL_LIST::iterator Iter ; // verifico validitā del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // trasformo le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->ToGlob( frRef) ; // trasformo i punti estremi m_PtStart.ToGlob( frRef) ; m_PtEnd.ToGlob( frRef) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ToLoc( const Frame3d& frRef) { PCRVSMPL_LIST::iterator Iter ; // verifico validitā del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // trasformo le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->ToLoc( frRef) ; // trasformo i punti estremi m_PtStart.ToLoc( frRef) ; m_PtEnd.ToLoc( frRef) ; return true ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetFirstCurve( void) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // vado all'inizio *(const_cast (&m_Iter)) = m_CrvSmplS.begin() ; // recupero la curva if ( m_Iter != m_CrvSmplS.end()) return (*m_Iter) ; else return nullptr ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetNextCurve( void) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // vado al successivo (*(const_cast (&m_Iter))) ++ ; // recupero la curva if ( m_Iter != m_CrvSmplS.end()) return (*m_Iter) ; else return nullptr ; } //---------------------------------------------------------------------------- bool CurveComposite::IsParamAtJoint( double dU) const { // se all'inizio, alla fine o lontano dagli interi if ( fabs( dU) < EPS_ZERO || fabs( dU - m_nCounter) < EPS_ZERO || fabs( dU - (int) ( dU + EPS_ZERO)) > EPS_ZERO) return false ; else return true ; }