//---------------------------------------------------------------------------- // EgalTech 2014-2014 //---------------------------------------------------------------------------- // File : IntersCrvCompoCrvCompo.cpp Data : 24.06.14 Versione : 1.5f6 // Contenuto : Implementazione della classe intersezione curva composita/cc. // // // // Modifiche : 24.06.14 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "IntersCrvCompoCrvCompo.h" #include "CurveAux.h" #include using namespace std ; //--------------------------- Local functions -------------------------------- static bool CompatibleParamA( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2, bool bCrvAClosed, double dCrvASpan) ; static bool CompatibleParamB( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2, bool bCrvBClosed, double dCrvBSpan) ; static void MediaParamPoints( IntCrvInfo& Ici1, IntCrvInfo& Ici2) ; static int GetCrvBDirAPrev( IntCrvCrvInfo& Icci) ; static int GetCrvBDirANext( IntCrvCrvInfo& Icci) ; static bool CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB, int& nType) ; static bool CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB1, double dUB2, int& nType) ; //---------------------------------------------------------------------------- IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA, const ICurveComposite& CCompoB) { // Le intersezioni sono calcolate nel piano XY locale. // nessuna intersezione trovata m_bOverlaps = false ; m_nNumInters = 0 ; m_Info.clear() ; // dati generali delle curve m_bCrvAClosed = CCompoA.IsClosed() ; m_bCrvBClosed = CCompoB.IsClosed() ; double dStart, dEnd ; if ( ! CCompoA.GetDomain( dStart, dEnd)) return ; m_dCrvASpan = dEnd - dStart ; if ( ! CCompoB.GetDomain( dStart, dEnd)) return ; m_dCrvBSpan = dEnd - dStart ; // doppio ciclo sulle entitเ delle curve composite // !!! questa parte ่ O(N^2), vanno usate Grid Gerarchiche o BVH per renderla O(N*logN) !!! int nCountA = 0 ; for ( const ICurve* pCrvA = CCompoA.GetFirstCurve() ; pCrvA != nullptr ; pCrvA = CCompoA.GetNextCurve(), ++ nCountA) { int nCountB = 0 ; for ( const ICurve* pCrvB = CCompoB.GetFirstCurve() ; pCrvB != nullptr ; pCrvB = CCompoB.GetNextCurve(), ++ nCountB) { // eseguo l'intersezione di queste curve semplici IntersCurveCurve intCC( *pCrvA, *pCrvB) ; // ne recupero i risultati int nCurrInters = intCC.GetNumInters() ; if ( nCurrInters > 0) { m_nNumInters += nCurrInters ; m_bOverlaps = ( intCC.GetOverlaps() ? true : m_bOverlaps) ; for ( int i = 0 ; i < nCurrInters ; ++ i) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( i, aInfo) ; aInfo.IciA[0].dU += nCountA ; aInfo.IciB[0].dU += nCountB ; if ( aInfo.bOverlap) { aInfo.IciA[1].dU += nCountA ; aInfo.IciB[1].dU += nCountB ; } m_Info.push_back( aInfo) ; } } } } // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva stable_sort( m_Info.begin(), m_Info.end(), SortGreater) ; // sistemazione di intersezioni coincidenti for ( int i = 0 ; i < m_nNumInters ; ++ i) { for ( int j = 0 ; j < m_nNumInters ; ++ j) { // se i due indici coincidono, passo oltre if ( i == j) continue ; // calcolo sottoindici int ki = 0 ; // del successivo si prende sempre il primo int kj = ( m_Info[j].bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap // verifico se precedente e corrente si riferiscono alla stessa intersezione (10 * EPS_SMALL) if ( SqDistXY( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI) < ( 100 * EPS_SMALL * EPS_SMALL) && SqDistXY( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI) < ( 100 * EPS_SMALL * EPS_SMALL) && CompatibleParamA( m_Info[j], m_Info[i], m_bCrvAClosed, m_dCrvASpan) && CompatibleParamB( m_Info[j], m_Info[i], m_bCrvBClosed, m_dCrvBSpan)) { // caso DET-NULL -> NULL-DET per prima curva if ( m_Info[j].IciA[kj].nPrevTy != ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL && m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy != ICCT_NULL) { // per la prima curva tengo i determinati m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ; m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; // se overlap equiverso if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { // per la seconda curva ogni sottotipo ่ il duale di quello della prima m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { // per la seconda curva ogni sottotipo ่ come quello della prima ma in posizione invertita m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } // se overlap equiverso if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } // medio parametri e punti separatamente per le due curve MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; // se entrambi overlap non cancello if ( m_Info[j].bOverlap && m_Info[i].bOverlap) continue ; // cancello un singolo if ( m_Info[i].bOverlap) { EraseOtherInfo( i, j) ; } else { EraseCurrentInfo( i, j) ; break ; } } // caso NULL-DET -> DET-NULL per prima curva (possibile su inizio/fine di curva chiusa) else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy != ICCT_NULL && m_Info[i].IciA[ki].nPrevTy != ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { // per la prima curva tengo i determinati m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[kj].nNextTy ; m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ; // se overlap equiverso if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { // per la seconda curva ogni sottotipo ่ il duale di quello della prima m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { // per la seconda curva ogni sottotipo ่ come quello della prima ma in posizione scambiata m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ; m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } // se overlap equiverso if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { // per la seconda curva ogni sottotipo ่ il duale di quello della prima m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ; m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { // per la seconda curva ogni sottotipo ่ come quello della prima ma in posizione scambiata m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ; m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ; } // medio parametri e punti separatamente per le due curve MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; // se entrambi overlap non cancello if ( m_Info[j].bOverlap && m_Info[i].bOverlap) continue ; // cancello un singolo if ( m_Info[i].bOverlap) { EraseOtherInfo( i, j) ; } else { EraseCurrentInfo( i, j) ; break ; } } // caso DET-NULL -> NULL-DET per seconda curva else if ( m_Info[j].IciB[kj].nPrevTy != ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL && m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy != ICCT_NULL) { // per la seconda curva tengo i determinati m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ; m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; // se overlap equiverso if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { // per la prima curva ogni sottotipo ่ il duale di quello della seconda m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { // per la prima curva ogni sottotipo ่ come quello della seconda ma in posizione scambiata m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; } // se overlap equiverso if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { // per la prima curva ogni sottotipo ่ il duale di quello della seconda m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { // per la prima curva ogni sottotipo ่ come quello della seconda ma in posizione scambiata m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; } // medio parametri e punti separatamente per le due curve MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; // se entrambi overlap non cancello if ( m_Info[j].bOverlap && m_Info[i].bOverlap) continue ; // cancello un singolo if ( m_Info[i].bOverlap) { EraseOtherInfo( i, j) ; } else { EraseCurrentInfo( i, j) ; break ; } } // caso NULL-DET -> DET-NULL per seconda curva (possibile su inizio/fine di curva chiusa) else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy != ICCT_NULL && m_Info[i].IciB[ki].nPrevTy != ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) { // per la seconda curva tengo i determinati m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ; m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ; // se overlap equiverso if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) { // per la prima curva ogni sottotipo ่ il duale di quello della seconda m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) { // per la prima curva ogni sottotipo ่ come quello della seconda ma in posizione scambiata m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ; m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ; } // se overlap equiverso if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) { // per la prima curva ogni sottotipo ่ il duale di quello della seconda m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ; m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ; } // se altrimenti overlap controverso else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) { // per la prima curva ogni sottotipo ่ come quello della seconda ma in posizione scambiata m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ; m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ; } // medio parametri e punti separatamente per le due curve MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj]) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj]) ; // se entrambi overlap non cancello if ( m_Info[j].bOverlap && m_Info[i].bOverlap) continue ; // cancello un singolo if ( m_Info[i].bOverlap) { EraseOtherInfo( i, j) ; } else { EraseCurrentInfo( i, j) ; break ; } } // caso NULL-NULL per corrente di prima curva else if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) EraseCurrentInfo( i, j) ; break ; } // caso NULL-NULL per precedente di prima curva else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL) { // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) EraseOtherInfo( i, j) ; } } } } // verifico se sono rimaste delle intersezioni di tipo non definito e cerco di risolverle for ( int i = 0 ; i < m_nNumInters ; ++ i) { // in assenza di overlap if ( ! m_Info[i].bOverlap) { // se il tipo di accostamento per la curva A non ่ definito if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoA, m_Info[i].IciA[0].dU, ICurve::FROM_MINUS, CCompoB, m_Info[i].IciB[0].dU, nType)) continue ; // aggiorno il tipo di accostamento della curva A alla curva B m_Info[i].IciA[0].nPrevTy = nType ; } // se il tipo di accostamento per la curva B non ่ definito if ( m_Info[i].IciB[0].nPrevTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoB, m_Info[i].IciB[0].dU, ICurve::FROM_MINUS, CCompoA, m_Info[i].IciA[0].dU, nType)) continue ; // aggiorno il tipo di accostamento della curva B alla curva A m_Info[i].IciB[0].nPrevTy = nType ; } // se il tipo di allontanamento per la curva A non ่ definito if ( m_Info[i].IciA[0].nNextTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoA, m_Info[i].IciA[0].dU, ICurve::FROM_PLUS, CCompoB, m_Info[i].IciB[0].dU, nType)) continue ; // aggiorno il tipo di allontanamento della curva A dalla curva B m_Info[i].IciA[0].nNextTy = nType ; } // se il tipo di allontanamento per la curva B non ่ definito if ( m_Info[i].IciB[0].nNextTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoB, m_Info[i].IciB[0].dU, ICurve::FROM_PLUS, CCompoA, m_Info[i].IciA[0].dU, nType)) continue ; // aggiorno il tipo di allontanamento della curva B dalla curva A m_Info[i].IciB[0].nNextTy = nType ; } } // in presenza di overlap else { // se il tipo di accostamento ่ non definito per la curva A if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoA, m_Info[i].IciA[0].dU, ICurve::FROM_MINUS, CCompoB, m_Info[i].IciB[0].dU, nType)) continue ; // aggiorno il tipo di accostamento della curva A alla curva B m_Info[i].IciA[0].nPrevTy = nType ; // aggiorno anche il corrispondente tipo sulla curva B if ( m_Info[i].bCBOverEq) m_Info[i].IciB[0].nPrevTy = GetDualIcct( nType) ; else m_Info[i].IciB[0].nNextTy = nType ; } // se il tipo di allontanamento ่ non definito per la curva A if ( m_Info[i].IciA[1].nNextTy == ICCT_NULL) { // devo studiare un intorno dell'intersezione int nType ; if ( ! CalcATypeFromDisk( CCompoA, m_Info[i].IciA[1].dU, ICurve::FROM_PLUS, CCompoB, m_Info[i].IciB[1].dU, nType)) continue ; // aggiorno il tipo di allontanamento della curva A dalla curva B m_Info[i].IciA[1].nNextTy = nType ; // aggiorno anche il corrispondente tipo sulla curva B if ( m_Info[i].bCBOverEq) m_Info[i].IciB[1].nNextTy = GetDualIcct( nType) ; else m_Info[i].IciB[1].nPrevTy = nType ; } } } // verifico se due intersezioni consecutive di tipo overlap si possono ridurre a una sola for ( int i = 0 ; i < m_nNumInters ; ++ i) { // calcolo indice precedente int j = i - 1 ; if ( i == 0) { // se prima curva aperta, salto alla prossima if ( ! CCompoA.IsClosed()) continue ; // ่ chiusa quindi prendo l'ultima j = m_nNumInters - 1 ; } // se i due indici coincidono, c'่ una sola intersezione e posso uscire if ( i == j) break ; // assegno sottoindici (considero solo intersezioni overlap) int ki = 0 ; int kj = 1 ; // verifico se entrambe overlap, la precedente termina con ON e la successiva inizia con ON // sia sulla curva A sia sulla curva B (tenendo conto del senso equiverso/controverso) if ( m_Info[j].bOverlap && m_Info[i].bOverlap && m_Info[j].IciA[kj].nNextTy == ICCT_ON && m_Info[i].IciA[ki].nPrevTy == ICCT_ON && GetCrvBDirANext( m_Info[j]) == ICCT_ON && GetCrvBDirAPrev( m_Info[i]) == ICCT_ON) { // CurvaA : riporto il secondo punto del successivo sul secondo punto del precedente m_Info[j].IciA[kj].dU = m_Info[i].IciA[kj].dU ; m_Info[j].IciA[kj].ptI = m_Info[i].IciA[kj].ptI ; m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[kj].nPrevTy ; m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[kj].nNextTy ; // CurvaB : riporto il secondo punto del successivo sul secondo punto del precedente m_Info[j].IciB[kj].dU = m_Info[i].IciB[kj].dU ; m_Info[j].IciB[kj].ptI = m_Info[i].IciB[kj].ptI ; m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[kj].nPrevTy ; m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[kj].nNextTy ; // cancello il successivo m_Info.erase( m_Info.begin() + i) ; -- i ; -- m_nNumInters ; } } // se ่ rimasta una sola intersezione con overlap anche ad entrambi gli estremi e le curve sono chiuse if ( m_nNumInters == 1 && CCompoA.IsClosed() && CCompoB.IsClosed() && m_Info[0].IciA[0].nPrevTy == ICCT_ON && m_Info[0].IciA[1].nNextTy == ICCT_ON && GetCrvBDirANext( m_Info[0]) == ICCT_ON && GetCrvBDirAPrev( m_Info[0]) == ICCT_ON) { // questa intersezione con overlap deve interessare completamente le due curve double dStart, dEnd ; CCompoA.GetDomain( dStart, dEnd) ; m_Info[0].IciA[0].dU = dStart ; m_Info[0].IciA[1].dU = dEnd ; CCompoB.GetDomain( dStart, dEnd) ; m_Info[0].IciB[0].dU = ( m_Info[0].bCBOverEq ? dStart : dEnd) ; m_Info[0].IciB[1].dU = ( m_Info[0].bCBOverEq ? dEnd : dStart) ; } // verifiche su intersezioni in zone non-manifold OrderNonManifoldInters( m_Info, CCompoA, CCompoB) ; } //---------------------------------------------------------------------------- bool IntersCrvCompoCrvCompo::EraseCurrentInfo( int& nIndCurr, int& nIndOther) { m_Info.erase( m_Info.begin() + nIndCurr) ; -- nIndCurr ; -- m_nNumInters ; return true ; } //---------------------------------------------------------------------------- bool IntersCrvCompoCrvCompo::EraseOtherInfo( int& nIndCurr, int& nIndOther) { m_Info.erase( m_Info.begin() + nIndOther) ; if ( nIndOther < nIndCurr) -- nIndCurr ; -- nIndOther ; -- m_nNumInters ; return true ; } //---------------------------------------------------------------------------- // Global functions //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- bool SortGreater( const IntCrvCrvInfo& aInfo1, const IntCrvCrvInfo& aInfo2) { double dU1, dU2 ; // determino il primo termine del confronto dU1 = aInfo1.IciA[0].dU ; if ( aInfo1.bOverlap) { // caso normale if ( aInfo1.IciA[0].dU < aInfo1.IciA[1].dU) dU1 = 0.5 * ( aInfo1.IciA[0].dU + aInfo1.IciA[1].dU) ; // a cavallo di fine / inizio else dU1 = aInfo1.IciA[0].dU + SPAN_PARAM ; } // determino il secondo termine del confronto dU2 = aInfo2.IciA[0].dU ; if ( aInfo2.bOverlap) { // caso normale if ( aInfo2.IciA[0].dU < aInfo2.IciA[1].dU) dU2 = 0.5 * ( aInfo2.IciA[0].dU + aInfo2.IciA[1].dU) ; // a cavallo di fine / inizio else dU2 = aInfo2.IciA[0].dU + SPAN_PARAM ; } return ( dU2 > dU1 + EPS_PARAM) ; } //---------------------------------------------------------------------------- bool OrderNonManifoldInters( ICCIVECTOR& Info, const ICurve& CurveA, const ICurve& CurveB) { // questi controlli sono validi solo se la curva B ่ chiusa if ( ! CurveB.IsClosed()) return false ; // questi controlli hanno senso se ci sono almeno due intersezioni int nNumInters = int( Info.size()) ; if ( nNumInters < 2) return true ; // dati generali delle curve bool bCrvAClosed = CurveA.IsClosed() ; bool bCrvBClosed = CurveB.IsClosed() ; double dStart, dEnd ; if ( ! CurveA.GetDomain( dStart, dEnd)) return false ; double dCrvASpan = dEnd - dStart ; if ( ! CurveB.GetDomain( dStart, dEnd)) return false ; double dCrvBSpan = dEnd - dStart ; // se ci sono delle intersezioni coincidenti, verifico che si seguano nell'ordine corretto // studio la topologia non-manifold del disco nell'intorno for ( int i = 0 ; i < nNumInters ; ++ i) { // calcolo indice precedente int j = i - 1 ; if ( i == 0) { // se prima curva aperta, salto alla prossima if ( ! CurveA.IsClosed()) continue ; // ่ chiusa quindi prendo l'ultima j = nNumInters - 1 ; } // se i due indici coincidono, salto if ( i == j) continue ; // se uno dei due overlap, ordinamento per forza corretto e quindi salto if ( Info[j].bOverlap || Info[i].bOverlap) continue ; // assegno sottoindici (non ci possono essere overlap) int ki = 0 ; // del successivo si prende sempre il primo int kj = 0 ; // del precedente si prende sempre il primo // verifico coincidenza dei parametri della curva A, differenza dei parametri della curva B // coincidenza dei punti della curva B if ( CompatibleParamA( Info[j], Info[i], bCrvAClosed, dCrvASpan) && ! CompatibleParamB( Info[j], Info[i], bCrvBClosed, dCrvBSpan) && SqDistXY( Info[j].IciB[kj].ptI, Info[i].IciB[ki].ptI) < ( 100 * EPS_SMALL * EPS_SMALL)) { // se sono diversi i precedenti if ( Info[j].IciA[kj].nPrevTy != Info[i].IciA[ki].nPrevTy) { // studio la topologia del disco non-manifold int nType ; if ( ! CalcATypeFromDisk2( CurveA, Info[j].IciA[kj].dU, ICurve::FROM_MINUS, CurveB, Info[j].IciB[kj].dU, Info[i].IciB[ki].dU, nType)) continue ; // se non corrispondono le tipologie del precedente, scambio le intersezioni if ( Info[j].IciA[kj].nPrevTy != nType) swap( Info[j], Info[i]) ; } // se altrimenti sono diversi i seguenti else if ( Info[j].IciA[kj].nNextTy != Info[i].IciA[ki].nNextTy) { // studio la topologia del disco non-manifold int nType ; if ( ! CalcATypeFromDisk2( CurveA, Info[j].IciA[kj].dU, ICurve::FROM_PLUS, CurveB, Info[j].IciB[kj].dU, Info[i].IciB[ki].dU, nType)) continue ; // se non corrispondono le tipologie del seguente, scambio le intersezioni if ( Info[i].IciA[ki].nNextTy != nType) swap( Info[j], Info[i]) ; } // altrimenti sono tutti uguali, quindi inutile fare approfondimenti } } return true ; } //---------------------------------------------------------------------------- // Local functions //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- static bool CompatibleParamA( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2, bool bCrvAClosed, double dCrvASpan) { int k = ( Icci1.bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap if ( fabs( Icci1.IciA[k].dU - Icci2.IciA[0].dU) > 0.1 * SPAN_PARAM && ( ! bCrvAClosed || fabs( fabs( Icci1.IciA[k].dU - Icci2.IciA[0].dU) - dCrvASpan) > 0.1 * SPAN_PARAM)) return false ; return true ; } //---------------------------------------------------------------------------- static bool CompatibleParamB( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2, bool bCrvBClosed, double dCrvBSpan) { int k = ( Icci1.bOverlap ? 1 : 0) ; // del precedente si prende il secondo se overlap if ( fabs( Icci1.IciB[k].dU - Icci2.IciB[0].dU) > 0.1 * SPAN_PARAM && ( ! bCrvBClosed || fabs( fabs( Icci1.IciB[k].dU - Icci2.IciB[0].dU) - dCrvBSpan) > 0.1 * SPAN_PARAM)) return false ; return true ; } //---------------------------------------------------------------------------- static void MediaParamPoints( IntCrvInfo& Ici1, IntCrvInfo& Ici2) { // medio i parametri e i punti // per non mediare i parametri tra gli estremi di curva chiusa if ( fabs( Ici1.dU - Ici2.dU) < 0.1 * SPAN_PARAM) { Ici1.dU = 0.5 * ( Ici1.dU + Ici2.dU) ; Ici2.dU = Ici1.dU ; } Ici1.ptI = 0.5 * ( Ici1.ptI + Ici2.ptI) ; Ici2.ptI = Ici1.ptI ; } //---------------------------------------------------------------------------- // Prev della curva B ma tenendo conto della direzione di A // => se controverse va preso Next static int GetCrvBDirAPrev( IntCrvCrvInfo& Icci) { // non ่ overlap, ่ il prev del primo punto if ( ! Icci.bOverlap) return Icci.IciB[0].nPrevTy ; // ่ overlap equiverso, ่ il prev del primo punto if ( Icci.bCBOverEq) return Icci.IciB[0].nPrevTy ; // ่ overlap controverso, ่ il next del primo punto return Icci.IciB[0].nNextTy ; } //---------------------------------------------------------------------------- // Next della curva B ma tenendo conto della direzione di A // => se controverse va preso Prev static int GetCrvBDirANext( IntCrvCrvInfo& Icci) { // non ่ overlap, ่ il next del primo punto if ( ! Icci.bOverlap) return Icci.IciB[0].nNextTy ; // ่ overlap equiverso, ่ il next del secondo punto if ( Icci.bCBOverEq) return Icci.IciB[1].nNextTy ; // ่ overlap controverso, ่ il prev del secondo punto return Icci.IciB[1].nPrevTy ; } //---------------------------------------------------------------------------- static bool CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB, int& nType) { // devo studiare un intorno dell'intersezione // spostandomi leggermente per evitare eventuali problemi di tangenza Point3d ptP ; // direzione di arrivo (FROM_MINUS) o partenza (FROM_PLUS) curva A Vector3d vtADir ; double dUAm = dUA ; if ( ! MoveParamToAvoidTg( dUAm, nSideA, CurveA) || ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) vtADir.Invert() ; // direzioni di arrivo (prev) e partenza (next) curva B Vector3d vtBpDir ; double dUBp = dUB ; if ( ! MoveParamToAvoidTg( dUBp, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUBp, ICurve::FROM_MINUS, ptP, vtBpDir)) return false ; vtBpDir.Invert() ; Vector3d vtBnDir ; double dUBn = dUB ; if ( ! MoveParamToAvoidTg( dUBn, ICurve::FROM_PLUS, CurveB) || ! CurveB.GetPointTang( dUBn, ICurve::FROM_PLUS, ptP, vtBnDir)) return false ; // angolo del versore DirA rispetto a DirBn double dAngADeg ; if ( ! vtBnDir.GetAngleXY( vtADir, dAngADeg)) return false ; if ( dAngADeg < 0) dAngADeg += ANG_FULL ; // angolo del versore DirBp rispetto a DirBn double dAngBpDeg ; if ( ! vtBnDir.GetAngleXY( vtBpDir, dAngBpDeg)) return false ; if ( dAngBpDeg < 0) dAngBpDeg += ANG_FULL ; // se l'angolo di DirA ่ compreso tra DirBn e DirBp (muovendosi in senso CCW) allora ่ IN, altrimenti OUT if ( dAngADeg > 0 && dAngADeg < dAngBpDeg) nType = ICCT_IN ; else nType = ICCT_OUT ; return true ; } //---------------------------------------------------------------------------- static bool CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA, const ICurve& CurveB, double dUB1, double dUB2, int& nType) { // devo studiare un intorno dell'intersezione (in questo caso A con due punti sovrapposti di B) Point3d ptP ; // direzione di arrivo (FROM_MINUS) o partenza (FROM_PLUS) curva A Vector3d vtADir ; double dUAm = dUA ; if ( ! MoveParamToAvoidTg( dUAm, nSideA, CurveA) || ! CurveA.GetPointTang( dUAm, nSideA, ptP, vtADir)) return false ; if ( nSideA == ICurve::FROM_MINUS) vtADir.Invert() ; // direzioni di arrivo (prev) e partenza (next) curva B (P1) Vector3d vtB1pDir ; double dUB1p = dUB1 ; if ( ! MoveParamToAvoidTg( dUB1p, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUB1p, ICurve::FROM_MINUS, ptP, vtB1pDir)) return false ; vtB1pDir.Invert() ; Vector3d vtB1nDir ; double dUB1n = dUB1 ; if ( ! MoveParamToAvoidTg( dUB1n, ICurve::FROM_PLUS, CurveB) || ! CurveB.GetPointTang( dUB1n, ICurve::FROM_PLUS, ptP, vtB1nDir)) return false ; // direzioni di arrivo (prev) e partenza (next) curva B (P2) Vector3d vtB2pDir ; double dUB2p = dUB2 ; if ( ! MoveParamToAvoidTg( dUB2p, ICurve::FROM_MINUS, CurveB) || ! CurveB.GetPointTang( dUB2p, ICurve::FROM_MINUS, ptP, vtB2pDir)) return false ; vtB2pDir.Invert() ; Vector3d vtB2nDir ; double dUB2n = dUB2 ; if ( ! MoveParamToAvoidTg( dUB2n, ICurve::FROM_PLUS, CurveB) || ! CurveB.GetPointTang( dUB2n, ICurve::FROM_PLUS, ptP, vtB2nDir)) return false ; // angolo del versore DirA rispetto a DirB1n double dAngADeg ; if ( ! vtB1nDir.GetAngleXY( vtADir, dAngADeg)) return false ; if ( dAngADeg < 0) dAngADeg += ANG_FULL ; // angolo del versore DirB2n rispetto a DirB1n double dAngB2nDeg ; if ( ! vtB1nDir.GetAngleXY( vtB2nDir, dAngB2nDeg)) return false ; if ( dAngB2nDeg < 0) dAngB2nDeg += ANG_FULL ; // angoli dei versori DirB1p e DirB2p rispetto a DirB1n double dAngB1pDeg ; if ( ! vtB1nDir.GetAngleXY( vtB1pDir, dAngB1pDeg)) return false ; if ( dAngB1pDeg < 0) dAngB1pDeg += ANG_FULL ; double dAngB2pDeg ; if ( ! vtB1nDir.GetAngleXY( vtB2pDir, dAngB2pDeg)) return false ; if ( dAngB2pDeg < 0) dAngB2pDeg += ANG_FULL ; // li ordino in senso crescente if ( dAngB1pDeg > dAngB2pDeg) swap( dAngB1pDeg, dAngB2pDeg) ; // IN ่ tra 0 e dAngB1pDeg e tra dAngB2nDeg e dAngB2pDeg if ( ( dAngADeg > 0 && dAngADeg < dAngB1pDeg) || ( dAngADeg > dAngB2nDeg && dAngADeg < dAngB2pDeg)) nType = ICCT_IN ; else nType = ICCT_OUT ; return true ; }