//---------------------------------------------------------------------------- // 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 "GeoConst.h" #include "/EgtDev/Include/EGkArcPntDirTgCurve.h" #include "/EgtDev/Include/EGkDistPointLine.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_BEZIER : { 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 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 ( abs( 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 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 = abs( ptInt.x) ; Vector3d vtDir = ptP2 - ptP1 ; vtDir.Normalize() ; double dLen = dLenXY * vtDir.Len() / vtDir.LenXY() ; // con segno + Point3d PtTg1 = ptInt + dLen * vtDir ; PtrOwner 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 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 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 = (static_cast( 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 && abs( 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 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 = (static_cast( 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 && abs( 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 pCrvCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyArc( PA)) return nullptr ; // calcolo la circonferenza tangente a questa approssimazione Point3d ptTg ; PtrOwner pCrv( 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 = SQ_INFINITO ; PtrOwner pCrvNew ; for ( const ICurve* pCrv = crvCompo.GetFirstCurve() ; pCrv != nullptr ; pCrv = crvCompo.GetNextCurve()) { // recupero la circonferenza tangente alla curva elementare Point3d ptTg ; PtrOwner pCrvTmp( 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( pCrvTmp) ; if ( pPtTg != nullptr) *pPtTg = ptTg ; } } return Release( pCrvNew) ; }