diff --git a/ArcXxTgArc.cpp b/ArcXxTgArc.cpp index 757f679..64e7c12 100644 --- a/ArcXxTgArc.cpp +++ b/ArcXxTgArc.cpp @@ -176,8 +176,7 @@ GetArc2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStartDeg) // calcolo arco non riuscito, verifico se retta va bene Vector3d vtDiff = ptEnd - ptStart ; vtDiff.z = 0 ; - Vector3d vtDir ; - vtDir.FromPolar( 1, dDirStartDeg) ; + Vector3d vtDir = FromPolar( 1, dDirStartDeg) ; // verifico se i punti sono allineati con la direzione e nel giusto verso if ( fabs( CrossXY( vtDiff, vtDir)) < EPS_SMALL && ScalarXY( vtDiff, vtDir) > EPS_SMALL) { // creo l'oggetto retta @@ -204,8 +203,7 @@ GetArcPntDirTgArc( const Point3d& ptP, double dDirStartDeg, const ICurveArc& crv } // versore ortogonale alla direzione iniziale (si lavora nel piano XY locale) - Vector3d vtOrtho ; - vtOrtho.FromPolar( 1, dDirStartDeg) ; + Vector3d vtOrtho = FromPolar( 1, dDirStartDeg) ; vtOrtho.Rotate( Z_AX, 0, 1) ; // calcolo arco spostando il punto iniziale di + raggio in direzione ortogonale diff --git a/CalcDerivate.h b/CalcDerivate.h index 973d259..fc3b7ad 100644 --- a/CalcDerivate.h +++ b/CalcDerivate.h @@ -88,7 +88,7 @@ CalcCircleStartDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& vtDer = ptP0 - ptCen ; vtDer.Rotate( vtN, 0, 1) ; if ( ( vtDer * vtA) < 0) - vtDer *= - 1 ; + vtDer.Invert() ; // ne aggiusto il modulo if ( ! vtDer.Normalize()) return false ; @@ -120,7 +120,7 @@ CalcCircleEndDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& pt vtDer = ptP2 - ptCen ; vtDer.Rotate( vtN, 0, 1) ; if ( ( vtDer * ( ptP2 - ptP1)) < 0) - vtDer *= - 1 ; + vtDer.Invert() ; // ne aggiusto il modulo if ( ! vtDer.Normalize()) return false ; diff --git a/CurveArc.cpp b/CurveArc.cpp index b216147..1d64693 100644 --- a/CurveArc.cpp +++ b/CurveArc.cpp @@ -124,7 +124,7 @@ CurveArc::SetXY( const Point3d& ptCen, double dRad, double dAngIniDeg, double dA // assegno e calcolo i dati m_PtCen = ptCen ; m_VtN = Z_AX ; - m_VtS.FromPolar( 1, dAngIniDeg) ; + m_VtS = FromPolar( 1, dAngIniDeg) ; m_dRad = dRad ; m_dAngCenDeg = dAngCenDeg ; m_dDeltaN = dDeltaZ ; @@ -278,8 +278,7 @@ CurveArc::Set2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStart m_nStatus = ERR ; // vettore tangente iniziale ( nel piano XY) - Vector3d vtA ; - vtA.FromPolar( 1, dDirStartDeg) ; + Vector3d vtA = FromPolar( 1, dDirStartDeg) ; // vettore da inizio a fine ( nel piano XY) Vector3d vtB = ptEnd - ptStart ; vtB.z = 0 ; @@ -313,9 +312,9 @@ CurveArc::Set2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStart // se normale con Z negativa, inverto senza modificare la geometria if ( m_VtN.z < 0) { - m_VtN *= - 1 ; - m_dAngCenDeg *= - 1 ; - m_dDeltaN *= - 1 ; + m_VtN.Invert() ; + m_dAngCenDeg = - m_dAngCenDeg ; + m_dDeltaN = - m_dDeltaN ; } // imposto ricalcolo della grafica @@ -605,6 +604,21 @@ CurveArc::Validate( void) return ( m_nStatus == OK) ; } +//---------------------------------------------------------------------------- +bool +CurveArc::IsFlat( Plane3d& plPlane, double dToler) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // assegno dati possibile piano + plPlane.vtN = m_VtN ; + plPlane.dDist = ( m_PtCen - ORIG) * plPlane.vtN ; + // verifico piattezza + return IsFlat( dToler) ; +} + //---------------------------------------------------------------------------- bool CurveArc::GetStartPoint( Point3d& ptStart) const @@ -845,8 +859,43 @@ CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) cons ArcApproxer aAppr( dLinTol, dAngTolDeg, true, *this) ; double dU ; Point3d ptPos ; - while ( aAppr.GetPoint( dU, ptPos)) - PL.AddUPoint( dU, ptPos) ; + while ( aAppr.GetPoint( dU, ptPos)) { + if ( ! PL.AddUPoint( dU, ptPos)) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +CurveArc::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const +{ + // pulisco la polilinea + PA.Clear() ; + + // la curva deve essere validata + if ( m_nStatus != OK) + return false ; + + // la curva deve avere normale coincidente con Z + if ( ! m_VtN.IsZplus() && ! m_VtN.IsZminus()) + return false ; + + // inserisco punto iniziale con bulge + Point3d ptStart ; + GetStartPoint( ptStart) ; + double dBulge = tan( m_dAngCenDeg / 4 * DEGTORAD) ; + if ( m_VtN.IsZminus()) + dBulge = - dBulge ; + if ( ! PA.AddUPoint( 0, ptStart, dBulge)) + return false ; + + // inserisco punto finale senza bulge + Point3d ptEnd ; + GetEndPoint( ptEnd) ; + if ( ! PA.AddUPoint( 1, ptEnd, 0)) + return false ; return true ; } @@ -1357,9 +1406,9 @@ CurveArc::InvertN( void) return false ; // si inverte il verso della normale senza modificare la geometria dell'arco - m_VtN *= - 1 ; - m_dAngCenDeg *= - 1 ; - m_dDeltaN *= - 1 ; + m_VtN.Invert() ; + m_dAngCenDeg = - m_dAngCenDeg ; + m_dDeltaN = - m_dDeltaN ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; diff --git a/CurveArc.h b/CurveArc.h index f89feb6..ba0a92e 100644 --- a/CurveArc.h +++ b/CurveArc.h @@ -55,6 +55,7 @@ class CurveArc : public ICurveArc, public IGeoObjRW { return true ; } virtual bool IsClosed( void) const { return ::IsClosed( *this) ; } + virtual bool IsFlat( Plane3d& plPlane, double dToler = EPS_SMALL) const ; virtual bool GetStartPoint( Point3d& ptStart) const ; virtual bool GetEndPoint( Point3d& ptEnd) const ; virtual bool GetMidPoint( Point3d& ptMid) const ; @@ -85,6 +86,7 @@ class CurveArc : public ICurveArc, public IGeoObjRW return ::GetPointDiffGeom( *this, dU, nS, oDiffG) ; } virtual bool IsPointOn( const Point3d& ptP, double dTol = EPS_SMALL) const ; virtual bool ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const ; + virtual bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const ; virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) ; @@ -108,8 +110,8 @@ class CurveArc : public ICurveArc, public IGeoObjRW virtual bool Set2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStartDeg) ; virtual bool Set2PRS( const Point3d& ptStart, const Point3d& ptEnd, double dRad, bool bCCW = true) ; virtual bool SetC2P( const Point3d& ptCen, const Point3d& ptStart, const Point3d& ptNearEnd) ; - virtual bool IsFlat( void) const - { return ( fabs( m_dDeltaN) < EPS_SMALL) ; } + virtual bool IsFlat( double dToler = EPS_SMALL) const + { return ( fabs( m_dDeltaN) < dToler) ; } virtual bool IsACircle( void) const { return ( IsFlat() && IsClosed()) ; } virtual bool IsInPlaneXY( void) const @@ -164,3 +166,15 @@ class CurveArc : public ICurveArc, public IGeoObjRW double m_dAngCenDeg ; // angolo al centro in gradi (positivo se antiorario visto da VtN) double m_dDeltaN ; // variazione di quota lungo VtN della fine rispetto all'inizio } ; + +//----------------------------------------------------------------------------- +inline CurveArc* CreateBasicCurveArc( void) + { return (static_cast( CreateGeoObj( CRV_ARC))) ; } +inline CurveArc* CloneBasicCurveArc( const IGeoObj* pGObj) + { if ( pGObj == nullptr || pGObj->GetType() != CRV_ARC) + return nullptr ; + return (static_cast(pGObj->Clone())) ; } +inline const CurveArc* GetBasicCurveArc( const IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } +inline CurveArc* GetBasicCurveArc( IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } diff --git a/CurveAux.cpp b/CurveAux.cpp index 8ab4271..898094f 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -110,7 +110,7 @@ GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Ve if ( ! crvC.GetPointD1D2( dU, nS, ptDummy, &vtD1near)) return false ; if ( ( vtTang * vtD1near) < 0) - vtTang *= - 1 ; + vtTang.Invert() ; return true ; } @@ -152,7 +152,7 @@ GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGe 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.vtT.Invert() ; oDiffG.nStatus = CrvPointDiffGeom::TANG ; } else { diff --git a/CurveBezier.cpp b/CurveBezier.cpp index 3745a03..59b6bfd 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -473,6 +473,52 @@ CurveBezier::GetBBox( const Frame3d& frRef, BBox3d& b3Ref) const return true ; } +//---------------------------------------------------------------------------- +bool +CurveBezier::IsFlat( Plane3d& plPlane, double dToler) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // polilinea dei punti rappresentativi + PolyLine shPL ; + int nLastPC = m_nDeg ; + for ( int i = 0 ; i <= nLastPC ; ++ i) { + double dU = i / double( nLastPC) ; + if ( ! shPL.AddUPoint( dU, GetControlPoint( i))) + return false ; + } + // recupero dati sulla planarità + int nRank ; + Point3d ptCen ; + Vector3d vtDir ; + bool bFlat = shPL.IsFlat( nRank, ptCen, vtDir, dToler) ; + // se punto + switch ( nRank) { + case 0 : // punto + if ( bFlat) { + plPlane.vtN = Z_AX ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + } + else { + plPlane.vtN = V_NULL ; + plPlane.dDist = 0 ; + } + break ; + case 1 : // linea + plPlane.vtN = FromUprightOrtho( vtDir) ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + break ; + default : // piana o 3d + plPlane.vtN = vtDir ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + break ; + } + + return bFlat ; +} + //---------------------------------------------------------------------------- bool CurveBezier::GetStartPoint( Point3d& ptStart) const @@ -1201,9 +1247,7 @@ CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) c // se di primo grado, basta inserire gli estremi if ( m_nDeg == 1) { - PL.AddUPoint( 0, m_aPtCtrl[0]) ; - PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ; - return true ; + return ( PL.AddUPoint( 0, m_aPtCtrl[0]) && PL.AddUPoint( 1, m_aPtCtrl[m_nDeg])) ; } // limiti minimi su tolleranza e deviazione angolare @@ -1211,18 +1255,30 @@ CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) c dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ; // inserisco il punto iniziale - PL.AddUPoint( 0, m_aPtCtrl[0]) ; + if ( ! PL.AddUPoint( 0, m_aPtCtrl[0])) + return false ; // verifico se va divisa - FlatOrSplit( 0, *this, 0, 1, dLinTol, dAngTolDeg, PL) ; + if ( ! FlatOrSplit( 0, *this, 0, 1, dLinTol, dAngTolDeg, PL)) + return false ; // se è stato inserito un solo punto, aggiungo il finale if ( PL.GetPointNbr() == 1) - PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ; + return PL.AddUPoint( 1, m_aPtCtrl[m_nDeg]) ; return true ; } +//---------------------------------------------------------------------------- +bool +CurveBezier::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const +{ + // pulisco la polilinea + PA.Clear() ; + + return false ; +} + //---------------------------------------------------------------------------- ICurve* CurveBezier::CopyParamRange( double dUStart, double dUEnd) const diff --git a/CurveBezier.h b/CurveBezier.h index 38e4311..d396dfc 100644 --- a/CurveBezier.h +++ b/CurveBezier.h @@ -56,6 +56,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW virtual bool IsSimple( void) const { return true ; } virtual bool IsClosed( void) const { return ::IsClosed( *this) ; } + virtual bool IsFlat( Plane3d& plPlane, double dToler) const ; virtual bool GetStartPoint( Point3d& ptStart) const ; virtual bool GetEndPoint( Point3d& ptEnd) const ; virtual bool GetMidPoint( Point3d& ptMid) const ; @@ -87,6 +88,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW return ::GetPointDiffGeom( *this, dU, nS, oDiffG) ; } virtual bool IsPointOn( const Point3d& ptP, double dTol = EPS_SMALL) const ; virtual bool ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const ; + virtual bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const ; virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) @@ -159,3 +161,15 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW Point3d m_aStPtCtrl[ST_PTC] ; // array predefinito di 4 punti di controllo double m_aStWeCtrl[ST_PTC] ; // array predefinito di 4 pesi di controllo } ; + +//----------------------------------------------------------------------------- +inline CurveBezier* CreateBasicCurveBezier( void) + { return (static_cast( CreateGeoObj( CRV_BEZ))) ; } +inline CurveBezier* CloneBasicCurveBezier( const IGeoObj* pGObj) + { if ( pGObj == nullptr || pGObj->GetType() != CRV_BEZ) + return nullptr ; + return (static_cast(pGObj->Clone())) ; } +inline const CurveBezier* GetBasicCurveBezier( const IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } +inline CurveBezier* GetBasicCurveBezier( IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } diff --git a/CurveComposite.cpp b/CurveComposite.cpp index 3e587a3..452dfda 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -15,14 +15,14 @@ #include "stdafx.h" #include "CurveComposite.h" #include "DistPointCrvComposite.h" +#include "CurveLine.h" +#include "CurveArc.h" +#include "CurveBezier.h" #include "GeoConst.h" #include "GeoObjFactory.h" #include "NgeWriter.h" #include "NgeReader.h" #include "/EgtDev/Include/EGkStringUtils3d.h" -#include "/EgtDev/Include/EGkCurveLine.h" -#include "/EgtDev/Include/EGkCurveArc.h" -#include "/EgtDev/Include/EGkCurveBezier.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include @@ -325,7 +325,7 @@ CurveComposite::FromPointBulgeVector( const UPNTVECTOR& vUPnt, const Vector3d& v // se retta if ( fabs( vUPnt[i-1].first) < EPS_SMALL) { // creo la retta - PtrOwner pCrvLine( CreateCurveLine()) ; + PtrOwner pCrvLine( CreateBasicCurveLine()) ; if ( ! ::IsValid( pCrvLine)) return false ; // setto la linea @@ -338,7 +338,7 @@ CurveComposite::FromPointBulgeVector( const UPNTVECTOR& vUPnt, const Vector3d& v // altrimenti arco else { // creo l'arco - PtrOwner pCrvArc( CreateCurveArc()) ; + PtrOwner pCrvArc( CreateBasicCurveArc()) ; if ( ! ::IsValid( pCrvArc)) return false ; // setto l'arco @@ -384,7 +384,7 @@ CurveComposite::PolygonCenterCorner( int nSides, const Point3d& ptCen, const Poi return false ; } // creo il segmento di retta - PtrOwner pCrvLine( CreateCurveLine()) ; + PtrOwner pCrvLine( CreateBasicCurveLine()) ; if ( ! ::IsValid( pCrvLine)) return false ; // assegno i punti estremi @@ -473,11 +473,11 @@ bool CurveComposite::CopyFrom( const IGeoObj* pGObjSrc) { // se sorgente è una curva composita - const CurveComposite* pCC = dynamic_cast( pGObjSrc) ; + const CurveComposite* pCC = GetBasicCurveComposite( pGObjSrc) ; if ( pCC != nullptr) return CopyFrom( *pCC) ; // se sorgente è un'altro tipo di curva - const ICurve* pCrv = dynamic_cast( pGObjSrc) ; + const ICurve* pCrv = GetCurve( pGObjSrc) ; if ( pCrv != nullptr) { Clear() ; return AddCurve( *pCrv) ; @@ -716,6 +716,89 @@ CurveComposite::Validate( void) return ( m_nStatus == OK) ; } +//---------------------------------------------------------------------------- +bool +CurveComposite::IsFlat( Plane3d& plPlane, double dToler) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // polilinea dei punti rappresentativi + PolyLine shPL ; + // punto iniziale + Point3d ptP ; + if ( ! GetStartPoint( ptP) || + ! shPL.AddUPoint( 0, ptP)) + return false ; + // ciclo sulle curve semplici (aggiungo solo eventuali punti intermedi e finali) + int nCount = 0 ; + for ( const ICurve* pCrv = GetFirstCurve() ; + pCrv != nullptr ; + pCrv = GetNextCurve(), ++ nCount) { + switch ( pCrv->GetType()) { + case CRV_LINE : + // punto finale + if ( ! pCrv->GetEndPoint( ptP) || + ! shPL.AddUPoint( nCount + 1, ptP)) + return false ; + break ; + case CRV_ARC : + // punto a 1/3 + if ( ! pCrv->GetPointD1D2( 0.3333, ICurve::FROM_MINUS, ptP) || + ! shPL.AddUPoint( nCount + 0.3333, ptP)) + return false ; + // punto a 7/11 + if ( ! pCrv->GetPointD1D2( 0.6363, ICurve::FROM_MINUS, ptP) || + ! shPL.AddUPoint( nCount + 0.6363, ptP)) + return false ; + // punto finale + if ( ! pCrv->GetEndPoint( ptP) || + ! shPL.AddUPoint( nCount + 1, ptP)) + return false ; + break ; + case CRV_BEZ : + { const CurveBezier* pBez = GetBasicCurveBezier( pCrv) ; + // inserisco tutti i punti di controllo tranne il primo + int nLastPC = pBez->GetDegree() ; + for ( int i = 1 ; i <= nLastPC ; ++ i) { + double dU = nCount + i / double( nLastPC) ; + if ( ! shPL.AddUPoint( dU, pBez->GetControlPoint( i))) + return false ; + } + } break ; + } + } + // recupero dati sulla planarità della polilinea + int nRank ; + Point3d ptCen ; + Vector3d vtDir ; + bool bFlat = shPL.IsFlat( nRank, ptCen, vtDir, dToler) ; + // se punto + switch ( nRank) { + case 0 : // punto + if ( bFlat) { + plPlane.vtN = Z_AX ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + } + else { + plPlane.vtN = V_NULL ; + plPlane.dDist = 0 ; + } + break ; + case 1 : // linea + plPlane.vtN = FromUprightOrtho( vtDir) ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + break ; + default : // piana o 3d + plPlane.vtN = vtDir ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + break ; + } + + return bFlat ; +} + //---------------------------------------------------------------------------- bool CurveComposite::GetStartPoint( Point3d& ptStart) const @@ -999,6 +1082,43 @@ CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL return true ; } +//---------------------------------------------------------------------------- +bool +CurveComposite::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const +{ + // pulisco il poliarco + PA.Clear() ; + + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // eseguo approssimazione + bool bFirst = true ; + double dStartPar = 0 ; + PolyArc PASmpl ; + PCRVSMPL_DEQUE::const_iterator Iter ; + for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { + // recupero approssimazione per curva semplice + if ( ! (*Iter)->ApproxWithArcs( dLinTol, dAngTolDeg, PASmpl)) + return false ; + // la accodo opportunamente a quella della curva composita + if ( bFirst) { + PA.Splice( PASmpl) ; + bFirst = false ; + } + else { + PA.EraseLastUPoint() ; + PASmpl.AddOffsetToU( dStartPar) ; + PA.Splice( PASmpl) ; + } + // incremento inizio parametro per prossima curva semplice + dStartPar += 1 ; + } + + return true ; +} + //---------------------------------------------------------------------------- ICurve* CurveComposite::CopyParamRange( double dUStart, double dUEnd) const @@ -1230,10 +1350,11 @@ CurveComposite::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) if ( dUStartTrim < - EPS_PARAM || dUStartTrim > m_nCounter + EPS_PARAM || dUEndTrim < - EPS_PARAM || dUEndTrim > m_nCounter + EPS_PARAM) return false ; +#if 0 // verifico che i trim non cancellino interamente la curva if ( dUStartTrim > dUEndTrim - EPS_PARAM) return false ; -#if 0 +#endif // se il parametro start supera quello di end if ( dUStartTrim > dUEndTrim - EPS_PARAM) { // se curva aperta, il trim la cancella completamente quindi errore @@ -1252,7 +1373,6 @@ CurveComposite::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) } } } -#endif // per parametro start : determino la curva di appartenenza e il valore locale del parametro int nCs ; double dUcs ; @@ -1757,11 +1877,11 @@ CurveComposite::ArcsToBezierCurves( void) for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) { // se arco, devo trasformare in una o più curve di Bezier if ( (*Iter)->GetType() == CRV_ARC) { - const ICurveArc* pArc = GetCurveArc( (*Iter)) ; + const CurveArc* pArc = GetBasicCurveArc( (*Iter)) ; // se angolo al centro sotto il limite, basta una curva if ( fabs( pArc->GetAngCenter()) <= BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL) { // creo la curva di Bezier - PtrOwner pCrvBez( CreateCurveBezier()) ; + PtrOwner pCrvBez( CreateBasicCurveBezier()) ; if ( ! ::IsValid( pCrvBez)) return false ; if ( ! pCrvBez->FromArc( *pArc)) diff --git a/CurveComposite.h b/CurveComposite.h index 7792a56..2d836a4 100644 --- a/CurveComposite.h +++ b/CurveComposite.h @@ -56,6 +56,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW virtual bool IsSimple( void) const { return false ; } virtual bool IsClosed( void) const { return ( m_nStatus == OK && m_bClosed) ; } + virtual bool IsFlat( Plane3d& plPlane, double dToler = EPS_SMALL) const ; virtual bool GetStartPoint( Point3d& ptStart) const ; virtual bool GetEndPoint( Point3d& ptEnd) const ; virtual bool GetMidPoint( Point3d& ptMid) const ; @@ -86,6 +87,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW return ::GetPointDiffGeom( *this, dU, nS, oDiffG) ; } virtual bool IsPointOn( const Point3d& ptP, double dTol = EPS_SMALL) const ; virtual bool ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const ; + virtual bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const ; virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) @@ -154,3 +156,15 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW bool m_bClosed ; // flag per indicare che la curva è chiusa mutable PCRVSMPL_DEQUE::const_iterator m_Iter ; // iteratore } ; + +//----------------------------------------------------------------------------- +inline CurveComposite* CreateBasicCurveComposite( void) + { return (static_cast( CreateGeoObj( CRV_COMPO))) ; } +inline CurveComposite* CloneBasicCurveComposite( const IGeoObj* pGObj) + { if ( pGObj == nullptr || pGObj->GetType() != CRV_COMPO) + return nullptr ; + return (static_cast(pGObj->Clone())) ; } +inline const CurveComposite* GetBasicCurveComposite( const IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } +inline CurveComposite* GetBasicCurveComposite( IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } diff --git a/CurveLine.cpp b/CurveLine.cpp index 94cad60..b450d58 100644 --- a/CurveLine.cpp +++ b/CurveLine.cpp @@ -79,7 +79,7 @@ CurveLine::SetPDL( const Point3d& ptStart, double dDirAngDeg, double dLen) // assegno i dati m_PtStart = ptStart ; Vector3d vtDelta ; - vtDelta.FromPolar( dLen, dDirAngDeg) ; + vtDelta = FromPolar( dLen, dDirAngDeg) ; m_PtEnd = ptStart + vtDelta ; m_nStatus = TO_VERIFY ; @@ -229,6 +229,21 @@ CurveLine::Validate( void) return ( m_nStatus == OK) ; } +//---------------------------------------------------------------------------- +bool +CurveLine::IsFlat( Plane3d& plPlane, double dToler) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + + // assegno dati piano + plPlane.vtN = FromUprightOrtho( m_PtEnd - m_PtStart) ; ; + plPlane.dDist = ( m_PtStart - ORIG) * plPlane.vtN ; + // ritorno conferma + return true ; +} + //---------------------------------------------------------------------------- bool CurveLine::GetStartPoint( Point3d& ptStart) const @@ -422,6 +437,21 @@ CurveLine::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) con return true ; } +//---------------------------------------------------------------------------- +bool +CurveLine::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const +{ + // pulisco la polilinea + PA.Clear() ; + + // la curva deve essere validata + if ( m_nStatus != OK) + return false ; + + // inserisco gli estremi + return ( PA.AddUPoint( 0, m_PtStart, 0) && PA.AddUPoint( 1, m_PtEnd, 0)) ; +} + //---------------------------------------------------------------------------- ICurve* CurveLine::CopyParamRange( double dUStart, double dUEnd) const diff --git a/CurveLine.h b/CurveLine.h index cffb147..b3f617a 100644 --- a/CurveLine.h +++ b/CurveLine.h @@ -55,6 +55,7 @@ class CurveLine : public ICurveLine, public IGeoObjRW { return true ; } virtual bool IsClosed( void) const { return ::IsClosed( *this) ; } + virtual bool IsFlat( Plane3d& plPlane, double dToler) const ; virtual bool GetStartPoint( Point3d& ptStart) const ; virtual bool GetEndPoint( Point3d& ptEnd) const ; virtual bool GetMidPoint( Point3d& ptMid) const ; @@ -85,6 +86,7 @@ class CurveLine : public ICurveLine, public IGeoObjRW return ::GetPointDiffGeom( *this, dU, nS, oDiffG) ; } virtual bool IsPointOn( const Point3d& ptP, double dTol = EPS_SMALL) const ; virtual bool ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const ; + virtual bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const ; virtual ICurve* CopyParamRange( double dUStart, double dUEnd) const ; virtual bool Invert( void) ; virtual bool Offset( double dDist, int nSide, int nType = OFF_FILLET) ; @@ -132,3 +134,15 @@ class CurveLine : public ICurveLine, public IGeoObjRW Point3d m_PtStart ; // punto iniziale Point3d m_PtEnd ; // punto finale } ; + +//----------------------------------------------------------------------------- +inline CurveLine* CreateBasicCurveLine( void) + { return (static_cast( CreateGeoObj( CRV_LINE))) ; } +inline CurveLine* CloneBasicCurveLine( const IGeoObj* pGObj) + { if ( pGObj == nullptr || pGObj->GetType() != CRV_LINE) + return nullptr ; + return (static_cast(pGObj->Clone())) ; } +inline const CurveLine* GetBasicCurveLine( const IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } +inline CurveLine* GetBasicCurveLine( IGeoObj* pGObj) + { return (dynamic_cast(pGObj)) ; } diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 1c8ffb6..9b33d94 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index f9d7312..e6ab123 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -277,6 +277,9 @@ copy $(TargetPath) \EgtProg\Dll64 + + + @@ -330,6 +333,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -388,6 +392,8 @@ copy $(TargetPath) \EgtProg\Dll64 + + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 53b917f..330684e 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -216,6 +216,15 @@ File di origine\GeoCreate + + File di origine\Base + + + File di origine\Base + + + File di origine\Base + @@ -524,6 +533,15 @@ File di intestazione + + File di intestazione + + + File di intestazione + + + File di intestazione + diff --git a/ExtText.cpp b/ExtText.cpp index 6130164..e8b28c8 100644 --- a/ExtText.cpp +++ b/ExtText.cpp @@ -48,7 +48,7 @@ ExtText::Set( const string& sText, const Point3d& ptP, double dAngDeg, double dH // assegno i dati m_ptP = ptP ; m_vtN = Z_AX ; - m_vtD.FromPolar( 1, dAngDeg) ; + m_vtD = FromPolar( 1, dAngDeg) ; m_sText = sText ; m_sFont.clear() ; m_nWeight = 400 ; @@ -79,7 +79,7 @@ ExtText::Set( const string& sText, const Point3d& ptP, double dAngDeg, // assegno i dati m_ptP = ptP ; m_vtN = Z_AX ; - m_vtD.FromPolar( 1, dAngDeg) ; + m_vtD = FromPolar( 1, dAngDeg) ; m_sText = sText ; m_sFont = sFont ; m_nWeight = nW ; @@ -802,8 +802,8 @@ ExtText::Mir( bool bOnLen) case ETXT_IPBR : m_nInsPos = ETXT_IPBL ; break ; } // inverto i versori - m_vtN *= - 1 ; - m_vtD *= - 1 ; + m_vtN.Invert() ; + m_vtD.Invert() ; } // altrimenti auto-mirror su altezza del testo else { @@ -817,7 +817,7 @@ ExtText::Mir( bool bOnLen) case ETXT_IPBR : m_nInsPos = ETXT_IPTR ; break ; } // inverto il versore normale - m_vtN *= - 1 ; + m_vtN.Invert() ; } return true ; diff --git a/Frame3d.cpp b/Frame3d.cpp index 5628db8..abd1b90 100644 --- a/Frame3d.cpp +++ b/Frame3d.cpp @@ -102,7 +102,7 @@ Frame3d::Set( const Point3d& ptOrig, const Vector3d& vtDirZ) m_vtVersX = Z_AX ^ m_vtVersZ ; if ( ! m_vtVersX.Normalize()) return false ; - // verzsore Y + // versore Y m_vtVersY = m_vtVersZ ^ m_vtVersX ; if ( ! m_vtVersY.Normalize()) return false ; @@ -526,7 +526,7 @@ Frame3d::GetRotationsCAC1( double& dAngCDeg, double& dAngADeg, double& dAngC1Deg m_vtVersX.ToSpherical( nullptr, nullptr, &dAngCDeg) ; // calcolo l'asse X senza la rotazione attorno a C' - vtXnoC1.FromPolar( 1, dAngCDeg) ; + vtXnoC1 = FromPolar( 1, dAngCDeg) ; // calcolo la rotazione attorno a C' if ( ! vtXnoC1.GetRotation( m_vtVersX, m_vtVersZ, dAngC1Deg, bDet) || ! bDet) diff --git a/GdbExecutor.cpp b/GdbExecutor.cpp index a6f145e..1851c2e 100644 --- a/GdbExecutor.cpp +++ b/GdbExecutor.cpp @@ -383,8 +383,7 @@ GdbExecutor::VectorFromSpherical( const STRVECTOR& vsParams) IGeoVector3d* pGVect = CreateGeoVector3d() ; if ( pGVect == nullptr) return false ; - Vector3d vtV ; - vtV.FromSpherical( dLen, dAngVertDeg, dAngOrizzDeg) ; + Vector3d vtV = FromSpherical( dLen, dAngVertDeg, dAngOrizzDeg) ; pGVect->Set( vtV) ; return AddGeoObj( vsParams[0], vsParams[1], pGVect) ; } @@ -2461,8 +2460,7 @@ GdbExecutor::GetPolylineFromCurve( int nId, const Frame3d& frDest, double dLinTo if ( ! IsValid( pModCrv)) return false ; // eseguo la trasformazione - pModCrv->ToGlob( frCrv) ; - pModCrv->ToLoc( frDest) ; + pModCrv->LocToLoc( frCrv, frDest) ; // ricavo l'approssimazione if ( ! pModCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, PL)) return false ; diff --git a/IntersCrvCompoCrvCompo.cpp b/IntersCrvCompoCrvCompo.cpp index 54f0367..6c0d787 100644 --- a/IntersCrvCompoCrvCompo.cpp +++ b/IntersCrvCompoCrvCompo.cpp @@ -655,14 +655,14 @@ CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nSideA, ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) - vtADir *= - 1 ; + vtADir.Invert() ; // direzioni di arrivo (prev) e partenza (next) curva B Vector3d vtBpDir ; double dUBp = dUB ; if ( ! MoveParamToAvoidTg( dUBp, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUBp, ICurve::FROM_MINUS, ptP, vtBpDir)) return false ; - vtBpDir *= - 1 ; + vtBpDir.Invert() ; Vector3d vtBnDir ; double dUBn = dUB ; if ( ! MoveParamToAvoidTg( dUBn, ICurve::FROM_PLUS, CurveB) || @@ -702,14 +702,14 @@ CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) - vtADir *= - 1 ; + vtADir.Invert() ; // direzioni di arrivo (prev) e partenza (next) curva B (P1) Vector3d vtB1pDir ; double dUB1p = dUB1 ; if ( ! MoveParamToAvoidTg( dUB1p, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUB1p, ICurve::FROM_MINUS, ptP, vtB1pDir)) return false ; - vtB1pDir *= - 1 ; + vtB1pDir.Invert() ; Vector3d vtB1nDir ; double dUB1n = dUB1 ; if ( ! MoveParamToAvoidTg( dUB1n, ICurve::FROM_PLUS, CurveB) || @@ -721,7 +721,7 @@ CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, if ( ! MoveParamToAvoidTg( dUB2p, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUB2p, ICurve::FROM_MINUS, ptP, vtB2pDir)) return false ; - vtB2pDir *= - 1 ; + vtB2pDir.Invert() ; Vector3d vtB2nDir ; double dUB2n = dUB2 ; if ( ! MoveParamToAvoidTg( dUB2n, ICurve::FROM_PLUS, CurveB) || diff --git a/PointsPCA.cpp b/PointsPCA.cpp new file mode 100644 index 0000000..3905796 --- /dev/null +++ b/PointsPCA.cpp @@ -0,0 +1,164 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : PointsPCA.cpp Data : 12.08.14 Versione : 1.5h3 +// Contenuto : Implementazione della classe PointsPCA, +// Principal Components Analysis di un insieme di punti. +// +// +// Modifiche : 12.08.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "PointsPCA.h" + + +//---------------------------------------------------------------------------- +PointsPCA::PointsPCA( void) +{ + // azzero numero punti + m_nPntNbr = 0 ; + // azzero il baricentro + m_ptCen.Set( 0, 0, 0) ; + // azzero matrice di covarianza + m_CovMat.setZero() ; + // inizializzo il rank ad un valore assurdo + m_nRank = - 1 ; +} + +//---------------------------------------------------------------------------- +void +PointsPCA::AddPoint( const Point3d& ptP) +{ + // incremento numero punti + ++ m_nPntNbr ; + // aggiorno il baricentro + m_ptCen += ptP ; + // aggiorno la matrice di covarianza (solo triangolo superiore perchè simmetrica) + m_CovMat(0,0) += ptP.x * ptP.x ; + m_CovMat(1,1) += ptP.y * ptP.y ; + m_CovMat(2,2) += ptP.z * ptP.z ; + m_CovMat(0,1) += ptP.x * ptP.y ; + m_CovMat(0,2) += ptP.x * ptP.z ; + m_CovMat(1,2) += ptP.y * ptP.z ; +} + +//---------------------------------------------------------------------------- +bool +PointsPCA::Finalize( void) +{ + // se già eseguito il calcolo finale, esco + if ( m_nRank >= 0) + return true ; + + // il rank viene annullato ( non sono ancora note direzioni principali) + m_nRank = 0 ; + + // se non sono stati assegnati punti, esco + if ( m_nPntNbr == 0) + return false ; + + // fattore di scala per numero di punti + double dScale = 1 / double( m_nPntNbr) ; + + // calcolo del baricentro + m_ptCen *= dScale ; + + // completo la matrice di covarianza + m_CovMat(0,0) = m_CovMat(0,0) * dScale - m_ptCen.x * m_ptCen.x ; + m_CovMat(1,1) = m_CovMat(1,1) * dScale - m_ptCen.y * m_ptCen.y ; + m_CovMat(2,2) = m_CovMat(2,2) * dScale - m_ptCen.z * m_ptCen.z ; + m_CovMat(0,1) = m_CovMat(0,1) * dScale - m_ptCen.x * m_ptCen.y ; + m_CovMat(0,2) = m_CovMat(0,2) * dScale - m_ptCen.x * m_ptCen.z ; + m_CovMat(1,2) = m_CovMat(1,2) * dScale - m_ptCen.y * m_ptCen.z ; + m_CovMat(1,0) = m_CovMat(0,1) ; + m_CovMat(2,0) = m_CovMat(0,2) ; + m_CovMat(2,1) = m_CovMat(1,2) ; + + // calcolo gli autovalori e autovettori (essendo matrice 3x3 uso metodo diretto) + Eigen::SelfAdjointEigenSolver es ; + es.compute( m_CovMat) ; // non usare computeDirect : errore nell'ordine degli autovettori + if ( es.info() == Eigen::NoConvergence) + return false ; + + // recupero gli autovettori corrispondenti agli autovalori non nulli + for ( int i = 0 ; i < 3 ; ++ i) { + int j = ( i + 1) % 3 ; + int k = ( i + 2) % 3 ; + // se l'autovalore corrente è il più grande in modulo + if ( fabs( es.eigenvalues()(i)) >= fabs( es.eigenvalues()(j)) && + fabs( es.eigenvalues()(i)) >= fabs( es.eigenvalues()(k)) && + fabs( es.eigenvalues()(i)) > EPS_SMALL * EPS_SMALL) { + // il suo autovettore è il primo + ++ m_nRank ; + m_vtPC[0].Set( es.eigenvectors()(0,i), es.eigenvectors()(1,i), es.eigenvectors()(2,i)) ; + // se il successivo autovalore è maggiore del rimanente in modulo + if ( fabs( es.eigenvalues()(j)) >= fabs(es.eigenvalues()(k)) && + fabs( es.eigenvalues()(j)) > EPS_SMALL * EPS_SMALL) { + // il suo autovettore è il secondo + ++ m_nRank ; + m_vtPC[1].Set( es.eigenvectors()(0,j), es.eigenvectors()(1,j), es.eigenvectors()(2,j)) ; + // se il rimanente autovalore è non nullo + if ( fabs( es.eigenvalues()(k)) > EPS_SMALL * EPS_SMALL) { + // il suo autovettore è il terzo + ++ m_nRank ; + m_vtPC[2].Set( es.eigenvectors()(0,k), es.eigenvectors()(1,k), es.eigenvectors()(2,k)) ; + } + } + // altrimenti, se il rimanente autovalore è maggiore del successivo in modulo + else if ( fabs( es.eigenvalues()(k)) >= fabs( es.eigenvalues()(j)) && + fabs( es.eigenvalues()(k)) > EPS_SMALL * EPS_SMALL) { + // il suo autovettore è il secondo + ++ m_nRank ; + m_vtPC[1].Set( es.eigenvectors()(0,k), es.eigenvectors()(1,k), es.eigenvectors()(2,k)) ; + // se il rimanente autovalore è non nullo + if ( fabs( es.eigenvalues()(j)) > EPS_SMALL * EPS_SMALL) { + // il suo autovettore è il terzo + ++ m_nRank ; + m_vtPC[2].Set( es.eigenvectors()(0,j), es.eigenvectors()(1,j), es.eigenvectors()(2,j)) ; + } + } + break ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +int +PointsPCA::GetRank( void) +{ + // verifico completamento conti + Finalize() ; + + return m_nRank ; +} + +//---------------------------------------------------------------------------- +bool +PointsPCA::GetCenter( Point3d& ptCen) +{ + // verifico completamento conti + Finalize() ; + // assegno i dati + ptCen = m_ptCen ; + return ( m_nPntNbr > 0) ; +} + +//---------------------------------------------------------------------------- +bool +PointsPCA::GetPrincipalComponent( int nId, Vector3d& vtPC) +{ + // verifico completamento conti + Finalize() ; + // verifico esistenza componente (indice 0-based) + if ( nId < 0 || nId >= m_nRank) + return false ; + // assegno dati + vtPC = m_vtPC[nId] ; + return true ; +} diff --git a/PointsPCA.h b/PointsPCA.h new file mode 100644 index 0000000..a2d8770 --- /dev/null +++ b/PointsPCA.h @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : PointsPCA.h Data : 12.08.14 Versione : 1.5h3 +// Contenuto : Dichiarazione della classe PointsPCA. +// +// +// +// Modifiche : 12.08.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkFrame3d.h" +#include "/EgtDev/Include/EGkPlane3d.h" +#include "/EgtDev/Extern/Eigen/Dense" + +//---------------------------------------------------------------------------- +class PointsPCA +{ + public : + PointsPCA( void) ; + void AddPoint( const Point3d& ptP) ; + int GetRank( void) ; + bool GetCenter( Point3d& ptCen) ; + bool GetPrincipalComponent( int nId, Vector3d& vtPC) ; + + private : + bool Finalize( void) ; + + private : + static const int MAX_RANK = 3 ; + + private : + int m_nPntNbr ; // numero punti + Point3d m_ptCen ; // baricentro + Eigen::Matrix3d m_CovMat ; // matrice di covarianza + int m_nRank ; // numero delle componenti principali (MAX_RANK = 3) + Vector3d m_vtPC[MAX_RANK] ; // direzioni delle componenti principali +} ; \ No newline at end of file diff --git a/PolyArc.cpp b/PolyArc.cpp new file mode 100644 index 0000000..4111594 --- /dev/null +++ b/PolyArc.cpp @@ -0,0 +1,176 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : PolyArc.cpp Data : 14.08.14 Versione : 1.5h3 +// Contenuto : Implementazione della classe PolyArc. +// +// +// +// Modifiche : 14.08.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "\EgtDev\Include\EGkPolyArc.h" + + +//---------------------------------------------------------------------------- +PolyArc::PolyArc( void) +{ + m_nCount = 0 ; + m_iter = m_lUPointBs.end() ; +} + +//---------------------------------------------------------------------------- +PolyArc::~PolyArc( void) +{ +} + +//---------------------------------------------------------------------------- +bool +PolyArc::Clear( void) +{ + m_nCount = 0 ; + m_lUPointBs.clear() ; + m_iter = m_lUPointBs.end() ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::AddUPoint( double dPar, const Point3d& ptP, double dBulge) +{ + try { + m_lUPointBs.push_back( UPointB( dPar, ptP, dBulge)) ; + } + catch (...) { + return false ; + } + + m_nCount ++ ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::EraseFirstUPoint( void) +{ + if ( m_lUPointBs.empty()) + return false ; + + m_lUPointBs.pop_front() ; + m_nCount -- ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::EraseLastUPoint( void) +{ + if ( m_lUPointBs.empty()) + return false ; + + m_lUPointBs.pop_back() ; + m_nCount -- ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::AddOffsetToU( double dOffset) +{ + UPNTBLIST::iterator iter ; + for ( iter = m_lUPointBs.begin() ; iter != m_lUPointBs.end() ; ++ iter) + iter->dU += dOffset ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::ToGlob( const Frame3d& frRef) +{ + UPNTBLIST::iterator iter ; + for ( iter = m_lUPointBs.begin() ; iter != m_lUPointBs.end() ; ++ iter) + iter->ptP.ToGlob( frRef) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::ToLoc( const Frame3d& frRef) +{ + UPNTBLIST::iterator iter ; + for ( iter = m_lUPointBs.begin() ; iter != m_lUPointBs.end() ; ++ iter) + iter->ptP.ToLoc( frRef) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) +{ + UPNTBLIST::iterator iter ; + for ( iter = m_lUPointBs.begin() ; iter != m_lUPointBs.end() ; ++ iter) + iter->ptP.LocToLoc( frOri, frDest) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::Splice( PolyArc& PA) +{ + m_lUPointBs.splice( m_lUPointBs.end(), PA.m_lUPointBs) ; + m_nCount += PA.GetPointNbr() ; + PA.m_nCount = 0 ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::GetFirstUPoint( double* pdPar, Point3d* pptP, double* pdBulge) const +{ + m_iter = m_lUPointBs.begin() ; + if ( m_iter == m_lUPointBs.end()) + return false ; + + if ( pdPar != nullptr) + *pdPar = m_iter->dU ; + if ( pptP != nullptr) + *pptP = m_iter->ptP ; + if ( pdBulge != nullptr) + *pdBulge = m_iter->dB ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolyArc::GetNextUPoint( double* pdPar, Point3d* pptP, double* pdBulge, bool bNotLast) const +{ + if ( m_iter == m_lUPointBs.end()) + return false ; + ++ m_iter ; + if ( m_iter == m_lUPointBs.end()) + return false ; + if ( bNotLast && m_iter == -- ( m_lUPointBs.end())) + return false ; + + if ( pdPar != nullptr) + *pdPar = m_iter->dU ; + if ( pptP != nullptr) + *pptP = m_iter->ptP ; + if ( pdBulge != nullptr) + *pdBulge = m_iter->dB ; + + return true ; +} diff --git a/PolyLine.cpp b/PolyLine.cpp index 843ef1e..4d4017c 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -14,6 +14,8 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "DistPointLine.h" +#include "PolygonPlane.h" +#include "PointsPCA.h" #include "\EgtDev\Include\EGkPolyLine.h" #include "\EgtDev\Include\EGkPlane3d.h" @@ -379,57 +381,70 @@ PolyLine::GetPrevULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* //---------------------------------------------------------------------------- bool -PolyLine::NewellPlane( Plane3d& plPlane, double& dArea) const +PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) const { - // Compute normal as being proportional to projected areas of polygon onto the yz, - // xz, and xy planes. Also compute centroid as representative point on the plane - Vector3d vtN ; - Point3d ptCen ; - int nNumSide = 0 ; - Point3d ptIni, ptFin ; - for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { - vtN.x += ( ptIni.y - ptFin.y) * ( ptIni.z + ptFin.z) ; // projection on yz - vtN.y += ( ptIni.z - ptFin.z) * ( ptIni.x + ptFin.x) ; // projection on xz - vtN.z += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy - ptCen += ptFin ; - ++ nNumSide ; + // cerco le componenti principali (tramite PCA) + Point3d ptP ; + PointsPCA ptsPCA ; + for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) + ptsPCA.AddPoint( ptP) ; + // recupero il rango, ovvero la dimensionalità dell'insieme di punti + nRank = ptsPCA.GetRank() ; + // se dimensione nulla, o non ci sono punti o sono tutti praticamente coincidenti + if ( nRank == 0) + return ptsPCA.GetCenter( ptCen) ; + // se dimensione 1, allora i punti sono distribuiti su una linea + if ( nRank == 1) { + // assegno il centro e la direzione della linea (il verso è indifferente) + ptsPCA.GetCenter( ptCen) ; + ptsPCA.GetPrincipalComponent( 0, vtDir) ; + return true ; } - // If open and existent, add segment from last to first points - if ( ! IsClosed() && nNumSide > 0) { - ptIni = ptFin ; - GetFirstPoint( ptFin) ; - vtN.x += ( ptIni.y - ptFin.y) * ( ptIni.z + ptFin.z) ; // projection on yz - vtN.y += ( ptIni.z - ptFin.z) * ( ptIni.x + ptFin.x) ; // projection on xz - vtN.z += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy - ptCen += ptFin ; - ++ nNumSide ; + // altrimenti dimensione 2 o 3, allora è determinato un piano principale, verifico se tutti i punti vi giacciono + // Center and normal vector + ptsPCA.GetCenter( ptCen) ; + Vector3d vtX, vtY ; + ptsPCA.GetPrincipalComponent( 0, vtX) ; + ptsPCA.GetPrincipalComponent( 1, vtY) ; + vtDir = vtX ^ vtY ; + if ( ! vtDir.Normalize()) { + // riduco la dimensionalità a lineare + nRank = 1 ; + // assegno il centro e la direzione della linea (il verso è indifferente) + ptsPCA.GetCenter( ptCen) ; + vtDir = vtX ; + return true ; + } + if ( vtDir.z < 0) + vtDir.Invert() ; + // Plane calculation + Plane3d plPlane ; + plPlane.vtN = vtDir ; + plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; + // Test each vertex to see if it is farther from plane than allowed max distance + for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { + double dDist = ( ( ptP - ORIG) * plPlane.vtN) - plPlane.dDist ; + if ( fabs( dDist) > dToler) + return false ; } - // At least 3 sides - if ( nNumSide < 3) - return false ; - // Normal must be normalizable (the length of the normal is the double of the area of the polygon) - double dLenN = vtN.Len() ; - if ( dLenN < EPS_SMALL) - return false ; - vtN /= dLenN ; - // Fill in the plane equation fields - plPlane.vtN = vtN ; - plPlane.dDist = ( ( ptCen - ORIG) * plPlane.vtN) / nNumSide ; // “centroid / n” is the true centroid point - // Set area - dArea = 0.5 * dLenN ; - return true ; } //---------------------------------------------------------------------------- bool -PolyLine::IsFlat( Plane3d& plPlane, double& dArea, double dToler) const +PolyLine::IsClosedAndFlat( Plane3d& plPlane, double& dArea, double dToler) const { + // Test if closed + if ( ! IsClosed()) + return false ; // Compute a representative plane for the polygon - if ( ! NewellPlane( plPlane, dArea)) + Point3d ptP ; + PolygonPlane PolyPlane ; + for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) + PolyPlane.AddPoint( ptP) ; + if ( ! PolyPlane.GetPlane( plPlane) || ! PolyPlane.GetArea( dArea)) return false ; // Test each vertex to see if it is farther from plane than allowed max distance - Point3d ptP ; for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { double dDist = ( ( ptP - ORIG) * plPlane.vtN) - plPlane.dDist ; if ( fabs( dDist) > dToler) diff --git a/PolygonPlane.cpp b/PolygonPlane.cpp new file mode 100644 index 0000000..f52549c --- /dev/null +++ b/PolygonPlane.cpp @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : PolygonPlane.cpp Data : 12.08.14 Versione : 1.5h3 +// Contenuto : Implementazione della classe PolygonPlane. +// Calcolo della normale e delle aree con il metodo di Newell. +// +// +// Modifiche : 12.08.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "PolygonPlane.h" + + +//---------------------------------------------------------------------------- +void +PolygonPlane::AddPoint( const Point3d& ptP) +{ + // se è il primo punto (parto da -1 perchè verrà contato alla chiusura) + if ( m_nPntNbr == -1) + m_ptFirst = ptP ; + // dal secondo punto posso cominciare ad eseguire le somme parziali + else { + // Compute normal as being proportional to projected areas of polygon onto the yz, + // xz, and xy planes. Also compute centroid as representative point on the plane + m_vtN.x += ( m_ptLast.y - ptP.y) * ( m_ptLast.z + ptP.z) ; // projection on yz + m_vtN.y += ( m_ptLast.z - ptP.z) * ( m_ptLast.x + ptP.x) ; // projection on xz + m_vtN.z += ( m_ptLast.x - ptP.x) * ( m_ptLast.y + ptP.y) ; // projection on xy + m_ptCen += ptP ; + } + // salvo punto e incremento numero di punti + m_ptLast = ptP ; + ++ m_nPntNbr ; +} + +//---------------------------------------------------------------------------- +bool +PolygonPlane::Finalize( void) +{ + // almeno 3 punti (il triangolo è il poligono con minimo numero di lati) + if ( m_nPntNbr < 3) + return false ; + // se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato + if ( ! AreSamePointApprox( m_ptFirst, m_ptLast)) { + // aggiungo il primo punto per far eseguire i conti sul lato di chiusura + AddPoint( m_ptFirst) ; + } + // se non effettuato, eseguo il calcolo finale + if ( m_dLenN < EPS_SMALL) { + // lunghezza della normale (doppio dell'area del poligono) + m_dLenN = m_vtN.Len() ; + if ( m_dLenN < EPS_SMALL) + return false ; + // normalizzo + m_vtN /= m_dLenN ; + // sistemo baricentro + m_ptCen /= m_nPntNbr ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolygonPlane::GetPlane( Plane3d& plPlane) +{ + // verifico completamento conti + if ( ! Finalize()) + return false ; + // assegno i dati al piano + plPlane.vtN = m_vtN ; + plPlane.dDist = ( ( m_ptCen - ORIG) * plPlane.vtN) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +PolygonPlane::GetArea( double& dArea) +{ + // verifico completamento conti + if ( ! Finalize()) + return false ; + // assegno l'area + dArea = 0.5 * m_dLenN ; + return true ; +} diff --git a/PolygonPlane.h b/PolygonPlane.h new file mode 100644 index 0000000..39e06e3 --- /dev/null +++ b/PolygonPlane.h @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------------- +// EgalTech 2014-2014 +//---------------------------------------------------------------------------- +// File : PolygonPlane.h Data : 12.08.14 Versione : 1.5h3 +// Contenuto : Dichiarazione della classe PolygonPlane. +// +// +// +// Modifiche : 12.08.14 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkPlane3d.h" + + +//---------------------------------------------------------------------------- +class PolygonPlane +{ + public : + PolygonPlane( void) : m_nPntNbr( -1), m_dLenN( 0) {} + void AddPoint( const Point3d& ptP) ; + bool GetPlane( Plane3d& plPlane) ; + bool GetArea( double& dArea) ; + + private : + bool Finalize( void) ; + + private : + int m_nPntNbr ; // numero punti aggiunti + double m_dLenN ; // lunghezza della normale + Point3d m_ptFirst ; // primo punto aggiunto + Point3d m_ptLast ; // ultimo punto aggiunto + Vector3d m_vtN ; // versore normale + Point3d m_ptCen ; // baricentro +} ; \ No newline at end of file diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 5f797f6..5b99d7f 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -1752,7 +1752,7 @@ SurfTriMesh::InvertTriangle( int nT) // scambio delle conseguenti due adiacenze swap( m_vTria[nT].nIdAdjac[0], m_vTria[nT].nIdAdjac[2]) ; // inversione della normale - m_vTria[nT].vtN *= - 1 ; + m_vTria[nT].vtN.Invert() ; return true ; } diff --git a/Triangulate.cpp b/Triangulate.cpp index 517ae70..ac5851f 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -27,13 +27,10 @@ using namespace std ; bool Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr) { - // verifico che la polilinea sia chiusa -> poligono - if ( ! PL.IsClosed()) - return false ; - // calcolo il piano medio del poligono + // verific che la polilinea sia chiusa e calcolo il piano medio del poligono double dArea ; Plane3d plPlane ; - if ( ! PL.IsFlat( plPlane, dArea, 50 * EPS_SMALL)) + if ( ! PL.IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) return false ; bool bCCW ; if ( fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.x) && diff --git a/Vector3d.cpp b/Vector3d.cpp index 75ac417..ac43e9a 100644 --- a/Vector3d.cpp +++ b/Vector3d.cpp @@ -13,7 +13,6 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "\EgtDev\Include\EGkGeoConst.h" #include "\EgtDev\Include\EGkVector3d.h" #include "\EgtDev\Include\EGKFrame3d.h" @@ -21,27 +20,49 @@ //---------------------------------------------------------------------------- // Definizione a partire da coordinate sferiche //---------------------------------------------------------------------------- -void -Vector3d::FromSpherical( double dLen, double dAngVertDeg, double dAngOrizzDeg) +Vector3d +FromSpherical( double dLen, double dAngVertDeg, double dAngOrizzDeg) { double dAngVertRad = dAngVertDeg * DEGTORAD ; double dAngOrizzRad = dAngOrizzDeg * DEGTORAD ; double dSinAngVert = sin( dAngVertRad) ; - x = dLen * dSinAngVert * cos( dAngOrizzRad) ; - y = dLen * dSinAngVert * sin( dAngOrizzRad) ; - z = dLen * cos( dAngVertRad) ; + Vector3d vtV( dLen * dSinAngVert * cos( dAngOrizzRad), + dLen * dSinAngVert * sin( dAngOrizzRad), + dLen * cos( dAngVertRad)) ; + return vtV ; } //---------------------------------------------------------------------------- -// Definizione a partire da coordinate polari +// Definizione a partire da coordinate polari ( nel piano XY, Z = 0) //---------------------------------------------------------------------------- -void -Vector3d::FromPolar( double dLen, double dAngDeg) +Vector3d +FromPolar( double dLen, double dAngDeg) { double dAngRad = dAngDeg * DEGTORAD ; - x = dLen * cos( dAngRad) ; - y = dLen * sin( dAngRad) ; - z = 0 ; + Vector3d vtV( dLen * cos( dAngRad), + dLen * sin( dAngRad), + 0) ; + return vtV ; +} + +//---------------------------------------------------------------------------- +// Definizione dal più verticale dei vettori ortogonali a quello ricevuto +//---------------------------------------------------------------------------- +Vector3d +FromUprightOrtho( const Vector3d& vtV) +{ + // se vettore nullo, imposto asse Z+ + if ( vtV.IsZero()) + return Z_AX ; + // se vettore coincidente con asse Z, imposto asse X+ + if ( vtV.IsZplus() || vtV.IsZminus()) + return X_AX ; + // caso generico + Vector3d vtAx = vtV ; + vtAx.z = 0 ; + vtAx.Normalize( EPS_ZERO) ; + vtAx.Rotate( Z_AX, 0, 1) ; + return ( vtV ^ vtAx) ; } //----------------------------------------------------------------------------