//---------------------------------------------------------------------------- // 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 #include "\EgtDev\Include\EGnStringUtils.h" #include "CurveComposite.h" #include "GeoObjFactory.h" using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( CRV_COMPO, "C_CMP", CurveComposite) ; //---------------------------------------------------------------------------- const double CurveComposite::PAR_START = 0 ; //---------------------------------------------------------------------------- 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::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 = PAR_START ; dEnd = m_nCounter ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetPointD1D2( double dU, Point3d& ptPos, Vector3d& vtDer1, Vector3d& vtDer2) const { PCRVSMPL_LIST::const_iterator Iter ; // il parametro U deve essere compreso tra 0 e m_nCounter if ( dU < PAR_START) dU = PAR_START ; else if ( dU > m_nCounter) dU = m_nCounter ; // determino la curva di appartenenza e faccio eseguire il calcolo for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { if ( dU <= 1) return (*Iter)->GetPointD1D2( dU, ptPos, vtDer1, vtDer2) ; 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::Reverse( void) { PCRVSMPL_LIST::iterator Iter ; // inverto le singole curve for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Reverse() ; // 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 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 sempre 1 // lunghezza parametrica progressiva dUToTrim -= 1 ; // 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 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 delle curve semplici sempre 1 // lunghezza parametrica progressiva dUToTrim -= 1 ; // 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 ; }