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
+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