//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : IntersCurveCurve.cpp Data : 20.06.14 Versione : 1.5f6 // Contenuto : Implementazione della classe intersezione linea/linea. // // // // Modifiche : 15.06.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "GeoConst.h" #include "IntersLineLine.h" #include "IntersLineArc.h" #include "IntersArcArc.h" #include "IntersCrvCompoCrvCompo.h" #include "CurveLine.h" #include "CurveComposite.h" #include "/EgtDev/Include/EGkIntersCurveCurve.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkPlane3d.h" #include "/EgtDev/Include/EGtPointerOwner.h" #include using namespace std ; //---------------------------------------------------------------------------- IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments) { // Le intersezioni sono calcolate nel piano XY locale. // Il flag bAreSegments vale solo per intersezione tra due linee e riguarda entrambe. // inizializzazioni m_bOverlaps = false ; m_nNumInters = 0 ; m_pCurve[0] = &CurveA ; m_pCurve[1] = &CurveB ; // chiamo calcolatore opportuno switch ( CurveA.GetType()) { case CRV_LINE : switch ( CurveB.GetType()) { case CRV_LINE : LineLineCalculate( CurveA, CurveB, bAreSegments) ; break ; case CRV_ARC : LineArcCalculate( CurveA, CurveB) ; break ; case CRV_BEZ : break ; case CRV_COMPO : LineCrvCompoCalculate( CurveA, CurveB) ; break ; } break ; case CRV_ARC : switch ( CurveB.GetType()) { case CRV_LINE : ArcLineCalculate( CurveA, CurveB) ; break ; case CRV_ARC : ArcArcCalculate( CurveA, CurveB) ; break ; case CRV_BEZ : break ; case CRV_COMPO : ArcCrvCompoCalculate( CurveA, CurveB) ; break ; } break ; case CRV_BEZ : break ; case CRV_COMPO : switch ( CurveB.GetType()) { case CRV_LINE : CrvCompoLineCalculate( CurveA, CurveB) ; break ; case CRV_ARC : CrvCompoArcCalculate( CurveA, CurveB) ; break ; case CRV_BEZ : break ; case CRV_COMPO : CrvCompoCrvCompoCalculate( CurveA, CurveB) ; break ; } break ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments) { IntersLineLine intLnLn( *GetCurveLine( &CurveA), *GetCurveLine( &CurveB), bAreSegments) ; if ( intLnLn.m_nNumInters > 0) { m_bOverlaps = intLnLn.m_bOverlaps ; m_nNumInters = intLnLn.m_nNumInters ; if ( m_nNumInters == 1) m_Info.push_back( intLnLn.m_Info) ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB) { IntersLineArc intLnAr( *GetCurveLine( &CurveA), *GetCurveArc( &CurveB)) ; if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; m_nNumInters = intLnAr.m_nNumInters ; for ( int i = 0 ; i < m_nNumInters ; ++ i) m_Info.push_back( intLnAr.m_Info[i]) ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::LineCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) { // trasformo la linea in curva composita CurveComposite crvCompo ; crvCompo.CopyFrom( &CurveA) ; // eseguo l'intersezione tra curve composite CrvCompoCrvCompoCalculate( crvCompo, CurveB) ; } //---------------------------------------------------------------------------- void IntersCurveCurve::ArcLineCalculate( const ICurve& CurveA, const ICurve& CurveB) { IntersLineArc intLnAr( *GetCurveLine( &CurveB), *GetCurveArc( &CurveA)) ; if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; m_nNumInters = intLnAr.m_nNumInters ; for ( int i = 0 ; i < m_nNumInters ; ++ i) m_Info.push_back( intLnAr.m_Info[i]) ; // devo scambiare opportunamente le info di intersezione tra A e B SwapInfoAB( m_Info, 0) ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::ArcArcCalculate( const ICurve& CurveA, const ICurve& CurveB) { IntersArcArc intArAr( *GetCurveArc( &CurveA), *GetCurveArc( &CurveB)) ; if ( intArAr.m_nNumInters > 0) { m_bOverlaps = intArAr.m_bOverlaps ; m_nNumInters = intArAr.m_nNumInters ; for ( int i = 0 ; i < m_nNumInters ; ++ i) m_Info.push_back( intArAr.m_Info[i]) ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::ArcCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) { // trasformo l'arco in curva composita CurveComposite crvCompo ; crvCompo.CopyFrom( &CurveA) ; // eseguo l'intersezione tra curve composite CrvCompoCrvCompoCalculate( crvCompo, CurveB) ; } //---------------------------------------------------------------------------- void IntersCurveCurve::CrvCompoLineCalculate( const ICurve& CurveA, const ICurve& CurveB) { // trasformo la linea in curva composita CurveComposite crvCompo ; crvCompo.CopyFrom( &CurveB) ; // eseguo l'intersezione tra curve composite CrvCompoCrvCompoCalculate( CurveA, crvCompo) ; } //---------------------------------------------------------------------------- void IntersCurveCurve::CrvCompoArcCalculate( const ICurve& CurveA, const ICurve& CurveB) { // trasformo l'arco in curva composita CurveComposite crvCompo ; crvCompo.CopyFrom( &CurveB) ; // eseguo l'intersezione tra curve composite CrvCompoCrvCompoCalculate( CurveA, crvCompo) ; } //---------------------------------------------------------------------------- void IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB) { IntersCrvCompoCrvCompo intCcCc( *GetCurveComposite( &CurveA), *GetCurveComposite( &CurveB)) ; 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]) ; } } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetOverlaps( void) { return m_bOverlaps ; } //---------------------------------------------------------------------------- int IntersCurveCurve::GetNumInters( void) { return m_nNumInters ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) { if ( nInd < 0 || nInd >= m_nNumInters) return false ; aInfo = m_Info[nInd] ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI) { if ( m_nNumInters == 0 || nCrv < 0 || nCrv > 1) 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 = ( nCrv == 0 ? m_Info[i].IciA[0].ptI : m_Info[i].IciB[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 ; if ( nCrv == 0) { dUStartTrim = m_Info[i].IciA[0].dU ; dUEndTrim = m_Info[i].IciA[1].dU ; } else { dUStartTrim = m_Info[i].IciB[0].dU ; dUEndTrim = m_Info[i].IciB[1].dU ; if ( ! m_Info[i].bCBOverEq) swap( dUStartTrim, dUEndTrim) ; } PtrOwner pCrv( m_pCurve[nCrv]->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 ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetCurveClassification( int nCrv, CRVCVECTOR& ccClass) { // pulisco vettore classificazioni ccClass.clear() ; // verifico definizione delle due curve if ( m_pCurve[0] == nullptr || m_pCurve[1] == nullptr) return false ; // se richiesta classificazione della curva A if ( nCrv == 0) { // la curva rispetto a cui si classifica deve essere chiusa if ( ! m_pCurve[1]->IsClosed()) return false ; // se esiste almeno una intersezione if ( m_nNumInters >= 1) return CalcCurveClassification( m_pCurve[0], m_Info, ccClass) ; // altrimenti la curva è completamente interna oppure completamente esterna else return CalcCurveInOrOut( m_pCurve[0], m_pCurve[1], ccClass) ; } // se richiesta classificazione della curva B else if ( nCrv == 1) { // la curva rispetto a cui si classifica deve essere chiusa if ( ! m_pCurve[0]->IsClosed()) return false ; // devo scambiare opportunamente le info di intersezione tra A e B // copia temporanea delle info di intersezione ICCIVECTOR InfoTmp = m_Info ; // esecuzione scambio e controlli SwapInfoAB( InfoTmp, 1) ; // se esiste almeno una intersezione if ( m_nNumInters >= 1) return CalcCurveClassification( m_pCurve[1], InfoTmp, ccClass) ; // altrimenti la curva è completamente interna oppure completamente esterna else return CalcCurveInOrOut( m_pCurve[1], m_pCurve[0], ccClass) ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::SwapInfoAB( ICCIVECTOR& Info, int IndCrvOrd) { if ( IndCrvOrd < 0 || IndCrvOrd > 1) return false ; // eseguo lo scambio for ( int i = 0 ; i < m_nNumInters ; ++ i) { // scambio le informazioni tra A e B swap( Info[i].IciA[0], Info[i].IciB[0]) ; swap( Info[i].IciA[1], Info[i].IciB[1]) ; // riordino eventuali sovrapposizioni controverse if ( Info[i].bOverlap && ! Info[i].bCBOverEq) { swap( Info[i].IciA[0], Info[i].IciA[1]) ; swap( Info[i].IciB[0], Info[i].IciB[1]) ; } } // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva stable_sort( Info.begin(), Info.end(), SortGreater) ; // verifiche su intersezioni in zone non-manifold OrderNonManifoldInters( Info, *(m_pCurve[IndCrvOrd]), *(m_pCurve[1-IndCrvOrd])) ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTOR& Info, CRVCVECTOR& ccClass) { // numero intersezioni int nNumInters = int( Info.size()) ; if ( nNumInters < 1) return false ; // recupero il dominio parametrico della curva in esame double dStartPar, dEndPar ; if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar)) return false ; // recupero la classificazione all'inizio della curva int nLastTy = ICCT_NULL ; double dCurrPar = dStartPar ; // se è chiusa, recupero come finisce if ( pCurve->IsClosed()) { if ( ! Info[nNumInters-1].bOverlap) nLastTy = Info[nNumInters-1].IciA[0].nNextTy ; else { nLastTy = Info[nNumInters-1].IciA[1].nNextTy ; // se attraversa il punto di giunzione (parametro di fine minore di quello di inizio) if ( Info[nNumInters-1].IciA[1].dU < Info[nNumInters-1].IciA[0].dU) { dCurrPar = Info[nNumInters-1].IciA[1].dU ; dEndPar = dCurrPar ; } } } // costruisco il vettore delle classificazioni for ( int i = 0 ; i < nNumInters ; ++ i) { // se è definito un tratto precedente if ( Info[i].IciA[0].dU > dCurrPar + EPS_PARAM) { // verifico che la definizione sul tratto sia omogenea e valida int nPrevTy = Info[i].IciA[0].nPrevTy ; if ( ( nLastTy != ICCT_NULL && nPrevTy != nLastTy) || nPrevTy == ICCT_NULL || nPrevTy == ICCT_ON) return false ; // assegno i dati CrvClass segClass ; segClass.dParS = dCurrPar ; segClass.dParE = Info[i].IciA[0].dU ; segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ; ccClass.push_back( segClass) ; // salvo dati correnti dCurrPar = Info[i].IciA[0].dU ; nLastTy = Info[i].IciA[0].nNextTy ; } // altrimenti, salvo il tipo else nLastTy = Info[i].IciA[0].nNextTy ; // se è definito un tratto in sovrapposizione if ( Info[i].bOverlap) { // assegno i dati CrvClass segClass ; segClass.dParS = dCurrPar ; segClass.dParE = Info[i].IciA[1].dU ; segClass.nClass = ( Info[i].bCBOverEq ? CRVC_ON_P : CRVC_ON_M) ; ccClass.push_back( segClass) ; // salvo dati correnti dCurrPar = Info[i].IciA[1].dU ; nLastTy = Info[i].IciA[1].nNextTy ; } } // eventuale tratto finale rimasto if ( dCurrPar < dEndPar - EPS_PARAM) { // verifico che la definizione sul tratto sia valida if ( nLastTy == ICCT_NULL || nLastTy == ICCT_ON) return false ; // assegno i dati CrvClass segClass ; segClass.dParS = dCurrPar ; segClass.dParE = dEndPar ; segClass.nClass = (( nLastTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ; ccClass.push_back( segClass) ; } return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB, CRVCVECTOR& ccClass) { // recupero il dominio parametrico della curva A double dStartPar, dEndPar ; if ( ! pCurveA->GetDomain( dStartPar, dEndPar)) return false ; // se i box delle due curve non interferiscono è sicuramente default BBox3d boxCrvA, boxCrvB ; if ( ! pCurveA->GetLocalBBox( boxCrvA) || ! pCurveB->GetLocalBBox( boxCrvB)) return false ; if ( ! boxCrvA.OverlapsXY( boxCrvB)) { // determino il tipo di esterno int nClass ; if ( ! GetCurveOutClass( pCurveB, nClass)) return false ; // assegno i dati CrvClass segClass ; segClass.dParS = dStartPar ; segClass.dParE = dEndPar ; segClass.nClass = nClass ; ccClass.push_back( segClass) ; return true ; } // intersezione tra una semiretta parallela a X dal punto iniziale della curva A e la curva B // costruisco la linea Point3d ptStart ; if ( ! pCurveA->GetStartPoint( ptStart)) return false ; double dLen = boxCrvB.GetMax().x - boxCrvB.GetMin().x + 1. ; CurveLine clLine ; if ( ! clLine.SetPDL( ptStart, 0, dLen)) return false ; // calcolo l'intersezione IntersCurveCurve iCC( clLine, *pCurveB) ; // dichiaro la classe della curva per default int nClass = CRVC_OUT ; // se c'è almeno una intersezione if ( iCC.GetNumInters() > 0) { // se quanto precede la prima intersezione è interno, allora la curva è interna IntCrvCrvInfo aInfo ; iCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( aInfo.IciA[0].nPrevTy == ICCT_IN) nClass = CRVC_IN ; } // altrimenti sono esterni tra loro else { // determino il tipo di esterno if ( ! GetCurveOutClass( pCurveB, nClass)) return false ; } // assegno i dati CrvClass segClass ; segClass.dParS = dStartPar ; segClass.dParE = dEndPar ; segClass.nClass = nClass ; ccClass.push_back( segClass) ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetCurveOutClass( const ICurve* pCurve, int& nClass) { PolyLine PL ; if ( ! pCurve->ApproxWithLines( LIN_TOL_APPROX, ANG_TOL_APPROX_DEG, PL)) return false ; double dArea ; if ( ! PL.GetAreaXY( dArea)) return false ; nClass = (( dArea > 0) ? CRVC_OUT : CRVC_IN) ; return true ; }