diff --git a/RotationMinimizeFrame.cpp b/RotationMinimizeFrame.cpp index 39ccc43..13603db 100644 --- a/RotationMinimizeFrame.cpp +++ b/RotationMinimizeFrame.cpp @@ -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 ; diff --git a/RotationMinimizeFrame.h b/RotationMinimizeFrame.h index fda7651..c3b80ba 100644 --- a/RotationMinimizeFrame.h +++ b/RotationMinimizeFrame.h @@ -24,20 +24,21 @@ typedef std::vector 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 } ; diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index ec20f0c..7e60df8 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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