Files
EgtGeomKernel/LineTgTwoArcs.cpp
T
Dario Sassi c7d10b83e1 EgtGeomKernel 1.5h7 :
- modificta gestione versione dei file Nge
- alle curve aggiunti vettore estrusione e spessore
- IsFlat ora tiene conto del vettore estrusione
- a TSC aggiunte CurveModify.EXTRusion e CurveModify.THickness.
2014-08-25 17:12:55 +00:00

240 lines
8.2 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2014
//----------------------------------------------------------------------------
// File : LineTgArc.cpp Data : 09.06.14 Versione : 1.5f4
// Contenuto : Implementazione funzioni per calcolo rette tangenti a circonferenze
//
//
//
// Modifiche : 09.06.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "LinePntTgCurve.h"
#include "CurveArc.h"
#include "/EgtDev/Include/EgkGeoCollection.h"
#include "/EgtDev/Include/EgkLineTgTwoArcs.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
static int CalcLineExtTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt) ;
static int CalcLineIntTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt) ;
static int CalcLineTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt) ;
//----------------------------------------------------------------------------
ICurveLine*
GetLineTgTwoArcs( const ICurveArc& crvArc1, const Point3d& ptNear1,
const ICurveArc& crvArc2, const Point3d& ptNear2)
{
// verifico che i due archi abbiano lo stesso piano intrinseco
if ( ! AreSameOrOppositeVectorApprox( crvArc1.GetNormVersor(), crvArc2.GetNormVersor()))
return nullptr ;
// calcolo il riferimento intrinseco del primo arco (Z->DirNorm e X->DirStart)
Frame3d frIntr ;
if ( ! frIntr.Set( crvArc1.GetCenter(), crvArc1.GetNormVersor(), crvArc1.GetStartVersor()))
return nullptr ;
// porto il secondo arco nel riferimento intrinseco del primo
CurveArc crvArc2Loc = dynamic_cast<const CurveArc&>( crvArc2) ;
crvArc2Loc.ToLoc( frIntr) ;
// calcolo le linee di tangenza alle due circonferenze
BIPNTVECTOR vBiPnt( 4) ;
int nSol = CalcLineTg2Circles( ORIG, crvArc1.GetRadius(), crvArc2Loc.GetCenter(), crvArc2Loc.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 = 3 ; i >= 0 ; -- i) {
if ( nSol > i) {
if ( ! crvArc1.IsPointOn( vBiPnt[i].first) ||
! crvArc2.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 ai punti di riferimento
int nIdOk = 0 ;
double dMinDist = INFINITO ;
for ( int i = 0 ; i < nSol ; ++ i) {
double dDist = Dist( vBiPnt[i].first, ptNear1) + Dist( vBiPnt[i].second, ptNear2) ;
if ( dDist < dMinDist) {
dMinDist = dDist ;
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
CalcLineExtTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt)
{
// deve essere dRad2 >= dRad1
if ( dRad2 < dRad1)
return 0 ;
// inizializzo il numero di soluzioni
int nSol = 0 ;
// tangenti p.to - circonf. riducendo le circonferenze della differenza dei raggi
BIPNTVECTOR vAuxBiPnt( 2) ;
int nSol1 = CalcLinePointTgCircle( ptC1, ptC2, ( dRad2 - dRad1), vAuxBiPnt) ;
// offsetto i risultati di dRad1
if ( nSol1 == 1) {
Vector3d vtDir ;
Point3d ptT1, ptT2 ;
// direzione della retta
vtDir = ptC2 - ptC1 ;
vtDir.Normalize() ;
vtDir.Rotate( Z_AX, 0, 1) ;
vtDir *= dRad1 ;
// offset a sinistra
ptT1 = ptC1 + vtDir ;
ptT2 = ptC2 + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
// offset a destra
ptT1 = ptC1 - vtDir ;
ptT2 = ptC2 - vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
}
else if ( nSol1 == 2) {
Vector3d vtDir ;
Point3d ptT1, ptT2 ;
// direzione di offset della prima retta
vtDir = vAuxBiPnt[0].second - ptC2 ;
vtDir *= dRad1 / ( dRad2 - dRad1) ;
// punti della prima retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[0].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
// direzione di offset della seconda retta
vtDir = vAuxBiPnt[1].second - ptC2 ;
vtDir *= dRad1 / ( dRad2 - dRad1) ;
// punti della seconda retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[1].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
}
return nSol ;
}
//----------------------------------------------------------------------------
int
CalcLineIntTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt)
{
// inizializzo il numero di soluzioni
int nSol = 0 ;
// tangenti p.to - circonf. riducendo la prima a un punto e aumentando la prima di dRad1
BIPNTVECTOR vAuxBiPnt( 2) ;
int nSol1 = CalcLinePointTgCircle( ptC1, ptC2, ( dRad2 + dRad1), vAuxBiPnt) ;
// non può esserci una sola soluzione
if ( nSol1 == 1) {
nSol = 0 ;
}
// sposto le rette di dRad1
else if ( nSol1 == 2) {
Vector3d vtDir ;
Point3d ptT1, ptT2 ;
// direzione di offset della prima retta
vtDir = ptC2 - vAuxBiPnt[0].second ;
vtDir *= dRad1 / ( dRad1 + dRad2) ;
// punti della prima retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[0].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
// direzione di offset della seconda retta
vtDir = ptC2 - vAuxBiPnt[1].second ;
vtDir *= dRad1 / ( dRad1 + dRad2) ;
// punti della seconda retta
ptT1 = ptC1 + vtDir ;
ptT2 = vAuxBiPnt[1].second + vtDir ;
vBiPnt.push_back( make_pair( ptT1, ptT2)) ;
++ nSol ;
}
return nSol ;
}
//----------------------------------------------------------------------------
int
CalcLineTg2Circles( const Point3d& ptC1, double dRad1, const Point3d& ptC2, double dRad2, BIPNTVECTOR& vBiPnt)
{
// --- si lavora nel piano XY ---
// svuoto il vettore dei risultati (sono coppie di punti)
vBiPnt.clear() ;
// se uno dei due raggi è negativo non ci sono soluzioni
if ( dRad1 < - EPS_SMALL || dRad2 < - EPS_SMALL)
return 0 ;
// se almeno uno dei due raggi è nullo, si cade nel caso di linea per p.to tangente a circonferenza
if ( dRad1 < EPS_SMALL)
return CalcLinePointTgCircle( ptC1, ptC2, dRad2, vBiPnt) ;
else if ( dRad2 < EPS_SMALL) {
int nSol = CalcLinePointTgCircle( ptC2, ptC1, dRad1, vBiPnt) ;
if ( nSol >= 1)
swap( vBiPnt[0].first, vBiPnt[0].second) ;
if ( nSol == 2)
swap( vBiPnt[1].first, vBiPnt[1].second) ;
}
// numero di soluzioni trovate (il numero di punti è il doppio)
int nSol = 0 ;
// calcolo delle tangenti esterne
if ( dRad2 >= dRad1) {
nSol += CalcLineExtTg2Circles( ptC1, dRad1, ptC2, dRad2, vBiPnt) ;
}
else {
nSol += CalcLineExtTg2Circles( ptC2, dRad2, ptC1, dRad1, vBiPnt) ;
if ( nSol >= 1)
swap( vBiPnt[0].first, vBiPnt[0].second) ;
if ( nSol == 2)
swap( vBiPnt[1].first, vBiPnt[1].second) ;
}
// calcolo delle tangenti interne
nSol += CalcLineIntTg2Circles( ptC1, dRad1, ptC2, dRad2, vBiPnt) ;
return nSol ;
}