d0521e8f92
- sistemata approssimazione di curve di Bezier con archi - aggiunta a CurveBezier metodo per sapere se è collassata in un punto - in PolyArc e PolyLine sostituite Splice con Join e aggiunte Split - in TSC non si accetta più la creazione di una curva di Bezier collassata in un punto.
161 lines
4.9 KiB
C++
161 lines
4.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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<ICurveLine> 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 ;
|
|
}
|