Files
EgtGeomKernel/BiArcs.cpp
T
Dario Sassi de246fc3e7 EgtGeomKernel :
- ricompilazione.
2014-08-18 08:58:56 +00:00

160 lines
6.2 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2014
//----------------------------------------------------------------------------
// File : BiArcs.cpp Data : 30.07.14 Versione : 1.5g4
// Contenuto : Implementazione funzioni per calcolo biarchi.
//
//
//
// Modifiche : 30.07.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "/EgtDev/Include/EGkAngle.h"
#include "/EgtDev/Include/EgkBiArcs.h"
#include "/EgtDev/Include/EgkCurveLine.h"
#include "/EgtDev/Include/EgkCurveComposite.h"
#include "/EgtDev/Include/EgkArcXxTgArc.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
static ICurve* CalcJCurve( const Point3d& ptP0, double dDir0Deg, const Point3d& ptP1, double dDir1Deg) ;
//----------------------------------------------------------------------------
ICurve*
GetBiArc( const Point3d& ptP0, double dDir0Deg, const Point3d& ptP1, double dDir1Deg, double dU)
{
// calcolo la curva dove giacciono i punti di giunzione tra i due archi del biarco
PtrOwner<ICurve> pJCrv( CalcJCurve( ptP0, dDir0Deg, ptP1, dDir1Deg)) ;
if ( ! ::IsValid( pJCrv))
return nullptr ;
// limito il parametro nell'intervallo 0 - 1
if ( dU < 0)
dU = 0 ;
else if ( dU > 1)
dU = 1 ;
// recupero il punto di giunzione
Point3d ptJ ;
if ( ! pJCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptJ))
return nullptr ;
// preparo la curva composita per i biarchi
PtrOwner<ICurveComposite> pBiArc( CreateCurveComposite()) ;
if ( ! IsValid( pBiArc))
return nullptr ;
// calcolo la curva dal punto iniziale alla giunzione
if ( ! AreSamePointApprox( ptP0, ptJ)) {
ICurve* pCrv = GetArc2PD( ptP0, ptJ, dDir0Deg) ;
if ( pCrv == nullptr)
return nullptr ;
pBiArc->AddCurve( pCrv) ;
}
// calcolo la curva dalla giunzione al punto finale
if ( ! AreSamePointApprox( ptJ, ptP1)) {
// curva dal punto finale, direzione opposta alla giunzione
ICurve* pCrv = GetArc2PD( ptP1, ptJ, dDir1Deg + ANG_STRAIGHT) ;
if ( pCrv == nullptr)
return nullptr ;
// inverto la curva
pCrv->Invert() ;
pBiArc->AddCurve( pCrv) ;
}
// se il biarco non esiste
if ( pBiArc->GetCurveNumber() == 0)
return nullptr ;
return ::Release( pBiArc) ;
}
//----------------------------------------------------------------------------
ICurve*
GetBiArc( const PolyLine& PL, double dU0, double dDir0Deg, double dU1, double dDir1Deg)
{
// recupero i punti estremi della parte di interesse della polilinea
//double dU ;
//Point3d ptP, ptP0, ptP1 ;
//for ( bool bFound = PL.GetFirstUPoint( dU, &ptP) ;
// bFound ;
// bFound = PL.GetNextUPoint( dU, &ptP)) {
//}
// calcolo la curva dove giacciono i punti di giunzione tra i due archi del biarco
//PtrOwner<ICurve> pJCrv( CalcJCurve( ptP0, dDir0Deg, ptP1, dDir1Deg)) ;
//if ( ! ::IsValid( pJCrv))
// return nullptr ;
return nullptr ;
}
//----------------------------------------------------------------------------
static ICurve*
CalcJCurve( const Point3d& ptP0, double dDir0Deg, const Point3d& ptP1, double dDir1Deg)
{
// se i due punti coincidono, non si può fare alcunché
if ( AreSamePointApprox( ptP0, ptP1))
return nullptr ;
// angolo di rotazione dalla prima direzione alla seconda -> angolo al centro
double dAngDeg = DiffAngle( dDir1Deg, dDir0Deg) ;
// se rotazione nulla, allora segmento di retta tra i due punti
if ( fabs( dAngDeg) < EPS_ANG_SMALL) {
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
if ( ! ::IsValid( pLine) || ! pLine->Set( ptP0, ptP1))
return nullptr ;
// inverto per avere parametrizzazione crescente allontanandosi da Dir0 e avvicinandosi a Dir1
pLine->Invert() ;
return ::Release( pLine) ;
}
// caso generico
Point3d ptMed = 0.5 * ( ptP0 + ptP1) ;
ptMed.z = ptP0.z ;
Vector3d vtDiff = ptMed - ptP0 ;
double dHalfDist = vtDiff.LenXY() ;
vtDiff /= dHalfDist ;
double dDirDiffDeg ;
vtDiff.ToSpherical( nullptr, nullptr, &dDirDiffDeg) ;
double dH = dHalfDist / tan( 0.5 * dAngDeg * DEGTORAD) ;
vtDiff.Rotate( Z_AX, 0, 1) ;
Point3d ptCen = ptMed + dH * vtDiff ;
Vector3d vtStart = ptP0 - ptCen ;
double dRad, dAngStart ;
vtStart.ToSpherical( &dRad, nullptr, &dAngStart) ;
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ;
if ( ! ::IsValid( pArc) || ! pArc->SetXY( ptCen, dRad, dAngStart, dAngDeg, ( ptP1.z - ptP0.z)))
return nullptr ;
double dDirStartDeg = dAngStart + ( dAngDeg > 0 ? ANG_RIGHT : - ANG_RIGHT) ;
// determinazione regione tra le curve estreme in cui contenere l'arco (tramite angoli su start)
// direzione iniziale arco rispetto a direzione P0->P1
double dDirStartRelDeg = DiffAngle( dDirStartDeg, dDirDiffDeg) ;
// direzione iniziale primo arco limite rispetto a direzione P0->P1
double dDir0RelDeg = DiffAngle( dDir0Deg, dDirDiffDeg) ;
// direzione iniziale secondo arco limite rispetto a direzione P0->P1 (dalla finale simmetrico e invert)
double dDir1RelDeg = - DiffAngle( dDir1Deg, dDirDiffDeg) ;
// nel caso di direzioni a 180deg si sceglie la più compatta
if ( fabs( fabs( dDir1RelDeg) - ANG_STRAIGHT) < EPS_SMALL)
dDir1RelDeg = ( dDir0RelDeg > 0 ? ANG_STRAIGHT : - ANG_STRAIGHT) ;
else if ( fabs( fabs( dDir0RelDeg) - ANG_STRAIGHT) < EPS_SMALL)
dDir0RelDeg = ( dDir1RelDeg > 0 ? ANG_STRAIGHT : - ANG_STRAIGHT) ;
// intervallo angolare ammissibile a partire da direzione iniziale primo arco ammissibile ( == Dir0)
double dDeltaAngDeg = - dDir0RelDeg + dDir1RelDeg ;
// se non è nella regione, prendo l'altra parte di arco
if ( ! AngleInSpan( dDirStartRelDeg, dDir0RelDeg, dDeltaAngDeg))
pArc->ToAdditional() ;
// inverto per avere parametrizzazione crescente allontanandosi da Dir0 e avvicinandosi a Dir1
pArc->Invert() ;
return ::Release( pArc) ;
}