2ed2a34d55
- modifiche per DistPointLine con interfaccia portata in Include.
250 lines
9.6 KiB
C++
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) ;
|
|
}
|