Files
EgtGeomKernel/ArcPntDirTgCurve.cpp
T
Dario Sassi 6c14e51ef6 EgtGeomKernel 1.6c2 :
- aggiunte funzioni per circonferenze e archi tangenti.
2015-03-16 07:38:43 +00:00

347 lines
14 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : ArcPntDirTgCurve.cpp Data : 13.03.15 Versione : 1.6c2
// Contenuto : Implementazione funzioni per calcolo arco dato punto iniziale
// direzione e tangente a curva.
//
//
// Modifiche : 13.03.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "CreateCurveAux.h"
#include "DistPointLine.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EgkArcPntDirTgCurve.h"
#include "/EgtDev/Include/EgkDistPointCurve.h"
#include "/EgtDev/Include/EgkArcSpecial.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
//----------------------------------------------------------------------------
static ICurve* GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
static ICurve* GetArcPntDirTgLine( const Point3d& ptP, const Vector3d& vtDir, const CurveLine& crvLine,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
static ICurve* GetArcPntDirTgArc( const Point3d& ptP, const Vector3d& vtDir, const CurveArc& crvArc,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
static ICurve* GetArcPntDirTgBezier( const Point3d& ptP, const Vector3d& vtDir, const CurveBezier& crvBezier,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
static ICurve* GetArcPntDirTgCompo( const Point3d& ptP, const Vector3d& vtDir, const CurveComposite& crvCompo,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg) ;
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
const Point3d& ptNear, const Vector3d& vtN)
{
return GetArcPntDirTgCurve( ptP, vtDir, cCrv, ptNear, vtN, nullptr) ;
}
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgCurve( const Point3d& ptP, const Vector3d& vtDir, const ICurve& cCrv,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
{
// verifica dei parametri
if ( &ptP == nullptr || &vtDir == 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 GetArcPntDirTgLine( ptP, vtDir, crvLine, ptNear, vtN, pPtTg) ; }
case CRV_ARC :
{ const CurveArc& crvArc = *GetBasicCurveArc( &cCrv) ;
return GetArcPntDirTgArc( ptP, vtDir, crvArc, ptNear, vtN, pPtTg) ; }
case CRV_BEZ :
{ const CurveBezier& crvBezier = *GetBasicCurveBezier( &cCrv) ;
return GetArcPntDirTgBezier( ptP, vtDir, crvBezier, ptNear, vtN, pPtTg) ; }
case CRV_COMPO :
{ const CurveComposite& crvCompo = *GetBasicCurveComposite( &cCrv) ;
return GetArcPntDirTgCompo( ptP, vtDir, crvCompo, ptNear, vtN, pPtTg) ; }
default :
return nullptr ;
}
}
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgLine( const Point3d& ptP, const Vector3d& vtDir, const CurveLine& crvLine,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
{
// calcolo il riferimento intrinseco dell'arco da creare (DirNorm->Z e DirStart->X)
Frame3d frIntr ;
if ( ! frIntr.Set( ptP, vtN, vtDir))
return nullptr ;
// porto la linea di tangenza in questo riferimento
CurveLine crvLineL = crvLine ;
crvLineL.ToLoc( frIntr) ;
// inclinazione della linea
Point3d ptP1 = crvLineL.GetStart() ;
Point3d ptP2 = crvLineL.GetEnd() ;
// se linea perpendicolare al piano XY
if ( AreSamePointXYApprox( ptP1, ptP2)) {
Point3d ptTg( ptP1.x, ptP1.y, 0) ;
PtrOwner<ICurve> pCrv( GetArc2PD( ORIG, ptTg, 0)) ;
if ( ! IsNull( pCrv) && pCrv->ToGlob( frIntr)) {
if ( pPtTg != nullptr) {
ptTg.ToGlob( frIntr) ;
*pPtTg = ptTg ;
}
return Release( pCrv) ;
}
else
return nullptr ;
}
// se linea parallela all'asse X
else if ( fabs( ptP2.y - ptP1.y) < EPS_SMALL) {
Point3d ptTg( 0, ptP1.y, ptP1.z + ( 0 - ptP1.x) * ( ptP2.z - ptP1.z) / ( ptP2.x - ptP1.x)) ;
PtrOwner<ICurve> pCrv( GetArc2PD( ORIG, ptTg, 0)) ;
if ( ! IsNull( pCrv) && pCrv->ToGlob( frIntr)) {
if ( pPtTg != nullptr) {
ptTg.ToGlob( frIntr) ;
*pPtTg = ptTg ;
}
return Release( pCrv) ;
}
else
return nullptr ;
}
// altrimenti linea inclinata
else {
// intersezione con asse X (linea di direzione nel riferimento intrinseco)
double dCoeff = ( 0 - ptP1.y) / ( ptP2.y - ptP1.y) ;
Point3d ptInt( ptP1.x + dCoeff * ( ptP2.x - ptP1.x), 0, ptP1.z + dCoeff * ( ptP2.z - ptP1.z)) ;
// punto distante da intersezione in XY come intersezione da origine
double dLenXY = fabs( ptInt.x) ;
Vector3d vtDir = ptP2 - ptP1 ;
vtDir.Normalize() ;
double dLen = dLenXY * vtDir.Len() / vtDir.LenXY() ;
// con segno +
Point3d PtTg1 = ptInt + dLen * vtDir ;
PtrOwner<ICurve> pCrv1( GetArc2PD( ORIG, PtTg1, 0)) ;
bool bOk1 = ( ! IsNull( pCrv1)) ;
// porto l'arco nel riferimento locale
bOk1 = bOk1 && pCrv1->ToGlob( frIntr) ;
// recupero il punto finale (è quello di tangenza)
Point3d ptEnd1 ;
bOk1 = bOk1 && pCrv1->GetEndPoint( ptEnd1) ;
// verifico se il punto di tangenza sta sul segmento
bOk1 = bOk1 && crvLine.IsPointOn( ptEnd1) ;
// con segno -
Point3d PtTg2 = ptInt - dLen * vtDir ;
PtrOwner<ICurve> pCrv2( GetArc2PD( ORIG, PtTg2, 0)) ;
bool bOk2 = ( ! IsNull( pCrv2)) ;
// porto l'arco nel riferimento locale
bOk2 = bOk2 && pCrv2->ToGlob( frIntr) ;
// recupero il punto finale (è quello di tangenza)
Point3d ptEnd2 ;
bOk2 = bOk2 && pCrv2->GetEndPoint( ptEnd2) ;
// verifico se il punto di tangenza sta sul segmento
bOk2 = bOk2 && crvLine.IsPointOn( ptEnd2) ;
// se due soluzioni, verifico quale ha il punto di tg più vicino al richiesto
if ( bOk1 && bOk2) {
if ( SqDist( ptEnd1, ptNear) <= SqDist( ptEnd2, ptNear))
bOk2 = false ;
else
bOk1 = false ;
}
// restituisco la soluzione
if ( bOk1) {
if ( pPtTg != nullptr)
*pPtTg = ptEnd1 ;
return Release( pCrv1) ;
}
else if ( bOk2) {
if ( pPtTg != nullptr)
*pPtTg = ptEnd2 ;
return Release( pCrv2) ;
}
else
return nullptr ;
}
}
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgArc( const Point3d& ptP, const Vector3d& vtDir, const CurveArc& crvArc,
const Point3d& ptNear, const Vector3d& vtN, 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 da creare (DirNorm->Z e DirStart->X)
Frame3d frIntr ;
if ( ! frIntr.Set( ptP, vtN, vtDir))
return nullptr ;
// porto l'arco di tangenza in questo riferimento
CurveArc crvArcL = crvArc ;
crvArcL.ToLoc( frIntr) ;
// versore ortogonale alla direzione iniziale (ora si lavora nel piano XY locale)
Vector3d vtOrtho = Y_AX ;
// angolo direzione iniziale
bool bOutSide = ( DistXY( ORIG, crvArcL.GetCenter()) >= crvArcL.GetRadius()) ;
// calcolo arco spostando il punto iniziale di + raggio in direzione ortogonale
Point3d ptP1 = ORIG + vtOrtho * crvArcL.GetRadius() ;
PtrOwner<ICurve> pCrv1( GetArc2PD( ptP1, crvArcL.GetCenter(), ( bOutSide ? 0 : 180))) ;
bool bOk1 = ( ! IsNull( pCrv1)) ;
// compenso lo spostamento ( più -> offset a destra)
if ( bOk1) {
double dOffset = ( bOutSide ? crvArcL.GetRadius() : - crvArcL.GetRadius()) ;
if ( pCrv1->GetType() == CRV_ARC)
bOk1 = (dynamic_cast<CurveArc*>(Get(pCrv1)))->ExtendedOffset( dOffset) ;
else
bOk1 = pCrv1->SimpleOffset( dOffset) ;
}
// porto l'arco nel riferimento locale
bOk1 = bOk1 && pCrv1->ToGlob( frIntr) ;
// recupero il punto finale (è quello di tangenza)
Point3d ptEnd1 ;
bOk1 = bOk1 && pCrv1->GetEndPoint( ptEnd1) ;
// se l'arco di tangenza ha deltaN, devo considerarne quota parte
if ( bOk1 && fabs( crvArc.GetDeltaN()) > EPS_SMALL) {
double dAngDeg ;
if ( crvArc.CalcPointAngle( ptEnd1, dAngDeg)) {
ptEnd1 += crvArc.GetNormVersor() * crvArc.GetDeltaN() * dAngDeg / crvArc.GetAngCenter() ;
bOk1 = bOk1 && pCrv1->ModifyEnd( ptEnd1) ;
}
else
bOk1 = false ;
}
// verifico se il punto di tangenza sta sull'arco
else
bOk1 = bOk1 && crvArc.IsPointOn( ptEnd1) ;
// calcolo arco spostando il punto iniziale di - raggio in direzione ortogonale
Point3d ptP2 = ORIG - vtOrtho * crvArcL.GetRadius() ;
PtrOwner<ICurve> pCrv2( GetArc2PD( ptP2, crvArcL.GetCenter(), ( bOutSide ? 0 : 180))) ;
bool bOk2 = ( ! IsNull( pCrv2)) ;
// compenso lo spostamento ( meno -> offset a sinistra)
if ( bOk2) {
double dOffset = ( bOutSide ? - crvArcL.GetRadius() : crvArcL.GetRadius()) ;
if ( pCrv2->GetType() == CRV_ARC)
bOk2 = (dynamic_cast<CurveArc*>(Get(pCrv2)))->ExtendedOffset( dOffset) ;
else
bOk2 = pCrv2->SimpleOffset( dOffset) ;
}
// porto l'arco nel riferimento locale
bOk2 = bOk2 && pCrv2->ToGlob( frIntr) ;
// recupero il punto finale (è quello di tangenza)
Point3d ptEnd2 ;
bOk2 = bOk2 && pCrv2->GetEndPoint( ptEnd2) ;
// se l'arco di tangenza ha deltaN, devo considerarne quota parte
if ( bOk2 && fabs( crvArc.GetDeltaN()) > EPS_SMALL) {
double dAngDeg ;
if ( crvArc.CalcPointAngle( ptEnd2, dAngDeg)) {
ptEnd2 += crvArc.GetNormVersor() * crvArc.GetDeltaN() * dAngDeg / crvArc.GetAngCenter() ;
bOk2 = bOk2 && pCrv2->ModifyEnd( ptEnd2) ;
}
else
bOk2 = false ;
}
// verifico se il punto di tangenza sta sull'arco
else
bOk2 = bOk2 && crvArc.IsPointOn( ptEnd2) ;
// se due soluzioni, verifico quale ha il punto di tg più vicino al richiesto
if ( bOk1 && bOk2) {
if ( SqDist( ptEnd1, ptNear) <= SqDist( ptEnd2, ptNear))
bOk2 = false ;
else
bOk1 = false ;
}
// restituisco la soluzione
if ( bOk1) {
if ( pPtTg != nullptr)
*pPtTg = ptEnd1 ;
return Release( pCrv1) ;
}
else if ( bOk2) {
if ( pPtTg != nullptr)
*pPtTg = ptEnd2 ;
return Release( pCrv2) ;
}
else
return nullptr ;
}
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgBezier( const Point3d& ptP, const Vector3d& vtDir, const CurveBezier& crvBezier,
const Point3d& ptNear, const Vector3d& vtN, 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<ICurve> pCrv( GetCurve( GetArcPntDirTgCurve( ptP, vtDir, *pCrvCompo, ptNear, vtN, &ptTg))) ;
if ( IsNull( pCrv))
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 arco
pCrv.Set( GetArc2PVN( ptP, ptTg2, vtDir, vtN)) ;
if ( IsNull( pCrv))
return nullptr ;
// se richiesto, assegno il punto di tg
if ( pPtTg != nullptr)
*pPtTg = ptTg2 ;
// restituisco la circonferenza
return Release( pCrv) ;
}
//----------------------------------------------------------------------------
ICurve*
GetArcPntDirTgCompo( const Point3d& ptP, const Vector3d& vtDir, const CurveComposite& crvCompo,
const Point3d& ptNear, const Vector3d& vtN, Point3d* pPtTg)
{
// ciclo sulla curva composita
double dMinSqDist = INFINITO * INFINITO ;
PtrOwner<ICurve> pCrvNew ;
for ( const ICurve* pCrv = crvCompo.GetFirstCurve() ;
pCrv != nullptr ;
pCrv = crvCompo.GetNextCurve()) {
// recupero la circonferenza tangente alla curva elementare
Point3d ptTg ;
PtrOwner<ICurve> pCrvTmp( GetCurve( GetArcPntDirTgCurve( ptP, vtDir, *pCrv, ptNear, vtN, &ptTg))) ;
if ( IsNull( pCrvTmp))
continue ;
// verifico se è la più vicina al punto desiderato
double dSqDist = SqDist( ptNear, ptTg) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
pCrvNew.Set( Release( pCrvTmp)) ;
if ( pPtTg != nullptr)
*pPtTg = ptTg ;
}
}
return Release( pCrvNew) ;
}