//---------------------------------------------------------------------------- // 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) { // assegno i parametri m_pCrv = pCrv->Clone() ; m_Frame0 = fr_Start ; } //---------------------------------------------------------------------------- RotationMinimizeFrame::~RotationMinimizeFrame( void) { Clear() ; } //---------------------------------------------------------------------------- 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() ; return true ; } //---------------------------------------------------------------------------- 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 che l'origine del frame sia sulla curva e che l'asse Z sia tangente alla curva Point3d ptS ; Vector3d vtZ ; if ( ! m_pCrv->GetPointD1D2( 0., ICurve::FROM_MINUS, ptS, &vtZ) || ! vtZ.Normalize() || ! AreSamePointApprox( ptS, m_Frame0.Orig()) || ! AreSameVectorEpsilon( vtZ, m_Frame0.VersZ(), 5 * EPS_SMALL)) return false ; return true ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::GetFrameAtLength( const Frame3d& frAct, const double dLenNext, Frame3d& frNext) { /* Double Reflection Computation of Rotation Minimizing Frame in Computer Graphics Wenping Wang Bert Juttler Dayue Zheng Yang Liu */ // ricavo i parametri dal frame if ( ! frAct.IsValid()) return false ; // origine del frame e versori ( ptAct, [ vt_r, vt_s, vt_t]) Point3d ptCurr = frAct.Orig() ; Vector3d vt_r = frAct.VersX() ; Vector3d vt_t = frAct.VersZ() ; // ( vt_s è implicito ) double dUNext ; // parametro sulla curva nello step successivo Point3d ptNext ; // punto sulla curva allo step successivo // 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() || ! vt_t_next.Normalize()) // versore tangente 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 Vector3d vt_r_next = vt_r_L - ( 2 / dPar2) * ( vR2_norm * vt_r_L) * vR2_norm ; // versore t del nuovo frame Vector3d vt_s_next = vt_t_next ^ vt_r_next ; // imposto il nuovo frame frNext.Set( ptNext, vt_r_next, vt_s_next, vt_t_next) ; if ( ! frNext.IsValid()) { // il frame potrebbe non essere nelle tolleranze... // ... sistemo ricavando il versore "s" mediante "t" ed "r" ... frNext.Set( ptNext, vt_t_next, vt_r_next) ; if ( ! frNext.IsValid()) return false ; } return true ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::GetFramesByStep( FRAME3DVECTOR& vRMFrames, double dStep, bool bUniform) { // controllo sullo step dStep = max( 10 * EPS_SMALL, dStep) ; // controllo validità if ( ! IsValid()) { Clear() ; return false ; } // calcolo lunghezza della curva double dLen = 0. ; if ( ! m_pCrv->GetLength( dLen)) return false ; // in prima posizione viene inserito il frame iniziale vRMFrames.push_back( m_Frame0) ; // ricavo il numero degli step int nStep = int( ceil( dLen / dStep)) ; if ( nStep == 0) // se non ho step allora serve sono il frame iniziale return true ; // lunghezza della curva identificata dal punto successivo double dLenNext ; // step corrente double dMyStep = dStep ; if ( bUniform) dMyStep = 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 - 10 * EPS_SMALL, ( i + 1) * dMyStep) ; // ricavo il frame alla lunghezza calcolata Frame3d frNext ; if ( ! GetFrameAtLength( vRMFrames[i], dLenNext, frNext)) return false ; // aggiornamento vettore dei frame vRMFrames.push_back( frNext) ; } return true ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::GetFramesBySplit( FRAME3DVECTOR& vRMFrames, int nIntervals) { // controllo sul numero di intervalli nIntervals = max( 1, nIntervals) ; // ricavo lo step associato double dLen = 0 ; if ( ! m_pCrv->GetLength( dLen)) return false ; // ricavo lo step associato double dStep = dLen / nIntervals ; return GetFramesByStep( vRMFrames, dStep) ; } //---------------------------------------------------------------------------- bool RotationMinimizeFrame::GetFramesByTollerance( FRAME3DVECTOR& vRMFrames, double dTol) { // controllo sulla tolleranza dTol = max( EPS_SMALL, dTol) ; // controllo validità if ( ! IsValid()) { Clear() ; return false ; } // ricavo la PolyLine associata alla curva mediante tale tolleranza PolyLine PL ; if ( ! m_pCrv->ApproxWithLines( dTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) return false ; // ricavo la lunghezza della curva double dCrvLen = 0 ; if ( ! m_pCrv->GetLength( dCrvLen)) return false ; // devo calcolare il RMF su ogni punto ricavato dall'approssimazione Point3d ptCurr ; bool bPoint = PL.GetFirstPoint( ptCurr) ; bool bFirst = true ; while ( bPoint) { if ( bFirst) { // in prima posizione viene inserito il frame iniziale vRMFrames.push_back( m_Frame0) ; bFirst = false ; } else { // ricavo la lunghezza della curva al punto corrente double dLen = 0. ; if ( ! m_pCrv->GetLengthAtPoint( ptCurr, dLen)) return false ; // per sicurezza controllo che sia minore della lunghezza complessiva dLen = min( dCrvLen - 10 * EPS_SMALL , dLen) ; // ricavo il Frame associato a tale lunghezza Frame3d frNext ; if ( ! GetFrameAtLength( vRMFrames.back(), dLen, frNext)) return false ; vRMFrames.emplace_back( frNext) ; } // passo al punto successivo bPoint = PL.GetNextPoint( ptCurr) ; } return true ; }