//---------------------------------------------------------------------------- // EgalTech 2014-2018 //---------------------------------------------------------------------------- // File : CurveArc.cpp Data : 23.11.18 Versione : 1.9k2 // Contenuto : Implementazione della classe Arco di Circonferenza. // // // // Modifiche : 16.04.13 DS Creazione modulo. // 03.01.16 DS Agg. SetCPA e SetCPAN. // 23.11.18 DS Corretta ApproxWithArcs ora vtExtr assegnato. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveArc.h" #include "CurveComposite.h" #include "DistPointArc.h" #include "PolygonPlane.h" #include "GeoConst.h" #include "GeoObjFactory.h" #include "NgeWriter.h" #include "NgeReader.h" #include "Voronoi.h" #include "/EgtDev/Include/EGkAngle.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/ENkPolynomialRoots.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgtPointerOwner.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(), m_dAngCenDeg(), m_dDeltaN(), m_VtExtr(), m_dThick(), m_nTempProp{0,0}, m_dTempParam{0.0, 0.0}, m_pVoronoiObj( nullptr) { } //---------------------------------------------------------------------------- CurveArc::~CurveArc( void) { ResetVoronoiObject() ; } //---------------------------------------------------------------------------- // 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 di Voronoi ResetVoronoiObject() ; // 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 ; m_VtN.Normalize() ; Frame3d frF ; if ( ! frF.Set( ORIG, vtN)) return false ; m_VtS = frF.VersX() ; m_dRad = dRad ; m_dAngCenDeg = ANG_FULL ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY //---------------------------------------------------------------------------- bool CurveArc::SetXY( 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 di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per circonferenza completa nel piano XY //---------------------------------------------------------------------------- bool CurveArc::SetXY( 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 = ANG_FULL ; m_dDeltaN = 0 ; m_nStatus = TO_VERIFY ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonf. o circonferenza completa per 3 Punti // ( algoritmo da Comp. Geom. di Faux e Pratt pagg. 67 e 68 ) //---------------------------------------------------------------------------- bool CurveArc::Set3P( const Point3d& ptStart, const Point3d& ptOther, const Point3d& ptEnd, bool bCirc) { // arco non ancora definito correttamente m_nStatus = ERR ; // vettori dal primo punto agli altri due Vector3d vtA = ptOther - ptStart ; Vector3d vtB = ptEnd - ptStart ; // calcolo del versore normale m_VtN = vtA ^ vtB ; double dNSqLen = m_VtN.SqLen() ; // se i punti sono praticamente allineati non si può calcolare la circonferenza if ( ! m_VtN.Normalize( EPS_ZERO)) return false ; // calcolo del centro m_PtCen = ptStart + ( vtB.SqLen() * ( vtA.SqLen() - vtA * vtB) * vtA + vtA.SqLen() * ( vtB.SqLen() - vtA * vtB) * vtB) / ( 2 * dNSqLen) ; // calcolo del versore start e del raggio m_VtS = ptStart - m_PtCen ; m_dRad = m_VtS.Len() ; if ( m_dRad < EPS_SMALL) return false ; m_VtS /= m_dRad ; // calcolo dell'angolo al centro if ( bCirc) m_dAngCenDeg = ANG_FULL ; else { // calcolo dell'angolo di rotazione attorno al centro dal primo al secondo punto bool bDet1 ; double dAng1Deg ; if ( ! m_VtS.GetRotation( ( ptOther - m_PtCen), m_VtN, dAng1Deg, bDet1) || ! bDet1) return false ; // calcolo dell'angolo di rotazione attorno al centro dal primo al terzo punto bool bDet2 ; double dAng2Deg ; if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, dAng2Deg, bDet2) || ! bDet2) return false ; // deduzione dell'angolo al centro // se uno dei due angoli è nullo, errore if ( abs( dAng1Deg) < EPS_ANG_SMALL || abs( dAng2Deg) < EPS_ANG_SMALL) return false ; // se i due angoli hanno lo stesso segno e Ang1 è minore di Ang2 in modulo else if ( dAng1Deg * dAng2Deg > 0 && abs( dAng1Deg) < abs( dAng2Deg)) m_dAngCenDeg = dAng2Deg ; // altrimenti hanno segno opposto oppure Ang1 è maggiore di Ang2 in modulo else m_dAngCenDeg = - _copysign( ANG_FULL, dAng2Deg) + dAng2Deg ; } // non c'è DeltaN m_dDeltaN = 0 ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonf. definito dagli estremi, versore normale e bulge //---------------------------------------------------------------------------- bool CurveArc::Set2PNB( const Point3d& ptIni, const Point3d& ptFin, const Vector3d& vtN, double dBulge) { // arco non ancora definito correttamente m_nStatus = ERR ; // 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 ; vtDiff -= m_dDeltaN * m_VtN ; if ( abs( m_dDeltaN) < EPS_SMALL) m_dDeltaN = 0 ; // verifico sia un arco (uso la lunghezza della saetta) double dDist = vtDiff.Len() ; if ( abs( dBulge * 0.5 * dDist) < EPS_ZERO) 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 = abs( 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 di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY con ptStart, ptEnd, dirStart //---------------------------------------------------------------------------- bool CurveArc::Set2PD( const Point3d& ptStart, const Point3d& ptEnd, double dDirStartDeg) { // arco non ancora definito correttamente m_nStatus = ERR ; // vettore tangente iniziale ( nel piano XY) Vector3d vtA = FromPolar( 1, dDirStartDeg) ; // vettore da inizio a fine ( nel piano XY) Vector3d vtB = ptEnd - ptStart ; vtB.z = 0 ; // calcolo del versore normale m_VtN = vtA ^ vtB ; double dNSqLen = m_VtN.SqLen() ; // se tangente e punti sono praticamente allineati non si può calcolare la circonferenza if ( ! m_VtN.Normalize( EPS_ZERO)) return false ; // calcolo del centro m_PtCen = ptStart + vtB.SqLen() * ( vtB - ( vtA * vtB) * vtA) / ( 2 * dNSqLen) ; // calcolo del versore start e del raggio m_VtS = ptStart - m_PtCen ; m_dRad = m_VtS.Len() ; if ( m_dRad < EPS_SMALL) return false ; m_VtS /= m_dRad ; // calcolo dell'angolo al centro // angolo di rotazione da start a end bool bDet1 ; double dAng1Deg ; if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, dAng1Deg, bDet1) || ! bDet1) return false ; // poichè il senso di rotazione è sempre CCW, se l'angolo è negativo prendo il suo complemento al giro if ( dAng1Deg < 0) m_dAngCenDeg = ANG_FULL + dAng1Deg ; else m_dAngCenDeg = dAng1Deg ; // DeltaN m_dDeltaN = ( ptEnd.z - ptStart.z) * m_VtN.z ; // se normale con Z negativa, inverto senza modificare la geometria if ( m_VtN.z < 0) { m_VtN.Invert() ; m_dAngCenDeg = - m_dAngCenDeg ; m_dDeltaN = - m_dDeltaN ; } // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza in un piano generico con ptStart, ptEnd, vtDirStart, vtN //---------------------------------------------------------------------------- bool CurveArc::Set2PVN( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDirS, const Vector3d& vtN) { // calcolo il riferimento OCS derivato da vtN Frame3d frOcs ; if ( ! frOcs.Set( ORIG, vtN)) return false ; // porto i punti in questo riferimento Point3d ptSloc = ptStart ; ptSloc.ToLoc( frOcs) ; Point3d ptEloc = ptEnd ; ptEloc.ToLoc( frOcs) ; // porto la direzione in questo riferimento e verifico che definisca un angolo nel piano Vector3d vtSloc = vtDirS ; vtSloc.ToLoc( frOcs) ; if ( abs( vtSloc.x) < EPS_SMALL && abs( vtSloc.y) < EPS_SMALL) return false ; double dDirStartDeg ; vtSloc.ToSpherical( nullptr, nullptr, &dDirStartDeg) ; // calcolo l'arco in questo piano if ( ! Set2PD( ptSloc, ptEloc, dDirStartDeg)) return false ; // riporto l'arco nel riferimento naturale return ToGlob( frOcs) ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY con ptStart, ptEnd, dRad, bCCW // ( si suppone |dAngCenDeg| <= 180deg) //---------------------------------------------------------------------------- bool CurveArc::Set2PRS( const Point3d& ptStart, const Point3d& ptEnd, double dRad, bool bCCW) { // arco non ancora definito correttamente m_nStatus = ERR ; // il piano dell'arco coincide con XY m_VtN = Z_AX ; m_dDeltaN = ptEnd.z - ptStart.z ; // semi-vettore da inizio a fine Vector3d vtA = 0.5 * ( ptEnd - ptStart) ; vtA.z = 0 ; double dLenA = vtA.Len() ; if ( dLenA < EPS_ZERO || dLenA > ( dRad + EPS_ZERO)) return false ; // distanza del centro dalla corda tra inizio e fine double dLenH ; if ( dLenA > ( dRad - EPS_ZERO)) dLenH = 0 ; else dLenH = sqrt( dRad * dRad - dLenA * dLenA) ; // versore dal punto medio della corda al centro Vector3d vtH = vtA / dLenA ; vtH.Rotate( Z_AX, 0, ( bCCW ? 1 : -1)) ; // calcolo del centro m_PtCen = ptStart + vtA + vtH * dLenH ; // assegno il raggio if ( dRad < EPS_ZERO) return false ; m_dRad = dRad ; // calcolo il versore di start m_VtS = ( ptStart - m_PtCen) / m_dRad ; m_VtS.Normalize() ; // calcolo l'angolo al centro bool bDet ; if ( ! m_VtS.GetRotation( ( ptEnd - m_PtCen), m_VtN, m_dAngCenDeg, bDet) || ! bDet) return false ; // quando è 180deg il segno è determinato solo dal senso if ( abs( m_dAngCenDeg - ANG_STRAIGHT) < 10 * EPS_ANG_SMALL && ( ( bCCW && m_dAngCenDeg < 0) || ( ! bCCW && m_dAngCenDeg > 0))) m_dAngCenDeg = - m_dAngCenDeg ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza in un piano generico con ptStart, ptEnd, vtN, dRad, bCCW // ( si suppone |dAngCenDeg| <= 180deg) //---------------------------------------------------------------------------- bool CurveArc::Set2PNRS( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtN, double dRad, bool bCCW) { // calcolo il riferimento OCS derivato da vtN Frame3d frOcs ; if ( ! frOcs.Set( ORIG, vtN)) return false ; // porto i punti in questo riferimento Point3d ptSloc = ptStart ; ptSloc.ToLoc( frOcs) ; Point3d ptEloc = ptEnd ; ptEloc.ToLoc( frOcs) ; // calcolo l'arco in questo piano if ( ! Set2PRS( ptSloc, ptEloc, dRad, bCCW)) return false ; // riporto l'arco nel riferimento naturale return ToGlob( frOcs) ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY con ptCen, ptStart, dAngCenDeg, dDeltaZ //---------------------------------------------------------------------------- bool CurveArc::SetCPA( const Point3d& ptCen, const Point3d& ptStart, double dAngCenDeg, double dDeltaZ) { // arco non ancora definito correttamente m_nStatus = ERR ; // il piano dell'arco coincide con XY m_VtN = Z_AX ; m_dDeltaN = dDeltaZ ; // assegno il centro m_PtCen = ptCen ; m_PtCen.z = ptStart.z ; // assegno il versore iniziale e il raggio m_VtS = ptStart - m_PtCen ; m_dRad = m_VtS.Len() ; if ( m_dRad < EPS_ZERO) return false ; m_VtS /= m_dRad ; // assegno l'angolo al centro m_dAngCenDeg = dAngCenDeg ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza in un piano generico con ptCen, ptStart, dAngCenDeg, dDeltaZ, vtN //---------------------------------------------------------------------------- bool CurveArc::SetCPAN( const Point3d& ptCen, const Point3d& ptStart, double dAngCenDeg, double dDeltaZ, const Vector3d& vtN) { // calcolo il riferimento OCS derivato da vtN Frame3d frOcs ; if ( ! frOcs.Set( ORIG, vtN)) return false ; // porto i punti in questo riferimento Point3d ptCloc = ptCen ; ptCloc.ToLoc( frOcs) ; Point3d ptSloc = ptStart ; ptSloc.ToLoc( frOcs) ; // calcolo l'arco in questo piano if ( ! SetCPA( ptCloc, ptSloc, dAngCenDeg, dDeltaZ)) return false ; // riporto l'arco nel riferimento naturale return ToGlob( frOcs) ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza nel piano XY con ptCen, ptStart, ptNearEnd // ( si suppone |dAngCenDeg| <= 180deg) //---------------------------------------------------------------------------- bool CurveArc::SetC2P( const Point3d& ptCen, const Point3d& ptStart, const Point3d& ptNearEnd) { // arco non ancora definito correttamente m_nStatus = ERR ; // il piano dell'arco coincide con XY m_VtN = Z_AX ; m_dDeltaN = ptNearEnd.z - ptStart.z ; // assegno il centro m_PtCen = ptCen ; m_PtCen.z = ptStart.z ; // assegno il versore iniziale e il raggio m_VtS = ptStart - m_PtCen ; m_dRad = m_VtS.Len() ; if ( m_dRad < EPS_ZERO) return false ; m_VtS /= m_dRad ; // calcolo l'angolo al centro (la funzione trova sempre il più piccolo) bool bDet ; if ( ! m_VtS.GetRotation( ( ptNearEnd - m_PtCen), m_VtN, m_dAngCenDeg, bDet) || ! bDet) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // Set per arco di circonferenza in un piano generico con ptCen, ptStart, ptNearEnd, vtN // ( si suppone |dAngCenDeg| <= 180deg) //---------------------------------------------------------------------------- bool CurveArc::SetC2PN( const Point3d& ptCen, const Point3d& ptStart, const Point3d& ptNearEnd, const Vector3d& vtN) { // calcolo il riferimento OCS derivato da vtN Frame3d frOcs ; if ( ! frOcs.Set( ORIG, vtN)) return false ; // porto i punti in questo riferimento Point3d ptCloc = ptCen ; ptCloc.ToLoc( frOcs) ; Point3d ptSloc = ptStart ; ptSloc.ToLoc( frOcs) ; Point3d ptNEloc = ptNearEnd ; ptNEloc.ToLoc( frOcs) ; // calcolo l'arco in questo piano if ( ! SetC2P( ptCloc, ptSloc, ptNEloc)) return false ; // riporto l'arco nel riferimento naturale return ToGlob( frOcs) ; } //---------------------------------------------------------------------------- CurveArc* CurveArc::Clone( void) const { // alloco oggetto CurveArc* pCrv = new( nothrow) CurveArc ; if ( pCrv != nullptr) { if ( ! pCrv->CopyFrom( *this)) { delete pCrv ; return nullptr ; } } return pCrv ; } //---------------------------------------------------------------------------- bool CurveArc::CopyFrom( const IGeoObj* pGObjSrc) { const CurveArc* pCA = GetBasicCurveArc( pGObjSrc) ; if ( pCA == nullptr) return false ; return CopyFrom( *pCA) ; } //---------------------------------------------------------------------------- bool CurveArc::CopyFrom( const CurveArc& caSrc) { if ( &caSrc == this) return true ; m_VtExtr = caSrc.m_VtExtr ; m_dThick = caSrc.m_dThick ; m_nTempProp[0] = caSrc.m_nTempProp[0] ; m_nTempProp[1] = caSrc.m_nTempProp[1] ; m_dTempParam[0] = caSrc.m_dTempParam[0] ; m_dTempParam[1] = caSrc.m_dTempParam[1] ; 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, bool bMM, const char* szNewLine) const { // dati generali di una curva if ( ! CurveDump( *this, sOut, bMM, szNewLine)) return false ; // parametri : Centro, Normale, DirStart, Rad, AngCenDeg, DeltaN sOut += "C(" + ToString( GetInUiUnits( m_PtCen, bMM), 3) + ") " + szNewLine ; sOut += "VN(" + ToString( m_VtN, 6) + ") " + szNewLine ; sOut += "VS(" + ToString( m_VtS, 6) + ") " + szNewLine ; sOut += "R=" + ToString( GetInUiUnits( m_dRad, bMM), 3) ; sOut += " Ac=" + ToString( m_dAngCenDeg, 3) ; sOut += " Dn=" + ToString( GetInUiUnits( m_dDeltaN, bMM), 3) + szNewLine ; return true ; } //---------------------------------------------------------------------------- int CurveArc::GetNgeId( void) const { return GEOOBJ_GETNGEID( CurveArc) ; } //---------------------------------------------------------------------------- bool CurveArc::Save( NgeWriter& ngeOut) const { // centro if ( ! ngeOut.WritePoint( m_PtCen, ";")) return false ; // versore Normale if ( ! ngeOut.WriteVector( m_VtN, ";")) return false ; // raggio if ( ! ngeOut.WriteDouble( m_dRad, ";")) return false ; // versore Iniziale if ( ! ngeOut.WriteVector( m_VtS, ";")) return false ; // angolo al centro int nDec = ( m_dRad < 0.1 * BIG_ARC_RAD ? 6 : 9) ; if ( ! ngeOut.WriteDouble( m_dAngCenDeg, ";", false, nDec)) return false ; // deltaN if ( ! ngeOut.WriteDouble( m_dDeltaN, ";", true)) return false ; // da versione 1008 : linea con VtEstrusione e Spessore if ( ! ngeOut.WriteVector( m_VtExtr, ";")) return false ; if ( ! ngeOut.WriteDouble( m_dThick, ";", true)) return false ; 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 ; m_VtS.Normalize() ; // per garantire la precisione con raggi grandi // recupero l'angolo al centro if ( ! ngeIn.ReadDouble( m_dAngCenDeg, ";")) return false ; // recupero il delta N if ( ! ngeIn.ReadDouble( m_dDeltaN, ";", true)) return false ; // da versione 1008 : linea con VtEstrusione e Spessore if ( ngeIn.GetFileVersion() >= NGE_VER_1008) { if ( ! ngeIn.ReadVector( m_VtExtr, ";")) return false ; if ( ! ngeIn.ReadDouble( m_dThick, ";", true)) return false ; } // eseguo validazione return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::GetLocalBBox( BBox3d& b3Loc, int nFlag) const { // richiamo della funzione generale return GetBBox( GLOB_FRM, b3Loc, nFlag) ; } //---------------------------------------------------------------------------- bool CurveArc::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) 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() ; // ricavo il riferimento intrinseco dell'arco Frame3d frArc; frArc.Set( m_PtCen, ( m_dAngCenDeg > 0 ? m_VtN : -m_VtN), m_VtS) ; // pendenza intrinseca double dPitch = m_dDeltaN * ( m_dAngCenDeg > 0 ? 1 : -1) / abs( m_dAngCenDeg * DEGTORAD) ; // cordinate nel frRef dei versori del sistema di riferimento dell'arco Vector3d vtXRef = frArc.VersX() ; vtXRef.ToGlob( frRef) ; Vector3d vtYRef = frArc.VersY() ; vtYRef.ToGlob( frRef) ; Vector3d vtZRef = frArc.VersZ() ; vtZRef.ToGlob( frRef) ; // il punto iniziale e finale sono punti candidati per estremanti Point3d ptS, ptE ; GetStartPoint( ptS) ; ptS.ToGlob( frRef) ; b3Ref.Add( ptS) ; GetEndPoint( ptE) ; ptE.ToGlob( frRef) ; b3Ref.Add( ptE) ; // vettore degli angoli dei punti candidati estremi DBLVECTOR vdTheta ; // arco piatto if ( abs( dPitch) < EPS_SMALL) { double dAngXDeg = atan2( vtYRef.x, vtXRef.x) * RADTODEG ; bool bAngXSmall = (abs( dAngXDeg) <= EPS_ANG_ZERO) ; if ( ! bAngXSmall) { vdTheta.push_back( dAngXDeg) ; vdTheta.push_back( dAngXDeg + ANG_STRAIGHT) ; } double dAngYDeg = atan2( vtYRef.y, vtXRef.y) * RADTODEG ; bool bAngYSmall = (abs( dAngYDeg) <= EPS_ANG_ZERO) ; if ( ! bAngYSmall) { vdTheta.push_back( dAngYDeg) ; vdTheta.push_back( dAngYDeg + ANG_STRAIGHT) ; } double dAngZDeg = atan2( vtYRef.z, vtXRef.z) * RADTODEG ; bool bAngZSmall = (abs( dAngZDeg) <= EPS_ANG_ZERO) ; if ( ! bAngZSmall) { vdTheta.push_back( dAngZDeg) ; vdTheta.push_back( dAngZDeg + ANG_STRAIGHT) ; } if ( bAngXSmall || bAngYSmall || bAngZSmall) vdTheta.push_back( ANG_STRAIGHT) ; } // altrimenti arco di elica else { for ( int i = 0 ; i < 3 ; ++ i) { DBLVECTOR vdPoly{ m_dRad * vtYRef.v[i] + dPitch * vtZRef.v[i], - 2 * m_dRad * vtXRef.v[i], - m_dRad * vtYRef.v[i] + dPitch * vtZRef.v[i]} ; DBLVECTOR vdRoot ; int nRoot = PolynomialRoots( 2, vdPoly, vdRoot) ; for ( int i = 0 ; i < nRoot ; ++ i) { double dAngDeg = atan2( 2 * vdRoot[i], (1 - vdRoot[i] * vdRoot[i])) * RADTODEG ; if ( abs( dAngDeg) > EPS_ANG_ZERO) { vdTheta.push_back( dAngDeg) ; vdTheta.push_back( dAngDeg + ANG_STRAIGHT) ; } else vdTheta.push_back( ANG_STRAIGHT) ; } } } // verifica degli angoli sull'arco ed eventuale considerazione dei punti for ( int i = 0 ; i < int( vdTheta.size()) ; ++ i) { double dTheta = ( vdTheta[i] > 0 ? vdTheta[i] : vdTheta[i] + ANG_FULL) ; if ( dTheta < abs( m_dAngCenDeg)) { Point3d ptP ; GetPointD1D2( dTheta / ( abs( m_dAngCenDeg)), FROM_MINUS, ptP) ; ptP.ToGlob( frRef) ; b3Ref.Add( ptP) ; } } // se c'è estrusione, devo tenerne conto if ( ! m_VtExtr.IsSmall() && abs( m_dThick) > EPS_SMALL) { Vector3d vtFrExtr = m_VtExtr ; vtFrExtr.ToGlob( frRef) ; Point3d ptMinExtr = b3Ref.GetMin() + vtFrExtr * m_dThick ; Point3d ptMaxExtr = b3Ref.GetMax() + vtFrExtr * m_dThick ; b3Ref.Add( ptMinExtr) ; b3Ref.Add( ptMaxExtr) ; } return true ; } //---------------------------------------------------------------------------- bool CurveArc::Validate( void) { if ( m_nStatus == TO_VERIFY) { // limito l'angolo al centro a un giro se è piatto ( non è elica) if ( abs( m_dDeltaN) < EPS_SMALL) { 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_PtCen.IsValid() && m_VtN.IsNormalized() && m_VtS.IsNormalized() && AreOrthoApprox( m_VtN, m_VtS) && m_dRad > EPS_SMALL && m_dRad < MAX_ARC_RAD && abs( m_dAngCenDeg) > EPS_ANG_ZERO) ? OK : ERR) ; } return ( m_nStatus == OK) ; } //---------------------------------------------------------------------------- bool CurveArc::IsFlat( Plane3d& plPlane, bool bUseExtrusion, double dToler) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno dati possibile piano bool bFlat = IsPlane( dToler) ; Vector3d vtN ; if ( ! bUseExtrusion || m_VtExtr.IsSmall()) { vtN = m_VtN ; } else { vtN = m_VtExtr ; bFlat = bFlat && AreSameOrOppositeVectorApprox( m_VtExtr, m_VtN) ; } plPlane.Set( m_PtCen, vtN) ; // ritorno conferma return bFlat ; } //---------------------------------------------------------------------------- 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 ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) ptEnd += m_dDeltaN * m_VtN ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetMidPoint( Point3d& ptMid) const { // verifico lo stato if ( m_nStatus != OK) return false ; // calcolo il punto double dAng = 0.5 * m_dAngCenDeg * DEGTORAD ; Vector3d vtDir = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ; ptMid = m_PtCen + m_dRad * vtDir ; if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) ptMid += ( 0.5 * m_dDeltaN) * m_VtN ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetCenterPoint( Point3d& ptCen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // assegno il centro ptCen = m_PtCen ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetCentroid( Point3d& ptCen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // approssimo la curva con una polilinea PolyLine PL ; if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, APL_STD, PL)) return false ; // calcolo il centro mediante PolygonPlane Point3d ptP ; PolygonPlane PolyPlane ; for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP)) PolyPlane.AddPoint( ptP) ; if ( PolyPlane.GetCentroid( ptCen)) return true ; // se non riuscito, uso il punto medio return GetMidPoint( ptCen) ; } //---------------------------------------------------------------------------- bool CurveArc::GetDir( double dU, Vector3d& vtDir) const { // la curva deve essere valida if ( m_nStatus != OK) return false ; // il parametro U deve essere compreso tra 0 e 1 dU = Clamp( dU, 0., 1.) ; // versore al punto nel piano della circonferenza (ruoto m_VtS di dU * m_dAngCenDeg attorno a m_VtN) double dAng = dU * m_dAngCenDeg * DEGTORAD ; Vector3d vtRad = cos( dAng) * m_VtS + sin( dAng) * ( m_VtN ^ m_VtS) ; // calcolo della tangente nel punto finale vtDir = ( m_dRad * m_dAngCenDeg * DEGTORAD) * ( m_VtN ^ vtRad) ; if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) vtDir += m_dDeltaN * m_VtN ; // normalizzo return vtDir.Normalize( EPS_ZERO) ; } //---------------------------------------------------------------------------- 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 dU = Clamp( dU, 0., 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 ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) ptPos += ( dU * m_dDeltaN) * m_VtN ; // calcolo della derivata prima if ( pvtDer1 != nullptr) { *pvtDer1 = ( m_dRad * m_dAngCenDeg * DEGTORAD) * ( m_VtN ^ vtDir) ; if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) *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 * abs( m_dAngCenDeg) * DEGTORAD ; // aggiunta eventuale parte ortogonale if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) dLen = sqrt( dLen * dLen + m_dDeltaN * m_dDeltaN) ; return ( dLen > EPS_SMALL) ; } //---------------------------------------------------------------------------- bool CurveArc::GetLengthAtParam( double dU, double& dLen) const { // verifico lo stato if ( m_nStatus != OK) return false ; // fuori dominio del parametro -> errore if ( dU < 0 - EPS_PARAM) return false ; if ( dU > ( 1 + EPS_PARAM)) return false ; // inizio if ( dU < 0 + EPS_PARAM) { dLen = 0 ; return true ; } // lunghezza totale double dTotLen ; if ( ! GetLength( dTotLen)) return false ; // fine if ( dU > 1 - EPS_PARAM) { dLen = dTotLen ; return true ; } // posizione intermedia dLen = dU * dTotLen ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::GetParamAtLength( double dLen, double& dU) const { // verifico lo stato if ( m_nStatus != OK) return false ; // se prima di inizio, errore if ( dLen < - EPS_SMALL) return false ; // inizio if ( dLen < EPS_SMALL) { dU = 0 ; return true ; } // lunghezza totale double dTotLen ; if ( ! GetLength( dTotLen)) return false ; // se dopo fine, errore if ( dLen > dTotLen + EPS_SMALL) return false ; // fine if ( dLen > dTotLen - EPS_SMALL) { dU = 1 ; return true ; } // posizione intermedia dU = dLen / dTotLen ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::IsPointOn( const Point3d& ptP, double dTol) const { // verifico la distanza return ( DistPointArc( ptP, *this).IsEpsilon( dTol)) ; } //---------------------------------------------------------------------------- bool CurveArc::GetParamAtPoint( const Point3d& ptP, double& dPar, double dTol) const { DistPointArc DPA( ptP, *this) ; if ( ! DPA.IsEpsilon( dTol)) return false ; int nFlag ; return DPA.GetParamAtMinDistPoint( 0, dPar, nFlag) ; } //---------------------------------------------------------------------------- bool CurveArc::GetLengthAtPoint( const Point3d& ptP, double& dLen, double dTol) const { double dU ; if ( ! GetParamAtPoint( ptP, dU, dTol)) return false ; return GetLengthAtParam( dU, dLen) ; } //---------------------------------------------------------------------------- bool CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const { // pulisco la polilinea PL.Clear() ; // la curva deve essere validata if ( m_nStatus != OK) return false ; // determino se approssimazione interna o esterna Vector3d vtExtr = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ; bool bCCW = ( (( vtExtr * m_VtN) > - EPS_ZERO) ? ( m_dAngCenDeg > 0) : ( m_dAngCenDeg < 0)) ; bool bInside = true ; if ( ( ( nType == APL_RIGHT || nType == APL_RIGHT_CONVEX) && bCCW) || ( ( nType == APL_LEFT || nType == APL_LEFT_CONVEX) && ! bCCW)) bInside = false ; // eseguo approssimazione ArcApproxer aAppr( dLinTol, dAngTolDeg, bInside, *this) ; double dU ; Point3d ptPos ; while ( aAppr.GetPoint( dU, ptPos)) { if ( ! PL.AddUPoint( dU, ptPos)) return false ; } // se necessario, sistemo per convessità dalla parte ammessa if ( nType == APL_RIGHT_CONVEX || nType == APL_LEFT_CONVEX) { if ( ! PL.MakeConvex( vtExtr, ( nType == APL_LEFT_CONVEX))) 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 ; // determinazione versore normale al piano di riferimento Vector3d vtNref = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ; // assegno estrusione al poliarco PA.SetExtrusion( vtNref) ; // se l'arco non ha direzione normale coincidente con il versore del piano, approssimo con rette if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref)) { ArcApproxer aAppr( dLinTol, dAngTolDeg, true, *this) ; double dU ; Point3d ptPos ; while ( aAppr.GetPoint( dU, ptPos)) { if ( ! PA.AddUPoint( dU, ptPos, 0)) return false ; } return true ; } // calcolo il numero di archi con bulge da usare ( ognuno deve avere un angolo al centro <= 240deg) const double MAX_ANG_ARC_BULGE = 240 ; int nArcs = int( ceil( abs( m_dAngCenDeg) / MAX_ANG_ARC_BULGE)) ; nArcs = max( nArcs, 1) ; double dBulge = tan( m_dAngCenDeg / ( 4 * nArcs) * DEGTORAD) ; // se direzioni opposte, senso di rotazione contrario if ( m_VtN * vtNref < 0) dBulge = - dBulge ; // inserisco i punti di inizio di ogni arco for ( int i = 0 ; i < nArcs ; ++ i) { Point3d ptStart ; double dU = i / double( nArcs) ; if ( ! GetPointD1D2( dU, ICurve::FROM_MINUS, ptStart) || ! PA.AddUPoint( dU, ptStart, dBulge)) return false ; } // inserisco punto finale senza bulge Point3d ptEnd ; if ( ! GetEndPoint( ptEnd) || ! PA.AddUPoint( 1, ptEnd, 0)) return false ; return true ; } //---------------------------------------------------------------------------- ICurve* CurveArc::CopyParamRange( double dUStart, double dUEnd) const { // i parametri start ed end devono essere compresi nel dominio parametrico della curva if ( dUStart < - EPS_PARAM || dUStart > 1 + EPS_PARAM || dUEnd < - EPS_PARAM || dUEnd > 1 + EPS_PARAM) return nullptr ; // se il parametro start supera quello di end if ( dUStart > dUEnd - EPS_PARAM) { // se curva aperta, il trim la cancella completamente quindi non resta alcunchè if ( ! IsClosed()) return nullptr ; // se curva chiusa, il trim si avvolge attorno al punto di giunzione else { // eseguo la copia sulla curva composita equivalente CurveComposite cCompo ; cCompo.CopyFrom( this) ; return cCompo.CopyParamRange( dUStart, dUEnd) ; } } // creo l'arco copia PtrOwner pCopy( Clone()) ; if ( IsNull( pCopy)) return nullptr ; // eseguo il trim if ( ! pCopy->TrimStartEndAtParam( dUStart, dUEnd)) return nullptr ; return ( ::Release( pCopy)) ; } //---------------------------------------------------------------------------- bool CurveArc::Invert( void) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // il centro va spostato di DeltaN if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) 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 di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::SimpleOffset( double dDist, int nType, double dMaxAngExt) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // determinazione versore normale al piano di offset Vector3d vtNref = Z_AX ; if ( ! m_VtExtr.IsSmall()) vtNref = m_VtExtr ; // la normale deve coincidere con il versore del piano di offset if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref)) return false ; // calcolo il nuovo raggio e lo valido bool bCCW = ( ( m_dAngCenDeg > 0 && m_VtN * vtNref > 0) || ( m_dAngCenDeg < 0 && m_VtN * vtNref < 0)) ; double dNewRad = m_dRad + ( bCCW ? + dDist : - dDist) ; if ( dNewRad < EPS_SMALL) return false ; // aggiorno il raggio m_dRad = dNewRad ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::MyExtendedOffset( double dDist, bool bAll) { // bAll == true fa accettare raggi nulli ==> da usare solo internamente // quando si è sicuri di aumentare subito il raggio o di cancellare // la curva deve essere validata if ( m_nStatus != OK) return false ; // determinazione versore normale al piano di offset Vector3d vtNref = Z_AX ; if ( ! m_VtExtr.IsSmall()) vtNref = m_VtExtr ; // la normale deve coincidere con il versore del piano di offset if ( ! AreSameOrOppositeVectorApprox( m_VtN, vtNref)) return false ; // calcolo il nuovo raggio e lo valido bool bCCW = ( ( m_dAngCenDeg > 0 && m_VtN * vtNref > 0) || ( m_dAngCenDeg < 0 && m_VtN * vtNref < 0)) ; double dNewRad = m_dRad + ( bCCW ? + dDist : - dDist) ; if ( abs( dNewRad) < EPS_SMALL) { if ( bAll) dNewRad = 0.1 * EPS_SMALL ; else return false ; } if ( dNewRad < 0) { dNewRad = - dNewRad ; m_VtS = - m_VtS ; } // aggiorno il raggio m_dRad = dNewRad ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata m_OGrMgr.Reset() ; // quando raggio nullo ritorno false come indicativo dello stato return ( m_dRad > EPS_SMALL) ; } //---------------------------------------------------------------------------- bool CurveArc::ModifyStart( const Point3d& ptNewStart) { // verifico lo stato if ( m_nStatus != OK) return false ; // inverto l'arco Invert() ; // modifico la fine dell'arco invertito bool bOk = ModifyEnd( ptNewStart) ; // re-inverto Invert() ; return bOk ; } //---------------------------------------------------------------------------- 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 ( AreSamePointXYExact( ptOldEndIntr, ptEndIntr)) { 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 ( abs( 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 di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::TrimStartAtParam( double dUTrim) { // riporto i parametri nel loro range dUTrim = Clamp( dUTrim, 0., 1.) ; // recupero lunghezza double dLen ; if ( ! GetLength( dLen)) return false ; // utilizzo il trim sulle lunghezze return TrimStartAtLen( dUTrim * dLen) ; } //---------------------------------------------------------------------------- bool CurveArc::TrimEndAtParam( double dUTrim) { // riporto i parametri nel loro range dUTrim = Clamp( dUTrim, 0., 1.) ; // recupero lunghezza double dLen ; if ( ! GetLength( dLen)) return false ; // utilizzo il trim sulle lunghezze return TrimEndAtLen( dUTrim * dLen) ; } //---------------------------------------------------------------------------- bool CurveArc::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim) { // i parametri start ed end devono essere compresi nel dominio parametrico della curva if ( dUStartTrim < - EPS_PARAM || dUStartTrim > 1 + EPS_PARAM || dUEndTrim < - EPS_PARAM || dUEndTrim > 1 + EPS_PARAM) return false ; // verifico che i trim non cancellino interamente la curva if ( dUStartTrim > dUEndTrim - EPS_PARAM) return false ; // trim finale if ( ! TrimEndAtParam( dUEndTrim)) return false ; // trim iniziale con il parametro opportunamente ricalcolato double dNewUStartTrim = dUStartTrim / dUEndTrim ; return TrimStartAtParam( dNewUStartTrim) ; } //---------------------------------------------------------------------------- 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) ; m_dAngCenDeg -= dAngRot ; if ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) { dMoveN = m_dDeltaN * dLenTrim / dLen ; m_PtCen.Translate( m_VtN * dMoveN) ; m_dDeltaN -= dMoveN ; } } // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // 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 ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) m_dDeltaN *= dLenTrim / dLen ; } // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // con i controlli sopra fatti rimane validata, ma la grafica va ricalcolata m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::ExtendStartByLen( double dLenExt) { // la lunghezza di estensione deve essere positiva if ( dLenExt < - EPS_ZERO) return false ; // inverto l'arco, lo estendo alla fine o lo reinverto Invert() ; bool bOk = ExtendEndByLen( dLenExt) ; Invert() ; return bOk ; } //---------------------------------------------------------------------------- bool CurveArc::ExtendEndByLen( double dLenExt) { // la lunghezza deve essere positiva if ( dLenExt < - EPS_ZERO) return false ; // ricavo la lunghezza originale double dLen ; if ( ! GetLength( dLen)) return false ; // eseguo l'estensione double dCoeff = ( dLen + dLenExt) / dLen ; m_dAngCenDeg *= dCoeff ; if ( ! IsPlane()) m_dDeltaN *= dCoeff ; else if ( abs( m_dAngCenDeg) > ANG_FULL) m_dAngCenDeg = _copysign( ANG_FULL, m_dAngCenDeg) ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->Translate( vtMove) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // traslo il centro m_PtCen.Translate( vtMove) ; 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->Rotate( ptAx, vtAx, dCosAng, dSinAng) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // 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) ; // ruoto il vettore estrusione m_VtExtr.Rotate( vtAx, dCosAng, dSinAng) ; 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 ; // se riferimento con asse Z perpendicolare al piano dell'arco if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersZ())) { // la scalatura deve essere uniforme nel piano dell'arco if ( abs( dCoeffX - dCoeffY) > EPS_SMALL) return false ; // verifico non sia nulla if ( abs( dCoeffX) < EPS_ZERO || m_dRad * abs( dCoeffX) <= EPS_SMALL) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // scalo il centro e le dimensioni lineari m_PtCen.Scale( frRef, dCoeffX, dCoeffX, dCoeffZ) ; m_dRad *= abs( dCoeffX) ; m_dDeltaN *= dCoeffZ ; if ( dCoeffZ < 0) m_VtS = - m_VtS ; // scalo vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Scale( frRef, dCoeffX, dCoeffX, dCoeffZ) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } m_nStatus = TO_VERIFY ; // ritorno risultato della validazione return Validate() ; } // se riferimento con asse X perpendicolare al piano dell'arco else if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersX())) { // la scalatura deve essere uniforme nel piano dell'arco if ( abs( dCoeffY - dCoeffZ) > EPS_SMALL) return false ; // verifico non sia nulla if ( abs( dCoeffY) < EPS_ZERO || m_dRad * abs( dCoeffY) <= EPS_SMALL) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // scalo il centro e le dimensioni lineari m_PtCen.Scale( frRef, dCoeffX, dCoeffY, dCoeffY) ; m_dRad *= abs( dCoeffY) ; m_dDeltaN *= dCoeffX ; if ( dCoeffX < 0) m_VtS = - m_VtS ; // scalo vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Scale( frRef, dCoeffX, dCoeffY, dCoeffY) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } m_nStatus = TO_VERIFY ; // ritorno risultato della validazione return Validate() ; } // se riferimento con asse Y perpendicolare al piano dell'arco else if ( AreSameOrOppositeVectorApprox( m_VtN, frRef.VersY())) { // la scalatura deve essere uniforme nel piano dell'arco if ( abs( dCoeffZ - dCoeffX) > EPS_SMALL) return false ; // verifico non sia nulla if ( abs( dCoeffZ) < EPS_ZERO || m_dRad * abs( dCoeffZ) <= EPS_SMALL) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // scalo il centro e le dimensioni lineari m_PtCen.Scale( frRef, dCoeffZ, dCoeffY, dCoeffZ) ; m_dRad *= abs( dCoeffZ) ; m_dDeltaN *= dCoeffY ; if ( dCoeffY < 0) m_VtS = - m_VtS ; // scalo vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Scale( frRef, dCoeffZ, dCoeffY, dCoeffZ) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } m_nStatus = TO_VERIFY ; // ritorno risultato della validazione return Validate() ; } // altrimenti riferimento generico rispetto all'arco else { // la scalatura deve essere completamente uniforme if ( abs( dCoeffX - dCoeffY) > EPS_SMALL || abs( dCoeffX - dCoeffZ) > EPS_SMALL) return false ; // verifico non sia nulla if ( abs( dCoeffX) < EPS_ZERO || m_dRad * abs( dCoeffX) <= EPS_SMALL) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // scalo il centro e le dimensioni lineari m_PtCen.Scale( frRef, dCoeffX, dCoeffX, dCoeffX) ; m_dRad *= abs( dCoeffX) ; m_dDeltaN *= dCoeffX ; if ( dCoeffX < 0) m_VtS = - m_VtS ; // scalo vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Scale( frRef, dCoeffX, dCoeffX, dCoeffX) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } m_nStatus = TO_VERIFY ; // ritorno risultato della validazione 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 ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // 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 ; // specchio il vettore estrusione m_VtExtr.Mirror( vtNorm) ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità dei parametri if ( vtNorm.IsSmall() || vtDir.IsSmall()) return false ; // possibile solo se l'arco è piatto e il piano di scorrimento coincide con quello dell'arco if ( ! ( abs( m_dDeltaN) < EPS_SMALL) || ! AreSameOrOppositeVectorExact( m_VtN, vtNorm)) return false ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // eseguo scorrimento del centro m_PtCen.Shear( ptOn, vtNorm, vtDir, dCoeff) ; // eseguo scorrimento del vettore estrusione, lo normalizzo e aggiusto spessore m_VtExtr.Shear( vtNorm, vtDir, dCoeff) ; double dLen = m_VtExtr.Len() ; if ( dLen > EPS_ZERO) { m_VtExtr /= dLen ; m_dThick *= dLen ; } 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 ; // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; // trasformo Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->ToGlob( frRef) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo il centro e i versori return ( m_PtCen.ToGlob( frRef) && m_VtN.ToGlob( frRef) && m_VtS.ToGlob( frRef) && m_VtExtr.ToGlob( frRef)) ; } //---------------------------------------------------------------------------- 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 ; // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; // trasformo Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->ToLoc( frRef) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo il centro e i versori return ( m_PtCen.ToLoc( frRef) && m_VtN.ToLoc( frRef) && m_VtS.ToLoc( frRef) && m_VtExtr.ToLoc( frRef)) ; } //---------------------------------------------------------------------------- bool CurveArc::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità dei frame if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR) return false ; // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; // trasformo Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->LocToLoc( frOri, frDest) ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // trasformo il centro e i versori return ( m_PtCen.LocToLoc( frOri, frDest) && m_VtN.LocToLoc( frOri, frDest) && m_VtS.LocToLoc( frOri, frDest) && m_VtExtr.LocToLoc( frOri, frDest)) ; } //---------------------------------------------------------------------------- bool CurveArc::InvertN( void) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // si inverte il verso della normale senza modificare la geometria dell'arco m_VtN.Invert() ; m_dAngCenDeg = - m_dAngCenDeg ; m_dDeltaN = - m_dDeltaN ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::IsPointInSector( const Point3d& ptP) const { // verifico sia compreso nell'angolo al centro bool bDet ; double dAngDeg ; if ( ! m_VtS.GetRotation( ( ptP - m_PtCen), m_VtN, dAngDeg, bDet) || ! bDet) return false ; return AngleInSpan( dAngDeg, 0, m_dAngCenDeg) ; } //---------------------------------------------------------------------------- bool CurveArc::CalcPointAngle( const Point3d& ptP, double& dAngDeg) const { // verifico lo stato if ( m_nStatus != OK) return false ; // posizione angolare del punto rispetto al centro a partire dalla direzione start bool bDet ; if ( ! m_VtS.GetRotation( ( ptP - m_PtCen), m_VtN, dAngDeg, bDet) || ! bDet) return false ; if ( m_dAngCenDeg > 0 && dAngDeg < - EPS_ANG_ZERO) dAngDeg += ANG_FULL ; else if ( m_dAngCenDeg < 0 && dAngDeg > EPS_ANG_ZERO) dAngDeg -= ANG_FULL ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::MyCalcPointParamPosiz( const Point3d& ptP, double& dU, int& nPos, double dLinTol) const { // calcolo la posizione angolare double dAngDeg ; if ( ! CalcPointAngle( ptP, dAngDeg)) return false ; // calcolo parametro dU = dAngDeg / m_dAngCenDeg ; // verifica posizione punto su arco nPos = PP_NULL ; // fuori if ( abs( DiffAngle( dAngDeg, 0) * DEGTORAD * m_dRad) < dLinTol) { nPos = ( IsACircle() ? PP_MID : PP_START) ; // se cerchio è interno, altrimenti vicino a inizio dU = AngleNearAngle( dAngDeg, 0) / m_dAngCenDeg ; dU = max( dU, 0.) ; } else if ( abs( DiffAngle( dAngDeg, m_dAngCenDeg) * DEGTORAD * m_dRad) < dLinTol) { nPos = ( IsACircle() ? PP_MID : PP_END) ; // se cerchio è interno, altrimenti vicino a fine dU = AngleNearAngle( dAngDeg, m_dAngCenDeg) / m_dAngCenDeg ; dU = min( dU, 1.) ; } else if ( dU > 0 && dU < 1) nPos = PP_MID ; // nell'interno return true ; } //---------------------------------------------------------------------------- bool CurveArc::ChangeRadius( double dNewRadius) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico validità del raggio if ( ! ( dNewRadius > EPS_SMALL && dNewRadius < MAX_ARC_RAD)) return false ; // cambio il raggio m_dRad = dNewRadius ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // eseguo validazione m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::ChangeDeltaN( double dNewDeltaN) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // cambio il parametro m_dDeltaN = dNewDeltaN ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // eseguo validazione m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::ChangeAngCenter( double dNewAngCenDeg) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // verifico accettabilità angolo if ( ! ( abs( m_dAngCenDeg) > EPS_ANG_ZERO)) return false ; // cambio il parametro m_dAngCenDeg = dNewAngCenDeg ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; // eseguo validazione m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- bool CurveArc::ChangeStartPoint( double dU) { // la curva deve essere chiusa (ne verifica anche lo stato) if ( ! IsClosed()) return false ; // recupero il punto che corrisponde al valore del parametro Point3d ptP ; if ( ! GetPointD1D2( dU, ICurve::FROM_MINUS, ptP)) return false ; // cambio il versore start Vector3d vtDir = ptP - m_PtCen ; if ( ! vtDir.Normalize()) return false ; m_VtS = vtDir ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::ToExplementary( void) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // l'angolo al centro deve essere minore di un giro if ( abs( m_dAngCenDeg) > ( ANG_FULL - EPS_ANG_SMALL)) return false ; // basta prendere l'angolo al centro che completa il giro m_dAngCenDeg = - _copysign( ANG_FULL, m_dAngCenDeg) + m_dAngCenDeg ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::Flip( void) { // la curva deve essere validata if ( m_nStatus != OK) return false ; // l'angolo al centro deve essere minore di un giro if ( abs( m_dAngCenDeg) > ( ANG_FULL - EPS_ANG_SMALL)) return false ; // si calcola l'arco simmetrico rispetto alla linea che unisce gli estremi Point3d ptStart, ptEnd ; if ( ! GetStartPoint( ptStart) || ! GetEndPoint( ptEnd)) return false ; // il punto finale mi interessa nel piano dell'arco if ( abs( m_dDeltaN) > EPS_SMALL) ptEnd -= m_dDeltaN * m_VtN ; m_PtCen = ptStart + ( ptEnd - m_PtCen) ; m_VtS = ptStart - m_PtCen ; m_VtS.Normalize() ; m_dAngCenDeg = - m_dAngCenDeg ; // imposto ricalcolo di Voronoi ResetVoronoiObject() ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; m_nStatus = TO_VERIFY ; return Validate() ; } //---------------------------------------------------------------------------- // 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) { // 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 double dAngStepDeg ; double dLinTolRel = dLinTol / arArc.GetRadius() ; if ( bInside) dAngStepDeg = sqrt( 8 * dLinTolRel) * RADTODEG ; else dAngStepDeg = sqrt( 8 * dLinTolRel / ( 1 + dLinTolRel)) * RADTODEG ; dAngStepDeg = min( dAngStepDeg, dAngTolDeg) ; // dall'angolo al centro ricavo il numero di passi int nStep = int( abs( 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) { // 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 ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) 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 Vector3d vtA1p = m_vtA1 ; Vector3d 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 ( abs( m_dDeltaN) > 0.1 * EPS_SMALL) ptP += ( dU * m_dDeltaN) * m_VtN ; return true ; } //---------------------------------------------------------------------------- bool CurveArc::CalcVoronoiObject() const { if ( m_nStatus != OK) return false ; // creo oggetto vroni con la curva m_pVoronoiObj = new( std::nothrow) Voronoi( this, false) ; if ( m_pVoronoiObj == nullptr) return false ; return true ; } //---------------------------------------------------------------------------- Voronoi* CurveArc::GetVoronoiObject() const { if ( m_nStatus != OK) return nullptr ; // se non è stato calcolato, lo calcolo if ( m_pVoronoiObj == nullptr) CalcVoronoiObject() ; // restituisco Voronoi return m_pVoronoiObj ; } //---------------------------------------------------------------------------- void CurveArc::ResetVoronoiObject() const { if ( m_pVoronoiObj != nullptr) delete m_pVoronoiObj ; m_pVoronoiObj = nullptr ; }