diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index cb4717d..604464a 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -319,6 +319,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -462,6 +463,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 2144f62..4f6765b 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -528,6 +528,9 @@ File di origine\GeoCreate + + File di origine\Base + @@ -1196,6 +1199,12 @@ File di intestazione\Include + + File di intestazione + + + File di intestazione + diff --git a/RotationMinimizingFrame.cpp b/RotationMinimizingFrame.cpp new file mode 100644 index 0000000..edb3366 --- /dev/null +++ b/RotationMinimizingFrame.cpp @@ -0,0 +1,268 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2024 +//---------------------------------------------------------------------------- +// File : RotationMinimizingFrame.cpp Data : 05.03.24 Versione : 2.6d1 +// Contenuto : Classe per RotationMinimizeFrame +// +// +// +// Modifiche : 05.03.24 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "RotationMinimizingFrame.h" +#include "GeoConst.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +RotationMinimizingFrame::RotationMinimizingFrame( const ICurve* pCrv, const Frame3d& fr_Start) +{ + // assegno i parametri + m_pCrv = pCrv->Clone() ; + m_Frame0 = fr_Start ; +} + +//---------------------------------------------------------------------------- +RotationMinimizingFrame::~RotationMinimizingFrame( void) +{ + Clear() ; +} + +//---------------------------------------------------------------------------- +bool +RotationMinimizingFrame::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 +RotationMinimizingFrame::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 +RotationMinimizingFrame::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_t = frAct.VersZ() ; + // ( vt_s è implicito ) + + 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 +RotationMinimizingFrame::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 +RotationMinimizingFrame::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 +RotationMinimizingFrame::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 ; +} diff --git a/RotationMinimizingFrame.h b/RotationMinimizingFrame.h new file mode 100644 index 0000000..d382125 --- /dev/null +++ b/RotationMinimizingFrame.h @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2024 +//---------------------------------------------------------------------------- +// File : RotationMinimizingFrame.h Data : 05.03.24 Versione : 2.6d1 +// Contenuto : Dichiarazione della classe RotationMinimizingFrame. +// +// +// +// Modifiche : 05.03.24 RE Creazione modulo. + +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkFrame3d.h" +#include "/EgtDev/Include/EGkCurve.h" +#include + +//---------------------------------------------------------------------------- +typedef std::vector FRAME3DVECTOR ; + +//---------------------------------------------------------------------------- +class RotationMinimizingFrame +{ + public : + RotationMinimizingFrame( const ICurve* pCrv, const Frame3d& fr_Start) ; + ~RotationMinimizingFrame( void) ; + + public : + 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 +} ; diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index 0af869f..7ee3d52 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -1,4 +1,4 @@ -//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : StmFromCurves.cpp Data : 01.02.15 Versione : 1.6b1 @@ -19,10 +19,12 @@ #include "CurveComposite.h" #include "SurfTriMesh.h" #include "Voronoi.h" +#include "RotationMinimizingFrame.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Include/EGkSfrCreate.h" #include #include #include @@ -110,9 +112,9 @@ GetSurfTriMeshByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr, PtrOwner pSTM( CreateBasicSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByExtrusion( PL, vtExtr)) return nullptr ; - // se da fare, metto i tappi sulle estremità + // se da fare, metto i tappi sulle estremità if ( bDoCapEnds) { - // creo la prima superficie di estremità + // creo la prima superficie di estremità SurfTriMesh STM1 ; if ( ! STM1.CreateByFlatContour( PL)) return nullptr ; @@ -156,7 +158,7 @@ GetSurfTriMeshByRegionExtrusion( const CICURVEPVECTOR& vpCurve, const Vector3d& for ( int i = 0 ; i < int( vPL.size()) ; ++ i) vPL[i].Invert() ; } - // creo la prima superficie di estremità + // creo la prima superficie di estremità PtrOwner pSTM( CreateBasicSurfTriMesh()) ; if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL)) return nullptr ; @@ -288,7 +290,7 @@ GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vecto return nullptr ; // se richiesti caps if ( bCapEnds) { - // determino se la sezione è chiusa e piatta + // determino se la sezione è chiusa e piatta Plane3d plPlane ; double dArea ; bool bSectClosedFlat = PL.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL) ; // determino non sia una semplice rivoluzione @@ -332,7 +334,7 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) return nullptr ; Vector3d vtNorm = plGuide.GetVersN() ; - // determino se la guida è chiusa + // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; // curve di offset OffsetCurve OffsCrvR ; @@ -373,7 +375,7 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, pSTM->SetSmoothAngle( 20) ; // se guida aperta e tappi piatti if ( ! bGuideClosed && nCapType == RSCAP_FLAT) { - // verifico che le due estremità siano chiuse e piatte + // verifico che le due estremità siano chiuse e piatte POLYLINEVECTOR vPL ; if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) return nullptr ; @@ -452,7 +454,7 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub Point3d ptCen ; pGuide->GetStartPoint( ptCen) ; ptCen -= dDimV / 2 * vtNorm ; - // determino se la guida è chiusa + // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; // curve di offset const int NUM_OFFS = 4 ; @@ -475,7 +477,7 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub } } else { - // se Voronoi non è possibile calcolare gli offset di una stessa curva in parallelo + // se Voronoi non è possibile calcolare gli offset di una stessa curva in parallelo for ( int i = 0 ; i < NUM_OFFS && bOk ; ++ i) bOk = vOffsCrv[i].Make( pGuide, vDist[i], ICurve::OFF_FILLET) ; } @@ -552,7 +554,7 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub StmFromTriangleSoup stmCapSoup ; if ( ! stmCapSoup.Start( nBuckets)) return nullptr ; - // verifico che le due estremità siano chiuse e piatte + // verifico che le due estremità siano chiuse e piatte POLYLINEVECTOR vPL ; if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) return nullptr ; @@ -651,46 +653,289 @@ GetSurfTriMeshRectSwept( double dDimH, double dDimV, double dBevelH, double dBev //------------------------------------------------------------------------------- ISurfTriMesh* -GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol) +GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol, Vector3d* vtStatic) { // verifica parametri if ( pSect == nullptr || pGuide == nullptr) return nullptr ; + // calcolo la polilinea che approssima la sezione PolyLine PL ; if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) return nullptr ; - // determino se la sezione è chiusa + + // determino se la sezione è chiusa bool bSectClosed = PL.IsClosed() ; - // verifico che la linea guida sia piana - Plane3d plGuide ; - if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) - return nullptr ; - // determino se la guida è chiusa + // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; - // riferimento all'inizio della linea guida - Frame3d frStart ; - Point3d ptStart ; - pGuide->GetStartPoint( ptStart) ; - Vector3d vtStart ; - pGuide->GetStartDir( vtStart) ; - 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 ; - // calcolo 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 ( viene definito a seconda dei casi ) + Frame3d frStart ; + + /* GUIDA PIANA */ + + // verifico che la linea guida sia piana + Plane3d plGuide ; + 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 dalla PolyLine approssimata come Curva + PtrOwner pSecLocApprox( CreateBasicCurveComposite()) ; + if ( IsNull( pSecLocApprox) || + ! pSecLocApprox->FromPolyLine( PL) || + ! pSecLocApprox->IsValid()) + return nullptr ; + + // recupero il frame iniziale sulla guida ( Origine sul punto iniziale e asse Z tangente ) + frStart.Set( ptStart, vtStart) ; + if ( ! frStart.IsValid()) + return nullptr ; + + // tengo in memoria il frame nel punto iniziale e finale della guida in caso di caps + Frame3d frCaps_start ; + Frame3d frCaps_end ; + + // (1) versore statico + if ( vtStatic != nullptr) { + + // creo il piano di proiezione con normale definita dal vettore + Plane3d plProj ; + plProj.Set( ORIG, *vtStatic) ; + if ( ! plProj.IsValid()) + return nullptr ; + + // porto la sezione nel frame definito dalla guida, tenendo il versore X del frame nel piano + // definito da vtStatic + Vector3d vtX = vtStart ; // versore tangente alla curva + vtX.Rotate( *vtStatic, 90) ; // ruoto di 90 gradi rispetto a vtStatic + OrthoCompo( vtX, *vtStatic) ; // tengo la componente nel piano + vtX.Normalize() ; // normalizzo + Frame3d frInitial ; frInitial.Set( ptStart, vtStart, vtX) ; // creo il frame + if ( ! frInitial.IsValid()) + return nullptr ; + + // porto la sezione nel riferimento + pSecLocApprox->ToLoc( frInitial) ; + PL.ToLoc( frInitial) ; //... porto anche la PolyLine del bordo della sezione + + // 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 ; + + // punto attuale e punto successivo sulla guida su cui definire il frame + Point3d ptCurr, ptSucc ; + if ( ! PL_G.GetFirstPoint( ptCurr)) + return nullptr ; + bool bNextPoint = PL_G.GetNextPoint( ptSucc) ; + if ( ! bNextPoint) + return nullptr ; + + // 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 ; // per salvare il frame iniziale nel caso di caps + 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 guida + if ( ! pGuide->GetPointD1D2( dParSucc, ICurve::FROM_MINUS, ptSucc, &vtTanSucc) || + ! vtTanSucc.Normalize()) + return nullptr ; + + // creazione del frame nel punto corrente + Vector3d vtX_curr = vtTanCurr ; + vtX_curr.Rotate( *vtStatic, 90) ; + OrthoCompo( vtX_curr, *vtStatic) ; + vtX_curr.Normalize() ; + frCurr.Set( ptCurr, vtTanCurr, vtX_curr) ; + if ( ! frCurr.IsValid()) + return nullptr ; + + // memorizzo il primo frame di caso di caps + if ( bFirstIter) { + frCaps_start = frCurr ; + bFirstIter = false ; + } + + // creazione del frame nel punto successivo + Vector3d vtX_succ = vtTanSucc ; + vtX_succ.Rotate( *vtStatic, 90) ; + OrthoCompo( vtX_curr, *vtStatic) ; + vtX_succ.Normalize() ; + frSucc.Set( ptSucc, vtTanSucc, vtX_succ) ; + if ( ! frSucc.IsValid()) + return nullptr ; + + + frCaps_end = frSucc ; // aggiorno il frame finale ad ogni step + + // definisco la sezione allo step corrente + PtrOwner pSecCurr( pSecLocApprox->Clone()) ; + if ( IsNull( pSecCurr) || ! pSecCurr->IsValid()) + return nullptr ; + + // considero la sezione ( in locale ) come vista dal globale + if ( ! pSecCurr->ToGlob( frCurr)) + return nullptr ; + + // definisco la sezione allo step successivo + PtrOwner pSecSucc( pSecLocApprox->Clone()) ; + if ( IsNull( pSecSucc) || ! pSecSucc->IsValid()) + return nullptr ; + + // considero la sezione ( in locale ) come vista dal globale + 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_G.GetNextPoint( ptSucc) ; // il successivo lo recupero dalla PolyLine + vtTanCurr = vtTanSucc ; // il versore tangete corrente diventa il successivo + } + // la superficie definita dal RMF è invertita, il versore Z è diretto come la tangente della curva + pSTM->Invert() ; + + } + + // (2) Rotation Minimizing Frame + else { + + // porto la PolyLine e la curva della sezione nel riferimento nel punto iniziale della guida + pSecLocApprox->ToLoc( frStart) ; + PL.ToLoc( frStart) ; + + // calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita + RotationMinimizingFrame 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 ; + + // considero la sezione ( in locale ) come vista dal globale + if ( ! pSecCurr->ToGlob( vRMF[i])) + return nullptr ; + + // definisco la sezione allo step successivo + PtrOwner pSecSucc( pSecLocApprox->Clone()) ; + if ( IsNull( pSecSucc) || ! pSecSucc->IsValid()) + return nullptr ; + + // considero la sezione ( in locale ) come vista dal globale + 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 versore 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 + // (1) vtStatic, (2) Rotation Minimize Frame + if ( bCapEnds && bSectClosed && ! bGuideClosed) { + + // 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) ; + // 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) ; + + pSce->Invert() ; // il versore z è definito dalle tangenti alla curva + + // 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) ; + + } + + /* + GUIDA PIANA + 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 + // nuova curva ( definita dall'Offset ) OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0) return nullptr ; @@ -698,21 +943,26 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d if ( IsNull( pCurrCrv)) return nullptr ; pCurrCrv->Translate( ptP.y * frStart.VersY()) ; - // se esiste la curva precedente, costruisco la rigata (di tipo minima distanza) + + // 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 ; + // unisco pSTM->DoSewing( *pSr) ; } + // 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) { - // verifico che le due estremità siano chiuse e piatte + // verifico che le due estremità siano chiuse e piatte POLYLINEVECTOR vPL ; if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) return nullptr ; @@ -726,6 +976,7 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL)) return nullptr ; pSci->ToGlob( frStart) ; + // unisco pSTM->DoSewing( *pSci) ; // riferimento alla fine della linea guida Frame3d frEnd ; @@ -740,6 +991,7 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d return nullptr ; pSce->Invert() ; pSce->ToGlob( frEnd) ; + // unisco pSTM->DoSewing( *pSce) ; } // se superficie risultante chiusa, verifico che la normale sia verso l'esterno @@ -750,6 +1002,72 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d return Release( pSTM) ; } +//------------------------------------------------------------------------------- +ISurfTriMesh* +GetSurfTriMeshSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, bool bCapEnds, + double dLinTol, Vector3d* vtStatic) +{ + // verifica dei parametri + if ( pSfrSect == nullptr || pGuide == nullptr) + return nullptr ; + + // creo la Trimesh da restituire + PtrOwner pStmSwept( CreateBasicSurfTriMesh()) ; + if ( IsNull( pStmSwept) || ! pStmSwept->AdjustTopology()) + return nullptr ; + + StmFromTriangleSoup StmSoup ; + StmSoup.Start() ; + // per ogni loop della superficie, creo una Swept + for ( int c = 0 ; c < pSfrSect->GetChunkCount() ; ++ c) { + for ( int l = 0 ; l < pSfrSect->GetLoopCount( c) ; ++ l) { + // recupero il loop + PtrOwner pCrvLoop( pSfrSect->GetLoop( c, l)) ; + if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) + return nullptr ; + // creo la Trimesh Swept + PtrOwner pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, false, dLinTol, vtStatic)) ; + if ( IsNull( pStmLoopSwept) || ! pStmLoopSwept->IsValid()) + return nullptr ; + // aggiungo la Swept ricavata al risultato finale ( come triangoli ) + StmSoup.AddSurfTriMesh( *pStmLoopSwept) ; + } + } + StmSoup.End() ; + if ( ! pStmSwept.Set( StmSoup.GetSurf()) || IsNull( pStmSwept) || + ! pStmSwept->IsValid() || ! pStmSwept->AdjustTopology()) + return nullptr ; + + + // se rischista chiusura... + // NB. Controllo solo che al guida non sia chiusa, la sezione derivando da una Flatregion è chiusa per + // definizione + if ( bCapEnds && ! pGuide->IsClosed()) { + // creo il cap sull'inizio e lo attacco alla swept ( è già in posizione giusta ) + PtrOwner pSci( pSfrSect->GetAuxSurf()->Clone()) ; + if ( IsNull( pSci) || ! pSci->IsValid()) + return nullptr ; + pStmSwept->DoSewing( *pSci) ; + // recupero i loops alla fine + POLYLINEVECTOR vPL ; + if ( ! pStmSwept->GetLoops( vPL)) + return nullptr ; + // creo la superficie alla fine e la attacco + PtrOwner pSce( CreateSurfTriMesh()) ; + if ( ! pSce->CreateByRegion( vPL)) + return nullptr ; + // attacco la superficie finale alla swept + pSce->Invert() ; + pStmSwept->DoSewing( *pSce) ; + } + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pStmSwept->GetVolume( dVol) && dVol < 0) + pStmSwept->Invert() ; + + return Release( pStmSwept) ; +} + //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshTransSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol) @@ -757,7 +1075,7 @@ GetSurfTriMeshTransSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEn // verifica parametri if ( pSect == nullptr || pGuide == nullptr) return nullptr ; - // determino se la sezione è chiusa + // determino se la sezione è chiusa bool bSectClosed = pSect->IsClosed() ; // punto iniziale della sezione e vettore a inizio guida Point3d ptStart ; @@ -771,7 +1089,7 @@ GetSurfTriMeshTransSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEn PolyLine PLG ; if ( ! pGuide->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PLG)) return nullptr ; - // determino se la guida è chiusa + // determino se la guida è chiusa bool bGuideClosed = PLG.IsClosed() ; // calcolo la superficie PtrOwner pSTM( CreateBasicSurfTriMesh()) ; @@ -937,7 +1255,7 @@ CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, vCrvCompo[i]->ToLoc( frRef) ; } - // creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle + // creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle // successive i loop interni INTMATRIX vnPLIndMat ; @@ -970,10 +1288,10 @@ CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, } bFirstCrv = false ; } - // ... altrimenti verifico se il loop è interno o no + // ... altrimenti verifico se il loop è interno o no else { - // il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo - // esterno a tutti i loop già inseriti nella riga attuale. + // il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo + // esterno a tutti i loop già inseriti nella riga attuale. // verifica rispetto loop esterno IntersCurveCurve ccInt( *vCrvCompo[vnPLIndMat.back().front()], *vCrvCompo[j]) ; CRVCVECTOR ccClass ;