//---------------------------------------------------------------------------- // EgalTech 2013-2014 //---------------------------------------------------------------------------- // File : LinePntTgCurve.cpp Data : 09.06.14 Versione : 1.5f4 // Contenuto : Implementazione funzioni per calcolo rette tangenti a curve. // // // // Modifiche : 09.06.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "LinePntTgCurve.h" #include "/EgtDev/Include/EgkGeoCollection.h" #include "/EgtDev/Include/EgkLinePntTgCurve.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- ICurveLine* GetLinePointTgCurve( const Point3d& ptP, const ICurve& cCrv, const Point3d& ptNear) { switch ( cCrv.GetType()) { case CRV_LINE : return nullptr ; case CRV_ARC : { const ICurveArc& crvArc = *GetCurveArc( &cCrv) ; return GetLinePointTgArc( ptP, crvArc, ptNear) ; } case CRV_BEZ : return nullptr ; case CRV_COMPO : return nullptr ; default : return nullptr ; } } //---------------------------------------------------------------------------- ICurveLine* GetLinePointTgArc( const Point3d& ptP, const ICurveArc& crvArc, const Point3d& ptNear) { // calcolo il riferimento intrinseco dell'arco (DirNorm->Z e DirStart->X) Frame3d frIntr ; if ( ! frIntr.Set( crvArc.GetCenter(), crvArc.GetNormVersor(), crvArc.GetStartVersor())) return nullptr ; // porto il punto nel riferimento intrinseco Point3d ptPLoc = ptP ; ptPLoc.ToLoc( frIntr) ; // calcolo le linee tangenti alla circonferenza BIPNTVECTOR vBiPnt( 2) ; int nSol = CalcLinePointTgCircle( ptPLoc, ORIG, crvArc.GetRadius(), vBiPnt) ; if ( nSol == 0) return nullptr ; // porto i punti nel riferimento standard dell'arco for ( size_t i = 0 ; i < vBiPnt.size() ; ++ i) { vBiPnt[i].first.ToGlob( frIntr) ; vBiPnt[i].second.ToGlob( frIntr) ; } // elimino le soluzioni che non stanno sull'arco for ( int i = 1 ; i >= 0 ; -- i) { if ( nSol > i) { if ( ! crvArc.IsPointOn( vBiPnt[i].second)) { -- nSol ; for ( int j = i ; j < nSol ; ++ j) vBiPnt[j] = vBiPnt[j+1] ; } } } // se non sono rimaste soluzioni, esco if ( nSol == 0) return nullptr ; // scelgo la soluzione più vicina al punto di riferimento int nIdOk = 0 ; double dMinSqDist = INFINITO * INFINITO ; for ( int i = 0 ; i < nSol ; ++ i) { double dSqDist = SqDist( vBiPnt[i].second, ptNear) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; nIdOk = i ; } } // creo la linea PtrOwner pCrvLine( CreateCurveLine()) ; if ( IsNull( pCrvLine)) return nullptr ; // costruisco la linea corrispondente alla soluzione scelta if ( pCrvLine->Set( vBiPnt[nIdOk].first, vBiPnt[nIdOk].second)) return Release( pCrvLine) ; else return nullptr ; } //---------------------------------------------------------------------------- int CalcLinePointTgCircle( const Point3d& ptP, const Point3d& ptCen, double dRad, BIPNTVECTOR& vBiPnt) { // --- si lavora nel piano XY --- // svuoto il vettore dei risultati (sono coppie di punti) vBiPnt.clear() ; // se il raggio è negativo non ci sono soluzioni if ( dRad < - EPS_SMALL) return 0 ; // vettore dal punto al centro nel piano XY e relativa lunghezza/distanza Vector3d vtPC = ptCen - ptP ; vtPC.z = 0 ; double dDist = vtPC.Len() ; // se il raggio è nullo ... if ( dRad < EPS_SMALL) { // se la distanza tra i punti è significativa, c'è una soluzione : la retta per i due punti if ( dDist > EPS_SMALL) { vBiPnt.push_back( make_pair( ptP, ptCen)) ; return 1 ; } // altrimenti, nessuna soluzione else return 0 ; } // se la distanza è inferiore o uguale al raggio non ci sono soluzioni (si esclude la retta tg nel punto P) if ( dDist < dRad + EPS_SMALL) return 0 ; // lunghezza delle tangenti double dLen = sqrt( dDist * dDist - dRad * dRad) ; // punto a metà tra i punti di tangenza Point3d ptK = ptP + vtPC * ( dLen * dLen / ( dDist * dDist)) ; // vettore ortogonale Vector3d vtOrtho = vtPC * ( dRad * dLen / ( dDist * dDist)) ; vtOrtho.Rotate( Z_AX, 0, 1) ; // tangente a destra Point3d ptT = ptK + vtOrtho ; ptT.z = ptCen.z ; vBiPnt.push_back( make_pair( ptP, ptT)) ; // tangente a sinistra ptT = ptK - vtOrtho ; ptT.z = ptCen.z ; vBiPnt.push_back( make_pair( ptP, ptT)) ; return 2 ; }