Files
EgtGeomKernel/CircleCenTgCurve.cpp
T
Dario Sassi 2ed2a34d55 EgtGeomKernel :
- modifiche per DistPointLine con interfaccia portata in Include.
2024-05-22 08:19:10 +02:00

250 lines
9.6 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : CircleCenTgCurve.cpp Data : 12.03.15 Versione : 1.6c2
// Contenuto : Implementazione funzioni per calcolo circonferenze di centro
// dato tangenti a curve.
//
//
// Modifiche : 12.03.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "CreateCurveAux.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkCircleCenTgCurve.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
static CurveArc* GetCircleCenTgLine( const Point3d& ptCen, const Vector3d& vtN, const CurveLine& crvLine,
const Point3d& ptNear, Point3d* pPtTg) ;
static CurveArc* GetCircleCenTgArc( const Point3d& ptCen, const Vector3d& vtN, const CurveArc& crvArc,
const Point3d& ptNear, Point3d* pPtTg) ;
static CurveArc* GetCircleCenTgBezier( const Point3d& ptCen, const Vector3d& vtN, const CurveBezier& crvBezier,
const Point3d& ptNear, Point3d* pPtTg) ;
static CurveArc* GetCircleCenTgCompo( const Point3d& ptCen, const Vector3d& vtN, const CurveComposite& crvCompo,
const Point3d& ptNear, Point3d* pPtTg) ;
//----------------------------------------------------------------------------
ICurveArc*
GetCircleCenTgCurve( const Point3d& ptCen, const Vector3d& vtN, const ICurve& cCrv, const Point3d& ptNear)
{
return GetCircleCenTgCurve( ptCen, vtN, cCrv, ptNear, nullptr) ;
}
//----------------------------------------------------------------------------
ICurveArc*
GetCircleCenTgCurve( const Point3d& ptCen, const Vector3d& vtN, const ICurve& cCrv, const Point3d& ptNear,
Point3d* pPtTg)
{
// verifica dei parametri
if ( &ptCen == nullptr || &vtN == nullptr || &cCrv == nullptr || &ptNear == nullptr)
return nullptr ;
// eseguo calcoli a seconda della curva tg
switch ( cCrv.GetType()) {
case CRV_LINE :
{ const CurveLine& crvLine = *GetBasicCurveLine( &cCrv) ;
return GetCircleCenTgLine( ptCen, vtN, crvLine, ptNear, pPtTg) ; }
case CRV_ARC :
{ const CurveArc& crvArc = *GetBasicCurveArc( &cCrv) ;
return GetCircleCenTgArc( ptCen, vtN, crvArc, ptNear, pPtTg) ; }
case CRV_BEZIER :
{ const CurveBezier& crvBezier = *GetBasicCurveBezier( &cCrv) ;
return GetCircleCenTgBezier( ptCen, vtN, crvBezier, ptNear, pPtTg) ; }
case CRV_COMPO :
{ const CurveComposite& crvCompo = *GetBasicCurveComposite( &cCrv) ;
return GetCircleCenTgCompo( ptCen, vtN, crvCompo, ptNear, pPtTg) ; }
default :
return nullptr ;
}
}
//----------------------------------------------------------------------------
CurveArc*
GetCircleCenTgLine( const Point3d& ptCen, const Vector3d& vtN, const CurveLine& crvLine,
const Point3d& ptNear, Point3d* pPtTg)
{
// devo considerare sempre la proiezione della linea sul piano della circonferenza
Point3d ptP1 = crvLine.GetStart() ;
Point3d ptP2 = crvLine.GetEnd() ;
ptP2 -= (( ptP2 - ptP1) * vtN) * vtN ;
// calcolo la proiezione perpendicolare del centro sulla linea
Point3d ptTg ;
if ( ! DistPointLine( ptCen, ptP1, ptP2, false).GetMinDistPoint( ptTg))
return nullptr ;
// verifico che stia sul segmento
if ( ! DistPointLine( ptTg, ptP1, ptP2).IsSmall())
return nullptr ;
// creo l'arco
PtrOwner<CurveArc> pCrvArc( CreateBasicCurveArc()) ;
if ( IsNull( pCrvArc))
return nullptr ;
// costruisco la circonferenza corrispondente alla soluzione scelta
double dRad = (( ptTg - ptCen) ^ vtN).Len() ;
if ( pCrvArc->Set( ptCen, vtN, dRad)) {
if ( pPtTg != nullptr)
*pPtTg = ptTg ;
return Release( pCrvArc) ;
}
else
return nullptr ;
}
//----------------------------------------------------------------------------
CurveArc*
GetCircleCenTgArc( const Point3d& ptCen, const Vector3d& vtN, const CurveArc& crvArc,
const Point3d& ptNear, Point3d* pPtTg)
{
// verifico che la normale della circonferenza coincida con quella dell'arco di tg
if ( ! AreSameOrOppositeVectorApprox( vtN, crvArc.GetNormVersor()))
return nullptr ;
// 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 ptCLoc = ptCen ;
ptCLoc.ToLoc( frIntr) ;
// calcolo le circonferenze tangenti alla circonferenza
BIPNTVECTOR vCenPtg( 2) ;
int nSol = CalcCircleCenTgCircle( ptCLoc, ORIG, crvArc.GetRadius(), vCenPtg) ;
if ( nSol == 0)
return nullptr ;
// porto i punti nel riferimento standard dell'arco
for ( size_t i = 0 ; i < vCenPtg.size() ; ++ i) {
vCenPtg[i].first.ToGlob( frIntr) ;
vCenPtg[i].second.ToGlob( frIntr) ;
}
// se l'arco di tangenza ha deltaN, devo applicarlo in proporzione a questi punti
if ( abs( crvArc.GetDeltaN()) > EPS_SMALL) {
for ( size_t i = 0 ; i < vCenPtg.size() ; ++ i) {
double dAngDeg ;
if ( crvArc.CalcPointAngle( vCenPtg[i].second, dAngDeg))
vCenPtg[i].second += crvArc.GetNormVersor() * crvArc.GetDeltaN() * dAngDeg / crvArc.GetAngCenter() ;
}
}
// elimino le soluzioni che non stanno sull'arco
for ( int i = 1 ; i >= 0 ; -- i) {
if ( nSol > i) {
if ( ! crvArc.IsPointOn( vCenPtg[i].second)) {
-- nSol ;
for ( int j = i ; j < nSol ; ++ j)
vCenPtg[j] = vCenPtg[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 = SQ_INFINITO ;
for ( int i = 0 ; i < nSol ; ++ i) {
double dSqDist = SqDist( vCenPtg[i].second, ptNear) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
nIdOk = i ;
}
}
// creo l'arco
PtrOwner<CurveArc> pCrvArc( CreateBasicCurveArc()) ;
if ( IsNull( pCrvArc))
return nullptr ;
// costruisco la circonferenza corrispondente alla soluzione scelta
double dRad = (( vCenPtg[nIdOk].second - vCenPtg[nIdOk].first) ^ vtN).Len() ;
if ( pCrvArc->Set( vCenPtg[nIdOk].first, vtN, dRad)) {
if ( pPtTg != nullptr)
*pPtTg = vCenPtg[nIdOk].second ;
return Release( pCrvArc) ;
}
else
return nullptr ;
}
//----------------------------------------------------------------------------
CurveArc*
GetCircleCenTgBezier( const Point3d& ptCen, const Vector3d& vtN, const CurveBezier& crvBezier,
const Point3d& ptNear, Point3d* pPtTg)
{
// calcolo approssimazione della curva di Bezier con archi e rette
PolyArc PA ;
if ( ! crvBezier.ApproxWithArcs( 10 * EPS_SMALL, ANG_TOL_STD_DEG, PA))
return nullptr ;
// la trasformo in curva composita
PtrOwner<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyArc( PA))
return nullptr ;
// calcolo la circonferenza tangente a questa approssimazione
Point3d ptTg ;
PtrOwner<CurveArc> pCrvArc( GetBasicCurveArc( GetCircleCenTgCurve( ptCen, vtN, *pCrvCompo, ptNear, &ptTg))) ;
if ( IsNull( pCrvArc))
return nullptr ;
// porto il punto di tangenza della circonferenza esattamente sulla curva di Bezier
DistPointCurve dstPtCurve( ptTg, crvBezier) ;
Point3d ptTg2 ;
int nFlag ;
if ( ! dstPtCurve.GetMinDistPoint( 0, ptTg2, nFlag))
return nullptr ;
// calcolo il nuovo raggio
double dRad = (( ptTg2 - ptCen) ^ vtN).Len() ;
// imposto il nuovo raggio
if ( ! pCrvArc->Set( ptCen, vtN, dRad))
return nullptr ;
// se richiesto, assegno il punto di tg
if ( pPtTg != nullptr)
*pPtTg = ptTg2 ;
// restituisco la circonferenza
return Release( pCrvArc) ;
}
//----------------------------------------------------------------------------
CurveArc*
GetCircleCenTgCompo( const Point3d& ptCen, const Vector3d& vtN, const CurveComposite& crvCompo,
const Point3d& ptNear, Point3d* pPtTg)
{
// ciclo sulla curva composita
double dMinSqDist = SQ_INFINITO ;
PtrOwner<CurveArc> pCrvArc ;
for ( const ICurve* pCrv = crvCompo.GetFirstCurve() ;
pCrv != nullptr ;
pCrv = crvCompo.GetNextCurve()) {
// recupero la circonferenza tangente alla curva elementare
Point3d ptTg ;
PtrOwner<CurveArc> pCrvAtmp( GetBasicCurveArc( GetCircleCenTgCurve( ptCen, vtN, *pCrv, ptNear, &ptTg))) ;
if ( IsNull( pCrvAtmp))
continue ;
// verifico se è la più vicina al punto desiderato
double dSqDist = SqDist( ptNear, ptTg) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
pCrvArc.Set( pCrvAtmp) ;
if ( pPtTg != nullptr)
*pPtTg = ptTg ;
}
}
return Release( pCrvArc) ;
}