From 2bd53476cae332c582583327ce62983e161e23d4 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Fri, 5 Apr 2024 16:55:20 +0200 Subject: [PATCH] EgtGeomKernel : - modifiche per RotationMinimizingFrame e RotationXplaneFrame - aggiornato calcolo superfici TriMesh da Swept di curva o di regione. --- EgtGeomKernel.vcxproj | 5 +- EgtGeomKernel.vcxproj.filters | 11 +- RotationMinimizingFrame.cpp | 191 +++++------- RotationMinimizingFrame.h | 43 --- RotationXplaneFrame.cpp | 223 ++++++++++++++ StmFromCurves.cpp | 528 +++++++++++++++------------------- Vector3d.cpp | 4 + 7 files changed, 538 insertions(+), 467 deletions(-) delete mode 100644 RotationMinimizingFrame.h create mode 100644 RotationXplaneFrame.cpp diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 604464a..94f3253 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -320,6 +320,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -332,6 +333,8 @@ copy $(TargetPath) \EgtProg\Dll64 + + @@ -463,8 +466,6 @@ copy $(TargetPath) \EgtProg\Dll64 - - diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 4f6765b..477d1e3 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -531,6 +531,9 @@ File di origine\Base + + File di origine\Base + @@ -1199,11 +1202,11 @@ File di intestazione\Include - - File di intestazione + + File di intestazione\Include - - File di intestazione + + File di intestazione\Include diff --git a/RotationMinimizingFrame.cpp b/RotationMinimizingFrame.cpp index edb3366..cbb878c 100644 --- a/RotationMinimizingFrame.cpp +++ b/RotationMinimizingFrame.cpp @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -// EgalTech 2015-2024 +// EgalTech 2024-2024 //---------------------------------------------------------------------------- // File : RotationMinimizingFrame.cpp Data : 05.03.24 Versione : 2.6d1 // Contenuto : Classe per RotationMinimizeFrame @@ -13,23 +13,26 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "RotationMinimizingFrame.h" #include "GeoConst.h" +#include "/EgtDev/Include/EGkRotationMinimizingFrame.h" using namespace std ; //---------------------------------------------------------------------------- -RotationMinimizingFrame::RotationMinimizingFrame( const ICurve* pCrv, const Frame3d& fr_Start) +bool +RotationMinimizingFrame::Set( const ICurve* pCrv, const Frame3d& fr_Start) { + // pulisco + Clear() ; + // verifico i parametri + if ( pCrv == nullptr || ! pCrv->IsValid() || + ! fr_Start.IsValid()) + return false ; // assegno i parametri m_pCrv = pCrv->Clone() ; m_Frame0 = fr_Start ; -} -//---------------------------------------------------------------------------- -RotationMinimizingFrame::~RotationMinimizingFrame( void) -{ - Clear() ; + return true ; } //---------------------------------------------------------------------------- @@ -40,7 +43,6 @@ RotationMinimizingFrame::Clear( void) if ( m_pCrv != nullptr) delete m_pCrv ; m_pCrv = nullptr ; - // reset del frame di partenza m_Frame0.Reset() ; @@ -49,7 +51,7 @@ RotationMinimizingFrame::Clear( void) //---------------------------------------------------------------------------- bool -RotationMinimizingFrame::IsValid() +RotationMinimizingFrame::IsValid( void) { // controllo validità della curva if ( m_pCrv == nullptr || ! m_pCrv->IsValid()) @@ -69,12 +71,11 @@ RotationMinimizingFrame::IsValid() return false ; return true ; - } //---------------------------------------------------------------------------- bool -RotationMinimizingFrame::GetFrameAtLength( const Frame3d& frAct, const double dLenNext, Frame3d& frNext) +RotationMinimizingFrame::GetFrameAtParam( const Frame3d& frAct, const double dParNext, Frame3d& frNext) { /* Double Reflection @@ -86,28 +87,21 @@ RotationMinimizingFrame::GetFrameAtLength( const Frame3d& frAct, const double dL if ( ! frAct.IsValid()) return false ; - // origine del frame e versori ( ptAct, [ vt_r, vt_s, vt_t]) + // origine del frame e versori ( ptCurr, [ vtCurrR, vtCurrS, vtCurrT]) Point3d ptCurr = frAct.Orig() ; - Vector3d vt_r = frAct.VersX() ; - Vector3d vt_t = frAct.VersZ() ; - // ( vt_s è implicito ) + Vector3d vtCurrR = frAct.VersX() ; + Vector3d vtCurrT = 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 + // punto i-esimo sulla curva e suo vettore tangente + Point3d ptNext ; + Vector3d vtNextT ; + if ( ! m_pCrv->GetPointD1D2( dParNext, ICurve::FROM_MINUS, ptNext, &vtNextT) || + ! vtNextT.Normalize()) 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 + if ( AreSamePointEpsilon( ptCurr, ptNext, EPS_ZERO) || // non esiste il piano R1 + abs( ( ptNext - ptCurr) * ( vtNextT + vtCurrT)) < EPS_ZERO) // non esiste il piano R2 return false ; // ricavo il vettore di riflessione rispetto al piano R1 @@ -119,11 +113,11 @@ RotationMinimizingFrame::GetFrameAtLength( const Frame3d& frAct, const double dL 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 ; + Vector3d vt_r_L = vtCurrR - ( 2 / dPar1) * ( vR1_norm * vtCurrR) * vR1_norm ; + Vector3d vt_t_L = vtCurrT - ( 2 / dPar1) * ( vR1_norm * vtCurrT) * vR1_norm ; // ricavo il vettore di riflessione rispetto al piano R1 - Vector3d vR2_norm = vt_t_next - vt_t_L ; + Vector3d vR2_norm = vtNextT - vt_t_L ; if ( ! vR2_norm.IsValid()) return false ; @@ -131,65 +125,47 @@ RotationMinimizingFrame::GetFrameAtLength( const Frame3d& frAct, const double dL 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 ; - + return frNext.Set( ptNext, vtNextT, vt_r_next) ; } //---------------------------------------------------------------------------- bool -RotationMinimizingFrame::GetFramesByStep( FRAME3DVECTOR& vRMFrames, double dStep, bool bUniform) +RotationMinimizingFrame::GetFramesByStep( double dStep, bool bUniform, FRAME3DVECTOR& vRMFrames) { + // controllo validità + if ( ! IsValid()) + return false ; + // controllo sullo step dStep = max( 10 * EPS_SMALL, dStep) ; - // controllo validità - if ( ! IsValid()) { - Clear() ; + // lunghezza della curva + double dCrvLen = 0. ; + if ( ! m_pCrv->GetLength( dCrvLen) || dCrvLen < 10 * EPS_SMALL) 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 ; + int nStep = int( ceil( dCrvLen / dStep)) ; + double dMyStep = ( bUniform ? dCrvLen / nStep : dStep) ; - // lunghezza della curva identificata dal punto successivo - double dLenNext ; - - // step corrente - double dMyStep = dStep ; - if ( bUniform) - dMyStep = dLen / nStep ; + // inserisco il frame iniziale nel vettore dei riferimenti + vRMFrames.clear() ; + vRMFrames.reserve( nStep + 1) ; + vRMFrames.push_back( m_Frame0) ; // 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)) + for ( int i = 1 ; i <= nStep ; ++ i) { + // ricavo il parametro della curva allo step i-esimo + double dParNext ; + if ( ! m_pCrv->GetParamAtLength( min( i * dMyStep, dCrvLen - EPS_SMALL), dParNext)) return false ; - // aggiornamento vettore dei frame + // ricavo il frame alla posizione calcolata + Frame3d frNext ; + if ( ! GetFrameAtParam( vRMFrames[i-1], dParNext, frNext)) + return false ; + // inserisco nuovo frame nel vettore dei riferimenti vRMFrames.push_back( frNext) ; } @@ -198,70 +174,57 @@ RotationMinimizingFrame::GetFramesByStep( FRAME3DVECTOR& vRMFrames, double dStep //---------------------------------------------------------------------------- bool -RotationMinimizingFrame::GetFramesBySplit( FRAME3DVECTOR& vRMFrames, int nIntervals) +RotationMinimizingFrame::GetFramesBySplit( int nIntervals, FRAME3DVECTOR& vRMFrames) { + // controllo validità + if ( ! IsValid()) + return false ; + // controllo sul numero di intervalli nIntervals = max( 1, nIntervals) ; - // ricavo lo step associato + // ricavo lo step double dLen = 0 ; if ( ! m_pCrv->GetLength( dLen)) return false ; - - // ricavo lo step associato double dStep = dLen / nIntervals ; - return GetFramesByStep( vRMFrames, dStep) ; + return GetFramesByStep( dStep, true, vRMFrames) ; } //---------------------------------------------------------------------------- bool -RotationMinimizingFrame::GetFramesByTollerance( FRAME3DVECTOR& vRMFrames, double dTol) +RotationMinimizingFrame::GetFramesByTolerance( double dTol, FRAME3DVECTOR& vRMFrames) { + // controllo validità + if ( ! IsValid()) + return false ; + // 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 ; + int nStep = PL.GetLineNbr() ; - // ricavo la lunghezza della curva - double dCrvLen = 0 ; - if ( ! m_pCrv->GetLength( dCrvLen)) - return false ; + // inserisco il frame iniziale nel vettore dei riferimenti + vRMFrames.clear() ; + vRMFrames.reserve( nStep + 1) ; + vRMFrames.push_back( m_Frame0) ; - // devo calcolare il RMF su ogni punto ricavato dall'approssimazione + // eseguo il calcolo dei frame 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) ; + PL.GetFirstPoint( ptCurr) ; + double dParNext ; + Point3d ptNext ; + while ( PL.GetNextUPoint( &dParNext, &ptNext)) { + // ricavo il Frame associato a questa posizione + Frame3d frNext ; + if ( ! GetFrameAtParam( vRMFrames.back(), dParNext, frNext)) + return false ; + vRMFrames.emplace_back( frNext) ; } return true ; diff --git a/RotationMinimizingFrame.h b/RotationMinimizingFrame.h deleted file mode 100644 index d382125..0000000 --- a/RotationMinimizingFrame.h +++ /dev/null @@ -1,43 +0,0 @@ -//---------------------------------------------------------------------------- -// 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/RotationXplaneFrame.cpp b/RotationXplaneFrame.cpp new file mode 100644 index 0000000..1bbe710 --- /dev/null +++ b/RotationXplaneFrame.cpp @@ -0,0 +1,223 @@ +//---------------------------------------------------------------------------- +// EgalTech 2024-2024 +//---------------------------------------------------------------------------- +// File : RotationXplaneFrame.cpp Data : 05.04.24 Versione : 2.6d1 +// Contenuto : Classe per RotationXplaneFrame. +// +// +// +// Modifiche : 05.04.24 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "GeoConst.h" +#include "/EgtDev/Include/EGkRotationXplaneFrame.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::Set( const ICurve* pCrv, const Vector3d& vtNorm, const Vector3d& vtNearX) +{ + // pulisco + Clear() ; + // verifico i parametri + if ( pCrv == nullptr || ! pCrv->IsValid() || + ! vtNorm.IsValid() || vtNorm.IsSmall() || ! vtNearX.IsValid()) + return false ; + // assegno i parametri + m_pCrv = pCrv->Clone() ; + m_vtNorm = vtNorm ; + m_vtNearX = vtNearX ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::Clear( void) +{ + // pulizia della curva + if ( m_pCrv != nullptr) + delete m_pCrv ; + m_pCrv = nullptr ; + // reset dei vettori + m_vtNorm = V_NULL ; + m_vtNearX = V_NULL ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::IsValid( void) +{ + // controllo validità della curva + if ( m_pCrv == nullptr || ! m_pCrv->IsValid()) + return false ; + + // controllo della normale al piano + if ( m_vtNorm.IsSmall()) + return false ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::GetFrameAtParam( const Frame3d& frAct, const double dParNext, Frame3d& frNext) +{ + // verifico il riferimento corrente + if ( ! frAct.IsValid()) + return false ; + + // recupero punto e tangente nel nuovo punto + Point3d ptNext ; + Vector3d vtNext ; + if ( ! m_pCrv->GetPointD1D2( dParNext, ICurve::FROM_MINUS, ptNext, &vtNext) || + ! vtNext.Normalize()) + return false ; + + // calcolo il nuovo riferimento + Vector3d vtAxX = m_vtNorm ^ vtNext ; + if ( vtAxX.IsSmall()) + vtAxX = frAct.VersX() ; + else if ( vtAxX * frAct.VersX() < 0) + vtAxX.Invert() ; + + // lo imposto + return frNext.Set( ptNext, vtNext, vtAxX) ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::GetFramesByStep( double dStep, bool bUniform, FRAME3DVECTOR& vRXFrames) +{ + // controllo validità + if ( ! IsValid()) + return false ; + + // controllo sullo step + dStep = max( 10 * EPS_SMALL, dStep) ; + + // lunghezza della curva + double dCrvLen = 0. ; + if ( ! m_pCrv->GetLength( dCrvLen) || dCrvLen < 10 * EPS_SMALL) + return false ; + + // numero e lunghezza effettiva di ogni step + int nStep = int( ceil( dCrvLen / dStep)) ; + double dMyStep = ( bUniform ? dCrvLen / nStep : dStep) ; + + // calcolo il riferimento iniziale + Point3d ptStart ; m_pCrv->GetStartPoint( ptStart) ; + Vector3d vtStart ; m_pCrv->GetStartDir( vtStart) ; + Vector3d vtAxX = m_vtNorm ^ vtStart ; + if ( vtAxX.IsSmall()) { + vtAxX = OrthoCompo( m_vtNearX, m_vtNorm) ; + if ( vtAxX.IsSmall()) { + vtAxX = FromUprightOrtho( m_vtNorm) ; + vtAxX.Rotate( m_vtNorm, 0, 1) ; + } + } + Frame3d frStart ; + if ( ! frStart.Set( ptStart, vtStart, vtAxX)) + return false ; + + // inserisco questo frame nel vettore dei riferimenti + vRXFrames.clear() ; + vRXFrames.reserve( nStep + 1) ; + vRXFrames.push_back( frStart) ; + + // ciclo sugli step in cui la curva è suddivisa + for ( int i = 1 ; i <= nStep ; ++ i) { + // ricavo il parametro della curva allo step i-esimo + double dParNext ; + if ( ! m_pCrv->GetParamAtLength( min( i * dMyStep, dCrvLen - EPS_SMALL), dParNext)) + return false ; + // ricavo il frame alla posizione calcolata + Frame3d frNext ; + if ( ! GetFrameAtParam( vRXFrames[i-1], dParNext, frNext)) + return false ; + // inserisco nuovo frame nel vettore dei riferimenti + vRXFrames.push_back( frNext) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::GetFramesBySplit( int nIntervals, FRAME3DVECTOR& vRXFrames) +{ + // controllo validità + if ( ! IsValid()) + return false ; + + // controllo sul numero di intervalli + nIntervals = max( 1, nIntervals) ; + + // ricavo lo step + double dLen = 0 ; + if ( ! m_pCrv->GetLength( dLen)) + return false ; + double dStep = dLen / nIntervals ; + + return GetFramesByStep( dStep, true, vRXFrames) ; +} + +//---------------------------------------------------------------------------- +bool +RotationXplaneFrame::GetFramesByTolerance( double dTol, FRAME3DVECTOR& vRXFrames) +{ + // controllo validità + if ( ! IsValid()) + return false ; + + // controllo sulla tolleranza + dTol = max( EPS_SMALL, dTol) ; + + // 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 ; + int nStep = PL.GetLineNbr() ; + + // calcolo il riferimento iniziale + Point3d ptStart ; m_pCrv->GetStartPoint( ptStart) ; + Vector3d vtStart ; m_pCrv->GetStartDir( vtStart) ; + Vector3d vtAxX = m_vtNorm ^ vtStart ; + if ( vtAxX.IsSmall()) { + vtAxX = OrthoCompo( m_vtNearX, m_vtNorm) ; + if ( vtAxX.IsSmall()) { + vtAxX = FromUprightOrtho( m_vtNorm) ; + vtAxX.Rotate( m_vtNorm, 0, 1) ; + } + } + Frame3d frStart ; + if ( ! frStart.Set( ptStart, vtStart, vtAxX)) + return false ; + + // inserisco questo frame nel vettore dei riferimenti + vRXFrames.clear() ; + vRXFrames.reserve( nStep + 1) ; + vRXFrames.push_back( frStart) ; + + // eseguo il calcolo dei frame sui punti della polyline approssimante + Point3d ptCurr ; + PL.GetFirstPoint( ptCurr) ; + double dParNext ; + Point3d ptNext ; + while ( PL.GetNextUPoint( &dParNext, &ptNext)) { + // ricavo il Frame associato a questa posizione + Frame3d frNext ; + if ( ! GetFrameAtParam( vRXFrames.back(), dParNext, frNext)) + return false ; + vRXFrames.emplace_back( frNext) ; + } + + return true ; +} diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index 7ee3d52..97f9540 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -19,16 +19,15 @@ #include "CurveComposite.h" #include "SurfTriMesh.h" #include "Voronoi.h" -#include "RotationMinimizingFrame.h" +#include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" +#include "/EgtDev/Include/EGkRotationMinimizingFrame.h" +#include "/EgtDev/Include/EGkRotationXplaneFrame.h" +#include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EgtPointerOwner.h" -#include "/EgtDev/Include/EGkSfrCreate.h" -#include -#include #include -#include using namespace std ; @@ -652,284 +651,36 @@ GetSurfTriMeshRectSwept( double dDimH, double dDimV, double dBevelH, double dBev } //------------------------------------------------------------------------------- -ISurfTriMesh* -GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol, Vector3d* vtStatic) +static ISurfTriMesh* +GetSurfTriMeshSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtNorm, bool bCapEnds, double dLinTol) { - // verifica parametri - if ( pSect == nullptr || pGuide == nullptr) - return nullptr ; + // determino se la sezione è chiusa + bool bSectClosed = pSect->IsClosed() ; + // determino se la guida è chiusa + bool bGuideClosed = pGuide->IsClosed() ; - // calcolo la polilinea che approssima la sezione + // riferimento all'inizio della linea guida + Frame3d frStart ; + Point3d ptStart ; + pGuide->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pGuide->GetStartDir( vtStart) ; + frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ; + + // 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 - bool bSectClosed = PL.IsClosed() ; - // determino se la guida è chiusa - bool bGuideClosed = pGuide->IsClosed() ; - - // definisco la superficie da restituire ( definendo la sua tolleranza ) - PtrOwner pSTM( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSTM)) - return nullptr ; - 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 + // porto la sezione in questo riferimento e ve la appiattisco if ( ! PL.ToLoc( frStart) || ! PL.Flatten()) return nullptr ; + // preparo collettore delle superfici componenti + StmFromTriangleSoup StmFts ; + if ( ! StmFts.Start()) + return nullptr ; + // superficie swept PtrOwner pPrevCrv ; Point3d ptP ; @@ -943,23 +694,29 @@ 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) if ( ! IsNull( pPrevCrv)) { PtrOwner pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; if ( IsNull( pSr)) return nullptr ; - // unisco - pSTM->DoSewing( *pSr) ; + // inserisco nel collettore + StmFts.AddSurfTriMesh( *pSr) ; } - // salvo la curva come prossima precedente pPrevCrv.Set( pCurrCrv) ; - // prossimo punto bPoint = PL.GetNextPoint( ptP) ; } + // recupero la supeficie risultante + if ( ! StmFts.End()) + return nullptr ; + PtrOwner pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ; + if ( IsNull( pSTM)) + return nullptr ; + // salvo tolleranza lineare usata + pSTM->SetLinearTolerance( dLinTol) ; + // se richiesti caps e sezione chiusa e guida aperta if ( bCapEnds && bSectClosed && ! bGuideClosed) { // verifico che le due estremità siano chiuse e piatte @@ -1002,59 +759,222 @@ GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, d return Release( pSTM) ; } +//------------------------------------------------------------------------------- +static ISurfTriMesh* +GetSurfTriMeshSwept3d( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx, bool bCapEnds, double dLinTol) +{ + // determino se la sezione è chiusa + bool bSectClosed = pSect->IsClosed() ; + // determino se la guida è chiusa + bool bGuideClosed = pGuide->IsClosed() ; + // determino algoritmo da usare per calcolare i riferimenti lungo la curva + bool bRMF = vtAx.IsSmall() ; + + // riferimento all'inizio della linea guida + Point3d ptStart ; + pGuide->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pGuide->GetStartDir( vtStart) ; + Frame3d frStart ; + if ( bRMF) { + if ( ! frStart.Set( ptStart, vtStart)) + return nullptr ; + } + else { + Vector3d vtAxX = vtAx ^ vtStart ; + if ( vtAxX.IsSmall()) { + vtAxX = FromUprightOrtho( vtAx) ; + vtAxX.Rotate( vtAx, 0, 1) ; + } + if ( ! frStart.Set( ptStart, vtStart, vtAxX)) + 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 ; + + // recupero la sezione dalla PolyLine approssimata come Curva + PtrOwner pSecLocApprox( CreateBasicCurveComposite()) ; + if ( IsNull( pSecLocApprox) || + ! pSecLocApprox->FromPolyLine( PL) || + ! pSecLocApprox->IsValid()) + return nullptr ; + + // porto la PolyLine e la curva della sezione nel riferimento nel punto iniziale della guida + PL.ToLoc( frStart) ; + pSecLocApprox->ToLoc( frStart) ; + + // calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita + FRAME3DVECTOR vFrames ; + if ( bRMF) { + RotationMinimizingFrame RMF ; + if ( ! RMF.Set( pGuide, frStart) || + ! RMF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty()) + return nullptr ; + } + else { + RotationXplaneFrame RXF ; + if ( ! RXF.Set( pGuide, vtAx, frStart.VersX()) || + ! RXF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty()) + return nullptr ; + } + + // preparo collettore delle superfici componenti + StmFromTriangleSoup StmFts ; + if ( ! StmFts.Start()) + return nullptr ; + + // per ogni Frame calcolato, la sezione va roto-traslata lungo la guida + for ( int i = 0 ; i < int( vFrames.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( vFrames[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( vFrames[i+1])) + return nullptr ; + + // creo la rigata tra queste due sezioni + PtrOwner pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_ISOPAR_SMOOTH, dLinTol)) ; + if ( IsNull( pSr) || ! pSr->IsValid()) + return nullptr ; + // la inverto + pSr->Invert() ; + // inserisco la superficie nel collettore + StmFts.AddSurfTriMesh( *pSr) ; + } + + // se richiesti caps e sezione chiusa e guida aperta + 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( vFrames.front()) ; + // aggiungo + StmFts.AddSurfTriMesh( *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( vFrames.back()) ; + // inverto + pSce->Invert() ; + // aggiungo + StmFts.AddSurfTriMesh( *pSce) ; + } + + // recupero la supeficie risultante + if ( ! StmFts.End()) + return nullptr ; + PtrOwner pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ; + if ( IsNull( pSTM)) + return nullptr ; + // salvo tolleranza lineare usata + pSTM->SetLinearTolerance( dLinTol) ; + + // 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) ; +} + //------------------------------------------------------------------------------- ISurfTriMesh* -GetSurfTriMeshSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, bool bCapEnds, - double dLinTol, Vector3d* vtStatic) +GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx, + bool bCapEnds, double dLinTol) +{ + // verifica parametri + if ( pSect == nullptr || pGuide == nullptr) + return nullptr ; + + // se la guida è piana + Plane3d plGuide ; + if ( pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) + return GetSurfTriMeshSweptInPlane( pSect, pGuide, plGuide.GetVersN(), bCapEnds, dLinTol) ; + + // altrimenti swept 3d + return GetSurfTriMeshSwept3d( pSect, pGuide, vtAx, bCapEnds, dLinTol) ; +} + +//------------------------------------------------------------------------------- +ISurfTriMesh* +GetSurfTriMeshSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, const Vector3d& vtAx, + bool bCapEnds, double dLinTol) { // 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 ; - + // predispongo collettore superfici componenti 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) { + for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) { // recupero il loop - PtrOwner pCrvLoop( pSfrSect->GetLoop( c, l)) ; + PtrOwner pCrvLoop( pSfrSect->GetLoop( nC, nL)) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return nullptr ; // creo la Trimesh Swept - PtrOwner pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, false, dLinTol, vtStatic)) ; + PtrOwner pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, vtAx, false, dLinTol)) ; 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 + // Recupero la superficie + if ( ! StmSoup.End()) + return nullptr ; + PtrOwner pStmSwept( StmSoup.GetSurf()) ; + if ( IsNull( pStmSwept)) + return nullptr ; + + // se rischiesta chiusura... + // Controllo solo che la guida non sia chiusa, la sezione derivando da una Flatregion è sempre chiusa 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()) + // recupero i loop all'inizio (dalla regione e apportunamente approssimati) + POLYLINEVECTOR vPLi ; + for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) { + vPLi.emplace_back() ; + if ( ! pSfrSect->ApproxLoopWithLines( nC, nL, dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPLi.back())) + return nullptr ; + } + } + // creo il cap sull'inizio e lo attacco alla swept ( è già in posizione giusta) + PtrOwner pSci( CreateSurfTriMesh()) ; + if ( ! pSci->CreateByRegion( vPLi)) return nullptr ; pStmSwept->DoSewing( *pSci) ; // recupero i loops alla fine - POLYLINEVECTOR vPL ; - if ( ! pStmSwept->GetLoops( vPL)) + POLYLINEVECTOR vPLe ; + if ( ! pStmSwept->GetLoops( vPLe)) return nullptr ; // creo la superficie alla fine e la attacco PtrOwner pSce( CreateSurfTriMesh()) ; - if ( ! pSce->CreateByRegion( vPL)) + if ( ! pSce->CreateByRegion( vPLe)) return nullptr ; // attacco la superficie finale alla swept pSce->Invert() ; diff --git a/Vector3d.cpp b/Vector3d.cpp index 927768b..61a9305 100644 --- a/Vector3d.cpp +++ b/Vector3d.cpp @@ -169,6 +169,10 @@ Vector3d::ToSpherical( double* pdLen, double* pdAngVertDeg, double* pdAngOrizzDe bool Vector3d::Normalize( double dEps) { + // verifico validità + if ( ! IsValid()) + return false ; + // se già normalizzato, ok double dSqLen = x * x + y * y + z * z ; if ( abs( 1.0 - dSqLen) < ( 2 * 1000 * DBL_EPSILON))