//---------------------------------------------------------------------------- // 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" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- SelfIntersCurve::SelfIntersCurve( const ICurve& Curve) { // Le auto-intersezioni sono calcolate nel piano XY locale. // inizializzazioni m_bOverlaps = false ; m_nIntersCount = 0 ; m_pCurve = &Curve ; // verifico che la curva sia definita if ( &Curve == nullptr || ! Curve.IsValid()) return ; // puntatore alla curva usata nei calcoli (originale o temporanea) const ICurve* pCalcCrv ; // eventuale approssimazione temporanea della curva PtrOwner pTmpCrv ; // eventuale parametrizzazione della approssimazione temporanea DBLVECTOR vTmpPar ; // se curva è arco da approssimare oppure è curva di Bezier if ( ( m_pCurve->GetType() == CRV_ARC && IsArcToApprox( *m_pCurve)) || m_pCurve->GetType() == CRV_BEZIER) { // approssimo con rette PolyLine PL ; if ( ! m_pCurve->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) return ; pTmpCrv.Set( CreateBasicCurveComposite()) ; if ( IsNull( pTmpCrv)) return ; if ( ! GetBasicCurveComposite( pTmpCrv)->FromPolyLine( PL)) return ; pCalcCrv = pTmpCrv ; // salvo la parametrizzazione della approssimazione temporanea vTmpPar.reserve( PL.GetPointNbr()) ; double dPar ; bool bFound = PL.GetFirstU( dPar) ; while ( bFound) { vTmpPar.push_back( dPar) ; bFound = PL.GetNextU( dPar) ; } } // altrimenti uso la curva originale else pCalcCrv = m_pCurve ; // chiamo calcolatore opportuno switch ( pCalcCrv->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( pCalcCrv), *GetCurveComposite( pCalcCrv)) ; if ( intCcCc.m_nNumInters > 0) { m_bOverlaps = intCcCc.m_bOverlaps ; m_nIntersCount = intCcCc.m_nNumInters ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intCcCc.m_Info[i]) ; } } break ; } // per curva approssimata, sistemo... AdjustIntersParams( ( pCalcCrv != m_pCurve), pCalcCrv, vTmpPar) ; } //---------------------------------------------------------------------------- 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()) || abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetCurveParamFromApproxParam( double& dU, const ICurve* pCalcCrv, const DBLVECTOR& vCalcPar) { int nInd = int( dU) ; double dFraz = dU - nInd ; if ( nInd >= 0 && nInd < int( vCalcPar.size()) - 1) { // parametrizzazione da vettore dei parametri, uniforme in ogni intervallino dU = vCalcPar[nInd] + dFraz * ( vCalcPar[nInd+1] - vCalcPar[nInd]) ; } else { // domini parametrici delle due curve double dCalcS, dCalcE ; pCalcCrv->GetDomain( dCalcS, dCalcE) ; double dCrvS, dCrvE ; m_pCurve->GetDomain( dCrvS, dCrvE) ; // considero una parametrizzazione uniforme sull'intero dominio dU = dCrvS + ( dU - dCalcS) * ( dCrvE - dCrvS) / ( dCalcE - dCalcS) ; } return true ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::AdjustIntersParams( bool bAdjCrv, const ICurve* pCalcCrv, const DBLVECTOR& vCalcPar) { // se la curva originale non è stata approssimata o non ci sono auto-intersezioni, non va fatto alcunché if ( ! bAdjCrv || m_Info.size() == 0) return true ; // procedo ad aggiustare for ( auto& aInfo : m_Info) { // devo ricalcolare i parametri dei punti di intersezione GetCurveParamFromApproxParam( aInfo.IciA[0].dU, pCalcCrv, vCalcPar) ; ImproveCurveParamAtPoint( aInfo.IciA[0].dU, aInfo.IciA[0].ptI, m_pCurve) ; if ( aInfo.bOverlap) { GetCurveParamFromApproxParam( aInfo.IciA[1].dU, pCalcCrv, vCalcPar) ; ImproveCurveParamAtPoint( aInfo.IciA[1].dU, aInfo.IciA[1].ptI, m_pCurve) ; } GetCurveParamFromApproxParam( aInfo.IciB[0].dU, pCalcCrv, vCalcPar) ; ImproveCurveParamAtPoint( aInfo.IciB[0].dU, aInfo.IciB[0].ptI, m_pCurve) ; if ( aInfo.bOverlap) { GetCurveParamFromApproxParam( aInfo.IciB[1].dU, pCalcCrv, vCalcPar) ; ImproveCurveParamAtPoint( aInfo.IciB[1].dU, aInfo.IciB[1].ptI, m_pCurve) ; } } return true ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetOverlaps( void) { return m_bOverlaps ; } //---------------------------------------------------------------------------- int SelfIntersCurve::GetIntersCount( void) { return m_nIntersCount ; } //---------------------------------------------------------------------------- int SelfIntersCurve::GetCrossIntersCount( void) { int nCrossIntersCount = 0 ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // se con sovrapposizione if ( m_Info[i].bOverlap) { if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[1].nNextTy && m_Info[i].IciA[0].nPrevTy != ICCT_SPK && m_Info[i].IciA[1].nNextTy != ICCT_SPK && m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[1].nNextTy != ICCT_NULL) ++ nCrossIntersCount ; } // altrimenti else { if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) ++ nCrossIntersCount ; } } return nCrossIntersCount ; } //---------------------------------------------------------------------------- int SelfIntersCurve::GetCrossOrOverlapIntersCount( void) { int nCrossOverIntersCount = 0 ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // se con sovrapposizione if ( m_Info[i].bOverlap) ++ nCrossOverIntersCount ; // se altrimenti con attraversamento else if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy && m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) ++ nCrossOverIntersCount ; } return nCrossOverIntersCount ; } //---------------------------------------------------------------------------- int SelfIntersCurve::GetTouchIntersCount( void) { int nTouchIntersCount = 0 ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) { // se con sovrapposizione if ( m_Info[i].bOverlap) { if ( ( m_Info[i].IciA[0].nPrevTy == m_Info[i].IciA[1].nNextTy || m_Info[i].IciA[0].nPrevTy == ICCT_SPK || m_Info[i].IciA[1].nNextTy == ICCT_SPK) && m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[1].nNextTy != ICCT_NULL) ++ nTouchIntersCount ; } // altrimenti else { if ( m_Info[i].IciA[0].nPrevTy == m_Info[i].IciA[0].nNextTy && m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL) ++ nTouchIntersCount ; } } return nTouchIntersCount ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) { if ( nInd < 0 || nInd >= m_nIntersCount) return false ; aInfo = m_Info[nInd] ; return true ; } //---------------------------------------------------------------------------- bool SelfIntersCurve::GetIntersPointNearTo( const Point3d& ptNear, Point3d& ptI) { if ( m_nIntersCount == 0) return false ; // ricerca del punto più vicino tra le intersezioni singole bool bFound = false ; double dMinSqDist = SQ_INFINITO ; for ( int i = 0 ; i < m_nIntersCount ; ++ 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 ; }