Files
EgtGeomKernel/RotationMinimizeFrame.cpp
T
Riccardo Elitropi 9880fa0173 EgtGeomKernel :
- migliorie varie.
2024-03-15 13:17:41 +01:00

257 lines
7.9 KiB
C++

//----------------------------------------------------------------------------
// 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_s = frAct.VersY() ;
Vector3d vt_t = frAct.VersZ() ;
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 ;
}