//---------------------------------------------------------------------------- // 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 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 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 pCrvCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyArc( PA)) return nullptr ; // calcolo la circonferenza tangente a questa approssimazione Point3d ptTg ; PtrOwner 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 pCrvArc ; for ( const ICurve* pCrv = crvCompo.GetFirstCurve() ; pCrv != nullptr ; pCrv = crvCompo.GetNextCurve()) { // recupero la circonferenza tangente alla curva elementare Point3d ptTg ; PtrOwner 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) ; }