//---------------------------------------------------------------------------- // 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 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 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) ; } //---------------------------------------------------------------------------- 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 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 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) ; }