EgtGeomKernel 1.5k5 :
- sviluppo linee tangenti e perpendicolari a curve.
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2013-2014
|
||||
//----------------------------------------------------------------------------
|
||||
// File : LineTgTwoCurves.cpp Data : 25.11.14 Versione : 1.5k5
|
||||
// Contenuto : Implementazione funzioni per calcolo rette tangenti a curve.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Modifiche : 09.06.14 DS Creazione modulo.
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//--------------------------- Include ----------------------------------------
|
||||
#include "stdafx.h"
|
||||
#include "CreateCurveAux.h"
|
||||
#include "DistPointLine.h"
|
||||
#include "/EgtDev/Include/EgkLineTgTwoCurves.h"
|
||||
#include "/EgtDev/Include/EgtPointerOwner.h"
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static CurveLine* GetLineTgTwoLines( const CurveLine& crvLine1, const Point3d& ptNear1,
|
||||
const CurveLine& crvLine2, const Point3d& ptNear2) ;
|
||||
static CurveLine* GetLineTgLineArc( const CurveLine& crvLine1, const Point3d& ptNear1,
|
||||
const CurveArc& crvArc2, const Point3d& ptNear2) ;
|
||||
static CurveLine* GetLineTgTwoArcs( const CurveArc& crvArc1, const Point3d& ptNear1,
|
||||
const CurveArc& crvArc2, const Point3d& ptNear2) ;
|
||||
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*
|
||||
GetLineTgTwoCurves( const ICurve& cCrv1, const Point3d& ptNear1,
|
||||
const ICurve& cCrv2, const Point3d& ptNear2)
|
||||
{
|
||||
switch ( cCrv1.GetType()) {
|
||||
case CRV_LINE :
|
||||
{ const CurveLine& crvLine1 = *GetBasicCurveLine( &cCrv1) ;
|
||||
switch ( cCrv2.GetType()) {
|
||||
case CRV_LINE :
|
||||
{ const CurveLine& crvLine2 = *GetBasicCurveLine( &cCrv2) ;
|
||||
return GetLineTgTwoLines( crvLine1, ptNear1, crvLine2, ptNear2) ; }
|
||||
case CRV_ARC :
|
||||
{ const CurveArc& crvArc2 = *GetBasicCurveArc( &cCrv2) ;
|
||||
return GetLineTgLineArc( crvLine1, ptNear1, crvArc2, ptNear2) ; }
|
||||
case CRV_BEZ :
|
||||
return nullptr ;
|
||||
case CRV_COMPO :
|
||||
return nullptr ;
|
||||
default :
|
||||
return nullptr ;
|
||||
}
|
||||
} break ;
|
||||
case CRV_ARC :
|
||||
{ const CurveArc& crvArc1 = *GetBasicCurveArc( &cCrv1) ;
|
||||
switch ( cCrv2.GetType()) {
|
||||
case CRV_LINE :
|
||||
{ const CurveLine& crvLine2 = *GetBasicCurveLine( &cCrv2) ;
|
||||
CurveLine* pCrvLine = GetLineTgLineArc( crvLine2, ptNear2, crvArc1, ptNear1) ;
|
||||
if ( pCrvLine != nullptr)
|
||||
pCrvLine->Invert() ;
|
||||
return pCrvLine ; }
|
||||
case CRV_ARC :
|
||||
{ const CurveArc& crvArc2 = *GetBasicCurveArc( &cCrv2) ;
|
||||
return GetLineTgTwoArcs( crvArc1, ptNear1, crvArc2, ptNear2) ; }
|
||||
case CRV_BEZ :
|
||||
return nullptr ;
|
||||
case CRV_COMPO :
|
||||
return nullptr ;
|
||||
default :
|
||||
return nullptr ;
|
||||
}
|
||||
}
|
||||
case CRV_BEZ :
|
||||
return nullptr ;
|
||||
case CRV_COMPO :
|
||||
return nullptr ;
|
||||
default :
|
||||
return nullptr ;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CurveLine*
|
||||
GetLineTgTwoLines( const CurveLine& crvLine1, const Point3d& ptNear1,
|
||||
const CurveLine& crvLine2, const Point3d& ptNear2)
|
||||
{
|
||||
// le due linee devono essere allineate ( i punti dell'una devo appartenere all'altra)
|
||||
if ( ! DistPointLine( crvLine2.GetStart(), crvLine1, false).IsSmall() ||
|
||||
! DistPointLine( crvLine2.GetEnd(), crvLine1, false).IsSmall())
|
||||
return nullptr ;
|
||||
// ricavo i due punti sulle linee più vicini ai rispettivi near
|
||||
Point3d ptP1 ;
|
||||
if ( ! DistPointLine( ptNear1, crvLine1).GetMinDistPoint( ptP1))
|
||||
return nullptr ;
|
||||
Point3d ptP2 ;
|
||||
if ( ! DistPointLine( ptNear2, crvLine2).GetMinDistPoint( ptP2))
|
||||
return nullptr ;
|
||||
// creo la linea
|
||||
PtrOwner<CurveLine> pCrvLine( CreateBasicCurveLine()) ;
|
||||
if ( IsNull( pCrvLine))
|
||||
return nullptr ;
|
||||
// costruisco la linea
|
||||
if ( ! pCrvLine->Set( ptP1, ptP2))
|
||||
return nullptr ;
|
||||
// restituisco la linea
|
||||
return Release( pCrvLine) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CurveLine*
|
||||
GetLineTgLineArc( const CurveLine& crvLine1, const Point3d& ptNear1,
|
||||
const CurveArc& crvArc2, const Point3d& ptNear2)
|
||||
{
|
||||
// l'arco deve essere piatto (no elica)
|
||||
if ( ! crvArc2.IsFlat())
|
||||
return nullptr ;
|
||||
// versore della linea
|
||||
Vector3d vtDir1 ;
|
||||
if ( ! crvLine1.GetStartDir( vtDir1))
|
||||
return nullptr ;
|
||||
// la linea deve giacere nel piano dell'arco o parallelo
|
||||
if ( ! AreOrthoApprox( vtDir1, crvArc2.GetNormVersor()))
|
||||
return nullptr ;
|
||||
// vettore spostamento dal piano linea parallelo al piano arco a questo
|
||||
Vector3d vtMove = ( crvArc2.GetCenter() - crvLine1.GetStart()) * crvArc2.GetNormVersor() * crvArc2.GetNormVersor() ;
|
||||
// sposto il centro sul piano della linea parallelo a quello dell'arco
|
||||
Point3d ptCen = crvArc2.GetCenter() - vtMove ;
|
||||
// il centro deve distare dalla linea quanto il raggio
|
||||
DistPointLine dstPL( ptCen, crvLine1, false) ;
|
||||
double dDist ;
|
||||
if ( ! dstPL.GetDist( dDist) || fabs( dDist - crvArc2.GetRadius()) > EPS_SMALL)
|
||||
return nullptr ;
|
||||
// sposto il punto sulla circonferenza e verifico appartenga all'arco
|
||||
Point3d ptP2 ;
|
||||
dstPL.GetMinDistPoint( ptP2) ;
|
||||
ptP2 += vtMove ;
|
||||
if ( ! crvArc2.IsPointOn( ptP2))
|
||||
return nullptr ;
|
||||
// punto sulla linea vicino al desiderato
|
||||
Point3d ptP1 ;
|
||||
if ( ! DistPointLine( ptNear1, crvLine1).GetMinDistPoint( ptP1))
|
||||
return nullptr ;
|
||||
// creo la linea
|
||||
PtrOwner<CurveLine> pCrvLine( CreateBasicCurveLine()) ;
|
||||
if ( IsNull( pCrvLine))
|
||||
return nullptr ;
|
||||
// costruisco la linea
|
||||
if ( ! pCrvLine->Set( ptP1, ptP2))
|
||||
return nullptr ;
|
||||
// restituisco la linea
|
||||
return Release( pCrvLine) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CurveLine*
|
||||
GetLineTgTwoArcs( const CurveArc& crvArc1, const Point3d& ptNear1,
|
||||
const CurveArc& crvArc2, const Point3d& ptNear2)
|
||||
{
|
||||
// verifico che i due archi abbiano lo stesso piano intrinseco e siano piatti
|
||||
if ( ! AreSameOrOppositeVectorApprox( crvArc1.GetNormVersor(), crvArc2.GetNormVersor()) ||
|
||||
! crvArc1.IsFlat() || ! crvArc2.IsFlat())
|
||||
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<CurveLine> pCrvLine( CreateBasicCurveLine()) ;
|
||||
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 ;
|
||||
}
|
||||
Reference in New Issue
Block a user