//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : CurveArc.cpp Data : 22.11.13 Versione : 1.3a1 // Contenuto : Implementazione della classe Arco di Circonferenza. // // // // Modifiche : 16.04.13 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveArc.h" #include "GeoConst.h" #include "GeoObjFactory.h" #include "NgeWriter.h" #include "NgeReader.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( CRV_ARC, NGE_C_ARC, CurveArc) ; //---------------------------------------------------------------------------- class ArcApproxer { public : ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc) ; bool GetPoint( double& dU, Point3d& ptP) ; private : Point3d m_PtCen ; Vector3d m_VtN ; double m_dRad ; double m_dDeltaN ; Vector3d m_vtA1 ; Vector3d m_vtA2 ; double m_dCosA ; double m_dSinA ; int m_nTotPnt ; int m_nCurrPnt ; bool m_bInside ; } ; //---------------------------------------------------------------------------- CurveArc::CurveArc( void) : m_nStatus( TO_VERIFY), m_PtCen(), m_VtN(), m_VtS(), m_dRad( 0), m_dAngCenDeg( 0), m_dDeltaN( 0) { } //---------------------------------------------------------------------------- CurveArc::~CurveArc( void) { } //---------------------------------------------------------------------------- // Set generico, richiede tutti i parametri //---------------------------------------------------------------------------- bool CurveArc::Set( const Point3d& ptCen, const Vector3d& vtN, double dRad, const Vector3d& vtS, double dAngCenDeg, double dDeltaN) { // assegno i dati m_PtCen = ptCen ; m_VtN = vtN ; m_VtS = vtS ; m_dRad = dRad ; m_dAngCenDeg = dAngCenDeg ; m_dDeltaN = dDeltaN ; m_nStatus = TO_VERIFY ; // sistemo i versori m_VtN.Normalize() ; m_VtS.Normalize() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonf. definito dagli estremi, versore normale e bulge //---------------------------------------------------------------------------- bool CurveArc::Set( const Point3d& ptIni, const Point3d& ptFin, const Vector3d& vtN, double dBulge) { // versore normale m_VtN = vtN ; if ( ! m_VtN.Normalize()) return false ; // vettore da inizio a fine Vector3d vtDiff = ptFin - ptIni ; if ( vtDiff.IsSmall()) return false ; // deltaN eventuale ( è componente parallela a VtN) m_dDeltaN = vtDiff * m_VtN ; if ( fabs( m_dDeltaN) > EPS_SMALL) vtDiff -= m_dDeltaN * m_VtN ; else m_dDeltaN = 0 ; // verifico sia un arco (uso la lunghezza della saetta) double dDist = vtDiff.Len() ; if ( fabs( dBulge * 0.5 * dDist) < EPS_SMALL) return false ; // calcolo del centro Vector3d vtOrtho = vtDiff ; // ruoto di +90 deg attorno a vtN (la moltiplica successiva tiene conto del segno di bulge) vtOrtho.Rotate( m_VtN, 0, 1) ; vtOrtho *= ( 1 - dBulge * dBulge) / ( 4 * dBulge) ; m_PtCen = ptIni + 0.5 * vtDiff + vtOrtho ; // calcolo il raggio m_dRad = fabs( dDist * ( 1 + dBulge * dBulge) / ( 4 * dBulge)) ; // calcolo il versore iniziale m_VtS = ptIni - m_PtCen ; m_VtS.Normalize() ; // calcolo l'angolo al centro m_dAngCenDeg = 4 * atan( dBulge) * RADTODEG ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY //---------------------------------------------------------------------------- bool CurveArc::Set( const Point3d& ptCen, double dRad, double dAngIniDeg, double dAngCenDeg, double dDeltaZ) { // assegno e calcolo i dati m_PtCen = ptCen ; m_VtN = Z_AX ; m_VtS.FromPolar( 1, dAngIniDeg) ; m_dRad = dRad ; m_dAngCenDeg = dAngCenDeg ; m_dDeltaN = dDeltaZ ; m_nStatus = TO_VERIFY ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per circonferenza completa //---------------------------------------------------------------------------- bool CurveArc::Set( const Point3d& ptCen, const Vector3d& vtN, double dRad) { // assegno e calcolo i dati m_PtCen = ptCen ; m_VtN = vtN ; Frame3d frF ; if ( ! frF.Set( ORIG, vtN)) return false ; m_VtS = frF.VersX() ; m_dRad = dRad ; m_dAngCenDeg = 360 ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per circonferenza completa nel piano XY //---------------------------------------------------------------------------- bool CurveArc::Set( const Point3d& ptCen, double dRad) { // assegno e calcolo i dati m_PtCen = ptCen ; m_VtN = Z_AX ; m_VtS = X_AX ; m_dRad = dRad ; m_dAngCenDeg = 360 ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- CurveArc* CurveArc::Clone( void) const { // alloco oggetto CurveArc* pCrv = new(nothrow) CurveArc ; if ( pCrv != nullptr) { if ( ! pCrv->Copy( *this)) { delete pCrv ; return nullptr ; } } return pCrv ; } //---------------------------------------------------------------------------- bool CurveArc::Copy( const IGeoObj* pGObjSrc) { const CurveArc* pCA = dynamic_cast( pGObjSrc) ; if ( pCA == nullptr) return false ; return Copy( *pCA) ; } //---------------------------------------------------------------------------- bool CurveArc::Copy( const CurveArc& caSrc) { if ( &caSrc == this) return true ; return Set( caSrc.m_PtCen, caSrc.m_VtN, caSrc.m_dRad, caSrc.m_VtS, caSrc.m_dAngCenDeg, caSrc.m_dDeltaN) ; } //---------------------------------------------------------------------------- GeoObjType CurveArc::GetType( void) const { return static_cast( GEOOBJ_GETTYPE( CurveArc)) ; } //---------------------------------------------------------------------------- const string& CurveArc::GetTitle( void) const { static const string sTitle = "Arc" ; return sTitle ; } //---------------------------------------------------------------------------- bool CurveArc::Dump( string& sOut, const char* szNewLine) const { // parametri : punti iniziale e finale sOut += "C(" + ToString( m_PtCen, 3) + ") " ; sOut += "VN(" + ToString( m_VtN, 6) + ") " ; sOut += "R=" + ToString( m_dRad, 3) + szNewLine ; sOut += "VS(" + ToString( m_VtS, 6) + ") " ; sOut += "Ac=" + ToString( m_dAngCenDeg, 3) + " " ; sOut += "Dn=" + ToString( m_dDeltaN, 3) + szNewLine ; return true ; } //---------------------------------------------------------------------------- int CurveArc::GetNgeId( void) const { return GEOOBJ_GETNGEID( CurveArc) ; } //---------------------------------------------------------------------------- bool CurveArc::Save( NgeWriter& ngeOut) const { // centro ngeOut.WritePoint( m_PtCen, ";") ; // versore Normale ngeOut.WriteVector( m_VtN, ";") ; // raggio ngeOut.WriteDouble( m_dRad, ";") ; // versore Iniziale ngeOut.WriteVector( m_VtS, ";") ; // angolo al centro ngeOut.WriteDouble( m_dAngCenDeg, ";") ; // deltaN ngeOut.WriteDouble( m_dDeltaN, ";", true) ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Load( NgeReader& ngeIn) { // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // leggo la prossima linea ( 6 parametri) // recupero il centro if ( ! ngeIn.ReadPoint( m_PtCen, ";")) return false ; // recupero il versore normale if ( ! ngeIn.ReadVector( m_VtN, ";")) return false ; // recupero il raggio if ( ! ngeIn.ReadDouble( m_dRad, ";")) return false ; // recupero il versore iniziale if ( ! ngeIn.ReadVector( m_VtS, ";")) return false ; // recupero l'angolo al centro if ( ! ngeIn.ReadDouble( m_dAngCenDeg, ";")) return false ; // recupero il delta N if ( ! ngeIn.ReadDouble( m_dDeltaN, ";", true)) return false ; // eseguo validazione return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::GetLocalBBox( BBox3d& b3Loc) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno il box in locale b3Loc.Reset() ; ArcApproxer aAppr( LIN_TOL_APPROX, ANG_TOL_APPROX_DEG, false, *this) ; double dU ; Point3d ptPos ; while ( aAppr.GetPoint( dU, ptPos)) b3Loc.Add( ptPos) ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetBBox( const Frame3d& frRef, BBox3d& b3Ref) const { // verifico lo stato if ( m_nStatus != OK) return false ; // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // assegno il box nel riferimento b3Ref.Reset() ; ArcApproxer aAppr( LIN_TOL_APPROX, ANG_TOL_APPROX_DEG, false, *this) ; double dU ; Point3d ptPos ; while ( aAppr.GetPoint( dU, ptPos)) { ptPos.ToGlob( frRef) ; b3Ref.Add( ptPos) ; } return true ; } //---------------------------------------------------------------------------- bool 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 ; } // eseguo il controllo m_nStatus = ( ( m_VtN.IsNormalized() && m_VtS.IsNormalized() && AreOrthoNear( m_VtN, m_VtS) && m_dRad > EPS_ZERO && fabs( m_dAngCenDeg) > EPS_ANG_ZERO) ? OK : ERR) ; } return ( m_nStatus == OK) ; } //---------------------------------------------------------------------------- bool CurveArc::GetStartPoint( Point3d& ptStart) const { // verifico lo stato if ( m_nStatus != OK) return false ; // calcolo il punto ptStart = m_PtCen + m_dRad * m_VtS ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetEndPoint( Point3d& ptEnd) const { // verifico lo stato if ( m_nStatus != OK) return false ; // calcolo il punto double dAng = m_dAngCenDeg * DEGTORAD ; Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ; ptEnd = m_PtCen + m_dRad * vtDir ; if ( fabs( m_dDeltaN) > EPS_ZERO) ptEnd += m_dDeltaN * m_VtN ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const { // la curva deve essere valida if ( m_nStatus != OK) return false ; // il parametro U deve essere compreso tra 0 e 1 if ( dU < 0) dU = 0 ; else if ( dU > 1) dU = 1 ; // versore al punto nel piano della circonferenza (ruoto m_VtS di dU di m_dAngCenDeg attorno a m_VtN) double dAng = dU * m_dAngCenDeg * DEGTORAD ; Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ; // calcolo del punto ptPos = m_PtCen + m_dRad * vtDir ; if ( fabs( m_dDeltaN) > EPS_ZERO) ptPos += ( dU * m_dDeltaN) * m_VtN ; // calcolo della derivata prima if ( pvtDer1 != nullptr) { *pvtDer1 = ( m_dRad * m_dAngCenDeg * DEGTORAD) * ( m_VtN ^ vtDir) ; if ( fabs( m_dDeltaN) > EPS_ZERO) *pvtDer1 += m_dDeltaN * m_VtN ; } // calcolo della derivata seconda if ( pvtDer2 != nullptr && pvtDer1 != nullptr) *pvtDer2 = - ( m_dRad * m_dAngCenDeg * DEGTORAD * m_dAngCenDeg * DEGTORAD) * vtDir ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetLength( double& dLen) const { // la curva deve essere validata if ( m_nStatus != OK) return false ; // lunghezza dell'arco piano dLen = m_dRad * fabs( m_dAngCenDeg) * DEGTORAD ; // aggiunta eventuale parte ortogonale if ( fabs( m_dDeltaN) > EPS_ZERO) dLen = sqrt( dLen * dLen + m_dDeltaN * m_dDeltaN) ; return ( dLen > EPS_SMALL) ; } //---------------------------------------------------------------------------- bool CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const { // pulisco la polilinea PL.Clear() ; // la curva deve essere validata if ( m_nStatus != OK) return false ; // eseguo approssimazione ArcApproxer aAppr( dLinTol, dAngTolDeg, true, *this) ; double dU ; Point3d ptPos ; while ( aAppr.GetPoint( dU, ptPos)) PL.AddUPoint( dU, ptPos) ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Invert( void) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // il centro va spostato di DeltaN if ( m_dDeltaN > EPS_ZERO) m_PtCen += m_dDeltaN * m_VtN ; // il versore normale rimane inalterato // il versore iniziale diventa quello finale double dAng = m_dAngCenDeg * DEGTORAD ; m_VtS = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ; // il raggio non cambia // l'angolo al centro inverte il segno m_dAngCenDeg = - m_dAngCenDeg ; // l'incremento sulla normale inverte il segno m_dDeltaN = - m_dDeltaN ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::TrimStartAtParam( double dUTrim) { double dLen ; // riporto i parametri nel loro range dUTrim = ( ( dUTrim < 0) ? 0 : (( dUTrim > 1) ? 1 : dUTrim)) ; // recupero lunghezza if ( ! GetLength( dLen)) return false ; // utilizzo il trim sulle lunghezze return TrimStartAtLen( dUTrim * dLen) ; } //---------------------------------------------------------------------------- bool CurveArc::TrimEndAtParam( double dUTrim) { double dLen ; // riporto i parametri nel loro range dUTrim = ( ( dUTrim < 0) ? 0 : (( dUTrim > 1) ? 1 : dUTrim)) ; // recupero lunghezza if ( ! GetLength( dLen)) return false ; // utilizzo il trim sulle lunghezze return TrimEndAtLen( dUTrim * dLen) ; } //---------------------------------------------------------------------------- bool CurveArc::TrimStartAtLen( double dLenTrim) { // lunghezze negative vengono considerate nulle dLenTrim = __max( dLenTrim, 0) ; // verifico che sia abbastanza lunga double dLen ; if ( ! GetLength( dLen)) return false ; if ( ( dLen - dLenTrim) < EPS_SMALL) return false ; // eseguo il trim if ( dLenTrim > EPS_ZERO) { double dAngRot ; double dMoveN ; dAngRot = m_dAngCenDeg * dLenTrim / dLen ; m_VtS.Rotate( m_VtN, dAngRot * DEGTORAD) ; m_dAngCenDeg -= dAngRot ; if ( fabs( m_dDeltaN) > EPS_ZERO) { dMoveN = m_dDeltaN * dLenTrim / dLen ; m_PtCen.Translate( m_VtN * dMoveN) ; m_dDeltaN -= dMoveN ; } } // con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::TrimEndAtLen( double dLenTrim) { // lunghezze negative vengono considerate nulle dLenTrim = __max( dLenTrim, 0) ; // verifico che sia abbastanza lunga double dLen ; if ( ! GetLength( dLen)) return false ; if ( dLenTrim < EPS_SMALL) return false ; // eseguo il trim if ( ( dLen - dLenTrim) > EPS_ZERO) { m_dAngCenDeg *= dLenTrim / dLen ; if ( fabs( m_dDeltaN) > EPS_ZERO) m_dDeltaN *= dLenTrim / dLen ; } // con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Translate( const Vector3d& vtMove) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // traslo il centro m_PtCen.Translate( vtMove) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità dell'asse di rotazione if ( vtAx.IsSmall()) return false ; // ruoto il centro e i versori m_PtCen.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; m_VtN.Rotate( vtAx, dCosAng, dSinAng) ; m_VtS.Rotate( vtAx, dCosAng, dSinAng) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // ammessa solo scalatura uniforme if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( dCoeffX - dCoeffZ) > EPS_SMALL) return false ; // verifico non sia nulla if ( fabs( dCoeffX) < EPS_ZERO) return false ; // scalo il centro e le dimensioni lineari m_PtCen.Scale( frRef, dCoeffX, dCoeffX, dCoeffX) ; m_dRad *= fabs( dCoeffX) ; m_dDeltaN *= dCoeffX ; if ( dCoeffX < 0) m_VtS = - m_VtS ; m_nStatus = TO_VERIFY ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità del piano di specchiatura if ( vtNorm.IsSmall()) return false ; // specchio il centro e i versori, inverto l'angolo al centro m_PtCen.Mirror( ptOn, vtNorm) ; m_VtN.Mirror( vtNorm) ; m_VtS.Mirror( vtNorm) ; m_dAngCenDeg *= -1 ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::ToGlob( const Frame3d& frRef) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // trasformo il centro e i versori m_PtCen.ToGlob( frRef) ; m_VtN.ToGlob( frRef) ; m_VtS.ToGlob( frRef) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::ToLoc( const Frame3d& frRef) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // trasformo i punti estremi m_PtCen.ToLoc( frRef) ; m_VtN.ToLoc( frRef) ; m_VtS.ToLoc( frRef) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- // Oggetto locale per approssimazione di archi // Approx interna è quella cordale standard. // Approx esterna è quella tangente a inizio e fine con metà tratto e un punto in più. // I punti si calcolano a partire dal triangolo tra due punti consecutivi interni e il centro, // usando il versore medio dal centro e moltiplicandolo per il coefficiente ( 2 / ( 1 + cosA)). // Il versore dell'ultimo punto è già stato calcolato per il penultimo. //---------------------------------------------------------------------------- ArcApproxer::ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc) { int nStep ; double dAngStepDeg ; // inizializzazioni m_nTotPnt = 0 ; m_nCurrPnt = - 1 ; // la curva deve essere validata if ( ! arArc.IsValid()) return ; // limiti minimi su tolleranza e deviazione angolare dLinTol = max( dLinTol, LIN_TOL_MIN) ; dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ; // limite massimo su deviazione angolare se approssimazione esterna if ( ! bInside) dAngTolDeg = min( dAngTolDeg, ANG_TOL_EXT_MAX_DEG) ; // determinazione dello step angolare dAngStepDeg = sqrt( 8 * dLinTol / arArc.GetRadius()) * RADTODEG ; dAngStepDeg = min( dAngStepDeg, dAngTolDeg) ; // dall'angolo al centro ricavo il numero di passi nStep = (int) ( fabs( arArc.GetAngCenter()) / dAngStepDeg + 0.999) ; nStep = __max( nStep, 1) ; // sistemo lo step (per il numero intero di passi) dAngStepDeg = arArc.GetAngCenter() / nStep ; // versori di riferimento nel piano dell'arco m_vtA1 = arArc.GetStartVersor() ; m_vtA2 = arArc.GetNormVersor() ^ arArc.GetStartVersor() ; // seno e coseno dell'angolo di step m_dCosA = cos( dAngStepDeg * DEGTORAD) ; m_dSinA = sin( dAngStepDeg * DEGTORAD) ; // salvo i dati m_bInside = bInside ; m_nTotPnt = ( m_bInside ? ( nStep + 1) : ( nStep + 2)) ; m_PtCen = arArc.GetCenter() ; m_VtN = arArc.GetNormVersor() ; m_dRad = arArc.GetRadius() ; m_dDeltaN = arArc.GetDeltaN() ; } //---------------------------------------------------------------------------- bool ArcApproxer::GetPoint( double& dU, Point3d& ptP) { Vector3d vtA1p ; Vector3d vtA2p ; // incremento indice punto corrente ++ m_nCurrPnt ; // se oltrepassata la fine if ( m_nCurrPnt >= m_nTotPnt) return false ; // primo punto if ( m_nCurrPnt == 0) { dU = 0 ; ptP = m_PtCen + m_vtA1 * m_dRad ; return true ; } // se approx esterna e ultimo punto (uso rotazione precedente) if ( ! m_bInside && m_nCurrPnt == m_nTotPnt - 1) { dU = 1 ; ptP = m_PtCen + m_vtA1 * m_dRad ; if ( fabs( m_dDeltaN) > EPS_ZERO) ptP += ( dU * m_dDeltaN) * m_VtN ; return true ; } // punti successivi // calcolo parametro if ( m_bInside) dU = m_nCurrPnt / (double) ( m_nTotPnt - 1) ; else dU = ( m_nCurrPnt - 0.5) / (double) ( m_nTotPnt - 2) ; // nuovo valore versori vtA1p = m_vtA1 ; vtA2p = m_vtA2 ; m_vtA1 = m_dCosA * vtA1p + m_dSinA * vtA2p ; m_vtA2 = - m_dSinA * vtA1p + m_dCosA * vtA2p ; // calcolo del punto if ( m_bInside) ptP = m_PtCen + m_vtA1 * m_dRad ; else ptP = m_PtCen + ( vtA1p + m_vtA1) * ( m_dRad / ( 1 + m_dCosA)) ; if ( fabs( m_dDeltaN) > EPS_ZERO) ptP += ( dU * m_dDeltaN) * m_VtN ; return true ; }