//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : SelfIntersCurve.cpp Data : 06.07.15 Versione : 1.6g2 // Contenuto : Implementazione della classe auto-intersezione di curva. // // // // Modifiche : 06.07.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "GeoConst.h" #include "CurveArc.h" #include "CurveComposite.h" #include "IntersCrvCompoCrvCompo.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkDistPointCurve.h" using namespace std ; //---------------------------------------------------------------------------- SelfIntersCurve::SelfIntersCurve( const ICurve& Curve) { // Le auto-intersezioni sono calcolate nel piano XY locale. // inizializzazioni m_bOverlaps = false ; m_nNumInters = 0 ; m_pOriCrv = &Curve ; // se curva è arco da approssimare oppure è curva di Bezier if ( ( m_pOriCrv->GetType() == CRV_ARC && IsArcToApprox( *m_pOriCrv)) || m_pOriCrv->GetType() == CRV_BEZ) { // approssimo con rette PolyLine PL ; if ( ! m_pOriCrv->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return ; m_pTmpCrv.Set( CreateBasicCurveComposite()) ; if ( IsNull( m_pTmpCrv)) return ; if ( ! GetBasicCurveComposite( Get( m_pTmpCrv))->FromPolyLine( PL)) return ; m_pCurve = Get( m_pTmpCrv) ; } // altrimenti uso la curva originale else m_pCurve = m_pOriCrv ; // chiamo calcolatore opportuno switch ( m_pCurve->GetType()) { case CRV_LINE : // un segmento non può autointersecarsi (non considero auto-intersezione un segmento perpendicolare a XY) break ; case CRV_ARC : // un arco nel piano XY con angolo al centro non superiore al giro non può autointersecarsi break ; case CRV_COMPO : { IntersCrvCompoCrvCompo intCcCc( *GetCurveComposite( &Curve), *GetCurveComposite( &Curve)) ; if ( intCcCc.m_nNumInters > 0) { m_bOverlaps = intCcCc.m_bOverlaps ; m_nNumInters = intCcCc.m_nNumInters ; for ( int i = 0 ; i < m_nNumInters ; ++ i) m_Info.push_back( intCcCc.m_Info[i]) ; } } break ; } } //---------------------------------------------------------------------------- bool SelfIntersCurve::IsArcToApprox( const ICurve& Curve) { // recupero l'arco const CurveArc* pArc = GetBasicCurveArc( &Curve) ; if ( pArc == nullptr) return false ; // verifico se non è nel piano XY o ha più di un giro al centro return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) || fabs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetOverlaps( void) { return m_bOverlaps ; } //---------------------------------------------------------------------------- int SelfIntersCurve::GetNumInters( void) { return m_nNumInters ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) { if ( nInd < 0 || nInd >= m_nNumInters) return false ; aInfo = m_Info[nInd] ; // se curva originale approssimata, devo ricalcolare i parametri dei punti di intersezione if ( m_pCurve != m_pOriCrv) { if ( ! m_pOriCrv->GetParamAtPoint( aInfo.IciA[0].ptI, aInfo.IciA[0].dU, 10 * EPS_SMALL)) return false ; if ( aInfo.bOverlap && ! m_pOriCrv->GetParamAtPoint( aInfo.IciA[1].ptI, aInfo.IciA[1].dU, 10 * EPS_SMALL)) return false ; if ( ! m_pOriCrv->GetParamAtPoint( aInfo.IciB[0].ptI, aInfo.IciB[0].dU, 10 * EPS_SMALL)) return false ; if ( aInfo.bOverlap && ! m_pOriCrv->GetParamAtPoint( aInfo.IciB[1].ptI, aInfo.IciB[1].dU, 10 * EPS_SMALL)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetIntersPointNearTo( const Point3d& ptNear, Point3d& ptI) { if ( m_nNumInters == 0) return false ; // ricerca del punto più vicino tra le intersezioni singole bool bFound = false ; double dMinSqDist = INFINITO * INFINITO ; for ( int i = 0 ; i < m_nNumInters ; ++ i) { // se è un'intersezione singola if ( ! m_Info[i].bOverlap) { // faccio la verifica sul punto Point3d ptP = m_Info[i].IciA[0].ptI ; double dSqDist = SqDist( ptNear, ptP) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; ptI = ptP ; bFound = true ; } } // altrimenti else { // recupero il tratto di sovrapposizione double dUStartTrim, dUEndTrim ; dUStartTrim = m_Info[i].IciA[0].dU ; dUEndTrim = m_Info[i].IciA[1].dU ; PtrOwner pCrv( m_pCurve->CopyParamRange( dUStartTrim, dUEndTrim)) ; if ( IsNull( pCrv)) continue ; // cerco il punto int nFlag ; Point3d ptP ; if ( DistPointCurve( ptNear, *pCrv).GetMinDistPoint( 0.5, ptP, nFlag)) { // faccio la verifica double dSqDist = SqDist( ptNear, ptP) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; ptI = ptP ; bFound = true ; } } } } return bFound ; }