//---------------------------------------------------------------------------- // 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 "DistPointCrvComposite.h" #include "CurveLine.h" #include "CurveArc.h" #include "CurveBezier.h" #include "PolygonPlane.h" #include "GeoConst.h" #include "GeoObjFactory.h" #include "NgeWriter.h" #include "NgeReader.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( CRV_COMPO, NGE_C_CMP, CurveComposite) ; //---------------------------------------------------------------------------- CurveComposite::CurveComposite( void) : m_nStatus( TO_VERIFY), m_nCounter(), m_bClosed( false), m_VtExtr(), m_dThick(), m_nTempProp() { } //---------------------------------------------------------------------------- CurveComposite::~CurveComposite( void) { Clear() ; } //---------------------------------------------------------------------------- bool CurveComposite::Clear( void) { // ciclo di pulizia PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) delete (*Iter) ; m_CrvSmplS.clear() ; m_nStatus = TO_VERIFY ; m_nCounter = 0 ; m_bClosed = false ; m_VtExtr = V_NULL ; m_dThick = 0 ; m_nTempProp = 0 ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart, double dLinTol) { // 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, bEndOrStart, dLinTol)) 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 = ( bEndOrStart ? pCrvCompo->GetFirstCurve() : pCrvCompo->GetLastCurve()) ; while ( pCrvOri != nullptr) { // creo una copia della curva pSmplCrv = ::GetCurve( pCrvOri->Clone()) ; if ( pSmplCrv == nullptr) return false ; // inserisco la curva if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol)) return false ; // passo alla prossima curva componente pCrvOri = ( bEndOrStart ? pCrvCompo->GetNextCurve() : pCrvCompo->GetPrevCurve()) ; } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart, double dLinTol) { // verifica curva if ( pCrv == nullptr) return false ; // se curva semplice if ( pCrv->IsSimple()) { // inserisco la curva if ( ! AddSimpleCurve( pCrv, bEndOrStart, dLinTol)) return false ; } // altrimenti curva composita, devo aggiungere le singole curve semplici else { // riloco le curve dalla composita sorgente alla corrente CurveComposite* pCrvCompo = dynamic_cast( pCrv) ; if ( ! AddCurveByRelocate( *pCrvCompo, bEndOrStart, dLinTol)) return false ; // cancello la curva composita originaria delete pCrvCompo ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddCurveByRelocate( CurveComposite& ccSrc, bool bEndOrStart, double dLinTol) { // verifica curva if ( &ccSrc == nullptr) return false ; // recupero le curve componenti e le inserisco nella lista ICurve* pSmplCrv ; while ( ( pSmplCrv = ccSrc.RemoveFirstOrLastCurve( ! bEndOrStart)) != nullptr) { // inserisco la curva if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol)) return false ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinTol) { // prendo la proprietà del puntatore PtrOwner pCrv( pSmplCrv) ; if ( IsNull( pCrv)) return false ; // 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 ( ! pCrv->IsSimple()) return false ; // annullo l'estrusione e lo spessore pCrv->SetExtrusion( V_NULL) ; pCrv->SetThickness( 0) ; // recupero i punti iniziali e finali della curva Point3d ptStart, ptEnd ; if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetEndPoint( ptEnd)) return false ; // se non è la prima if ( m_nCounter > 0) { // se inserita alla fine if ( bEndOrStart) { // verifico sia in continuità con il finale attuale if ( ! AreSamePointApprox( ptStart, m_PtEnd)) { // se in tolleranza, modifico l'inizio dell'entità if ( SqDist( ptStart, m_PtEnd) < ( dLinTol * dLinTol)) { if ( ! pCrv->ModifyStart( m_PtEnd)) return false ; } else return false ; } } // altrimenti inserita all'inizio else { // verifico sia in continuità con l'iniziale attuale if ( ! AreSamePointApprox( ptEnd, m_PtStart)) { // se in tolleranza, modifico la fine dell'entità if ( SqDist( ptEnd, m_PtStart) < ( dLinTol * dLinTol)) { if ( ! pCrv->ModifyEnd( m_PtStart)) return false ; } else return false ; } } } // se prima curva, assegno il punto iniziale o finale if ( m_nCounter == 0) { if ( bEndOrStart) m_PtStart = ptStart ; else m_PtEnd = ptEnd ; } // inserisco la curva nella lista if ( bEndOrStart) m_CrvSmplS.push_back( ::Release( pCrv)) ; else m_CrvSmplS.push_front( ::Release( pCrv)) ; m_nCounter ++ ; // assegno il nuovo punto estremo if ( bEndOrStart) m_PtEnd = ptEnd ; else m_PtStart = ptStart ; // aggiorno il flag di curva chiusa m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; // aggiorno lo stato m_nStatus = OK ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::FromSplit( const ICurve& cCrv, int nParts) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // deve essere valida e semplice if ( ! cCrv.IsValid() || ! cCrv.IsSimple()) return false ; // se 1 parte o meno, non fa alcunchè if ( nParts <= 1) return true ; // calcolo la lunghezza della curva double dTotLen ; if ( ! cCrv.GetLength( dTotLen)) return false ; // ciclo di inserimento delle parti double dStartLen = 0 ; double dEndLen = 0 ; for ( int i = 1 ; i <= nParts ; ++ i) { dStartLen = dEndLen ; dEndLen = dTotLen * i / (double) nParts ; PtrOwner pSmplCrv( ::GetCurve( cCrv.Clone())) ; if ( IsNull( pSmplCrv)) return false ; if ( ! pSmplCrv->TrimEndAtLen( dEndLen) || ! pSmplCrv->TrimStartAtLen( dStartLen)) return false ; if ( ! AddSimpleCurve( Release( pSmplCrv))) return false ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::FromPolyLine( const PolyLine& PL) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // deve esserci almeno 1 linea (2 punti) if ( PL.GetLineNbr() < 1) return false ; // ciclo di inserimento dei segmenti che uniscono i punti Point3d ptIni, ptFin ; PL.GetFirstPoint( ptIni) ; while ( PL.GetNextPoint( ptFin)) { // se i punti della coppia coincidono, passo alla coppia successiva if ( AreSamePointApprox( ptIni, ptFin)) continue ; // creo il segmento di retta PtrOwner pCrvLine( CreateCurveLine()) ; if ( IsNull( pCrvLine)) return false ; // assegno i punti estremi if ( ! pCrvLine->Set( ptIni, ptFin)) return false ; // aggiungo la retta alla curva composita if ( ! AddSimpleCurve( Release( pCrvLine))) return false ; // aggiorno dati prossimo punto iniziale ptIni = ptFin ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::FromPolyArc( const PolyArc& PA) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // deve esserci almeno 1 arco (2 punti) if ( PA.GetArcNbr() < 1) return false ; // Creo le diverse curve semplici e le inserisco in quella composita double dBulge, dNextBulge ; Point3d ptIni, ptFin ; PA.GetFirstPoint( ptIni, dBulge) ; while ( PA.GetNextPoint( ptFin, dNextBulge)) { // se i punti della coppia coincidono, passo alla coppia successiva if ( AreSamePointApprox( ptIni, ptFin)) continue ; // se retta if ( fabs( dBulge) < EPS_SMALL) { // creo la retta PtrOwner pCrvLine( CreateBasicCurveLine()) ; if ( IsNull( pCrvLine)) return false ; // setto la linea if ( ! pCrvLine->Set( ptIni, ptFin)) return false ; // inserisco la linea nella curva composta if ( ! AddSimpleCurve( ::Release( pCrvLine))) return false ; } // altrimenti arco else { // creo l'arco PtrOwner pCrvArc( CreateBasicCurveArc()) ; if ( IsNull( pCrvArc)) return false ; // setto l'arco if ( ! pCrvArc->Set2PNB( ptIni, ptFin, PA.GetExtrusion(), dBulge)) return false ; // inserisco l'arco nella curva composta if ( ! AddSimpleCurve( Release( pCrvArc))) return false ; } // aggiorno dati prossimo punto iniziale ptIni = ptFin ; dBulge = dNextBulge ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::PolygonCenterCorner( int nSides, const Point3d& ptCen, const Point3d& ptCorner, const Vector3d& vtN) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // almeno 3 lati e normale ben definita if ( nSides < 3 || vtN.IsSmall()) return false ; // angolo al centro corrispondente ad un lato double dAngCenSideDeg = ANG_FULL / nSides ; double dCosAng = cos( dAngCenSideDeg * DEGTORAD) ; double dSinAng = sin( dAngCenSideDeg * DEGTORAD) ; // ciclo di inserimento dei segmenti che uniscono i punti Point3d ptStart = ptCorner ; Point3d ptEnd ; for ( int i = 1 ; i <= nSides ; ++ i) { // calcolo il secondo punto del lato ptEnd = ptStart ; ptEnd.Rotate( ptCen, vtN, dCosAng, dSinAng) ; // se primo lato, verifico che la lunghezza sia superiore al minimo if ( i == 1) { if ( AreSamePointApprox( ptStart, ptEnd)) return false ; } // creo il segmento di retta PtrOwner pCrvLine( CreateBasicCurveLine()) ; if ( IsNull( pCrvLine)) return false ; // assegno i punti estremi if ( ! pCrvLine->Set( ptStart, ptEnd)) return false ; // aggiungo la retta alla curva composita if ( ! AddSimpleCurve( Release( pCrvLine))) return false ; // aggiorno punto iniziale prossimo lato ptStart = ptEnd ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::PolygonCenterMidSide( int nSides, const Point3d& ptCen, const Point3d& ptMidSide, const Vector3d& vtN) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // almeno 3 lati e normale ben definita if ( nSides < 3 || vtN.IsSmall()) return false ; // calcolo la posizione del corner double dHalfCentSideAngDeg = ANG_FULL / ( 2 * nSides) ; double dCoeff = tan( dHalfCentSideAngDeg * DEGTORAD) ; Vector3d vtDir = ptCen - ptMidSide ; vtDir -= ( vtDir * vtN) * vtN / vtN.SqLen() ; vtDir.Rotate( vtN, 0, 1) ; Point3d ptCorner = ptMidSide + vtDir * dCoeff ; // ora costruisco come poligono con centro e corner return PolygonCenterCorner( nSides, ptCen, ptCorner, vtN) ; } //---------------------------------------------------------------------------- bool CurveComposite::PolygonSide( int nSides, const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtN) { // verifico lo stato if ( m_nCounter != 0 || m_nStatus != TO_VERIFY) return false ; // almeno 3 lati e normale ben definita if ( nSides < 3 || vtN.IsSmall()) return false ; // verifico che la lunghezza sia superiore al minimo if ( AreSamePointApprox( ptStart, ptEnd)) return false ; // calcolo la posizione del centro double dHalfCentSideAngDeg = ANG_FULL / ( 2 * nSides) ; double dCoeff = 1 / ( 2 * tan( dHalfCentSideAngDeg * DEGTORAD)) ; Vector3d vtDir = ptEnd - ptStart ; vtDir -= ( vtDir * vtN) * vtN / vtN.SqLen() ; vtDir.Rotate( vtN, 0, 1) ; Point3d ptCen = Media( ptStart, ptEnd, 0.5) + vtDir * dCoeff ; // ora costruisco come poligono con centro e corner return PolygonCenterCorner( nSides, ptCen, ptStart, vtN) ; } //---------------------------------------------------------------------------- CurveComposite* CurveComposite::Clone( void) const { // alloco oggetto CurveComposite* pCrv = new(nothrow) CurveComposite ; if ( pCrv != nullptr) { if ( ! pCrv->CopyFrom( *this)) { delete pCrv ; return nullptr ; } } return pCrv ; } //---------------------------------------------------------------------------- bool CurveComposite::CopyFrom( const IGeoObj* pGObjSrc) { // se sorgente è una curva composita const CurveComposite* pCC = GetBasicCurveComposite( pGObjSrc) ; if ( pCC != nullptr) return CopyFrom( *pCC) ; // se sorgente è un'altro tipo di curva const ICurve* pCrv = ::GetCurve( pGObjSrc) ; if ( pCrv != nullptr) { Clear() ; pCrv->GetExtrusion( m_VtExtr) ; pCrv->GetThickness( m_dThick) ; return AddCurve( *pCrv) ; } // altrimenti errroe return false ; } //---------------------------------------------------------------------------- bool CurveComposite::CopyFrom( const CurveComposite& ccSrc) { if ( &ccSrc == this) return true ; Clear() ; m_VtExtr = ccSrc.m_VtExtr ; m_dThick = ccSrc.m_dThick ; m_nTempProp = ccSrc.m_nTempProp ; PCSD_CONST_ITER Iter ; for ( Iter = ccSrc.m_CrvSmplS.begin() ; Iter != ccSrc.m_CrvSmplS.end() ; ++Iter) { if ( ! AddCurve( **Iter)) return false ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::RelocateFrom( CurveComposite& ccSrc) { if ( &ccSrc == this) return true ; Clear() ; m_VtExtr = ccSrc.m_VtExtr ; m_dThick = ccSrc.m_dThick ; m_nTempProp = ccSrc.m_nTempProp ; for ( ICurve* pCrv = ccSrc.RemoveFirstOrLastCurve( false) ; pCrv != nullptr ; pCrv = ccSrc.RemoveFirstOrLastCurve( false)) { if ( ! AddSimpleCurve( pCrv)) return false ; } return true ; } //---------------------------------------------------------------------------- GeoObjType CurveComposite::GetType( void) const { return static_cast( GEOOBJ_GETTYPE( CurveComposite)) ; } //---------------------------------------------------------------------------- const string& CurveComposite::GetTitle( void) const { static const string sTitle = "CComposite" ; return sTitle ; } //---------------------------------------------------------------------------- bool CurveComposite::Dump( string& sOut, const char* szNewLine) const { // dati generali di una curva if ( ! CurveDump( *this, sOut, szNewLine)) return false ; // parametri : numero di curve sOut += "CrvNbr=" + ToString( m_nCounter) + szNewLine ; // ciclo sulle curve componenti int i = 0 ; const ICurve* pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { // assegno ed emetto nome e tipo della curva semplice sOut += "#" + ToString( ++i) + " " + pCrvSmpl->GetTitle() + szNewLine ; // salvataggio della curva semplice if ( ! pCrvSmpl->Dump( sOut, szNewLine)) return false ; // passo alla successiva pCrvSmpl = GetNextCurve() ; } return true ; } //---------------------------------------------------------------------------- int CurveComposite::GetNgeId( void) const { return GEOOBJ_GETNGEID( CurveComposite) ; } //---------------------------------------------------------------------------- bool CurveComposite::Save( NgeWriter& ngeOut) const { // numero di curve if ( ! ngeOut.WriteInt( m_nCounter, nullptr, true)) return false ; // ciclo sulle curve componenti int i = 0 ; const ICurve* pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { // recupero il gestore di lettura/scrittura delle curve const IGeoObjRW* pCSmplRW = dynamic_cast( pCrvSmpl) ; if ( pCSmplRW == nullptr) return false ; // emetto tipo della curva semplice if ( ! ngeOut.WriteKey( pCSmplRW->GetNgeId())) return false ; // assegno ed emetto nome della curva semplice string sCrvName = "#" + ToString( ++i) ; if ( ! ngeOut.WriteString( sCrvName, nullptr, true)) return false ; // salvataggio della curva semplice if ( ! pCSmplRW->Save( ngeOut)) return false ; // passo alla successiva pCrvSmpl = GetNextCurve() ; } // da versione 1008 : linea con VtEstrusione e Spessore if ( ! ngeOut.WriteVector( m_VtExtr, ";")) return false ; if ( ! ngeOut.WriteDouble( m_dThick, ";", true)) return false ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Load( NgeReader& ngeIn) { // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // leggo la prossima linea ( 1 parametro) // recupero il numero di curve componenti int nCounter ; if ( ! ngeIn.ReadInt( nCounter, nullptr, true)) return false ; // leggo le curve componenti for ( int i = 0 ; i < nCounter ; ++ i) { // recupero la prossima linea (con il tipo di oggetto) int nNgeId ; if ( ! ngeIn.ReadKey( nNgeId)) return false ; // creo l'oggetto int nType = GEOOBJ_NGEIDTOTYPE( nNgeId) ; IGeoObj* pGeoO = GEOOBJ_CREATE( nType) ; if ( pGeoO == nullptr) return false ; // recupero la linea con il nome string sName ; bool bOk = ngeIn.ReadString( sName, nullptr, true) ; // ne leggo i dati IGeoObjRW* pGObjRW = dynamic_cast( pGeoO) ; bOk = bOk && ( pGObjRW != nullptr && pGObjRW->Load( ngeIn)) ; // verifico sia una curva ICurve* pCrv = ::GetCurve( pGeoO) ; bOk = bOk && ( pCrv != nullptr && pCrv->IsSimple()) ; // aggiungo questa curva (sicuramente semplice) bOk = bOk && AddSimpleCurve( pCrv) ; // se errore if ( ! bOk) return false ; } // da versione 1008 : linea con VtEstrusione e Spessore if ( ngeIn.GetFileVersion() >= NGE_VER_1008) { if ( ! ngeIn.ReadVector( m_VtExtr, ";")) return false ; if ( ! ngeIn.ReadDouble( m_dThick, ";", true)) return false ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetLocalBBox( BBox3d& b3Loc, int nFlag) 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, nFlag) ; // aggiorno il box b3Loc.Add( b3Crv) ; // passo alla curva successiva pCrvSmpl = GetNextCurve() ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) 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, nFlag) ; // aggiorno il box b3Ref.Add( b3Crv) ; // passo alla curva successiva pCrvSmpl = GetNextCurve() ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Validate( void) { if ( m_nStatus == TO_VERIFY) { Point3d ptPrevEnd ; Point3d ptStart ; // ciclo su tutte le curve int nCount = 0 ; PCSD_CONST_ITER Iter ; 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 ( ! AreSamePointApprox( ptPrevEnd, ptStart)) { m_nStatus = ERR ; return false ; } } // recupero il punto finale (*Iter)->GetEndPoint( ptPrevEnd) ; } // aggiorno m_nStatus = ( nCount > 0 ? OK : TO_VERIFY) ; m_nCounter = nCount ; if ( m_nStatus == OK) { m_CrvSmplS.front()->GetStartPoint( m_PtStart) ; m_CrvSmplS.back()->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; } else m_bClosed = false ; } return ( m_nStatus == OK) ; } //---------------------------------------------------------------------------- bool CurveComposite::ValidateMoveStart( void) { // ci deve essere almeno una curva if ( m_CrvSmplS.empty()) return false ; // imposto punto iniziale e verifico curva chiusa if ( ! m_CrvSmplS.front()->GetStartPoint( m_PtStart)) return false ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ValidateMoveEnd( void) { // ci deve essere almeno una curva if ( m_CrvSmplS.empty()) return false ; // imposto punto finale e verifica curva chiusa if ( ! m_CrvSmplS.back()->GetEndPoint( m_PtEnd)) return false ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::IsFlat( Plane3d& plPlane, double dToler) const { // verifico lo stato if ( m_nStatus != OK) return false ; // polilinea dei punti rappresentativi PolyLine shPL ; // punto iniziale Point3d ptP ; if ( ! GetStartPoint( ptP) || ! shPL.AddUPoint( 0, ptP)) return false ; // ciclo sulle curve semplici (aggiungo solo eventuali punti intermedi e finali) int nCount = 0 ; for ( const ICurve* pCrv = GetFirstCurve() ; pCrv != nullptr ; pCrv = GetNextCurve(), ++ nCount) { switch ( pCrv->GetType()) { case CRV_LINE : // punto finale if ( ! pCrv->GetEndPoint( ptP) || ! shPL.AddUPoint( nCount + 1, ptP)) return false ; break ; case CRV_ARC : // punto a 1/3 if ( ! pCrv->GetPointD1D2( 0.3333, ICurve::FROM_MINUS, ptP) || ! shPL.AddUPoint( nCount + 0.3333, ptP)) return false ; // punto a 7/11 if ( ! pCrv->GetPointD1D2( 0.6363, ICurve::FROM_MINUS, ptP) || ! shPL.AddUPoint( nCount + 0.6363, ptP)) return false ; // punto finale if ( ! pCrv->GetEndPoint( ptP) || ! shPL.AddUPoint( nCount + 1, ptP)) return false ; break ; case CRV_BEZ : { const CurveBezier* pBez = GetBasicCurveBezier( pCrv) ; // inserisco tutti i punti di controllo tranne il primo int nLastPC = pBez->GetDegree() ; for ( int i = 1 ; i <= nLastPC ; ++ i) { double dU = nCount + i / double( nLastPC) ; if ( ! shPL.AddUPoint( dU, pBez->GetControlPoint( i))) return false ; } } break ; } } // recupero dati sulla planarità della polilinea int nRank ; Point3d ptCen ; Vector3d vtDir ; bool bFlat = shPL.IsFlat( nRank, ptCen, vtDir, dToler) ; // se punto switch ( nRank) { case 0 : // punto if ( bFlat) { plPlane.vtN = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ; plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; } else { plPlane.vtN = ( m_VtExtr.IsSmall() ? V_NULL : m_VtExtr) ; plPlane.dDist = 0 ; } break ; case 1 : // linea if ( m_VtExtr.IsSmall()) { plPlane.vtN = FromUprightOrtho( vtDir) ; } else { plPlane.vtN = m_VtExtr ; bFlat = bFlat && ( AreOrthoApprox( m_VtExtr, vtDir)) ; } plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; break ; default : // piana o 3d if ( m_VtExtr.IsSmall()) { plPlane.vtN = vtDir ; } else { plPlane.vtN = m_VtExtr ; bFlat = bFlat && ( AreSameOrOppositeVectorApprox( m_VtExtr, vtDir)) ; } plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; break ; } return bFlat ; } //---------------------------------------------------------------------------- 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::GetMidPoint( Point3d& ptMid) const { // verifico lo stato if ( m_nStatus != OK) return false ; // determino il valore del parametro a metà lunghezza double dLen, dMid ; if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid)) return false ; // calcolo il punto return GetPointD1D2( dMid, FROM_MINUS, ptMid) ; } //---------------------------------------------------------------------------- bool CurveComposite::GetCentroid( Point3d& ptCen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // approssimo la curva con una polilinea PolyLine PL ; if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, PL)) return false ; // calcolo il centro mediante PolygonPlane Point3d ptP ; PolygonPlane PolyPlane ; for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP)) PolyPlane.AddPoint( ptP) ; if ( PolyPlane.GetCentroid( ptCen)) return true ; // se non riuscito, uso il punto medio return GetMidPoint( ptCen) ; } //---------------------------------------------------------------------------- bool CurveComposite::GetMidDir( Vector3d& vtDir) const { // verifico lo stato if ( m_nStatus != OK) return false ; // determino il valore del parametro a metà lunghezza double dLen, dMid ; if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid)) return false ; // calcolo la direzione return ::GetTang( *this, 0.5 * m_nCounter, FROM_MINUS, vtDir) ; } //---------------------------------------------------------------------------- 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::GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const { // verifico che il parametro non sia troppo fuori dai limiti if ( dU < - 100 * EPS_PARAM || dU > m_nCounter + 100 * EPS_PARAM) return false ; // il parametro U deve essere compreso tra 0 e m_nCounter (le curve chiuse sono cicliche) if ( dU < ( 0 + EPS_PARAM)) { // se chiusa e voglio valutare prima dell'inizio devo valutare prima della fine if ( m_bClosed && nS == ICurve::FROM_MINUS) dU = m_nCounter ; // altrimenti posso valutare solo dopo l'inizio else { dU = 0 ; nS = ICurve::FROM_PLUS ; } } else if ( dU > ( m_nCounter - EPS_PARAM)) { // se chiusa e voglio valutare dopo la fine devo valutare dopo l'inizio if ( m_bClosed && nS == ICurve::FROM_PLUS) dU = 0 ; // altrimenti posso valutare solo prima della fine else { dU = m_nCounter ; nS = ICurve::FROM_MINUS ; } } // determino la curva di appartenenza e il valore locale (ovvero nella curva) del parametro nSCrv = static_cast( dU) ; dLocU = dU - nSCrv ; if ( fabs( dLocU) < EPS_PARAM && nSCrv > 0 && nS == ICurve::FROM_MINUS) { -- nSCrv ; dLocU += 1 ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const { // verifico lo stato if ( m_nStatus != OK) return false ; // determino la curva di appartenenza e il valore locale del parametro int nC ; double dUc ; if ( ! GetIndSCurveAndLocPar( dU, nS, nC, dUc)) return false ; // eseguo il calcolo sulla curva semplice return m_CrvSmplS[nC]->GetPointD1D2( dUc, ICurve::FROM_MINUS, ptPos, pvtDer1, pvtDer2) ; } //---------------------------------------------------------------------------- bool CurveComposite::GetLength( double& dLen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // ciclo di calcolo dLen = 0 ; PCSD_CONST_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { double dLenCrvSmpl ; if ( (*Iter)->GetLength( dLenCrvSmpl)) dLen += dLenCrvSmpl ; else return false ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetLengthAtParam( double dU, double& dLen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // il parametro U deve essere compreso tra 0 e m_nCounter if ( dU < - EPS_PARAM || dU > ( m_nCounter + EPS_PARAM)) return false ; // ciclo di calcolo dLen = 0 ; double dUToGo = dU ; PCSD_CONST_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // dominio parametrico della curva semplice double dParStart, dParEnd ; (*Iter)->GetDomain( dParStart, dParEnd) ; // se resto nella curva if ( dUToGo <= ( dParEnd - dParStart)) { double dParamLen ; if ( ! (*Iter)->GetLengthAtParam( dUToGo, dParamLen)) return false ; dLen += dParamLen ; break ; } // altrimenti else { // lunghezza parametrica rimanente dUToGo -= ( dParEnd - dParStart) ; // lunghezza progressiva double dCrvLen ; if ( ! (*Iter)->GetLength( dCrvLen)) return false ; dLen += dCrvLen ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::GetParamAtLength( double dLen, double& dU) const { // verifico lo stato if ( m_nStatus != OK) return false ; // se prima di inizio, errore if ( dLen < - EPS_SMALL) return false ; // inizio if ( dLen < EPS_SMALL) { dU = 0 ; return true ; } // ciclo di calcolo dU = 0 ; double dLenToGo = dLen ; PCSD_CONST_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // lunghezza della curva semplice double dCrvLen ; if ( ! (*Iter)->GetLength( dCrvLen)) return false ; // se resto nella curva if ( dLenToGo <= dCrvLen) { double dULen ; if ( ! (*Iter)->GetParamAtLength( dLenToGo, dULen)) return false ; dU += dULen ; break ; } // altrimenti else { // lunghezza rimanente dLenToGo -= dCrvLen ; // lunghezza parametrica progressiva double dParStart, dParEnd ; (*Iter)->GetDomain( dParStart, dParEnd) ; dU += ( dParEnd - dParStart) ; } } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::IsPointOn( const Point3d& ptP, double dTol) const { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico che il punto sia sulla curva ( distanza minore di tolleranza) double dSqDist ; dTol = max( dTol, EPS_ZERO) ; return ( DistPointCrvComposite( ptP, *this).GetSqDist( dSqDist) && dSqDist < dTol * dTol) ; } //---------------------------------------------------------------------------- bool CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { // pulisco la polilinea PL.Clear() ; // verifico lo stato if ( m_nStatus != OK) return false ; // eseguo approssimazione double dStartPar = 0 ; PolyLine PLSmpl ; PCSD_CONST_ITER Iter ; 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 ( ! PL.Join( PLSmpl, dStartPar)) return false ; // incremento inizio parametro per prossima curva semplice dStartPar += 1 ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const { // pulisco il poliarco PA.Clear() ; // verifico lo stato if ( m_nStatus != OK) return false ; // eseguo approssimazione double dStartPar = 0 ; PolyArc PASmpl ; PCSD_CONST_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { ICurve* pCrv = (*Iter) ; // assegno estrusione e spessore della curva composita pCrv->SetExtrusion( m_VtExtr) ; pCrv->SetThickness( m_dThick) ; // recupero approssimazione per curva semplice if ( ! pCrv->ApproxWithArcs( dLinTol, dAngTolDeg, PASmpl)) return false ; // ripristino estrusione e spessore della curva semplice (annullandoli) pCrv->SetExtrusion( V_NULL) ; pCrv->SetThickness( 0) ; // la accodo opportunamente a quella della curva composita if ( ! PA.Join( PASmpl, dStartPar)) return false ; // incremento inizio parametro per prossima curva semplice dStartPar += 1 ; } // assegno estrusione della curva composita PA.SetExtrusion( m_VtExtr) ; return true ; } //---------------------------------------------------------------------------- ICurve* CurveComposite::CopyParamRange( double dUStart, double dUEnd) const { // i parametri start ed end devono essere compresi nel dominio parametrico della curva if ( dUStart < - EPS_PARAM || dUStart > m_nCounter + EPS_PARAM || dUEnd < - EPS_PARAM || dUEnd > m_nCounter + EPS_PARAM) return nullptr ; // se il parametro start supera quello di end if ( dUStart > dUEnd - EPS_PARAM) { // se curva aperta, il trim la cancella completamente quindi non resta alcunchè if ( ! m_bClosed) return nullptr ; // se curva chiusa, il trim si avvolge attorno al punto di giunzione else // incremento il parametro finale della dimensione del dominio parametrico originale della curva dUEnd += m_nCounter ; } // determino gli indici della prima e dell'ultima curva da copiare int nIdStart = static_cast( floor( dUStart)) ; int nIdEnd = static_cast( ceil( dUEnd)) ; // creo la curva composita copia PtrOwner pCopy( new CurveComposite()) ; if ( IsNull( pCopy)) return nullptr ; // eseguo la copia delle sole curve semplici necessarie for ( int i = nIdStart ; i < nIdEnd ; ++ i) { // quando supero il numero di curve nella composita originale riparto dall'inizio int j = i % m_nCounter ; // accodo la curva alla copia if ( ! pCopy->AddCurve( *(m_CrvSmplS[j]))) return nullptr ; } // aggiorno i parametri di trim, tenendo conto delle curve semplici saltate all'inizio dUStart -= nIdStart ; dUEnd -= nIdStart ; // eseguo il trim della copia if ( ! pCopy->TrimStartEndAtParam( dUStart, dUEnd)) return nullptr ; return ( ::Release( pCopy)) ; } //---------------------------------------------------------------------------- bool CurveComposite::Invert( void) { // verifico lo stato if ( m_nStatus != OK) return false ; // inverto le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Invert() ; // inverto l'ordine della lista reverse( m_CrvSmplS.begin(), m_CrvSmplS.end()) ; // scambio punti iniziale e finale swap( m_PtStart, m_PtEnd) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::SimpleOffset( double dDist, int nType) { // --- l'offset va effettuato in un piano perpendicolare al vettore estrusione --- // verifico il vettore estrusione bool bNeedRef = ( ! m_VtExtr.IsSmall() && ! m_VtExtr.IsZplus()) ; // se necessario cambio il riferimento Frame3d frExtr ; if ( bNeedRef) { // calcolo il riferimento OCS con VtExtr come asse Z if ( ! frExtr.Set( ORIG, m_VtExtr)) return false ; // esprimo la curva in questo riferimento ToLoc( frExtr) ; } // eseguo l'offset nel piano XY bool bOk = SimpleOffsetXY( dDist, nType) ; // riporto la curva nel riferimento originale if ( bNeedRef) ToGlob( frExtr) ; return bOk ; } //---------------------------------------------------------------------------- bool CurveComposite::ModifyStart( const Point3d& ptNewStart) { // verifico lo stato if ( m_nStatus != OK) return false ; // recupero la prima curva if ( m_CrvSmplS.empty()) return false ; ICurve* pCrv = m_CrvSmplS.front() ; // modifico l'inizio di questa curva if ( ! pCrv->ModifyStart( ptNewStart)) return false ; // aggiorno il punto iniziale e il flag di curva chiusa m_PtStart = ptNewStart ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ModifyEnd( const Point3d& ptNewEnd) { // verifico lo stato if ( m_nStatus != OK) return false ; // recupero l'ultima curva if ( m_CrvSmplS.empty()) return false ; ICurve* pCrv = m_CrvSmplS.back() ; // modifico la fine di questa curva if ( ! pCrv->ModifyEnd( ptNewEnd)) return false ; // aggiorno il punto finale e il flag di curva chiusa m_PtEnd = ptNewEnd ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimStartAtParam( double dUTrim) { // ciclo sulle diverse curve dall'inizio double dUToTrim = dUTrim ; PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // dominio parametrico della curva semplice double dParStart, dParEnd ; (*Iter)->GetDomain( dParStart, dParEnd) ; // lunghezza parametrica progressiva dUToTrim -= ( dParEnd - dParStart) ; // se lunghezza ancora da tagliare non nulla if ( dUToTrim > EPS_PARAM) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; } // se lunghezza ancora da tagliare nulla (entro la tolleranza) else if ( dUToTrim > - EPS_PARAM || ! (*Iter)->TrimStartAtParam( 1 + dUToTrim)) { delete (*Iter) ; Iter ++ ; m_CrvSmplS.pop_front() ; m_nCounter -- ; if ( m_nCounter == 0) return false ; (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; break ; } // altrimenti superata lunghezza ancora da tagliare (taglio già fatto al test sopra) else { (*Iter)->GetStartPoint( m_PtStart) ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; break ; } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimEndAtParam( double dUTrim) { // ciclo sulle diverse curve dalla fine bool bToErase = false ; double dUToTrim = dUTrim ; PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // dominio parametrico della curva semplice double dParStart, dParEnd ; (*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_PARAM) { Iter ++ ; } // se lunghezza parametrica ancora da tagliare nulla (entro la tolleranza) else if ( dUToTrim > - EPS_PARAM) { // imposto punto finale e verifico curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointApprox( 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)) { // se trim fallito, rimaneva troppo poco e quindi la cancello bToErase = true ; continue ; } // imposto punto finale e verifica curva chiusa (*Iter)->GetEndPoint( m_PtEnd) ; m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; // passo alla entità successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) { // i parametri start ed end devono essere compresi nel dominio parametrico della curva if ( dUStartTrim < - EPS_PARAM || dUStartTrim > m_nCounter + EPS_PARAM || dUEndTrim < - EPS_PARAM || dUEndTrim > m_nCounter + EPS_PARAM) return false ; // se il parametro start supera quello di end if ( dUStartTrim > dUEndTrim - EPS_PARAM) { // se curva aperta, il trim la cancella completamente quindi errore if ( ! m_bClosed) return false ; // se curva chiusa, il trim interessa il punto di giunzione else { // calcolo il minimo numero di curve da accodare per coprire il range esteso int nNumCrv = static_cast( ceil( dUEndTrim)) ; // incremento il parametro finale della dimensione del dominio parametrico originale della curva dUEndTrim += m_nCounter ; // eseguo accodamento delle curve for ( int i = 0 ; i < nNumCrv ; ++ i) { if ( ! AddCurve( *(m_CrvSmplS[i]))) return false ; } } } // per parametro start : determino la curva di appartenenza e il valore locale del parametro int nCs ; double dUcs ; if ( ! GetIndSCurveAndLocPar( dUStartTrim, ICurve::FROM_PLUS, nCs, dUcs)) return false ; // per parametro end : determino la curva di appartenenza e il valore locale del parametro int nCe ; double dUce ; if ( ! GetIndSCurveAndLocPar( dUEndTrim, ICurve::FROM_MINUS, nCe, dUce)) return false ; // trim finale if ( ! TrimEndAtParam( dUEndTrim)) return false ; // se i due trim sono fatti sulla stessa curva devo compensare la riparametrizzazione dopo il primo if ( nCs == nCe) { double dNewUStartTrim = nCs + dUcs / dUce ; return TrimStartAtParam( dNewUStartTrim) ; } // altrimenti, va bene il valore ricevuto come parametro else return TrimStartAtParam( dUStartTrim) ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimStartAtLen( double dLenTrim) { // ciclo sulle diverse curve dall'inizio double dLenToTrim = dLenTrim ; PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { // lunghezza della curva double dCrvLen ; 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 -- ; if ( m_nCounter == 0) return false ; } // 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 = ( AreSamePointApprox( 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 = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; break ; } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::TrimEndAtLen( double dLenTrim) { // ciclo sulle diverse curve dalla fine bool bToErase = false ; double dLenToTrim = dLenTrim ; PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) { double dCrvLen ; // 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 = ( AreSamePointApprox( 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 = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; // passo alla entità successiva ++ Iter ; // dichiaro ingresso in zona da cancellare bToErase = true ; } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ExtendStartByLen( double dLenExt) { // la lunghezza di estensione deve essere positiva if ( dLenExt < - EPS_ZERO) return false ; // recupero la prima curva ed estendo quella if ( m_CrvSmplS.begin() == m_CrvSmplS.end()) return false ; // estendo la prima curva if ( ! (*m_CrvSmplS.begin())->ExtendStartByLen( dLenExt)) { m_nStatus = ERR ; return false ; } // imposto punto iniziale e verifica curva chiusa ValidateMoveStart() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ExtendEndByLen( double dLenExt) { // la lunghezza di estensione deve essere positiva if ( dLenExt < - EPS_ZERO) return false ; // vado sulla fine PCSD_ITER Iter = m_CrvSmplS.end() ; if ( Iter == m_CrvSmplS.begin()) return false ; -- Iter ; // recupero la curva if ( Iter == m_CrvSmplS.end()) return false ; // estendo l'ultima curva if ( ! (*Iter)->ExtendEndByLen( dLenExt)) { m_nStatus = ERR ; return false ; } // imposto punto finale e verifica curva chiusa ValidateMoveEnd() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Translate( const Vector3d& vtMove) { // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // traslo le singole curve PCSD_ITER Iter ; 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) { // verifico validità dell'asse di rotazione if ( vtAx.IsSmall()) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // ruoto le singole curve PCSD_ITER Iter ; 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) ; // ruoto il vettore estrusione m_VtExtr.Rotate( vtAx, dCosAng, dSinAng) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { // verifico non sia nulla if ( fabs( dCoeffX) < EPS_ZERO && fabs( dCoeffY) < EPS_ZERO && fabs( dCoeffZ) < EPS_ZERO) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // se scalatura non omogenea, devo trasformare tutti gli archi in curve di Bezier if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( dCoeffX - dCoeffZ) > EPS_SMALL) { if ( ! ArcsToBezierCurves()) return false ; } // scalo le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // eseguo la scalatura if ( ! (*Iter)->Scale( frRef, dCoeffX, dCoeffY, dCoeffZ)) return false ; } // scalo i punti estremi m_PtStart.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ; m_PtEnd.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ; // scalo vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveComposite::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { // verifico validità del piano di specchiatura if ( vtNorm.IsSmall()) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // specchio le singole curve PCSD_ITER Iter ; 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) ; // specchio il vettore estrusione m_VtExtr.Mirror( vtNorm) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { // verifico validità dei parametri if ( vtNorm.IsSmall() || vtDir.IsSmall()) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo tutti gli archi in curve di Bezier (potrei controllare gli archi uno ad uno...) if ( ! ArcsToBezierCurves()) return false ; // eseguo scorrimento delle singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->Shear( ptOn, vtNorm, vtDir, dCoeff) ; // eseguo scorrimento dei punti estremi m_PtStart.Shear( ptOn, vtNorm, vtDir, dCoeff) ; m_PtEnd.Shear( ptOn, vtNorm, vtDir, dCoeff) ; // eseguo scorrimento del vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Shear( vtNorm, vtDir, dCoeff) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ToGlob( const Frame3d& frRef) { // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->ToGlob( frRef) ; // trasformo i punti estremi e il vettore estrusione m_PtStart.ToGlob( frRef) ; m_PtEnd.ToGlob( frRef) ; m_VtExtr.ToGlob( frRef) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ToLoc( const Frame3d& frRef) { // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) (*Iter)->ToLoc( frRef) ; // trasformo i punti estremi e il vettore estrusione m_PtStart.ToLoc( frRef) ; m_PtEnd.ToLoc( frRef) ; m_VtExtr.ToLoc( frRef) ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { // verifico validità dei frame if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR) return false ; // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { (*Iter)->LocToLoc( frOri, frDest) ; } // trasformo i punti estremi e il vettore estrusione m_PtStart.LocToLoc( frOri, frDest) ; m_PtEnd.LocToLoc( frOri, frDest) ; m_VtExtr.LocToLoc( frOri, frDest) ; return true ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetCurve( int nCrv) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // verifico che l'indice sia nei limiti if ( nCrv < 0 || nCrv >= int( m_CrvSmplS.size())) return nullptr ; // restituisco la curva return m_CrvSmplS[nCrv] ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetFirstCurve( void) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // vado all'inizio 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 ++ m_Iter ; // recupero la curva if ( m_Iter != m_CrvSmplS.end()) return (*m_Iter) ; else return nullptr ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetLastCurve( void) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // vado alla fine m_Iter = m_CrvSmplS.end() ; if ( m_Iter == m_CrvSmplS.begin()) return nullptr ; -- m_Iter ; // recupero la curva if ( m_Iter != m_CrvSmplS.end()) return (*m_Iter) ; else return nullptr ; } //---------------------------------------------------------------------------- const ICurve* CurveComposite::GetPrevCurve( void) const { // la curva deve essere validata if ( m_nStatus != OK) return nullptr ; // vado al precedente if ( m_Iter == m_CrvSmplS.begin()) return nullptr ; -- m_Iter ; // recupero la curva if ( m_Iter != m_CrvSmplS.end()) return (*m_Iter) ; else return nullptr ; } //---------------------------------------------------------------------------- ICurve* CurveComposite::RemoveFirstOrLastCurve( bool bLast) { // la curva composita deve essere validata if ( m_nStatus != OK) return nullptr ; // recupero la curva semplice iniziale o finale e la tolgo dalla lista if ( ! m_CrvSmplS.empty()) { ICurve* pCrv ; if ( bLast) { // recupero la curva pCrv = *(m_CrvSmplS.rbegin()) ; // la tolgo dalla lista m_CrvSmplS.pop_back() ; // aggiorno la curva composita pCrv->GetStartPoint( m_PtEnd) ; -- m_nCounter ; } else { // recupero la curva pCrv = *(m_CrvSmplS.begin()) ; // la tolgo dalla lista m_CrvSmplS.pop_front() ; // aggiorno la curva composita pCrv->GetEndPoint( m_PtStart) ; -- m_nCounter ; } // eseguo mini verifica m_nStatus = ( m_nCounter > 0 ? OK : TO_VERIFY) ; if ( m_nStatus == OK) m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; else m_bClosed = false ; // assegno estrusione e spessore della curva composita pCrv->SetExtrusion( m_VtExtr) ; pCrv->SetThickness( m_dThick) ; return pCrv ; } else return nullptr ; } //---------------------------------------------------------------------------- bool CurveComposite::IsParamAtJoint( double dU) const { // se aperta e all'inizio o alla fine o lontano dagli interi non è giunzione if ( ( ! m_bClosed && fabs( dU) < EPS_ZERO) || ( ! m_bClosed && fabs( dU - m_nCounter) < EPS_ZERO) || fabs( dU - (int) ( dU + EPS_ZERO)) > EPS_ZERO) return false ; else return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ChangeStartPoint( double dU) { // la curva deve essere chiusa (ne verifica anche lo stato) if ( ! IsClosed()) return false ; // questa funzione gestisce già anche il cambio di inizio su curve chiuse return TrimStartEndAtParam( dU, dU) ; } //---------------------------------------------------------------------------- bool CurveComposite::ArcsToBezierCurves( void) { // verifico le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // se arco, devo trasformare in una o più curve di Bezier if ( (*Iter)->GetType() == CRV_ARC) { // eseguo trasformazione PtrOwner pNewCrv( ArcToBezierCurve( (*Iter))) ; if ( IsNull( pNewCrv)) return false ; // se risultato è singola curva if ( pNewCrv->IsSimple()) { // elimino l'arco e lo sostituisco con la curva di Bezier delete (*Iter) ; (*Iter) = Release( pNewCrv) ; } // altrimenti è una curva composita else { CurveComposite* pCC = GetBasicCurveComposite( Get( pNewCrv)) ; if ( pCC == nullptr) return false ; // inserisco le curve prima dell'arco int nParts = 0 ; PCSD_ITER Iter2 ; for ( Iter2 = pCC->m_CrvSmplS.begin() ; Iter2 != pCC->m_CrvSmplS.end() ; ++ Iter2) { Iter = m_CrvSmplS.insert( Iter, (*Iter2)) ; ++ Iter ; ++ nParts ; } pCC->m_CrvSmplS.clear() ; pCC->m_nCounter = 0 ; // elimino l'arco (e sposto l'iteratore alla curva precedente) delete (*Iter) ; Iter = m_CrvSmplS.erase( Iter) ; -- Iter ; // aggiorno il numero di curve m_nCounter += nParts - 1 ; } } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveComposite::ArcsBezierCurvesToArcsPerpExtr( double dLinTol, double dAngTolDeg) { // verifico le singole curve PCSD_ITER Iter ; for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // se arco in piano non perpendicolare ad estrusione o curva di Bezier trasformo if ( ( (*Iter)->GetType() == CRV_ARC && ! GetBasicCurveArc((*Iter))->IsInPlanePerpExtr()) || (*Iter)->GetType() == CRV_BEZ) { // eseguo trasformazione PtrOwner pNewCrv( CurveToArcsPerpExtrCurve( (*Iter), dLinTol, dAngTolDeg)) ; if ( IsNull( pNewCrv)) return false ; // se risultato è singola curva if ( pNewCrv->IsSimple()) { // elimino l'arco e lo sostituisco con la curva di Bezier delete (*Iter) ; (*Iter) = Release( pNewCrv) ; } // altrimenti è una curva composita else { CurveComposite* pCC = GetBasicCurveComposite( Get( pNewCrv)) ; if ( pCC == nullptr) return false ; // inserisco le curve prima dell'originale int nParts = 0 ; PCSD_ITER Iter2 ; for ( Iter2 = pCC->m_CrvSmplS.begin() ; Iter2 != pCC->m_CrvSmplS.end() ; ++ Iter2) { Iter = m_CrvSmplS.insert( Iter, (*Iter2)) ; ++ Iter ; ++ nParts ; } pCC->m_CrvSmplS.clear() ; pCC->m_nCounter = 0 ; // elimino l'arco (e sposto l'iteratore alla curva precedente) delete (*Iter) ; Iter = m_CrvSmplS.erase( Iter) ; -- Iter ; // aggiorno il numero di curve m_nCounter += nParts - 1 ; } } } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; }