diff --git a/BBox3d.cpp b/BBox3d.cpp index 14ee845..eb5777a 100644 --- a/BBox3d.cpp +++ b/BBox3d.cpp @@ -162,6 +162,16 @@ BBox3d::GetCenter( Point3d& ptCenter) const return true ; } +//---------------------------------------------------------------------------- +bool +BBox3d::GetRadius( double& dRad) const +{ + if ( ! IsValid()) + return false ; + dRad = ( m_ptMax - m_ptMin).Len() * 0.5 ; + return true ; +} + //---------------------------------------------------------------------------- bool BBox3d::ToGlob( const Frame3d& frRef) diff --git a/ChainCurves.cpp b/ChainCurves.cpp new file mode 100644 index 0000000..761eb47 --- /dev/null +++ b/ChainCurves.cpp @@ -0,0 +1,331 @@ +//---------------------------------------------------------------------------- +// EgalTech 2013-2014 +//---------------------------------------------------------------------------- +// File : ChainCurves.cpp Data : 20.07.14 Versione : 1.5g3 +// Contenuto : Implementazione della funzione ChainCurves, per creare una o più +// curve composite a partire dalle curve date. +// +// +// Modifiche : 20.07.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "/EgtDev/Include/EgkChainCurves.h" +#include "/EgtDev/Include/EgkGeomDB.h" +#include "/EgtDev/Include/EgkCurve.h" + +//---------------------------------------------------------------------------- +bool +ChainCurves::Init( bool bAllowInvert, double dToler, int nCrvNbrHint) +{ + m_bAllowInvert = bAllowInvert ; + m_dToler = dToler ; + m_sCrvId.clear() ; + m_sCrvId.rehash( nCrvNbrHint) ; + m_vCrvData.clear() ; + m_vCrvData.reserve( nCrvNbrHint) ; + const double DIM_CELL = 5.0 ; + m_PointGrid.Init( 2 * nCrvNbrHint, DIM_CELL) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::AddCurve( int nId, const Point3d& ptStart, const Vector3d& vtStart, + const Point3d& ptEnd, const Vector3d& vtEnd) +{ + // verifico validità Id + if ( nId <= 0) + return false ; + // verifico non sia già stata aggiunta la stessa entità + if ( ! m_sCrvId.insert( nId).second) + return true ; + // inserisco i dati della curva nel vettore + m_vCrvData.push_back( CrvData( nId, ptStart, vtStart, ptEnd, vtEnd)) ; + int nV = int( m_vCrvData.size()) ; + // li inserisco nel PointGrid3d + m_PointGrid.InsertPoint( ptStart, nV) ; + m_PointGrid.InsertPoint( ptEnd, - nV) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::GetChainFromNear( const Point3d& ptStart, INTVECTOR& vIds) +{ + // pulisco il risultato + vIds.clear() ; + m_bIsFork = false ; + m_vFork.clear() ; + + // recupero l'entità più vicina al punto di start + int nStart ; + INTVECTOR vStart ; + if ( ! m_PointGrid.FindNearest( ptStart, vStart) || + ! ChooseStart( ptStart, vStart, nStart)) + return false ; + // recupero indice e verso + int nId = abs( nStart) - 1 ; + bool bEquiv = true ; + // tolgo dal grid + RemoveEntityFromGrid( nId) ; + + // concateno dopo la fine dell'entità di partenza + INTVECTOR vIdsAfter ; + if ( ! GetChainFromPoint( m_vCrvData[nId].ptEnd, m_vCrvData[nId].vtEnd, false, vIdsAfter)) + return false ; + + // concateno prima dell'inizio dell'entità di partenza + INTVECTOR vIdsBefore ; + if ( ! GetReverseChainFromPoint( m_vCrvData[nId].ptStart, m_vCrvData[nId].vtStart, false, vIdsBefore)) + return false ; + // inverto l'ordine + reverse( vIdsBefore.begin(), vIdsBefore.end()) ; + + // inserisco i risultati nel vettore complessivo + vIds.reserve( vIdsBefore.size() + 1 + vIdsAfter.size()) ; + vIds.insert( vIds.end(), vIdsBefore.begin(), vIdsBefore.end()) ; + AddToChain( nId, bEquiv, vIds) ; + vIds.insert( vIds.end(), vIdsAfter.begin(), vIdsAfter.end()) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::GetChainFromPoint( const Point3d& ptStart, const Vector3d& vtStart, bool bStopOnFork, + INTVECTOR& vIds) +{ + // pulisco il risultato + vIds.clear() ; + m_bIsFork = false ; + m_vFork.clear() ; + + // concateno in senso normale + Point3d ptCurr = ptStart ; + Vector3d vtCurr = vtStart ; + int nNext ; + INTVECTOR vNext ; + while ( m_PointGrid.Find( ptCurr, m_dToler, vNext) && + ChooseNext( vtCurr, vNext, bStopOnFork, nNext)) { + // recupero indice e verso + int nId = abs( nNext) - 1 ; + bool bEquiv = ( nNext > 0) ; + // inserisco nella concatenazione + AddToChain( nId, bEquiv, vIds) ; + // tolgo dal grid + RemoveEntityFromGrid( nId) ; + // determino il prossimo inizio + ptCurr = bEquiv ? m_vCrvData[nId].ptEnd : m_vCrvData[nId].ptStart ; + vtCurr = bEquiv ? m_vCrvData[nId].vtEnd : - m_vCrvData[nId].vtStart ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::GetReverseChainFromPoint( const Point3d& ptStart, const Vector3d& vtStart, bool bStopOnFork, + INTVECTOR& vIds) +{ + // pulisco il risultato + vIds.clear() ; + m_bIsFork = false ; + m_vFork.clear() ; + + // concateno in senso invertito + Point3d ptCurr = ptStart ; + Vector3d vtCurr = vtStart ; + int nPrev ; + INTVECTOR vPrev ; + while ( m_PointGrid.Find( ptCurr, m_dToler, vPrev) && + ChoosePrev( vtCurr, vPrev, bStopOnFork, nPrev)) { + // recupero indice e verso + int nId = abs( nPrev) - 1 ; + bool bEquiv = ( nPrev < 0) ; + // inserisco nella concatenazione + AddToChain( nId, bEquiv, vIds) ; + // tolgo dal grid + RemoveEntityFromGrid( nId) ; + // determino il prossimo inizio + ptCurr = bEquiv ? m_vCrvData[nId].ptStart : m_vCrvData[nId].ptEnd ; + vtCurr = bEquiv ? m_vCrvData[nId].vtStart : - m_vCrvData[nId].vtEnd ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::AddToChain( int nId, bool bEquiv, INTVECTOR& vIds) +{ + try { vIds.push_back( ( bEquiv ? m_vCrvData[nId].nId : - m_vCrvData[nId].nId)) ; } + catch (...) { return false ; } + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::RemoveEntityFromGrid( int nId) +{ + bool bOk = m_PointGrid.RemovePoint( m_vCrvData[nId].ptStart, ( nId + 1)) ; + bOk = m_PointGrid.RemovePoint( m_vCrvData[nId].ptEnd, - ( nId + 1)) && bOk ; + return bOk ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::ChooseStart( const Point3d& ptStart, const INTVECTOR& vStart, int& nStart) +{ + // numero di entità candidate + int nSize = int( vStart.size()) ; + + // se nessuna, errore + if ( nSize == 0) + return false ; + + // se una, la ritorno + if ( nSize == 1) { + nStart = vStart[0] ; + return true ; + } + + // altrimenti, cerco la migliore + int nI = - 1 ; + double dSqDistMin = INFINITO * INFINITO ; + for ( int i = 0 ; i < nSize ; ++ i) { + // recupero indice e verso + int nId = abs( vStart[i]) - 1 ; + bool bEquiv = ( vStart[i] > 0) ; + // calcolo un punto vicino all'estremo lungo la tangente + Point3d ptNear = ( bEquiv ? m_vCrvData[nId].ptStart + m_vCrvData[nId].vtStart : + m_vCrvData[nId].ptEnd - m_vCrvData[nId].vtEnd) ; + double dSqDist = SqDist( ptStart, ptNear) ; + if ( dSqDist < dSqDistMin) { + dSqDistMin = dSqDist ; + nI = i ; + } + } + + // se non trovato + if ( nI < 0) + return false ; + + // altrimenti assegno il migliore + nStart = vStart[nI] ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::ChooseNext( const Vector3d& vtCurr, const INTVECTOR& vNext, bool bStopOnFork, int& nNext) +{ + // cerco la direzione più vicina + int nI = - 1 ; + int nF = 0 ; + double dProScaMax = - 1.1 ; + for ( int i = 0 ; i < int( vNext.size()) ; ++ i) { + // recupero indice e verso + int nId = abs( vNext[i]) - 1 ; + bool bEquiv = ( vNext[i] > 0) ; + // se vietata inversione, salto se controverso + if ( ! m_bAllowInvert && ! bEquiv) + continue ; + // incremento contatore indice entità tra cui scegliere + ++ nF ; + if ( bStopOnFork) + m_vFork.push_back( vNext[i]) ; + // determino scarto angolare + Vector3d vtDir = ( bEquiv ? m_vCrvData[nId].vtStart : - m_vCrvData[nId].vtEnd) ; + double dProSca = vtCurr * vtDir ; + if ( dProSca > dProScaMax) { + dProScaMax = dProSca ; + nI = i ; + } + } + + // se non trovato + if ( nI < 0) { + m_bIsFork = false ; + return false ; + } + + // se richiesto arresto su biforcazione e trovata biforcazione + if ( bStopOnFork && nF > 1) { + m_bIsFork = true ; + return false ; + } + + // altrimenti assegno il migliore + nNext = vNext[nI] ; + m_bIsFork = false ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::ChoosePrev( const Vector3d& vtCurr, const INTVECTOR& vPrev, bool bStopOnFork, int& nPrev) +{ + // cerco la direzione più vicina + int nI = - 1 ; + int nF = 0 ; + double dProScaMax = - 1.1 ; + for ( int i = 0 ; i < int( vPrev.size()) ; ++ i) { + // recupero indice e verso + int nId = abs( vPrev[i]) - 1 ; + bool bEquiv = ( vPrev[i] < 0) ; + // se vietata inversione, salto se controverso + if ( ! m_bAllowInvert && ! bEquiv) + continue ; + // incremento contatore indice entità tra cui scegliere + ++ nF ; + if ( bStopOnFork) + m_vFork.push_back( vPrev[i]) ; + // determino scarto angolare + Vector3d vtDir = ( bEquiv ? m_vCrvData[nId].vtEnd : - m_vCrvData[nId].vtStart) ; + double dProSca = vtCurr * vtDir ; + if ( dProSca > dProScaMax) { + dProScaMax = dProSca ; + nI = i ; + } + } + + // se non trovato + if ( nI < 0) { + m_bIsFork = false ; + return false ; + } + + // se richiesto arresto su biforcazione e trovata biforcazione + if ( bStopOnFork && nF > 1) { + m_bIsFork = true ; + return false ; + } + + // altrimenti assegno il migliore + nPrev = vPrev[nI] ; + m_bIsFork = false ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ChainCurves::GetForkIds( INTVECTOR& vForkIds) +{ + // pulisco il risultato + vForkIds.clear() ; + + // verifico di essere su una diramazione + if ( ! m_bIsFork || m_vFork.empty()) + return false ; + + // assegno gli Id del GeomDB + for ( int i = 0 ; i < int( m_vFork.size()) ; ++ i) { + int nId = abs( m_vFork[i]) - 1 ; + vForkIds.push_back( m_vCrvData[nId].nId) ; + } + return true ; +} diff --git a/CurveArc.cpp b/CurveArc.cpp index aed804a..b216147 100644 --- a/CurveArc.cpp +++ b/CurveArc.cpp @@ -105,7 +105,7 @@ CurveArc::Set( const Point3d& ptCen, const Vector3d& vtN, double dRad) return false ; m_VtS = frF.VersX() ; m_dRad = dRad ; - m_dAngCenDeg = 360 ; + m_dAngCenDeg = ANG_FULL ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; @@ -147,7 +147,7 @@ CurveArc::SetXY( const Point3d& ptCen, double dRad) m_VtN = Z_AX ; m_VtS = X_AX ; m_dRad = dRad ; - m_dAngCenDeg = 360 ; + m_dAngCenDeg = ANG_FULL ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; @@ -187,7 +187,7 @@ CurveArc::Set3P( const Point3d& ptStart, const Point3d& ptOther, const Point3d& m_VtS /= m_dRad ; // calcolo dell'angolo al centro if ( bCirc) - m_dAngCenDeg = 360 ; + m_dAngCenDeg = ANG_FULL ; else { // calcolo dell'angolo di rotazione attorno al centro dal primo al secondo punto bool bDet1 ; @@ -208,7 +208,7 @@ CurveArc::Set3P( const Point3d& ptStart, const Point3d& ptOther, const Point3d& m_dAngCenDeg = dAng2Deg ; // altrimenti hanno segno opposto oppure Ang1 è maggiore di Ang2 in modulo else - m_dAngCenDeg = - _copysign( 360, dAng2Deg) + dAng2Deg ; + m_dAngCenDeg = - _copysign( ANG_FULL, dAng2Deg) + dAng2Deg ; } // non c'è DeltaN m_dDeltaN = 0 ; @@ -467,6 +467,9 @@ CurveArc::GetTitle( void) const bool CurveArc::Dump( string& sOut, const char* szNewLine) const { + // dati generali di una curva + if ( ! CurveDump( *this, sOut, szNewLine)) + return false ; // parametri : Centro, Normale, DirStart, Rad, AngCenDeg, DeltaN sOut += "C(" + ToString( m_PtCen, 3) + ") " + szNewLine ; sOut += "VN(" + ToString( m_VtN, 6) + ") " + szNewLine ; @@ -588,10 +591,10 @@ CurveArc::Validate( void) if ( m_nStatus == TO_VERIFY) { // limito l'angolo al centro a un giro se è piatto ( non è elica) if ( fabs( m_dDeltaN) < EPS_SMALL) { - if ( m_dAngCenDeg > 360.0) - m_dAngCenDeg = 360.0 ; - else if ( m_dAngCenDeg < - 360.0) - m_dAngCenDeg = - 360.0 ; + if ( m_dAngCenDeg > ANG_FULL) + m_dAngCenDeg = ANG_FULL ; + else if ( m_dAngCenDeg < - ANG_FULL) + m_dAngCenDeg = - ANG_FULL ; } // eseguo il controllo m_nStatus = ( ( m_VtN.IsNormalized() && m_VtS.IsNormalized() && @@ -938,6 +941,114 @@ CurveArc::Offset( double dDist, int nSide, int nType) return true ; } +//---------------------------------------------------------------------------- +bool +CurveArc::ModifyStart( const Point3d& ptNewStart) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X) + Frame3d frIntr ; + if ( ! frIntr.Set( m_PtCen, m_VtN, m_VtS)) + return false ; + // determino vecchio e nuovo punto iniziale nel riferimento intrinsseco + Point3d ptOldStart ; + GetStartPoint( ptOldStart) ; + Point3d ptOldStartIntr = ptOldStart ; + ptOldStartIntr.ToLoc( frIntr) ; + Point3d ptStartIntr = ptNewStart ; + ptStartIntr.ToLoc( frIntr) ; + // se coincidono nel piano XY, è cambiato solo il deltaN e il centro + if ( SqDistXY( ptOldStartIntr, ptStartIntr) < EPS_SMALL * EPS_SMALL) { + m_dDeltaN -= ptStartIntr.z - ptOldStartIntr.z ; + m_PtCen += ( ptNewStart - ptOldStart) ; + } + // altrimenti, calcolo un arco ausiliario nel riferimento intrinseco con i nuovi dati + else { + Point3d ptEndIntr ; + GetEndPoint( ptEndIntr) ; + ptEndIntr.ToLoc( frIntr) ; + double dOldAngCenDeg = m_dAngCenDeg ; + CurveArc arcAux ; + if ( ! arcAux.Set2PD( ptStartIntr, ptEndIntr, ( m_dAngCenDeg > 0 ? ANG_RIGHT : - ANG_RIGHT))) + return false ; + // aggiorno i dati dell'arco con quelli appena calcolati + m_PtCen = arcAux.m_PtCen ; + m_PtCen.ToGlob( frIntr) ; + m_VtN = arcAux.m_VtN ; + m_VtN.ToGlob( frIntr) ; + m_VtS = arcAux.m_VtS ; + m_VtS.ToGlob( frIntr) ; + m_dRad = arcAux.m_dRad ; + // se elica, devo avere un numero di giri vicino ai precedenti + if ( fabs( dOldAngCenDeg) >= ANG_FULL - EPS_ANG_ZERO) + m_dAngCenDeg = AngleNearAngle( arcAux.m_dAngCenDeg, dOldAngCenDeg) ; + else + m_dAngCenDeg = arcAux.m_dAngCenDeg ; + m_dDeltaN = arcAux.m_dDeltaN ; + } + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveArc::ModifyEnd( const Point3d& ptNewEnd) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X) + Frame3d frIntr ; + if ( ! frIntr.Set( m_PtCen, m_VtN, m_VtS)) + return false ; + // determino vecchio e nuovo punto finale nel riferimento intrinsseco + Point3d ptOldEndIntr ; + GetEndPoint( ptOldEndIntr) ; + ptOldEndIntr.ToLoc( frIntr) ; + Point3d ptEndIntr = ptNewEnd ; + ptEndIntr.ToLoc( frIntr) ; + // se coincidono nel piano XY, è cambiato solo il deltaN + if ( SqDistXY( ptOldEndIntr, ptEndIntr) < EPS_SMALL * EPS_SMALL) { + m_dDeltaN += ptEndIntr.z - ptOldEndIntr.z ; + } + // altrimenti, calcolo un arco ausiliario nel riferimento intrinseco con i nuovi dati + else { + Point3d ptStartIntr ; + GetStartPoint( ptStartIntr) ; + ptStartIntr.ToLoc( frIntr) ; + double dOldAngCenDeg = m_dAngCenDeg ; + CurveArc arcAux ; + if ( ! arcAux.Set2PD( ptStartIntr, ptEndIntr, ( m_dAngCenDeg > 0 ? ANG_RIGHT : - ANG_RIGHT))) + return false ; + // aggiorno i dati dell'arco con quelli appena calcolati + m_PtCen = arcAux.m_PtCen ; + m_PtCen.ToGlob( frIntr) ; + m_VtN = arcAux.m_VtN ; + m_VtN.ToGlob( frIntr) ; + m_VtS = arcAux.m_VtS ; + m_VtS.ToGlob( frIntr) ; + m_dRad = arcAux.m_dRad ; + // se elica, devo avere un numero di giri vicino ai precedenti + if ( fabs( dOldAngCenDeg) >= ANG_FULL - EPS_ANG_ZERO) + m_dAngCenDeg = AngleNearAngle( arcAux.m_dAngCenDeg, dOldAngCenDeg) ; + else + m_dAngCenDeg = arcAux.m_dAngCenDeg ; + m_dDeltaN = arcAux.m_dDeltaN ; + } + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + //---------------------------------------------------------------------------- bool CurveArc::TrimStartAtParam( double dUTrim) @@ -1353,7 +1464,7 @@ CurveArc::ToAdditional( void) return false ; // basta prendere l'angolo al centro che completa il giro - m_dAngCenDeg = - _copysign( 360, m_dAngCenDeg) + m_dAngCenDeg ; + m_dAngCenDeg = - _copysign( ANG_FULL, m_dAngCenDeg) + m_dAngCenDeg ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; diff --git a/CurveArc.h b/CurveArc.h index 38bbe01..f89feb6 100644 --- a/CurveArc.h +++ b/CurveArc.h @@ -88,6 +88,8 @@ class CurveArc : public ICurveArc, public IGeoObjRW virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) ; + virtual bool ModifyStart( const Point3d& ptNewStart) ; + virtual bool ModifyEnd( const Point3d& ptNewEnd) ; virtual bool TrimStartAtParam( double dUTrim) ; virtual bool TrimEndAtParam( double dUTrim) ; virtual bool TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) ; diff --git a/CurveAux.cpp b/CurveAux.cpp index 39df948..b8d9ff4 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -18,8 +18,11 @@ #include "/EgtDev/Include/EgkCurveComposite.h" #include "/EgtDev/Include/EgkCurveBezier.h" #include "/EgtDev/Include/EgkCurveArc.h" +#include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtPointerOwner.h" +using namespace std ; + //---------------------------------------------------------------------------- bool IsClosed( const ICurve& crvC) @@ -94,30 +97,37 @@ GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Ve return false ; if ( vtTang.Normalize()) return true ; - // nel caso la derivata prima sia nulla, utilizziamo la seconda + // nel caso la derivata prima sia nulla, utilizziamo la seconda Vector3d vtDummy ; if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDummy, &vtTang)) return false ; - return vtTang.Normalize() ; + if ( ! vtTang.Normalize()) + return false ; + // per il verso, lo confrontiamo con quello della derivata prima un poco discosta + Point3d ptDummy ; + Vector3d vtD1near ; + dU += ( nS == ICurve::FROM_MINUS ? -1 : +1) * 100 * EPS_PARAM ; + if ( ! crvC.GetPointD1D2( dU, nS, ptDummy, &vtD1near)) + return false ; + if ( ( vtTang * vtD1near) < 0) + vtTang *= - 1 ; + return true ; } //---------------------------------------------------------------------------- bool GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGeom& oDiffG) { - double dSqLenD1 ; + // calcolo punto e derivate Point3d ptPos ; - Vector3d vtDer1 ; - Vector3d vtDer2 ; - - + Vector3d vtDer1, vtDer2 ; if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDer1, &vtDer2)) return false ; // assegno parametro e posizione oDiffG.dU = dU ; oDiffG.ptP = ptPos ; // se esiste la derivata prima non nulla - dSqLenD1 = vtDer1.SqLen() ; + double dSqLenD1 = vtDer1.SqLen() ; if ( vtDer1.Normalize()) { oDiffG.vtT = vtDer1 ; // del vettore deriv2^ tengo la sola componente perpendicolare al vettore tangente @@ -136,7 +146,19 @@ GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGe oDiffG.vtT = vtDer2 ; oDiffG.vtN.Set( 0, 0, 0) ; oDiffG.dCurv = 0 ; - oDiffG.nStatus = CrvPointDiffGeom::TANG ; + // per il verso, lo confrontiamo con quello della derivata prima un poco discosta + Point3d ptDummy ; + Vector3d vtD1near ; + dU += ( nS == ICurve::FROM_MINUS ? -1 : +1) * 100 * EPS_PARAM ; + if ( crvC.GetPointD1D2( dU, nS, ptDummy, &vtD1near)) { + if ( ( oDiffG.vtT * vtD1near) < 0) + oDiffG.vtT *= - 1 ; + oDiffG.nStatus = CrvPointDiffGeom::TANG ; + } + else { + oDiffG.vtT.Set( 0, 0, 0) ; + oDiffG.nStatus = CrvPointDiffGeom::POS ; + } } // altrimenti non sono definite la tangente e la normale else { @@ -149,6 +171,45 @@ GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGe return true ; } +//---------------------------------------------------------------------------- +bool +CurveDump( const ICurve& crvC, string& sOut, const char* szNewLine) +{ + // verifico validità curva + if ( ! crvC.IsValid()) + return false ; + + // punti iniziale e finale + Point3d ptPS ; + crvC.GetStartPoint( ptPS) ; + sOut += "PS(" + ToString( ptPS, 3) + ")" + szNewLine ; + Point3d ptPE ; + crvC.GetEndPoint( ptPE) ; + sOut += "PE(" + ToString( ptPE, 3) + ")" + szNewLine ; + // direzioni iniziale e finale + Vector3d vtDirS ; + crvC.GetStartDir( vtDirS) ; + sOut += "VS(" + ToString( vtDirS, 3) + ")" + szNewLine ; + Vector3d vtDirE ; + crvC.GetEndDir( vtDirE) ; + sOut += "VE(" + ToString( vtDirE, 3) + ")" + szNewLine ; + // lunghezza + double dLen = 0 ; + crvC.GetLength( dLen) ; + sOut += "Len=" + ToString( dLen,3) + szNewLine ; + // altri dati per curva chiusa + if ( crvC.IsClosed()) { + PolyLine PL ; + crvC.ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, PL) ; + double dAreaXY = 0 ; + PL.GetAreaXY( dAreaXY) ; + bool bCCW = ( dAreaXY > 0) ; + sOut += string( "Closed") + ( bCCW ? " CCW" : " CW") + " AreaXY=" + ToString( fabs( dAreaXY),1) + szNewLine ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool ArcToBezierCurve( const ICurve* pCrv, ICurve*& pCrvNew) diff --git a/CurveAux.h b/CurveAux.h index b49d86d..71f4649 100644 --- a/CurveAux.h +++ b/CurveAux.h @@ -23,3 +23,4 @@ bool IsEndParam( const ICurve& crvC, double dPar) ; bool GetTang( const ICurve& crvC, double dU, ICurve::Side nS, Vector3d& vtTang) ; bool GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Vector3d& vtTang) ; bool GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGeom& oDiffG) ; +bool CurveDump( const ICurve& crvC, std::string& sOut, const char* szNewLine) ; diff --git a/CurveBezier.cpp b/CurveBezier.cpp index 7a3566e..3745a03 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -327,11 +327,14 @@ CurveBezier::GetTitle( void) const bool CurveBezier::Dump( string& sOut, const char* szNewLine) const { - // flag razionale + // dati generali di una curva + if ( ! CurveDump( *this, sOut, szNewLine)) + return false ; + // parametri : flag razionale sOut += ( m_bRat ? "Rat " : "Int ") ; - // grado + // grado sOut += "Deg=" + ToString( m_nDeg) + szNewLine ; - // ciclo sui punti di controllo ( con pesi se razionale) + // ciclo sui punti di controllo ( con pesi se razionale) for ( int i = 0 ; i <= m_nDeg ; ++ i) { sOut += "PC(" + ToString( m_aPtCtrl[i], 3) ; if ( m_bRat) @@ -1273,6 +1276,40 @@ CurveBezier::Invert( void) return true ; } +//---------------------------------------------------------------------------- +bool +CurveBezier::ModifyStart( const Point3d& ptNewStart) +{ + // la curva deve essere valida + if ( m_nStatus != OK) + return false ; + + // modifico il primo punto di controllo + m_aPtCtrl[0] = ptNewStart ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveBezier::ModifyEnd( const Point3d& ptNewEnd) +{ + // la curva deve essere valida + if ( m_nStatus != OK) + return false ; + + // modifico l'ultimo punto di controllo + m_aPtCtrl[m_nDeg] = ptNewEnd ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + //---------------------------------------------------------------------------- bool CurveBezier::TrimStartAtParam( double dUTrim) diff --git a/CurveBezier.h b/CurveBezier.h index 1beec93..38e4311 100644 --- a/CurveBezier.h +++ b/CurveBezier.h @@ -91,6 +91,8 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) { return false ; } + virtual bool ModifyStart( const Point3d& ptNewStart) ; + virtual bool ModifyEnd( const Point3d& ptNewEnd) ; virtual bool TrimStartAtParam( double dUTrim) ; virtual bool TrimEndAtParam( double dUTrim) ; virtual bool TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) ; diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 0c7bf0b..72dcf31 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -66,7 +66,7 @@ CurveComposite::Clear( void) //---------------------------------------------------------------------------- bool -CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart) +CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart, double dLinTol) { // se curva semplice if ( cCrv.IsSimple()) { @@ -75,7 +75,7 @@ CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart) if ( pSmplCrv == nullptr) return false ; // inserisco la curva - if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart)) + if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol)) return false ; } // altrimenti curva composta, devo aggiungere le singole curve semplici @@ -94,7 +94,7 @@ CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart) if ( pSmplCrv == nullptr) return false ; // inserisco la curva - if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart)) + if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol)) return false ; // passo alla prossima curva componente pCrvOri = ( bEndOrStart ? pCrvCompo->GetNextCurve() : pCrvCompo->GetPrevCurve()) ; @@ -109,12 +109,12 @@ CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart) //---------------------------------------------------------------------------- bool -CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart) +CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart, double dLinTol) { // se curva semplice if ( pCrv->IsSimple()) { // inserisco la curva - if ( ! AddSimpleCurve( pCrv, bEndOrStart)) + if ( ! AddSimpleCurve( pCrv, bEndOrStart, dLinTol)) return false ; } // altrimenti curva composta, devo aggiungere le singole curve semplici @@ -127,7 +127,7 @@ CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart) ICurve* pSmplCrv ; while ( ( pSmplCrv = pCrvCompo->RemoveFirstOrLastCurve( ! bEndOrStart)) != nullptr) { // inserisco la curva - if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart)) + if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol)) return false ; } // cancello la curva composita originaria @@ -142,7 +142,7 @@ CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart) //---------------------------------------------------------------------------- bool -CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart) +CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinTol) { // prendo la proprietà del puntatore PtrOwner pCrv( pSmplCrv) ; @@ -167,20 +167,38 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart) // se inserita alla fine if ( bEndOrStart) { // verifico sia in continuità con il finale attuale - if ( ! AreSamePointApprox( ptStart, m_PtEnd)) - return false ; + if ( ! AreSamePointApprox( ptStart, m_PtEnd)) { + // se in tolleranza, modifico l'inizio dell'entità + if ( SqDist( ptStart, m_PtEnd) < ( dLinTol * dLinTol)) { + if ( ! pCrv->ModifyStart( m_PtEnd)) + return false ; + } + else + return false ; + } } // altrimenti inserita all'inizio else { // verifico sia in continuità con l'iniziale attuale - if ( ! AreSamePointApprox( ptEnd, m_PtStart)) - return false ; + if ( ! AreSamePointApprox( ptEnd, m_PtStart)) { + // se in tolleranza, modifico la fine dell'entità + if ( SqDist( ptEnd, m_PtStart) < ( dLinTol * dLinTol)) { + if ( ! pCrv->ModifyEnd( m_PtStart)) + return false ; + } + else + return false ; + } } } - // se prima curva, assegno il punto iniziale - if ( m_nCounter == 0) - m_PtStart = ptStart ; + // se prima curva, assegno il punto iniziale o finale + if ( m_nCounter == 0) { + if ( bEndOrStart) + m_PtStart = ptStart ; + else + m_PtEnd = ptEnd ; + } // inserisco la curva nella lista if ( bEndOrStart) @@ -499,14 +517,12 @@ CurveComposite::GetTitle( void) const bool CurveComposite::Dump( string& sOut, const char* szNewLine) const { - // se curva aperta o chiusa - sOut += ( IsClosed() ? "Closed" : "Open") + string( szNewLine) ; - // punti iniziale e finale - sOut += "PS(" + ToString( m_PtStart, 3) + ")" + szNewLine ; - sOut += "PE(" + ToString( m_PtEnd, 3) + ")" + szNewLine ; - // numero di curve + // dati generali di una curva + if ( ! CurveDump( *this, sOut, szNewLine)) + return false ; + // parametri : numero di curve sOut += "CrvNbr=" + ToString( m_nCounter) + szNewLine ; - // ciclo sulle curve componenti + // ciclo sulle curve componenti int i = 0 ; const ICurve* pCrvSmpl = GetFirstCurve() ; while ( pCrvSmpl != nullptr) { @@ -1047,6 +1063,55 @@ CurveComposite::Invert( void) return true ; } +//---------------------------------------------------------------------------- +bool +CurveComposite::ModifyStart( const Point3d& ptNewStart) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // recupero la prima curva + if ( m_CrvSmplS.empty()) + return false ; + ICurve* pCrv = m_CrvSmplS.front() ; + // modifico l'inizio di questa curva + if ( ! pCrv->ModifyStart( ptNewStart)) + return false ; + // aggiorno il punto iniziale e il flag di curva chiusa + m_PtStart = ptNewStart ; + m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveComposite::ModifyEnd( const Point3d& ptNewEnd) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + // recupero l'ultima curva + if ( m_CrvSmplS.empty()) + return false ; + ICurve* pCrv = m_CrvSmplS.back() ; + // modifico la fine di questa curva + if ( ! pCrv->ModifyEnd( ptNewEnd)) + return false ; + // aggiorno il punto finale e il flag di curva chiusa + m_PtEnd = ptNewEnd ; + m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + //---------------------------------------------------------------------------- bool CurveComposite::TrimStartAtParam( double dUTrim) diff --git a/CurveComposite.h b/CurveComposite.h index 85b1029..7792a56 100644 --- a/CurveComposite.h +++ b/CurveComposite.h @@ -90,6 +90,8 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) { return false ; } + virtual bool ModifyStart( const Point3d& ptNewStart) ; + virtual bool ModifyEnd( const Point3d& ptNewEnd) ; virtual bool TrimStartAtParam( double dUTrim) ; virtual bool TrimEndAtParam( double dUTrim) ; virtual bool TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) ; @@ -99,8 +101,8 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW public : // ICurveComposite virtual bool CopyFrom( const IGeoObj* pGObjSrc) ; virtual bool Clear( void) ; - virtual bool AddCurve( const ICurve& cCrv, bool bEndOrStart = true) ; - virtual bool AddCurve( ICurve* pCrv, bool bEndOrStart = true) ; + virtual bool AddCurve( const ICurve& cCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; + virtual bool AddCurve( ICurve* pCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; virtual bool FromSplit( const ICurve& cCrv, int nParts) ; virtual bool FromPointVector( const PNTVECTOR& vPnt) ; virtual bool FromPointBulgeVector( const UPNTVECTOR& vUPnt, const Vector3d& vtN) ; @@ -133,7 +135,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW private : bool CopyFrom( const CurveComposite& ccSrc) ; bool Validate( void) ; - bool AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart = true) ; + bool AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ; bool GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const ; private : diff --git a/CurveLine.cpp b/CurveLine.cpp index ffeda3a..94cad60 100644 --- a/CurveLine.cpp +++ b/CurveLine.cpp @@ -143,14 +143,11 @@ CurveLine::GetTitle( void) const bool CurveLine::Dump( string& sOut, const char* szNewLine) const { - // parametri : punti iniziale e finale - sOut += "P1(" + ToString( m_PtStart, 3) + ")" + szNewLine ; - sOut += "P2(" + ToString( m_PtEnd, 3) + ")" + szNewLine ; - // altri dati : angolo vert, angolo orizz, lunghezza - double dLen, dAngVertDeg, dAngOrizzDeg ; - ( m_PtEnd - m_PtStart).ToSpherical( &dLen, &dAngVertDeg, &dAngOrizzDeg) ; - sOut += "Av=" + ToString( dAngVertDeg, 3) + " Ao=" + ToString( dAngOrizzDeg, 3) + - " L=" + ToString( dLen, 3) + szNewLine ; + // dati generali di una curva + if ( ! CurveDump( *this, sOut, szNewLine)) + return false ; + // parametri : sono già compresi nei dati generali (PS e PE) + return true ; } @@ -492,6 +489,46 @@ CurveLine::Offset( double dDist, int nSide, int nType) return true ; } +//---------------------------------------------------------------------------- +bool +CurveLine::ModifyStart( const Point3d& ptNewStart) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // la linea modificata deve essere ancora valida + if ( SqDist( ptNewStart, m_PtEnd) <= EPS_SMALL * EPS_SMALL) + return false ; + // assegno il nuovo inizio + m_PtStart = ptNewStart ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveLine::ModifyEnd( const Point3d& ptNewEnd) +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // la linea modificata deve essere ancora valida + if ( SqDist( m_PtStart, ptNewEnd) <= EPS_SMALL * EPS_SMALL) + return false ; + // assegno la nuova fine + m_PtEnd = ptNewEnd ; + + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + //---------------------------------------------------------------------------- bool CurveLine::TrimStartAtParam( double dUTrim) diff --git a/CurveLine.h b/CurveLine.h index 08ba074..cffb147 100644 --- a/CurveLine.h +++ b/CurveLine.h @@ -88,6 +88,8 @@ class CurveLine : public ICurveLine, public IGeoObjRW virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) ; + virtual bool ModifyStart( const Point3d& ptNewStart) ; + virtual bool ModifyEnd( const Point3d& ptNewEnd) ; virtual bool TrimStartAtParam( double dUTrim) ; virtual bool TrimEndAtParam( double dUTrim) ; virtual bool TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 8c590d7..c30876b 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 2acca5f..8a89a35 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -231,6 +231,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -293,6 +294,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 6d1c200..21389c5 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -207,6 +207,9 @@ File di origine\Base + + File di origine\GeoCreate + @@ -503,6 +506,9 @@ File di intestazione + + File di intestazione + diff --git a/Frame3d.cpp b/Frame3d.cpp index fa88e27..5628db8 100644 --- a/Frame3d.cpp +++ b/Frame3d.cpp @@ -521,7 +521,7 @@ Frame3d::GetRotationsCAC1( double& dAngCDeg, double& dAngADeg, double& dAngC1Deg // ricavo la prima rotazione attorno a Z if ( dAngADeg > EPS_ANG_SMALL) - dAngCDeg = dAngOrizzDeg + 90 ; + dAngCDeg = dAngOrizzDeg + ANG_RIGHT ; else m_vtVersX.ToSpherical( nullptr, nullptr, &dAngCDeg) ; diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index aabc7bf..ac6e635 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -34,6 +34,7 @@ #include "/EgtDev/Include/EgkCurveComposite.h" #include "/EgtDev/Include/EgkDistPointCurve.h" #include "/EgtDev/Include/EgkIntersCurveCurve.h" +#include "/EgtDev/Include/EgkChainCurves.h" #include "/EgtDev/Include/EgkSurfTriMesh.h" #include "/EgtDev/Include/EgkExtText.h" #include "/EgtDev/Include/EgtPointerOwner.h" @@ -118,16 +119,12 @@ GdbExecutor::GdbExecutor( void) m_ExecMgr.Insert( "MIR", &GdbExecutor::ExecuteMirror) ; m_ExecMgr.Insert( "MIRROR", &GdbExecutor::ExecuteMirror) ; m_ExecMgr.Insert( "SHEAR", &GdbExecutor::ExecuteShear) ; - m_ExecMgr.Insert( "INVC", &GdbExecutor::ExecuteInvertCurve) ; - m_ExecMgr.Insert( "INVERTCURVE", &GdbExecutor::ExecuteInvertCurve) ; - m_ExecMgr.Insert( "COPYC", &GdbExecutor::ExecuteCopyCurve) ; - m_ExecMgr.Insert( "COPYCURVE", &GdbExecutor::ExecuteCopyCurve) ; - m_ExecMgr.Insert( "INVS", &GdbExecutor::ExecuteInvertSurf) ; - m_ExecMgr.Insert( "INVERTSURF", &GdbExecutor::ExecuteInvertSurf) ; - m_ExecMgr.Insert( "TRC", &GdbExecutor::ExecuteTrimCurve) ; - m_ExecMgr.Insert( "TRIMCURVE", &GdbExecutor::ExecuteTrimCurve) ; - m_ExecMgr.Insert( "SPC", &GdbExecutor::ExecuteSplitCurve) ; - m_ExecMgr.Insert( "SPLITCURVE", &GdbExecutor::ExecuteSplitCurve) ; + m_ExecMgr.Insert( "CMOD", &GdbExecutor::ExecuteCurveModify) ; + m_ExecMgr.Insert( "CURVEMODIFY", &GdbExecutor::ExecuteCurveModify) ; + m_ExecMgr.Insert( "CCOPY", &GdbExecutor::ExecuteCurveCopy) ; + m_ExecMgr.Insert( "CURVECOPY", &GdbExecutor::ExecuteCurveCopy) ; + m_ExecMgr.Insert( "SMOD", &GdbExecutor::ExecuteSurfModify) ; + m_ExecMgr.Insert( "SURFMODIFY", &GdbExecutor::ExecuteSurfModify) ; m_ExecMgr.Insert( "NEW", &GdbExecutor::ExecuteNew) ; m_ExecMgr.Insert( "LOAD", &GdbExecutor::ExecuteLoad) ; m_ExecMgr.Insert( "SAVE", &GdbExecutor::ExecuteSave) ; @@ -1608,7 +1605,7 @@ GdbExecutor::CurveCompoMake( const STRVECTOR& vsParams) // altrimenti devo prima trasformare la curva else { // creo una copia della curva (da buttare alla fine) - PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; + PtrOwner pModCrv( pCrv->Clone()) ; if ( ! IsValid( pModCrv)) return false ; // eseguo la trasformazione @@ -2294,7 +2291,7 @@ GdbExecutor::GetPolylineFromCurve( int nId, const Frame3d& frDest, double dLinTo // altrimenti devo prima trasformare la curva else { // creo una copia della curva (da buttare alla fine) - PtrOwner pModCrv( GetCurve( pCrv->Clone())) ; + PtrOwner pModCrv( pCrv->Clone()) ; if ( ! IsValid( pModCrv)) return false ; // eseguo la trasformazione @@ -4371,7 +4368,30 @@ GdbExecutor::ExecuteShear( const string& sCmd2, const STRVECTOR& vsParams) //---------------------------------------------------------------------------- bool -GdbExecutor::ExecuteInvertCurve( const string& sCmd2, const STRVECTOR& vsParams) +GdbExecutor::ExecuteCurveModify( const string& sCmd2, const STRVECTOR& vsParams) +{ + if ( sCmd2 == "INV" || sCmd2 == "INVERT") + return CurveModifyInvert( vsParams) ; + else if ( sCmd2 == "SP" || sCmd2 == "STARTPOINT") + return CurveModifyStartPoint( vsParams) ; + else if ( sCmd2 == "EP" || sCmd2 == "ENDPOINT") + return CurveModifyEndPoint( vsParams) ; + if ( sCmd2 == "TRSL" || sCmd2 == "TRIMSTARTLEN") + return CurveModifyTrim( vsParams, SL) ; + else if ( sCmd2 == "TREL" || sCmd2 == "TRIMENDLEN") + return CurveModifyTrim( vsParams, EL) ; + else if ( sCmd2 == "TRSP" || sCmd2 == "TRIMSTARTPAR") + return CurveModifyTrim( vsParams, SP) ; + else if ( sCmd2 == "TREP" || sCmd2 == "TRIMENDPAR") + return CurveModifyTrim( vsParams, EP) ; + else if ( sCmd2 == "TRSEP" || sCmd2 == "TRIMSTARTENDPAR") + return CurveModifyTrim( vsParams, SEP) ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +GdbExecutor::CurveModifyInvert( const STRVECTOR& vsParams) { // 1 parametro : Id/s if ( vsParams.size() != 1) @@ -4393,77 +4413,56 @@ GdbExecutor::ExecuteInvertCurve( const string& sCmd2, const STRVECTOR& vsParams) //---------------------------------------------------------------------------- bool -GdbExecutor::ExecuteCopyCurve( const string& sCmd2, const STRVECTOR& vsParams) +GdbExecutor::CurveModifyStartPoint( const STRVECTOR& vsParams) { - if ( sCmd2 == "PR" || sCmd2 == "PARAMRANGE") - return CopyCurveByParamRange( vsParams) ; - else - return false ; -} - -//---------------------------------------------------------------------------- -bool -GdbExecutor::CopyCurveByParamRange( const STRVECTOR& vsParams) -{ - // 5 parametri : IdCrv, IdDest, IdGroupDest, StartPar, EndPar - if ( vsParams.size() != 5) + // 2 parametri : Id, PtNewStart + if ( vsParams.size() != 2) return false ; // recupero la curva sorgente int nIdCrv = GetIdParam( vsParams[0]) ; - const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; + ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; if ( pCrv == nullptr) return false ; // recupero il suo riferimento Frame3d frCrv ; if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) return false ; - // recupero il riferimento del gruppo destinazione - Frame3d frDest ; - if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[2]), frDest)) + // recupero il nuovo punto di inizio + Point3d ptNewStart ; + if ( ! GetPointParam( vsParams[1], frCrv, ptNewStart)) return false ; - // recupero i parametri del range - double dUStart, dUEnd ; - if ( ! FromString( vsParams[3], dUStart) || - ! FromString( vsParams[4], dUEnd)) - return false ; - // copio la parte di curva che interessa e la porto nel riferimento del gruppo destinazione - PtrOwner pCopy( pCrv->CopyParamRange( dUStart, dUEnd)) ; - if ( ! ::IsValid( pCopy)) - return false ; - pCopy->LocToLoc( frCrv, frDest) ; - // la inserisco nel gruppo - return AddGeoObj( vsParams[1], vsParams[2], ::Release( pCopy)) ; + // eseguo la modifica + return pCrv->ModifyStart( ptNewStart) ; } //---------------------------------------------------------------------------- bool -GdbExecutor::ExecuteInvertSurf( const string& sCmd2, const STRVECTOR& vsParams) +GdbExecutor::CurveModifyEndPoint( const STRVECTOR& vsParams) { - // 1 parametro ( Nome/i) - if ( vsParams.size() != 1) + // 2 parametri : Id, PtNewEnd + if ( vsParams.size() != 2) return false ; - // recupero lista nomi - INTVECTOR vnNames ; - if ( ! GetNamesParam( vsParams[0], vnNames)) + // recupero la curva sorgente + int nIdCrv = GetIdParam( vsParams[0]) ; + ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; + if ( pCrv == nullptr) return false ; - // esecuzione inversione normale superficie - INTVECTOR::iterator Iter ; - for ( Iter = vnNames.begin() ; Iter != vnNames.end() ; ++Iter) { - ISurf* pSurf = GetSurf( m_pGDB->GetGeoObj( *Iter)) ; - if ( pSurf == nullptr || ! pSurf->Invert()) - return false ; - } - - return true ; + // recupero il suo riferimento + Frame3d frCrv ; + if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) + return false ; + // recupero il nuovo punto di fine + Point3d ptNewEnd ; + if ( ! GetPointParam( vsParams[1], frCrv, ptNewEnd)) + return false ; + // eseguo la modifica + return pCrv->ModifyEnd( ptNewEnd) ; } //---------------------------------------------------------------------------- bool -GdbExecutor::ExecuteTrimCurve( const string& sCmd2, const STRVECTOR& vsParams) +GdbExecutor::CurveModifyTrim( const STRVECTOR& vsParams, int nTrimType) { - enum SeLp { SL, EL, SP, EP, SEP} ; - - // almeno 2 parametri : Nome, parametro [, secondo parametro] if ( vsParams.size() < 2) return false ; @@ -4475,26 +4474,12 @@ GdbExecutor::ExecuteTrimCurve( const string& sCmd2, const STRVECTOR& vsParams) double dPar ; if ( ! FromString( vsParams[1], dPar)) return false ; - // determino il tipo di trim - SeLp StEnLenPar ; - if ( sCmd2 == "STARTLEN" || sCmd2 == "SL") - StEnLenPar = SL ; - else if ( sCmd2 == "ENDLEN" || sCmd2 == "EL") - StEnLenPar = EL ; - else if ( sCmd2 == "STARTPAR" || sCmd2 == "SP") - StEnLenPar = SP ; - else if ( sCmd2 == "ENDPAR" || sCmd2 == "EP") - StEnLenPar = EP ; - else if ( sCmd2 == "STARTENDPAR" || sCmd2 == "SEP") - StEnLenPar = SEP ; - else - return false ; // esecuzione trim INTVECTOR::iterator Iter ; for ( Iter = vnNames.begin() ; Iter != vnNames.end() ; ++Iter) { ICurve* pCurve ; if ( ( pCurve = GetCurve( m_pGDB->GetGeoObj( *Iter))) != nullptr) { - switch ( StEnLenPar) { + switch ( nTrimType) { case SL : if ( ! pCurve->TrimStartAtLen( dPar)) return false ; @@ -4530,17 +4515,54 @@ GdbExecutor::ExecuteTrimCurve( const string& sCmd2, const STRVECTOR& vsParams) //---------------------------------------------------------------------------- bool -GdbExecutor::ExecuteSplitCurve( const string& sCmd2, const STRVECTOR& vsParams) +GdbExecutor::ExecuteCurveCopy( const string& sCmd2, const STRVECTOR& vsParams) { - if ( sCmd2 == "C" || sCmd2 == "CLASS") - return SplitCurveByClass( vsParams) ; - else - return false ; + if ( sCmd2 == "PR" || sCmd2 == "PARAMRANGE") + return CurveCopyByParamRange( vsParams) ; + else if ( sCmd2 == "SPC" || sCmd2 == "SPLITCLASS") + return CurveCopyBySplitClass( vsParams) ; + else if ( sCmd2 == "CHAIN") + return CurveCopyByChain( vsParams) ; + return false ; } //---------------------------------------------------------------------------- bool -GdbExecutor::SplitCurveByClass( const STRVECTOR& vsParams) +GdbExecutor::CurveCopyByParamRange( const STRVECTOR& vsParams) +{ + // 5 parametri : IdCrv, IdDest, IdGroupDest, StartPar, EndPar + if ( vsParams.size() != 5) + return false ; + // recupero la curva sorgente + int nIdCrv = GetIdParam( vsParams[0]) ; + const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nIdCrv)) ; + if ( pCrv == nullptr) + return false ; + // recupero il suo riferimento + Frame3d frCrv ; + if ( ! m_pGDB->GetGlobFrame( nIdCrv, frCrv)) + return false ; + // recupero il riferimento del gruppo destinazione + Frame3d frDest ; + if ( ! m_pGDB->GetGroupGlobFrame( GetIdParam( vsParams[2]), frDest)) + return false ; + // recupero i parametri del range + double dUStart, dUEnd ; + if ( ! FromString( vsParams[3], dUStart) || + ! FromString( vsParams[4], dUEnd)) + return false ; + // copio la parte di curva che interessa e la porto nel riferimento del gruppo destinazione + PtrOwner pCopy( pCrv->CopyParamRange( dUStart, dUEnd)) ; + if ( ! ::IsValid( pCopy)) + return false ; + pCopy->LocToLoc( frCrv, frDest) ; + // la inserisco nel gruppo + return AddGeoObj( vsParams[1], vsParams[2], ::Release( pCopy)) ; +} + +//---------------------------------------------------------------------------- +bool +GdbExecutor::CurveCopyBySplitClass( const STRVECTOR& vsParams) { // 6 parametri : IdCurve, IdClosedCurve, IdGroupIn, IdGroupOut, IdGroupOnP, IdGroupOnM if ( vsParams.size() != 6) @@ -4618,6 +4640,135 @@ GdbExecutor::SplitCurveByClass( const STRVECTOR& vsParams) return true ; } +//---------------------------------------------------------------------------- +bool +GdbExecutor::CurveCopyByChain( const STRVECTOR& vsParams) +{ + // 3, 4 o 5 parametri : IdCurve/s, IdGroupDest, ptNearStart [, bAllowInvert [, dToler]] + if ( vsParams.size() < 3) + return false ; + // recupero lista Id + INTVECTOR vnNames ; + if ( ! GetNamesParam( vsParams[0], vnNames)) + return false ; + // recupero il gruppo destinazione e il suo riferimento + int nIdDest = GetIdParam( vsParams[1]) ; + Frame3d frDest ; + if ( ! m_pGDB->GetGroupGlobFrame( nIdDest, frDest)) + return false ; + // recupero il punto vicino alla partenza + Point3d ptNearStart ; + if ( ! GetPointParam( vsParams[2], frDest, ptNearStart)) + return false ; + // recupero eventuale flag per consentire inversione di curve + bool bAllowInvert = true ; + if ( vsParams.size() >= 4 && ! FromString( vsParams[3], bAllowInvert)) + return false ; + // recupero eventuale tolleranza + double dToler = EPS_SMALL ; + if ( vsParams.size() >= 5 && ! FromString( vsParams[4], dToler)) + return false ; + // preparo i dati per il concatenamento + ChainCurves chainC ; + chainC.Init( bAllowInvert, dToler, int( vnNames.size())) ; + INTVECTOR::iterator Iter ; + for ( Iter = vnNames.begin() ; Iter != vnNames.end() ; ++Iter) { + // recupero la curva e il suo riferimento + ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( *Iter)) ; + if ( pCrv == nullptr) + return false ; + Frame3d frCrv ; + if ( ! m_pGDB->GetGlobFrame( *Iter, frCrv)) + return false ; + // recupero i dati della curva necessari al concatenamento e li assegno + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || + ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) + return false ; + ptStart.LocToLoc( frCrv, frDest) ; + vtStart.LocToLoc( frCrv, frDest) ; + ptEnd.LocToLoc( frCrv, frDest) ; + vtEnd.LocToLoc( frCrv, frDest) ; + if ( ! chainC.AddCurve( *Iter, ptStart, vtStart, ptEnd, vtEnd)) + return false ; + } + // recupero i percorsi concatenati + INTVECTOR vIds ; + while ( chainC.GetChainFromNear( ptNearStart, vIds)) { + // creo una curva composita + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( ! IsValid( pCrvCompo)) + return false ; + // recupero le curve semplici e le inserisco nella curva composita + INTVECTOR::iterator Iter ; + for ( Iter = vIds.begin() ; Iter != vIds.end() ; ++Iter) { + int nId = abs( *Iter) ; + bool bInvert = ( *Iter < 0) ; + // recupero la curva e il suo riferimento + ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nId)) ; + if ( pCrv == nullptr) + return false ; + Frame3d frCrv ; + if ( ! m_pGDB->GetGlobFrame( nId, frCrv)) + return false ; + // copio la curva + PtrOwner pCopCrv( pCrv->Clone()) ; + if ( ! IsValid( pCopCrv)) + return false ; + // se necessario, la inverto + if ( bInvert) + pCopCrv->Invert() ; + // la sistemo per i riferimenti + pCopCrv->LocToLoc( frCrv, frDest) ; + // la aggiungo alla curva composta + if ( ! pCrvCompo->AddCurve( ::Release( pCopCrv), true, dToler)) + return false ; + } + // aggiorno il nuovo punto vicino + if ( pCrvCompo->GetCurveNumber() > 0) + pCrvCompo->GetEndPoint( ptNearStart) ; + // inserisco la curva composita nel gruppo destinazione + if ( pCrvCompo->GetCurveNumber() > 0) { + if ( m_pGDB->AddGeoObj( GDB_ID_NULL, nIdDest, ::Release( pCrvCompo)) == GDB_ID_NULL) + return false ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +GdbExecutor::ExecuteSurfModify( const string& sCmd2, const STRVECTOR& vsParams) +{ + if ( sCmd2 == "INV" || sCmd2 == "INVERT") + return SurfModifyInvert( vsParams) ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +GdbExecutor::SurfModifyInvert( const STRVECTOR& vsParams) +{ + // 1 parametro ( Nome/i) + if ( vsParams.size() != 1) + return false ; + // recupero lista nomi + INTVECTOR vnNames ; + if ( ! GetNamesParam( vsParams[0], vnNames)) + return false ; + // esecuzione inversione normale superficie + INTVECTOR::iterator Iter ; + for ( Iter = vnNames.begin() ; Iter != vnNames.end() ; ++Iter) { + ISurf* pSurf = GetSurf( m_pGDB->GetGeoObj( *Iter)) ; + if ( pSurf == nullptr || ! pSurf->Invert()) + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool GdbExecutor::ExecuteNew( const string& sCmd2, const STRVECTOR& vsParams) diff --git a/GdbExecutor.h b/GdbExecutor.h index 18f9f2f..c51355d 100644 --- a/GdbExecutor.h +++ b/GdbExecutor.h @@ -132,13 +132,17 @@ class GdbExecutor : public IGdbExecutor bool ExecuteScale( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteMirror( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteShear( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool ExecuteInvertCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool ExecuteCopyCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool CopyCurveByParamRange( const STRVECTOR& vsParams) ; - bool ExecuteInvertSurf( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool ExecuteTrimCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool ExecuteSplitCurve( const std::string& sCmd2, const STRVECTOR& vsParams) ; - bool SplitCurveByClass( const STRVECTOR& vsParams) ; + bool ExecuteCurveModify( const std::string& sCmd2, const STRVECTOR& vsParams) ; + bool CurveModifyInvert( const STRVECTOR& vsParams) ; + bool CurveModifyStartPoint( const STRVECTOR& vsParams) ; + bool CurveModifyEndPoint( const STRVECTOR& vsParams) ; + bool CurveModifyTrim( const STRVECTOR& vsParams, int nTrimType) ; + bool ExecuteCurveCopy( const std::string& sCmd2, const STRVECTOR& vsParams) ; + bool CurveCopyByParamRange( const STRVECTOR& vsParams) ; + bool CurveCopyBySplitClass( const STRVECTOR& vsParams) ; + bool CurveCopyByChain( const STRVECTOR& vsParams) ; + bool ExecuteSurfModify( const std::string& sCmd2, const STRVECTOR& vsParams) ; + bool SurfModifyInvert( const STRVECTOR& vsParams) ; bool ExecuteNew( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteLoad( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool ExecuteSave( const std::string& sCmd2, const STRVECTOR& vsParams) ; @@ -146,6 +150,9 @@ class GdbExecutor : public IGdbExecutor bool ExecuteOutTsc( const std::string& sCmd2, const STRVECTOR& vsParams) ; bool OutGroupTsc( int nId, int nFlag, int nLev = 0) ; + private : + enum SeLp { SL, EL, SP, EP, SEP} ; + private : IGeomDB* m_pGDB ; ICmdParser* m_pParser ; diff --git a/GeoFrame3d.cpp b/GeoFrame3d.cpp index e719448..535e89e 100644 --- a/GeoFrame3d.cpp +++ b/GeoFrame3d.cpp @@ -195,37 +195,38 @@ bool GeoFrame3d::GetDrawWithArrowHeads( double dLenA, double dFrazLenAH, PolyLine& plX, PolyLine& plY, PolyLine& plZ) const { + const double A_WIDTH_COEFF = 0.3 ; double dLenAH = dFrazLenAH * dLenA ; // vettore X (con freccia) plX.AddUPoint( 0, m_frF.Orig()) ; Point3d ptTipX = m_frF.Orig() + m_frF.VersX() * dLenA ; plX.AddUPoint( 1, ptTipX) ; - Point3d ptP1X = ptTipX + ( - m_frF.VersX() - 0.5 * m_frF.VersY()) * dLenAH ; + Point3d ptP1X = ptTipX + ( - m_frF.VersX() - A_WIDTH_COEFF * m_frF.VersY()) * dLenAH ; plX.AddUPoint( 2, ptP1X) ; - Point3d ptP2X = ptTipX + ( - m_frF.VersX() + 0.5 * m_frF.VersY()) * dLenAH ; + Point3d ptP2X = ptTipX + ( - m_frF.VersX() + A_WIDTH_COEFF * m_frF.VersY()) * dLenAH ; plX.AddUPoint( 3, ptP2X) ; plX.AddUPoint( 4, ptTipX) ; // vettore Y (con freccia) plY.AddUPoint( 0, m_frF.Orig()) ; Point3d ptTipY = m_frF.Orig() + m_frF.VersY() * dLenA ; plY.AddUPoint( 1, ptTipY) ; - Point3d ptP1Y = ptTipY + ( - m_frF.VersY() - 0.5 * m_frF.VersX()) * dLenAH ; + Point3d ptP1Y = ptTipY + ( - m_frF.VersY() - A_WIDTH_COEFF * m_frF.VersX()) * dLenAH ; plY.AddUPoint( 2, ptP1Y) ; - Point3d ptP2Y = ptTipY + ( - m_frF.VersY() + 0.5 * m_frF.VersX()) * dLenAH ; + Point3d ptP2Y = ptTipY + ( - m_frF.VersY() + A_WIDTH_COEFF * m_frF.VersX()) * dLenAH ; plY.AddUPoint( 3, ptP2Y) ; plY.AddUPoint( 4, ptTipY) ; // vettore Z (con doppia freccia) plZ.AddUPoint( 0, m_frF.Orig()) ; Point3d ptTipZ = m_frF.Orig() + m_frF.VersZ() * dLenA ; plZ.AddUPoint( 1, ptTipZ) ; - Point3d ptP1Z = ptTipZ + ( - m_frF.VersZ() - 0.5 * m_frF.VersX()) * dLenAH ; + Point3d ptP1Z = ptTipZ + ( - m_frF.VersZ() - A_WIDTH_COEFF * m_frF.VersX()) * dLenAH ; plZ.AddUPoint( 2, ptP1Z) ; - Point3d ptP2Z = ptTipZ + ( - m_frF.VersZ() + 0.5 * m_frF.VersX()) * dLenAH ; + Point3d ptP2Z = ptTipZ + ( - m_frF.VersZ() + A_WIDTH_COEFF * m_frF.VersX()) * dLenAH ; plZ.AddUPoint( 3, ptP2Z) ; plZ.AddUPoint( 4, ptTipZ) ; - Point3d ptP3Z = ptTipZ + ( - m_frF.VersZ() - 0.5 * m_frF.VersY()) * dLenAH ; + Point3d ptP3Z = ptTipZ + ( - m_frF.VersZ() - A_WIDTH_COEFF * m_frF.VersY()) * dLenAH ; plZ.AddUPoint( 5, ptP3Z) ; - Point3d ptP4Z = ptTipZ + ( - m_frF.VersZ() + 0.5 * m_frF.VersY()) * dLenAH ; + Point3d ptP4Z = ptTipZ + ( - m_frF.VersZ() + A_WIDTH_COEFF * m_frF.VersY()) * dLenAH ; plZ.AddUPoint( 6, ptP4Z) ; plZ.AddUPoint( 7, ptTipZ) ; diff --git a/GeoVector3d.cpp b/GeoVector3d.cpp index 4ac2fc5..040d4af 100644 --- a/GeoVector3d.cpp +++ b/GeoVector3d.cpp @@ -208,20 +208,21 @@ GeoVector3d::GetDrawWithArrowHead( double dFrazLenAH, double dMaxDimA, PolyLine& Point3d ptTip = m_ptBase + m_vtV ; PL.AddUPoint( 1, ptTip) ; // doppia freccia + const double A_WIDTH_COEFF = 0.3 ; double dLenAH = min( dMaxDimA, dFrazLenAH * m_vtV.Len()) ; Frame3d frF ; frF.Set( ptTip, m_vtV) ; - Point3d ptP1 = ORIG + Vector3d( 0.5, 0, -1) * dLenAH ; + Point3d ptP1 = ORIG + Vector3d( A_WIDTH_COEFF, 0, -1) * dLenAH ; ptP1.ToGlob( frF) ; PL.AddUPoint( 2, ptP1) ; - Point3d ptP2 = ORIG + Vector3d( -0.5, 0, -1) * dLenAH ; + Point3d ptP2 = ORIG + Vector3d( -A_WIDTH_COEFF, 0, -1) * dLenAH ; ptP2.ToGlob( frF) ; PL.AddUPoint( 3, ptP2) ; PL.AddUPoint( 4, ptTip) ; - Point3d ptP3 = ORIG + Vector3d( 0, 0.5, -1) * dLenAH ; + Point3d ptP3 = ORIG + Vector3d( 0, A_WIDTH_COEFF, -1) * dLenAH ; ptP3.ToGlob( frF) ; PL.AddUPoint( 5, ptP3) ; - Point3d ptP4 = ORIG + Vector3d( 0, -0.5, -1) * dLenAH ; + Point3d ptP4 = ORIG + Vector3d( 0, -A_WIDTH_COEFF, -1) * dLenAH ; ptP4.ToGlob( frF) ; PL.AddUPoint( 6, ptP4) ; PL.AddUPoint( 7, ptTip) ; diff --git a/PointGrid3d.cpp b/PointGrid3d.cpp index b2d3742..c34488f 100644 --- a/PointGrid3d.cpp +++ b/PointGrid3d.cpp @@ -18,12 +18,122 @@ using namespace std ; +//---------------------------------------------------------------------------- +// Struct IBox +//---------------------------------------------------------------------------- +struct IBox { + int nXmin, nXmax ; + int nYmin, nYmax ; + int nZmin, nZmax ; + IBox( void) : nXmin( INT_MAX), nXmax( INT_MIN), + nYmin( INT_MAX), nYmax( INT_MIN), + nZmin( INT_MAX), nZmax( INT_MIN) {} + void Reset( void) + { nXmin = nYmin = nZmin = INT_MAX ; + nXmax = nYmax = nZmax = INT_MIN ; } + bool Encloses( int nX, int nY, int nZ) + { return ( nX >= nXmin && nX <= nXmax && + nY >= nYmin && nY <= nYmax && + nZ >= nZmin && nZ <= nZmax) ; } +} ; + +//---------------------------------------------------------------------------- +static const int N_SUBIBOX = 6 ; + +//---------------------------------------------------------------------------- +bool +SubtractIBox( const IBox& ibA, const IBox& ibB, IBox ibR[N_SUBIBOX]) +{ + // ibR = ibA - ibB (il risultato può essere formato da 6 box) + // se ibA non include alcunchè + if ( ibA.nXmin > ibA.nXmax || ibA.nYmin > ibA.nYmax || ibA.nZmin > ibA.nZmax) { + for ( int i = 0 ; i < N_SUBIBOX ; ++ i) + ibR[i].Reset() ; + return true ; + } + // se ibB non include alcunchè + if ( ibB.nXmin > ibB.nXmax || ibB.nYmin > ibB.nYmax || ibB.nZmin > ibB.nZmax) { + ibR[0] = ibA ; + for ( int i = 1 ; i < N_SUBIBOX ; ++ i) + ibR[i].Reset() ; + return true ; + } + // lungo asse X + if ( ibA.nXmin < ibB.nXmin) { + ibR[0].nXmin = ibA.nXmin ; + ibR[0].nXmax = ibB.nXmin - 1 ; + ibR[0].nYmin = ibA.nYmin ; + ibR[0].nYmax = ibA.nYmax ; + ibR[0].nZmin = ibA.nZmin ; + ibR[0].nZmax = ibA.nZmax ; + } + else + ibR[0].Reset() ; + if ( ibA.nXmax > ibB.nXmax) { + ibR[1].nXmin = ibB.nXmax + 1 ; + ibR[1].nXmax = ibA.nXmax ; + ibR[1].nYmin = ibA.nYmin ; + ibR[1].nYmax = ibA.nYmax ; + ibR[1].nZmin = ibA.nZmin ; + ibR[1].nZmax = ibA.nZmax ; + } + else + ibR[1].Reset() ; + // lungo asse Y + if ( ibA.nYmin < ibB.nYmin) { + ibR[2].nXmin = ibB.nXmin ; + ibR[2].nXmax = ibB.nXmax ; + ibR[2].nYmin = ibA.nYmin ; + ibR[2].nYmax = ibB.nYmin - 1 ; + ibR[2].nZmin = ibA.nZmin ; + ibR[2].nZmax = ibA.nZmax ; + } + else + ibR[2].Reset() ; + if ( ibA.nYmax > ibB.nYmax) { + ibR[3].nXmin = ibB.nXmin ; + ibR[3].nXmax = ibB.nXmax ; + ibR[3].nYmin = ibB.nYmax + 1 ; + ibR[3].nYmax = ibA.nYmax ; + ibR[3].nZmin = ibA.nZmin ; + ibR[3].nZmax = ibA.nZmax ; + } + else + ibR[3].Reset() ; + // lungo asse Z + if ( ibA.nZmin < ibB.nZmin) { + ibR[4].nXmin = ibB.nXmin ; + ibR[4].nXmax = ibB.nXmax ; + ibR[4].nYmin = ibB.nYmin ; + ibR[4].nYmax = ibB.nYmax ; + ibR[4].nZmin = ibA.nZmin ; + ibR[4].nZmax = ibB.nZmin - 1 ; + } + else + ibR[4].Reset() ; + if ( ibA.nZmax > ibB.nZmax) { + ibR[5].nXmin = ibB.nXmin ; + ibR[5].nXmax = ibB.nXmax ; + ibR[5].nYmin = ibB.nYmin ; + ibR[5].nYmax = ibB.nYmax ; + ibR[5].nZmin = ibB.nZmax + 1 ; + ibR[5].nZmax = ibA.nZmax ; + } + else + ibR[5].Reset() ; + return true ; +} + +//---------------------------------------------------------------------------- +// Class PointGrid3d //---------------------------------------------------------------------------- bool PointGrid3d::Init( int nBuckets, double dCellDim) { m_dCellDim = max( dCellDim, EPS_SMALL) ; m_dInvCellDim = 1 / m_dCellDim ; + m_BBox.Reset() ; + m_MMap.clear() ; try { m_MMap.rehash( nBuckets) ;} catch(...) { return false ;} return true ; @@ -33,30 +143,49 @@ PointGrid3d::Init( int nBuckets, double dCellDim) bool PointGrid3d::InsertPoint( const Point3d& ptP, int nId) { + // inserimento nel map int nKey = PointHash( Get1dCellNbr( ptP.x), Get1dCellNbr( ptP.y), Get1dCellNbr( ptP.z)) ; m_MMap.insert( make_pair( nKey, make_pair( ptP, nId))) ; + // aggiornamento del bbox complessivo + m_BBox.Add( ptP) ; return true ; } +//---------------------------------------------------------------------------- +bool +PointGrid3d::RemovePoint( const Point3d& ptP, int nId) +{ + // recupero gli elementi con la chiave + int nKey = PointHash( Get1dCellNbr( ptP.x), Get1dCellNbr( ptP.y), Get1dCellNbr( ptP.z)) ; + IPNTI_UMMAP_CRANGE MMrange = m_MMap.equal_range( nKey) ; + // cerco quello con l'Id voluto + for ( ; MMrange.first != MMrange.second ; ++ MMrange.first) { + // se coincidono punto e Id lo cancello + if ( SqDist( (*MMrange.first).second.first, ptP) < ( EPS_SMALL * EPS_SMALL) && + abs( (*MMrange.first).second.second) == abs( nId)) { + m_MMap.erase( MMrange.first) ; + return true ; + } + } + + return false ; +} + //---------------------------------------------------------------------------- bool PointGrid3d::Find( const Point3d& ptTest, double dTol, INTVECTOR& vnIds) { - // ricavo gli indici sui tre assi degli estremi del box - int nXmin = Get1dCellNbr( ptTest.x - dTol) ; - int nXmax = Get1dCellNbr( ptTest.x + dTol) ; - int nYmin = Get1dCellNbr( ptTest.y - dTol) ; - int nYmax = Get1dCellNbr( ptTest.y + dTol) ; - int nZmin = Get1dCellNbr( ptTest.z - dTol) ; - int nZmax = Get1dCellNbr( ptTest.z + dTol) ; // pulisco il risultato vnIds.clear() ; - // ciclo su tutte le celle comprese tra gli estremi - for ( int i = nXmin ; i <= nXmax ; ++ i) { - for ( int j = nYmin ; j <= nYmax ; ++ j) { - for ( int k = nZmin ; k <= nZmax ; ++ k) { - pair MMrange = - m_MMap.equal_range( PointHash( i, j, k)) ; + // determino il range di celle sui tre assi + IBox iBox ; + if ( ! Get3dRangeNbr( ptTest, dTol, iBox)) + return false ; + // ciclo su tutte le celle del range + for ( int i = iBox.nXmin ; i <= iBox.nXmax ; ++ i) { + for ( int j = iBox.nYmin ; j <= iBox.nYmax ; ++ j) { + for ( int k = iBox.nZmin ; k <= iBox.nZmax ; ++ k) { + IPNTI_UMMAP_CRANGE MMrange = m_MMap.equal_range( PointHash( i, j, k)) ; for ( ; MMrange.first != MMrange.second ; ++ MMrange.first) { if ( SqDist( (*MMrange.first).second.first, ptTest) < ( dTol * dTol)) vnIds.push_back( (*MMrange.first).second.second) ; @@ -72,19 +201,15 @@ PointGrid3d::Find( const Point3d& ptTest, double dTol, INTVECTOR& vnIds) bool PointGrid3d::Find( const Point3d& ptTest, double dTol, int& nId) { - // ricavo gli indici sui tre assi degli estremi del box - int nXmin = Get1dCellNbr( ptTest.x - dTol) ; - int nXmax = Get1dCellNbr( ptTest.x + dTol) ; - int nYmin = Get1dCellNbr( ptTest.y - dTol) ; - int nYmax = Get1dCellNbr( ptTest.y + dTol) ; - int nZmin = Get1dCellNbr( ptTest.z - dTol) ; - int nZmax = Get1dCellNbr( ptTest.z + dTol) ; - // ciclo su tutte le celle comprese tra gli estremi - for ( int i = nXmin ; i <= nXmax ; ++ i) { - for ( int j = nYmin ; j <= nYmax ; ++ j) { - for ( int k = nZmin ; k <= nZmax ; ++ k) { - pair MMrange = - m_MMap.equal_range( PointHash( i, j, k)) ; + // determino il range di celle sui tre assi + IBox iBox ; + if ( ! Get3dRangeNbr( ptTest, dTol, iBox)) + return false ; + // ciclo su tutte le celle del range + for ( int i = iBox.nXmin ; i <= iBox.nXmax ; ++ i) { + for ( int j = iBox.nYmin ; j <= iBox.nYmax ; ++ j) { + for ( int k = iBox.nZmin ; k <= iBox.nZmax ; ++ k) { + IPNTI_UMMAP_CRANGE MMrange = m_MMap.equal_range( PointHash( i, j, k)) ; for ( ; MMrange.first != MMrange.second ; ++ MMrange.first) { if ( SqDist( (*MMrange.first).second.first, ptTest) < ( dTol * dTol)) { nId = (*MMrange.first).second.second ; @@ -98,6 +223,90 @@ PointGrid3d::Find( const Point3d& ptTest, double dTol, int& nId) return false ; } +//---------------------------------------------------------------------------- +bool +PointGrid3d::FindNearest( const Point3d& ptTest, INTVECTOR& vnIds) +{ + const double NEAR_TOL = 100 * EPS_SMALL ; + // pulisco il risultato + vnIds.clear() ; + // raggio di ricerca + double dRad = max( m_BBox.DistFromPoint( ptTest), NEAR_TOL) ; + // delta di incremento per raggio di ricerca + const int N_CELL = 10 ; + double dDelta = N_CELL * m_dCellDim ; + // massimo numero di step di ricerca basato su raggio box di ingombro + double dBoxRad ; + if ( ! m_BBox.GetRadius( dBoxRad)) + return false ; + int nMaxSteps = int( 2 * ceil( dBoxRad / dDelta)) ; + // ciclo di ricerca con raggio crescente + IBox iBoxPrev ; + IBox ibR[N_SUBIBOX] ; + bool bFound = false ; + double dMinDist ; + double dSqMinDist ; + for ( int m = 0 ; m < nMaxSteps ; ++ m) { + // determino il range di celle sui tre assi + IBox iBox ; + if ( ! Get3dRangeNbr( ptTest, dRad, iBox)) + continue ; + // tolgo il range precedente + SubtractIBox( iBox, iBoxPrev, ibR) ; + // ciclo su tutte le celle dei range rimanenti + for ( int l = 0 ; l < N_SUBIBOX ; ++ l) { + for ( int i = ibR[l].nXmin ; i <= ibR[l].nXmax ; ++ i) { + for ( int j = ibR[l].nYmin ; j <= ibR[l].nYmax ; ++ j) { + for ( int k = ibR[l].nZmin ; k <= ibR[l].nZmax ; ++ k) { + // ciclo sui punti della cella + IPNTI_UMMAP_CRANGE MMrange = m_MMap.equal_range( PointHash( i, j, k)) ; + for ( ; MMrange.first != MMrange.second ; ++ MMrange.first) { + // se distanza inferiore al minimo, aggiorno... + double dSqDist = SqDist( (*MMrange.first).second.first, ptTest) ; + // altro punto con la stessa minima distanza già trovata + if ( bFound && fabs( dSqDist - dSqMinDist) < 2 * dMinDist * NEAR_TOL) { + // inserisco il punto nel vettore dei risultati + vnIds.push_back( (*MMrange.first).second.second) ; + } + // primo punto o punto con minima distanza più bassa + else if ( ! bFound || dSqDist < dSqMinDist) { + bFound = true ; + // aggiorno i minimi + dSqMinDist = dSqDist ; + dMinDist = sqrt( dSqMinDist) ; + // pulisco il vettore dei risultati ed inserisco questo + vnIds.clear() ; + vnIds.push_back( (*MMrange.first).second.second) ; + } + } + } + } + } + } + // se trovato, inutile continuare perchè ci si allontanerà + if ( bFound) + return true ; + // incremento il raggio di ricerca + dRad += dDelta ; + // salvo box di precedente ricerca + iBoxPrev = iBox ; + } + + return bFound ; +} + +//---------------------------------------------------------------------------- +bool +PointGrid3d::First( int& nId) +{ + // se vuoto + if ( m_MMap.empty()) + return false ; + // recupero il primo + nId = (*m_MMap.begin()).second.second ; + return true ; +} + //---------------------------------------------------------------------------- int PointGrid3d::Get1dCellNbr( double dCoord) @@ -105,6 +314,24 @@ PointGrid3d::Get1dCellNbr( double dCoord) return static_cast( floor( dCoord * m_dInvCellDim)) ; } +//---------------------------------------------------------------------------- +bool +PointGrid3d::Get3dRangeNbr( const Point3d& ptTest, double dTol, IBox& iBox) +{ + // calcolo intersezione tra box + BBox3d b3Int ; + if ( ! m_BBox.FindIntersection( BBox3d( ptTest, dTol), b3Int)) + return false ; + // ricavo gli indici sui tre assi degli estremi del box + iBox.nXmin = Get1dCellNbr( b3Int.GetMin().x) ; + iBox.nYmin = Get1dCellNbr( b3Int.GetMin().y) ; + iBox.nZmin = Get1dCellNbr( b3Int.GetMin().z) ; + iBox.nXmax = Get1dCellNbr( b3Int.GetMax().x) ; + iBox.nYmax = Get1dCellNbr( b3Int.GetMax().y) ; + iBox.nZmax = Get1dCellNbr( b3Int.GetMax().z) ; + return true ; +} + //---------------------------------------------------------------------------- int PointGrid3d::PointHash( int nX, int nY, int nZ) diff --git a/PolyLine.cpp b/PolyLine.cpp index de59e87..56db9f0 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -251,9 +251,9 @@ PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP) const return false ; if ( pdPar != nullptr) - *pdPar = m_lUPoints.back().first ; + *pdPar = m_iter->first ; if ( pptP != nullptr) - *pptP = m_lUPoints.back().second ; + *pptP = m_iter->second ; return true ; } @@ -325,6 +325,58 @@ PolyLine::GetNextULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::GetLastULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const +{ + // parametro e punto finali + m_iter = m_lUPoints.end() ; + if ( m_iter == m_lUPoints.begin()) + return false ; + -- m_iter ; + if ( m_iter == m_lUPoints.end()) + return false ; + if ( pdFin != nullptr) + *pdFin = m_iter->first ; + if ( pptFin != nullptr) + *pptFin = m_iter->second ; + + // parametro e punto iniziali + if ( m_iter == m_lUPoints.begin()) + return false ; + -- m_iter ; + if ( pdIni != nullptr) + *pdIni = m_iter->first ; + if ( pptIni != nullptr) + *pptIni = m_iter->second ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyLine::GetPrevULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const +{ + // parametro e punto finali + if ( m_iter == m_lUPoints.end()) + return false ; + if ( pdFin != nullptr) + *pdFin = m_iter->first ; + if ( pptFin != nullptr) + *pptFin = m_iter->second ; + + // parametro e punto iniziali + if ( m_iter == m_lUPoints.begin()) + return false ; + -- m_iter ; + if ( pdIni != nullptr) + *pdIni = m_iter->first ; + if ( pptIni != nullptr) + *pptIni = m_iter->second ; + + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::NewellPlane( Plane3d& plPlane, double& dArea) const @@ -387,6 +439,32 @@ PolyLine::IsPlanar( Plane3d& plPlane, double& dArea, double dToler) const return true ; } +//---------------------------------------------------------------------------- +bool +PolyLine::GetApproxLength( double& dLen) const +{ + // calcolo la lunghezza approssimata come somma di ogni singolo tratto lineare + dLen = 0 ; + Point3d ptIni, ptFin ; + for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { + dLen += ApproxDist( ptIni, ptFin) ; + } + return ( dLen > EPS_ZERO) ; +} + +//---------------------------------------------------------------------------- +bool +PolyLine::GetLength( double& dLen) const +{ + // calcolo la lunghezza come somma di ogni singolo tratto lineare + dLen = 0 ; + Point3d ptIni, ptFin ; + for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { + dLen += Dist( ptIni, ptFin) ; + } + return ( dLen > EPS_ZERO) ; +} + //---------------------------------------------------------------------------- bool PolyLine::GetAreaXY( double& dArea) const diff --git a/Vector3d.cpp b/Vector3d.cpp index 977f3b7..75ac417 100644 --- a/Vector3d.cpp +++ b/Vector3d.cpp @@ -94,22 +94,22 @@ Vector3d::ToSpherical( double* pdLen, double* pdAngVertDeg, double* pdAngOrizzDe else { // se diretto come Z if ( fabs( x) < EPS_ZERO && fabs( y) < EPS_ZERO) { - dAngVertDeg = (( z > 0) ? 0 : 180) ; + dAngVertDeg = (( z > 0) ? 0 : ANG_STRAIGHT) ; dAngOrizzDeg = 0 ; } // se altrimenti nel piano XY else if ( fabs( z) < EPS_ZERO) { - dAngVertDeg = 90.0 ; + dAngVertDeg = ANG_RIGHT ; dAngOrizzDeg = atan2( y, x) * RADTODEG ; if ( dAngOrizzDeg < 0) - dAngOrizzDeg += 360 ; + dAngOrizzDeg += ANG_FULL ; } // caso generico else { dAngVertDeg = acos( z / dLen) * RADTODEG ; dAngOrizzDeg = atan2( y, x) * RADTODEG ; if ( dAngOrizzDeg < 0) - dAngOrizzDeg += 360 ; + dAngOrizzDeg += ANG_FULL ; } }