EgtGeomKernel :
- Swept con o senza caps mediante RMF - inizio stesura codice per frame statico - migliorie varie.
This commit is contained in:
+226
-97
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user