//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : IntersCurveCurve.cpp Data : 17.08.15 Versione : 1.6h3 // Contenuto : Implementazione della classe intersezione curva/curva. // // // // Modifiche : 15.06.14 DS Creazione modulo. // 17.08.15 DS Modifiche per curve approssimate. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "GeoConst.h" #include "CurveLine.h" #include "CurveComposite.h" #include "IntersLineLine.h" #include "IntersLineArc.h" #include "IntersArcArc.h" #include "IntersCrvCompoCrvCompo.h" #include "/EgtDev/Include/EGkIntersCurves.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_nIntersCount = 0 ; m_pCurve[0] = &CurveA ; m_pCurve[1] = &CurveB ; // puntatori alle curve usate nei calcoli (originali o temporanee) const ICurve* pCalcCrv[2] ; // per eventuale esplosione temporanea delle curve PtrOwner pTmpCrv[2] ; // ciclo sulle curve per verificare se da approssimare for ( int i = 0 ; i < 2 ; ++ i) { // se curva è arco da approssimare oppure è curva di Bezier if ( ( m_pCurve[i]->GetType() == CRV_ARC && IsArcToApprox( *m_pCurve[i])) || m_pCurve[i]->GetType() == CRV_BEZIER) { // approssimo con rette PolyLine PL ; if ( ! m_pCurve[i]->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) return ; pTmpCrv[i].Set( CreateBasicCurveComposite()) ; if ( IsNull( pTmpCrv[i])) return ; if ( ! GetBasicCurveComposite( pTmpCrv[i])->FromPolyLine( PL)) return ; pCalcCrv[i] = pTmpCrv[i] ; } else pCalcCrv[i] = m_pCurve[i] ; } // chiamo calcolatore opportuno switch ( pCalcCrv[0]->GetType()) { case CRV_LINE : switch ( pCalcCrv[1]->GetType()) { case CRV_LINE : LineLineCalculate( *pCalcCrv[0], *pCalcCrv[1], bAreSegments) ; break ; case CRV_ARC : LineArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; case CRV_COMPO : LineCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; } break ; case CRV_ARC : switch ( pCalcCrv[1]->GetType()) { case CRV_LINE : ArcLineCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; case CRV_ARC : ArcArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; case CRV_COMPO : ArcCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; } break ; case CRV_COMPO : switch ( pCalcCrv[1]->GetType()) { case CRV_LINE : CrvCompoLineCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; case CRV_ARC : CrvCompoArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; case CRV_COMPO : CrvCompoCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ; break ; } break ; } // per curve approssimate, sistemo... AdjustIntersParams( ( pCalcCrv[0] != m_pCurve[0]), ( pCalcCrv[1] != m_pCurve[1])) ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::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) ; } //---------------------------------------------------------------------------- void IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments) { IntersLineLine intLnLn( *GetBasicCurveLine( &CurveA), *GetBasicCurveLine( &CurveB), bAreSegments) ; if ( intLnLn.m_nNumInters > 0) { m_bOverlaps = intLnLn.m_bOverlaps ; m_nIntersCount = intLnLn.m_nNumInters ; if ( m_nIntersCount == 1) m_Info.push_back( intLnLn.m_Info) ; } } //---------------------------------------------------------------------------- void IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB) { IntersLineArc intLnAr( *GetBasicCurveLine( &CurveA), *GetBasicCurveArc( &CurveB)) ; if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; m_nIntersCount = intLnAr.m_nNumInters ; for ( int i = 0 ; i < m_nIntersCount ; ++ 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( *GetBasicCurveLine( &CurveB), *GetBasicCurveArc( &CurveA)) ; if ( intLnAr.m_nNumInters > 0) { m_bOverlaps = false ; m_nIntersCount = intLnAr.m_nNumInters ; for ( int i = 0 ; i < m_nIntersCount ; ++ 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( *GetBasicCurveArc( &CurveA), *GetBasicCurveArc( &CurveB)) ; if ( intArAr.m_nNumInters > 0) { m_bOverlaps = intArAr.m_bOverlaps ; m_nIntersCount = intArAr.m_nNumInters ; for ( int i = 0 ; i < m_nIntersCount ; ++ 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_nIntersCount = intCcCc.m_nNumInters ; for ( int i = 0 ; i < m_nIntersCount ; ++ i) m_Info.push_back( intCcCc.m_Info[i]) ; } } //---------------------------------------------------------------------------- bool IntersCurveCurve::AdjustIntersParams( bool bAdjCrvA, bool bAdjCrvB) { // se non ci sono intersezioni, non va fatto alcunché if ( m_Info.size() == 0) return true ; // se le curve originali non sono state approssimate, non va fatto alcunché if ( ! bAdjCrvA && ! bAdjCrvB) return true ; // procedo ad aggiustare for ( auto& aInfo : m_Info) { // se curve originali approssimate, devo ricalcolare i parametri dei punti di intersezione if ( bAdjCrvA) { if ( ! m_pCurve[0]->GetParamAtPoint( aInfo.IciA[0].ptI, aInfo.IciA[0].dU, 10 * EPS_SMALL)) return false ; if ( aInfo.bOverlap && ! m_pCurve[0]->GetParamAtPoint( aInfo.IciA[1].ptI, aInfo.IciA[1].dU, 10 * EPS_SMALL)) return false ; } if ( bAdjCrvB) { if ( ! m_pCurve[1]->GetParamAtPoint( aInfo.IciB[0].ptI, aInfo.IciB[0].dU, 10 * EPS_SMALL)) return false ; if ( aInfo.bOverlap && ! m_pCurve[1]->GetParamAtPoint( aInfo.IciB[1].ptI, aInfo.IciB[1].dU, 10 * EPS_SMALL)) return false ; } } return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetOverlaps( void) { return m_bOverlaps ; } //---------------------------------------------------------------------------- int IntersCurveCurve::GetIntersCount( void) { return m_nIntersCount ; } //---------------------------------------------------------------------------- int IntersCurveCurve::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_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 IntersCurveCurve::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 ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo) { if ( nInd < 0 || nInd >= m_nIntersCount) return false ; aInfo = m_Info[nInd] ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI) { if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1) 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 = ( 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, double dLenMin, 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_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[0], m_Info, dLenMin, 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_nIntersCount >= 1) return CalcCurveClassification( m_pCurve[1], InfoTmp, dLenMin, 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_nIntersCount ; ++ 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(), SortGreaterA) ; // 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, double dLenMin, 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 ; // limito lunghezza minima dLenMin = max( dLenMin, EPS_ZERO) ; // elimino intersezioni senza attraversamento che giacciono in intervalli di sovrapposizione ICCIVECTOR InfoCorr ; InfoCorr.reserve( Info.size()) ; for ( size_t i = 0 ; i < Info.size() ; ++ i) { // se intersezione puntuale senza attraversamento if ( ! Info[i].bOverlap && Info[i].IciA[0].nPrevTy == Info[i].IciA[0].nNextTy) { // confronto con le intersezioni con sovrapposizione bool bToSkip = false ; for ( size_t j = 0 ; j < Info.size() ; ++ j) { // se coincide o puntuale if ( j == i || ! Info[j].bOverlap) continue ; // determino l'intervallo parametrico tenendo conto di eventuale avvolgimento attorno all'inizio double dU1 = Info[j].IciA[0].dU ; double dU2 = Info[j].IciA[1].dU ; if ( dU2 < dU1 && pCurve->IsClosed()) dU2 += dEndPar ; // se cade nell'intervallo è da saltare if ( Info[i].IciA[0].dU >= dU1 && Info[i].IciA[0].dU <= dU2) { bToSkip = true ; break ; } } if ( bToSkip) continue ; } // salvo dati intersezione InfoCorr.emplace_back( Info[i]) ; } // aggiorno numero di intersezioni da considerare nNumInters = int( InfoCorr.size()) ; // recupero la classificazione all'inizio della curva int nLastTy = ICCT_NULL ; double dCurrPar = dStartPar ; double dCurrLen = 0 ; double dEndLen ; pCurve->GetLength( dEndLen) ; // se è chiusa, recupero come finisce if ( pCurve->IsClosed()) { if ( ! InfoCorr[nNumInters-1].bOverlap) nLastTy = InfoCorr[nNumInters-1].IciA[0].nNextTy ; else { nLastTy = InfoCorr[nNumInters-1].IciA[1].nNextTy ; // se attraversa il punto di giunzione (parametro di fine minore di quello di inizio) if ( InfoCorr[nNumInters-1].IciA[1].dU < InfoCorr[nNumInters-1].IciA[0].dU) { dCurrPar = InfoCorr[nNumInters-1].IciA[1].dU ; double dTmpLen ; pCurve->GetLengthAtParam( dCurrPar, dTmpLen) ; dCurrLen = dTmpLen - dEndLen ; dEndPar = dCurrPar ; dEndLen = dTmpLen ; } } } // costruisco il vettore delle classificazioni for ( int i = 0 ; i < nNumInters ; ++ i) { // se è definito un tratto precedente double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].IciA[0].dU, dLenU) ; if ( InfoCorr[i].IciA[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) { // verifico che la definizione sul tratto sia omogenea e valida int nPrevTy = InfoCorr[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 = InfoCorr[i].IciA[0].dU ; segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ; ccClass.push_back( segClass) ; // salvo dati correnti dCurrPar = InfoCorr[i].IciA[0].dU ; dCurrLen = dLenU ; nLastTy = InfoCorr[i].IciA[0].nNextTy ; } // altrimenti, salvo il tipo else nLastTy = InfoCorr[i].IciA[0].nNextTy ; // se è definito un tratto in sovrapposizione if ( InfoCorr[i].bOverlap) { // assegno i dati CrvClass segClass ; segClass.dParS = dCurrPar ; segClass.dParE = InfoCorr[i].IciA[1].dU ; segClass.nClass = ( InfoCorr[i].bCBOverEq ? CRVC_ON_P : CRVC_ON_M) ; ccClass.push_back( segClass) ; // salvo dati correnti dCurrPar = InfoCorr[i].IciA[1].dU ; dCurrLen = dLenU ; nLastTy = InfoCorr[i].IciA[1].nNextTy ; } } // eventuale tratto finale rimasto if ( dCurrPar < dEndPar - EPS_PARAM && dEndLen - dCurrLen > dLenMin) { // 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 delle curve A e B double dStartParA, dEndParA ; if ( ! pCurveA->GetDomain( dStartParA, dEndParA)) return false ; double dStartParB, dEndParB ; if ( ! pCurveB->GetDomain( dStartParB, dEndParB)) return false ; // se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne BBox3d boxCrvA, boxCrvB ; if ( ! pCurveA->GetLocalBBox( boxCrvA) || ! pCurveB->GetLocalBBox( boxCrvB)) return false ; bool bAOut = ( ! boxCrvA.OverlapsXY( boxCrvB)) ; bool bBOut = bAOut ; for ( double dU = dStartParA ; dU <= dEndParA && ! bAOut ; dU += 1) { Point3d ptP ; if ( pCurveA->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) && ! boxCrvB.EnclosesXY( ptP)) bAOut = true ; } for ( double dU = dStartParB ; dU <= dEndParB && ! bBOut ; dU += 1) { Point3d ptP ; if ( pCurveB->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) && ! boxCrvA.EnclosesXY( ptP)) bBOut = true ; } if ( bAOut && bBOut) { // determino il tipo di esterno int nClass ; if ( ! GetCurveOutClass( pCurveB, nClass)) return false ; // assegno i dati CrvClass segClass ; segClass.dParS = dStartParA ; segClass.dParE = dEndParA ; 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.GetIntersCount() > 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 = dStartParA ; segClass.dParE = dEndParA ; segClass.nClass = nClass ; ccClass.push_back( segClass) ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveCurve::GetCurveOutClass( const ICurve* pCurve, int& nClass) { double dArea ; if ( ! pCurve->GetAreaXY( dArea)) return false ; nClass = (( dArea > 0) ? CRVC_OUT : CRVC_IN) ; return true ; } //---------------------------------------------------------------------------- int IntersCurveCurve::GetRegionCurveClassification( void) { // classifico la prima curva rispetto alla seconda CRVCVECTOR ccClass ; if ( ! GetCurveClassification( 0, EPS_SMALL, ccClass)) return CCREGC_NULL ; // derivo la classificazione delle curve come regioni bool bIn = false ; bool bOut = false ; bool bOnP = false ; bool bOnM = false ; for ( auto& ccOne : ccClass) { switch ( ccOne.nClass) { case CRVC_IN : bIn = true ; break ; case CRVC_OUT : bOut = true ; break ; case CRVC_ON_P : bOnP = true ; break ; case CRVC_ON_M : bOnM = true ; break ; default : return CCREGC_NULL ; } } if ( bIn) { if ( bOut) return CCREGC_INTERS ; else return CCREGC_IN1 ; } if ( bOut) { if ( bOnM) return CCREGC_OUT ; if ( bOnP) return CCREGC_IN2 ; CRVCVECTOR ccClass2 ; if ( ! GetCurveClassification( 1, EPS_SMALL, ccClass2) || ccClass2.empty()) return CCREGC_NULL ; if ( ccClass2[0].nClass == CRVC_OUT) return CCREGC_OUT ; else return CCREGC_IN2 ; } if ( bOnP) return CCREGC_SAME ; if ( bOnM) return CCREGC_OUT ; return CCREGC_NULL ; }