EgtGeomKernel :

- Swept con o senza caps mediante RMF
- inizio stesura codice per frame statico
- migliorie varie.
This commit is contained in:
Riccardo Elitropi
2024-03-14 13:04:09 +01:00
parent 4268da4a1f
commit d276809906
3 changed files with 386 additions and 208 deletions
+155 -107
View File
@@ -15,29 +15,11 @@
using namespace std ;
RotationMinimizeFrame::RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start, const double dStep)
RotationMinimizeFrame::RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start)
{
// 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 ;
}
//----------------------------------------------------------------------------
@@ -46,6 +28,21 @@ 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()
@@ -58,14 +55,6 @@ RotationMinimizeFrame::IsValid()
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 ;
// controllo che l'origine del frame sia sulla curva e che l'asse Z sia tangente alla curva
Point3d ptS ;
Vector3d vtZ ;
@@ -81,38 +70,85 @@ RotationMinimizeFrame::IsValid()
//----------------------------------------------------------------------------
bool
RotationMinimizeFrame::Clear( void)
RotationMinimizeFrame::GetFrameAtLength( const Frame3d& frAct, const double dLenNext, Frame3d& frNext)
{
// pulizia della curva
if ( m_pCrv != nullptr)
delete m_pCrv ;
m_pCrv = nullptr ;
// reset del frame di partenza
m_Frame0.Reset() ;
/*
Double Reflection
Computation of Rotation Minimizing Frame in Computer Graphics
Wenping Wang Bert Juttler Dayue Zheng Yang Liu
*/
// reset dell'intervallo di discretizzazione
m_dStep = 0. ;
// 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::GetFrames( FRAME3DVECTOR& vRMFrames)
RotationMinimizeFrame::GetFramesByStep( FRAME3DVECTOR& vRMFrames, double dStep, bool bUniform)
{
// controllo sullo step
dStep = max( 10 * EPS_SMALL, dStep) ;
// 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))
@@ -122,80 +158,92 @@ RotationMinimizeFrame::GetFrames( FRAME3DVECTOR& vRMFrames)
vRMFrames.push_back( m_Frame0) ;
// ricavo il numero degli step
int nStep = ceil( dLen / m_dStep) ;
int nStep = int( ceil( dLen / 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
// lunghezza della curva identificata dal punto successivo
double dLenNext ;
// 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 ;
// 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 - EPS_SMALL, ( i + 1) * dStep_real) ;
// parametro (i+1)-esimo sulla curva
if ( ! m_pCrv->GetParamAtLength( dLenNext, dUNext))
dLenNext = min( dLen - EPS_SMALL, ( i + 1) * dMyStep) ;
// ricavo il frame alla lunghezza calcolata
Frame3d frNext ;
if ( ! GetFrameAtLength( vRMFrames[i], dLenNext, frNext))
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 (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
vRMFrames.push_back( RMFrame_next) ;
// aggiornamento dei parametri
dLenCurr = dLenNext ;
dUCurr = dUNext ;
ptCurr = ptNext ;
vt_r = vt_r_next ;
vt_t = vt_t_next ;
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 ;
// 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 ;
// 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 ;
+5 -4
View File
@@ -24,20 +24,21 @@ typedef std::vector<Frame3d> FRAME3DVECTOR ;
class RotationMinimizeFrame
{
public :
RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start, const double dStep) ;
RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start, const int nStep) ;
RotationMinimizeFrame( const ICurve* pCrv, const Frame3d& fr_Start) ;
~RotationMinimizeFrame( void) ;
public :
bool GetFrames( FRAME3DVECTOR& vRMFrams) ;
bool GetFramesByStep( FRAME3DVECTOR& vRMFrames, double dStep, bool bUniform = false) ;
bool GetFramesBySplit( FRAME3DVECTOR& vRMFrames, int nIntervals) ;
bool GetFramesByTollerance( FRAME3DVECTOR& vRMFrames, double dTol) ;
private :
bool Clear( void) ;
bool IsValid( void) ;
bool GetFrameAtLength( const Frame3d& frAct, const double dLenNext, Frame3d& frNext) ;
private :
ICurve* m_pCrv ; // curva per il calcolo del rotation minimize frame
Frame3d m_Frame0 ; // frame iniziale della curva
double m_dStep ; // passo di discretizzazione
} ;
+226 -97
View File
@@ -665,109 +665,246 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d
bool bSectClosed = PL.IsClosed() ;
// determino se la guida è chiusa
bool bGuideClosed = pGuide->IsClosed() ;
// ricavo punto e versore iniziale
Point3d ptStart ; pGuide->GetStartPoint( ptStart) ;
Vector3d vtStart ; pGuide->GetStartDir( vtStart) ;
// creo il riferimento iniziale
Frame3d frStart ;
// inizializzo la superficie
// definisco la superficie da restituire ( definendo la sua tolleranza )
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSTM))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// calcolo punto e versore tangente iniziale
Point3d ptStart ;
pGuide->GetStartPoint( ptStart) ;
Vector3d vtStart ;
pGuide->GetStartDir( vtStart) ;
// inizializzazione del frame iniziale
Frame3d frStart ;
// verifico che la linea guida sia piana
Plane3d plGuide ;
Vector3d vtNorm ;
bool bIsFlat = pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL) ;
// inizializzo frame iniziale e finale nel caso di Rotation Minimize Frame per guide non piane
Frame3d frRMF_Start, frRMF_End ;
if ( bIsFlat) {
// definisco il frame iniziale
vtNorm = plGuide.GetVersN() ;
frStart.Set( ptStart, - vtStart, vtStart ^ vtNorm) ;
// porto la sezione in questo riferimento e appiattisco
if ( ! PL.ToLoc( frStart) || ! PL.Flatten())
return nullptr ;
// superficie swept
PtrOwner<ICurve> pPrevCrv ;
Point3d ptP ;
bool bPoint = PL.GetFirstPoint( ptP) ;
while ( bPoint) {
// nuova curva
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0)
return nullptr ;
PtrOwner<ICurve> pCurrCrv( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCurrCrv))
return nullptr ;
pCurrCrv->Translate( ptP.y * frStart.VersY()) ;
// se esiste la curva precedente, costruisco la rigata (di tipo minima distanza)
if ( ! IsNull( pPrevCrv)) {
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
if ( IsNull( pSr))
return nullptr ;
pSTM->DoSewing( *pSr) ;
}
// salvo la curva come prossima precedente
pPrevCrv.Set( pCurrCrv) ;
// prossimo punto
bPoint = PL.GetNextPoint( ptP) ;
}
}
else {
// definisco il frame iniziale
frStart.Set( ptStart, vtStart) ;
// porto la sezione in questo riferimento
if ( ! PL.ToLoc( frStart))
return nullptr ;
double dStep = 10 ;
// calcolo il vettore di Frame campionati lungo la curva
RotationMinimizeFrame RMF( pGuide, frStart, dStep) ;
FRAME3DVECTOR vRMF ;
if ( ! RMF.GetFrames( vRMF) || vRMF.empty())
return nullptr ;
// recupero la sezione come curve dalla PolyLine
if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) {
/*
La guida non è piana, l'estrusione può essere definita mediante :
( 1) un versore statico
( 2) mediante l'algoritmo del Rotation Minimize Frame
*/
// recupero la sezione come curva composite mediante tolleranza definita
PtrOwner<ICurveComposite> pSecLocApprox( CreateCurveComposite()) ;
if ( IsNull( pSecLocApprox) ||
if ( IsNull( pSecLocApprox) ||
! pSecLocApprox->FromPolyLine( PL) ||
! pSecLocApprox->IsValid())
return nullptr ;
/*
for ( int i = 0 ; i < int( vRMF.size()) ; ++ i) {
Vector3d vtH = vRMF[i].VersZ() ;
vtH.z = 0 ;
vtH.Normalize() ;
vRMF[i].Set( vRMF[i].Orig(), vtH, Z_AX ^ vtH) ;
}
pSecLocApprox->LocToLoc( frStart, vRMF[0]) ;
*/
// creo la sezione per lo step (i+1)-esimo che aggiornerò di volta in volta
for ( int i = 0 ; i < int( vRMF.size()) - 1 ; ++ i) {
// creo la sezione allo step corrente
PtrOwner<ICurve> pSecCurr( pSecLocApprox->Clone()) ;
if ( IsNull( pSecCurr) || ! pSecCurr->IsValid())
// recupero il frame iniziale sulla guida
frStart.Set( ptStart, vtStart) ;
if ( ! frStart.IsValid())
return nullptr ;
// porto la PolyLine della sezione in questo riferimento
if ( ! PL.ToLoc( frStart))
return nullptr ;
// tengo in memorial il frame nel punto iniziale e finale della guida in caso di caps
Frame3d frCaps_start ;
Frame3d frCaps_end ;
if ( true) { // (1) versore statico
Vector3d VETTORE( 0, 0, 1) ;
// creo il piano di proiezine in Z = 0 con normale definita dal vettore
Plane3d plProj ;
plProj.Set( ORIG, VETTORE) ;
if ( ! plProj.IsValid())
return nullptr ;
// porto la sezione nel frame corrente
if ( ! pSecCurr->ToGlob( vRMF[i]))
// approssimo la guida mediante la tolleranza richiesta
PolyLine PL_G ;
if ( ! pGuide->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL_G))
return nullptr ;
// creo la sezione allo step successivo
PtrOwner<ICurve> pSecNext( pSecLocApprox->Clone()) ;
if ( IsNull( pSecNext) || ! pSecNext->IsValid())
// punto attuale e punto successivo
Point3d ptCurr, ptSucc ;
if ( ! PL_G.GetFirstPoint( ptCurr))
return nullptr ;
// porto la sezione nel frame successivo
if ( ! pSecNext->ToGlob( vRMF[i+1]))
bool bNextPoint = PL_G.GetNextPoint( ptSucc) ;
if ( ! bNextPoint)
return nullptr ;
// creo la rigata tra queste due curve
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecNext, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
// parametro attuale e successivo riferito ai punti sulla guida
double dParCurr = 0 ;
double dParSucc ;
// versore attuale e successivo riferito ai punti sulla guida
Vector3d vtTanCurr, vtTanSucc ;
if ( ! pGuide->GetStartDir( vtTanCurr))
return nullptr ;
// frame iniziale e successivo riferito alla curva
Frame3d frCurr, frSucc ;
bool bFirstIter = true ;
while ( bNextPoint) { // finchè recupero un punto sucessivo...
// recupero il parametro successivo riferito alla guida
if ( ! pGuide->GetParamAtPoint( ptSucc, dParSucc))
return nullptr ;
// recupero il versore tangente riferito al punto successivo sulla griglia
if ( ! pGuide->GetPointD1D2( dParSucc, ICurve::FROM_MINUS, ptSucc, &vtTanSucc) ||
! vtTanSucc.Normalize())
return nullptr ;
// proietto i versori tangenti sul piano
Point3d ptS_proj( vtTanCurr.x, vtTanCurr.y, vtTanCurr.z) ;
ptS_proj = ProjectPointOnPlane( ptS_proj, plProj) ;
vtTanCurr.Set( ptS_proj.x, ptS_proj.y, ptS_proj.z) ;
if ( ! vtTanCurr.Normalize())
return nullptr ; // se tangente alla guida in ptCurr perpendicolare al piano...
Point3d ptE_proj( vtTanSucc.x, vtTanSucc.y, vtTanSucc.z) ;
ptE_proj = ProjectPointOnPlane( ptE_proj, plProj) ;
vtTanSucc.Set( ptE_proj.x, ptE_proj.y, ptE_proj.z) ;
if ( ! vtTanSucc.Normalize())
return nullptr ; // se tangente alla guida in ptSucc perpendicolare al piano...
// creazione del frame corrente
frCurr.Set( ptCurr, vtTanCurr, VETTORE ^ vtTanCurr) ;
if ( ! frCurr.IsValid())
return nullptr ;
if ( bFirstIter) { // memorizzo il primo frame di caso di caps
frCaps_start = frCurr ;
bFirstIter = false ;
}
// creazione del frame successivo
frSucc.Set( ptSucc, vtTanSucc, VETTORE ^ vtTanSucc) ;
if ( ! frSucc.IsValid())
return nullptr ;
frCaps_end = frSucc ; // aggiorno il frame finale
// definisco la sezione allo step corrente
PtrOwner<ICurve> pSecCurr( pSecLocApprox->Clone()) ;
if ( IsNull( pSecCurr) || ! pSecCurr->IsValid())
return nullptr ;
// porto la sezione corrente nel frame attuale
if ( ! pSecCurr->ToGlob( frCurr))
return nullptr ;
// definisco la sezione allo step successivo
PtrOwner<ICurve> pSecSucc( pSecLocApprox->Clone()) ;
if ( IsNull( pSecSucc) || ! pSecSucc->IsValid())
return nullptr ;
// porto questa sezione nel frame allo step successivo
if ( ! pSecSucc->ToGlob( frSucc))
return nullptr ;
// creo la rigata tra queste due sezioni
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
if ( IsNull( pSr) || ! pSr->IsValid())
return nullptr ;
// attacco la rigata alla superficie da restituire
pSTM->DoSewing( *pSr) ;
// aggiornamento dei parametri
ptCurr = ptSucc ; // il punto corrente diventa il successivo
bNextPoint = PL.GetNextPoint( ptSucc) ; // il successivo lo recupero dalla PolyLine
vtTanCurr = vtTanSucc ; // il versore tangete corrente diventa il successivo
}
// la superficie definita dal RMF è invertita, il verosre Z è diretto come la tangente della curva
pSTM->Invert() ;
}
else { // (2) Rotation Minimize Frame
// calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita
RotationMinimizeFrame RMF( pGuide, frStart) ;
FRAME3DVECTOR vRMF ;
if ( ! RMF.GetFramesByTollerance( vRMF, dLinTol) || vRMF.empty())
return nullptr ;
// per ogni RMF calcolato, la sezione va roto-traslata lungo la guida
for ( int i = 0 ; i < int( vRMF.size()) - 1 ; ++ i) {
// definisco la sezione allo step corrente
PtrOwner<ICurve> pSecCurr( pSecLocApprox->Clone()) ;
if ( IsNull( pSecCurr) || ! pSecCurr->IsValid())
return nullptr ;
// porto la sezione corrente nel frame attuale
if ( ! pSecCurr->ToGlob( vRMF[i]))
return nullptr ;
// definisco la sezione allo step successivo
PtrOwner<ICurve> pSecSucc( pSecLocApprox->Clone()) ;
if ( IsNull( pSecSucc) || ! pSecSucc->IsValid())
return nullptr ;
// porto questa sezione nel frame allo step successivo
if ( ! pSecSucc->ToGlob( vRMF[i+1]))
return nullptr ;
// creo la rigata tra queste due sezioni
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
if ( IsNull( pSr) || ! pSr->IsValid())
return nullptr ;
// attacco la rigata alla superficie da restituire
pSTM->DoSewing( *pSr) ;
}
// la superficie definita dal RMF è invertita, il verosre Z è diretto come la tangente della curva
pSTM->Invert() ;
// assegno frame iniziale e finale per caps
frCaps_start = vRMF[0] ;
frCaps_end = vRMF.back() ;
}
// se richiesti caps e sezione chiusa e guida aperta
if ( bCapEnds && bSectClosed && ! bGuideClosed) {
// inverto
pSTM->Invert() ;
// verifico che le due estremità siano chiuse e piatte
POLYLINEVECTOR vPL ;
if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2)
return nullptr ;
Plane3d plEnds ; double dArea ;
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL) ||
! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
return nullptr ;
// aggiungo il cap sull'inizio ( portandolo nel frame del punto iniziale della guida )
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL))
return nullptr ;
pSci->ToGlob( frCaps_start) ;
pSci->Invert() ; // il versore Z è tangente alla curva nella sua direzione di percorrenza
// unisco
pSTM->DoSewing( *pSci) ;
// aggiungo il cap sulla fine ( portandolo nel frame del punto finale della guida )
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL))
return nullptr ;
pSce->ToGlob( frCaps_end) ;
// unisco
pSTM->DoSewing( *pSce) ;
}
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
double dVol ;
if ( pSTM->GetVolume( dVol) && dVol < 0)
pSTM->Invert() ;
// restituisco la superficie
return Release( pSTM) ;
}
/*
La guida è piana, l'estrusione viene definita mediante Offset della guida sulla sezione
*/
// il frame iniziale è definito dal versore tangente e dalla normale al piano
// che contiene la guida
Vector3d vtNorm = plGuide.GetVersN() ;
frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ;
// porto la sezione in questo riferimento e ve la appiattisco
if ( ! PL.ToLoc( frStart) || ! PL.Flatten())
return nullptr ;
// superficie swept
PtrOwner<ICurve> pPrevCrv ;
Point3d ptP ;
bool bPoint = PL.GetFirstPoint( ptP) ;
while ( bPoint) {
// nuova curva
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0)
return nullptr ;
PtrOwner<ICurve> pCurrCrv( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCurrCrv))
return nullptr ;
pCurrCrv->Translate( ptP.y * frStart.VersY()) ;
// se esiste la curva precedente, costruisco la rigata ( di tipo minima distanza)
if ( ! IsNull( pPrevCrv)) {
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
if ( IsNull( pSr))
return nullptr ;
pSTM->DoSewing( *pSr) ;
}
// se devo chiudere la superficie, salvo i frame iniziali e finali
frRMF_Start = vRMF[0] ;
frRMF_End = vRMF.back() ;
// salvo la curva come prossima precedente
pPrevCrv.Set( pCurrCrv) ;
// prossimo punto
bPoint = PL.GetNextPoint( ptP) ;
}
// se richiesti caps e sezione chiusa e guida aperta
if ( bCapEnds && bSectClosed && ! bGuideClosed) {
@@ -776,37 +913,29 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d
if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2)
return nullptr ;
Plane3d plEnds ; double dArea ;
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL) ||
! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
return nullptr ;
if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
return nullptr ;
// aggiungo il cap sull'inizio
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL))
return nullptr ;
if ( ! bIsFlat)
frStart = frRMF_Start ;
pSci->ToGlob( frStart) ;
if ( ! bIsFlat)
pSci->Invert() ;
pSTM->DoSewing( *pSci) ;
// riferimento alla fine della linea guida
Frame3d frEnd ;
Point3d ptEnd ;
pGuide->GetEndPoint( ptEnd) ;
Vector3d vtEnd ;
pGuide->GetEndDir( vtEnd) ;
Frame3d frEnd ;
if ( ! bIsFlat)
frEnd = frRMF_End ;
else
frEnd.Set( ptEnd, - vtEnd, vtEnd ^ vtNorm) ;
frEnd.Set( ptEnd, -vtEnd, vtEnd ^ vtNorm) ;
// aggiungo il cap sulla fine
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL))
return nullptr ;
pSce->Invert() ;
pSce->ToGlob( frEnd) ;
if ( ! bIsFlat)
pSce->Invert() ;
pSTM->DoSewing( *pSce) ;
}
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno