//---------------------------------------------------------------------------- // EgalTech 2015-2024 //---------------------------------------------------------------------------- // File : RotationMinimizeFrame.cpp Data : 05.03.24 Versione : 2.6c1 // Contenuto : Classe per RotationMinimizeFrame // // // // Modifiche : 05.03.24 RE Creazione modulo. //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "RotationMinimizeFrame.h" #include "GeoConst.h" using namespace std ; RotationMinimizeFrame::RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start, const double dStep) { // assegno i parametri m_pCrv = pCrv->Clone() ; m_Frame0 = fr_Start ; m_dStep = dStep ; } RotationMinimizeFrame::RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start, const int nStep) { // assegno i parametri if ( nStep < 1) // devo averne almeno 1, altrimenti è automaticamente il fr_Start return ; // recupero la lunghezza della curva double dLen = 0 ; if ( pCrv == nullptr || ! pCrv->IsValid() || ! pCrv->GetLength( dLen)) return ; m_pCrv = pCrv->Clone() ; m_Frame0 = fr_Start ; m_dStep = dLen / nStep ; } //---------------------------------------------------------------------------- RotationMinimizeFrame::~RotationMinimizeFrame( void) { Clear() ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::IsValid() { // controllo validità della curva if ( m_pCrv == nullptr || ! m_pCrv->IsValid()) return false ; // controllo del frame iniziale if ( ! m_Frame0.IsValid()) return false ; // controllo sul parametro di discretizzazione if ( m_dStep < EPS_SMALL) return false ; // controllo che il passo non sia superiore alla lunghezza della curva double dLen = 0. ; if ( ! m_pCrv->GetLength( dLen) || m_dStep > dLen) return false ; return true ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::Clear( void) { // pulizia della curva if ( m_pCrv != nullptr) delete m_pCrv ; m_pCrv = nullptr ; // reset del frame di partenza m_Frame0.Reset() ; // reset dell'intervallo di discretizzazione m_dStep = 0. ; // pulizia del vettore dei frames m_vRMFrames.clear() ; return true ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::GetFrames( FRAME3DVECTOR& vRMFrams) { // controllo validità if ( ! IsValid()) { Clear() ; return false ; } /* Double Reflection Computation of Rotation Minimizing Frame in Computer Graphics Wenping Wang Bert Juttler Dayue Zheng Yang Liu */ // calcolo lunghezza della curva double dLen = 0. ; if ( ! m_pCrv->GetLength( dLen)) return false ; // in prima posizione viene inserito il frame iniziale m_vRMFrames.push_back( m_Frame0) ; // ricavo il numero degli step int nStep = ceil( dLen / m_dStep) ; if ( nStep == 0) // se non ho step allora serve sono il frame iniziale return true ; // variabili di utilizzo double dLenCurr = 0 ; // lunghezza della curva allo step i-esimo double dLenNext ; // lunghezza della curva allo step (i+1)-esimo double dUCurr = 0. ; // parametro sulla curva allo step i-esimo double dUNext ; // parametro sulla curva allo step (i+1)-esimo Point3d ptCurr ; // punto sulla curva allo step i-esimo if ( ! m_pCrv->GetStartPoint( ptCurr)) return false ; Point3d ptNext ; // punto sulla curva allo step (i+1)-esimo // definizione dei versori "r","s","t" Vector3d vt_r = m_Frame0.VersX() ; Vector3d vt_s = m_Frame0.VersY() ; Vector3d vt_t = m_Frame0.VersZ() ; // ricavo la lunghezza dello step di campionamento reale double dStep_real = dLen / nStep ; // ciclo sugli step in cui la curva è suddivisa for ( int i = 0 ; i < nStep ; ++ i) { // ricavo la lunghezza della curva relativo allo step (i+1)-esimo dLenNext = min( dLen - EPS_SMALL, ( i + 1) * dStep_real) ; // parametro (i+1)-esimo sulla curva if ( ! m_pCrv->GetParamAtLength( dLenNext, dUNext)) return false ; // punto (i+1)-esimo sulla curva e suo vettore tangente Vector3d vt_t_next ; if ( ! m_pCrv->GetPointD1D2( dUNext, ICurve::FROM_MINUS, ptNext, &vt_t_next) || ! vt_t_next.IsValid()) return false ; // controllo per casi degeneri if ( AreSamePointEpsilon( ptCurr, ptNext, EPS_ZERO) || // non esiste il piano R1 abs(( ptNext - ptCurr) * ( vt_t_next + vt_t)) < EPS_ZERO) // non esiste il piano R2 return false ; // ricavo il vettore di riflessione rispetto al piano R1 Vector3d vR1_norm = ptNext - ptCurr ; if ( ! vR1_norm.IsValid()) return false ; // parametro di riflessione per R1 double dPar1 = vR1_norm * vR1_norm ; // riflessione rispetto al piano R1 ( sistema sinistrorso L ) Vector3d vt_r_L = vt_r - ( 2 / dPar1) * ( vR1_norm * vt_r) * vR1_norm ; Vector3d vt_t_L = vt_t - ( 2 / dPar1) * ( vR1_norm * vt_t) * vR1_norm ; // ricavo il vettore di riflessione rispetto al piano R1 Vector3d vR2_norm = vt_t_next - vt_t_L ; if ( ! vR2_norm.IsValid()) return false ; // parametro di riflessione per R2 double dPar2 = vR2_norm * vR2_norm ; // versore r del nuovo frame (i+1)-esimo Vector3d vt_r_next = vt_r_L - ( 2 / dPar2) * ( vR2_norm * vt_r_L) * vR2_norm ; // versore t del nuovo frame (i+1)-esimo Vector3d vt_s_next = vt_t_next ^ vt_r_next ; // creazione del nuovo frame (i+1)-esimo Frame3d RMFrame_next ; RMFrame_next.Set( ptNext, vt_r_next, vt_s_next, vt_t_next) ; if ( ! RMFrame_next.IsValid()) { // il frame potrebbe non essere nelle tolleranze... // ... sistemo ricavando il versore "s" mediante "t" ed "r" ... RMFrame_next.Set( ptNext, vt_t_next, vt_r_next) ; if ( ! RMFrame_next.IsValid()) return false ; } // aggiornamento vettore dei frame m_vRMFrames.push_back( RMFrame_next) ; // aggiornamento dei parametri dLenCurr = dLenNext ; dUCurr = dUNext ; ptCurr = ptNext ; } // oriento i frames ottenuti in modo da avere il versore X tangente alla curva vRMFrams.resize( int( m_vRMFrames.size())) ; for ( int i = 0 ; i < int( m_vRMFrames.size()) ; ++ i) { //vRMFrams[i].Set( m_vRMFrames[i].Orig(), m_vRMFrames[i].VersY(), m_vRMFrames[i].VersZ()) ; vRMFrams[i] = m_vRMFrames[i] ; if ( ! vRMFrams[i].IsValid()) return false ; } return true ; }