//---------------------------------------------------------------------------- // EgalTech 2014-2018 //---------------------------------------------------------------------------- // File : IntersCrvCompoCrvCompo.cpp Data : 09.12.18 Versione : 1.9l1 // 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 "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkAngle.h" #include "/EgtDev/Include/EGkHashGrids2d.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, const ICurveComposite& crvCompo) ; 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() ; // determino se auto-intersezione bool bAutoInters = ( &CCompoA == &CCompoB) ; // dati generali delle curve bool bCrvAClosed = CCompoA.IsClosed() ; bool bCrvBClosed = CCompoB.IsClosed() ; double dStart, dEnd ; if ( ! CCompoA.GetDomain( dStart, dEnd)) return ; double dCrvASpan = dEnd - dStart ; if ( ! CCompoB.GetDomain( dStart, dEnd)) return ; double dCrvBSpan = dEnd - dStart ; // creo HashGrids2d per curva con maggior numero di elementi const int LIM_CRVNBRSQUARED = 4095 ; int nCrvNbrA = CCompoA.GetCurveCount() ; int nCrvNbrB = CCompoB.GetCurveCount() ; if ( nCrvNbrA >= nCrvNbrB) { HashGrids2d HHGrids ; HHGrids.SetActivationGrid( nCrvNbrA * nCrvNbrB > LIM_CRVNBRSQUARED) ; for ( int nA = 0 ; nA < nCrvNbrA ; ++ nA) { const ICurve* pCrvA = CCompoA.GetCurve( nA) ; BBox3d boxA ; pCrvA->GetLocalBBox( boxA) ; if ( ! HHGrids.Add( nA, boxA)) return ; } if ( ! HHGrids.Update()) return ; for ( int nB = 0 ; nB < nCrvNbrB ; ++ nB) { const ICurve* pCrvB = CCompoB.GetCurve( nB) ; BBox3d boxB ; pCrvB->GetLocalBBox( boxB) ; INTVECTOR vnIds ; if ( HHGrids.Find( boxB, vnIds)) { for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) { int nA = vnIds[i] ; const ICurve* pCrvA = CCompoA.GetCurve( nA) ; // eseguo l'intersezione di queste curve semplici IntersSimpleCurves( *pCrvA, nA, *pCrvB, nB, bAutoInters, bCrvAClosed, nCrvNbrA) ; } } } } else { HashGrids2d HHGrids ; HHGrids.SetActivationGrid( nCrvNbrA * nCrvNbrB > LIM_CRVNBRSQUARED) ; for ( int nB = 0 ; nB < nCrvNbrB ; ++ nB) { const ICurve* pCrvB = CCompoB.GetCurve( nB) ; BBox3d boxB ; pCrvB->GetLocalBBox( boxB) ; if ( ! HHGrids.Add( nB, boxB)) return ; } if ( ! HHGrids.Update()) return ; for ( int nA = 0 ; nA < nCrvNbrA ; ++ nA) { const ICurve* pCrvA = CCompoA.GetCurve( nA) ; BBox3d boxA ; pCrvA->GetLocalBBox( boxA) ; INTVECTOR vnIds ; if ( HHGrids.Find( boxA, vnIds)) { for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) { int nB = vnIds[i] ; const ICurve* pCrvB = CCompoB.GetCurve( nB) ; // eseguo l'intersezione di queste curve semplici IntersSimpleCurves( *pCrvA, nA, *pCrvB, nB, bAutoInters, bCrvAClosed, nCrvNbrA) ; } } } } // se non autointersezione e curva B chiusa, verifico per curva A tipo prima della prima intersezione e dopo l'ultima if ( ! bAutoInters && bCrvBClosed && m_nNumInters > 0) { // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ; // se punto iniziale della curva A con tipo precedente non definito Point3d ptStart ; if ( m_Info[0].IciA[0].nPrevTy == ICCT_NULL && CCompoA.GetStartPoint( ptStart)) { // posizione del punto iniziale di A rispetto alla curva B DistPointCurve dPCS( ptStart, CCompoB) ; int nSideStart ; if ( dPCS.GetSideAtMinDistPoint( 0, Z_AX, nSideStart)) { if ( nSideStart == MDS_RIGHT) m_Info[0].IciA[0].nPrevTy = ICCT_OUT ; else if ( nSideStart == MDS_LEFT) m_Info[0].IciA[0].nPrevTy = ICCT_IN ; } } // se punto finale della curva A con tipo successivo non definito Point3d ptEnd ; int nI = ( m_Info[m_nNumInters-1].bOverlap ? 1 : 0) ; if ( m_Info[m_nNumInters-1].IciA[nI].nNextTy == ICCT_NULL && CCompoA.GetEndPoint( ptEnd)) { // posizione del punto finale di A rispetto alla curva B DistPointCurve dPCE( ptEnd, CCompoB) ; int nSideEnd ; if ( dPCE.GetSideAtMinDistPoint( 0, Z_AX, nSideEnd)) { if ( nSideEnd == MDS_RIGHT) m_Info[m_nNumInters-1].IciA[nI].nNextTy = ICCT_OUT ; else if ( nSideEnd == MDS_LEFT) m_Info[m_nNumInters-1].IciA[nI].nNextTy = ICCT_IN ; } } } // se non autointersezione e curva A chiusa, verifico per curva B tipo prima della prima intersezione e dopo l'ultima if ( ! bAutoInters && bCrvAClosed && m_nNumInters > 0) { // ordino le intersezioni secondo l'ordine crescente del parametro della seconda curva stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ; // se punto iniziale della curva B con tipo precedente non definito Point3d ptStart ; if ( m_Info[0].IciB[0].nPrevTy == ICCT_NULL && CCompoB.GetStartPoint( ptStart)) { // posizione del punto iniziale di B rispetto alla curva A DistPointCurve dPCS( ptStart, CCompoA) ; int nSideStart ; if ( dPCS.GetSideAtMinDistPoint( 0, Z_AX, nSideStart)) { if ( nSideStart == MDS_RIGHT) m_Info[0].IciB[0].nPrevTy = ICCT_OUT ; else if ( nSideStart == MDS_LEFT) m_Info[0].IciB[0].nPrevTy = ICCT_IN ; } } // se punto finale della curva B con tipo successivo non definito Point3d ptEnd ; int nI = ( m_Info[m_nNumInters-1].bOverlap && m_Info[m_nNumInters-1].bCBOverEq ? 1 : 0) ; if ( m_Info[0].IciB[nI].nNextTy == ICCT_NULL && CCompoB.GetEndPoint( ptEnd)) { // posizione del punto finale di B rispetto alla curva A DistPointCurve dPCE( ptEnd, CCompoA) ; int nSideEnd ; if ( dPCE.GetSideAtMinDistPoint( 0, Z_AX, nSideEnd)) { if ( nSideEnd == MDS_RIGHT) m_Info[m_nNumInters-1].IciB[nI].nNextTy = ICCT_OUT ; else if ( nSideEnd == MDS_LEFT) m_Info[m_nNumInters-1].IciB[nI].nNextTy = ICCT_IN ; } } } // ordino le intersezioni secondo l'ordine crescente del parametro della prima curva stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ; // se auto-intersezione, elimino le seconde copie di una stessa intersezione if ( bAutoInters) { for ( int i = 0 ; i < m_nNumInters ; ++ i) { for ( int j = i + 1 ; j < m_nNumInters ; ++ j) { // se intersezioni puntuali if ( ! m_Info[i].bOverlap && ! m_Info[j].bOverlap) { // se coincidono U e ptInt tra A e B if ( abs( m_Info[i].IciA[0].dU - m_Info[j].IciB[0].dU) < EPS_SMALL && AreSamePointXYEpsilon( m_Info[i].IciA[0].ptI, m_Info[j].IciB[0].ptI, 10 * EPS_SMALL)) { // se non è alla fine di curva chiusa if ( ! bCrvAClosed || abs( m_Info[j].IciA[0].dU - dCrvBSpan) > EPS_SMALL) // elimino la seconda EraseOtherInfo( i, j) ; else // elimino la prima EraseCurrentInfo( i, j) ; break ; } } // se intersezioni sovrapposte else if ( m_Info[i].bOverlap && m_Info[j].bOverlap) { // se equiverse if ( m_Info[i].bCBOverEq && m_Info[j].bCBOverEq) { // se coincidono U e ptInt tra A e B if ( abs( m_Info[i].IciA[0].dU - m_Info[j].IciB[0].dU) < EPS_SMALL && abs( m_Info[i].IciA[1].dU - m_Info[j].IciB[1].dU) < EPS_SMALL && AreSamePointXYEpsilon( m_Info[i].IciA[0].ptI, m_Info[j].IciB[0].ptI, 10 * EPS_SMALL) && AreSamePointXYEpsilon( m_Info[i].IciA[1].ptI, m_Info[j].IciB[1].ptI, 10 * EPS_SMALL)) { // elimino la seconda EraseOtherInfo( i, j) ; break ; } } // se controverse else if ( ! m_Info[i].bCBOverEq && ! m_Info[j].bCBOverEq) { // se coincidono U e ptInt tra A e B invertiti if ( abs( m_Info[i].IciA[0].dU - m_Info[j].IciB[1].dU) < EPS_SMALL && abs( m_Info[i].IciA[1].dU - m_Info[j].IciB[0].dU) < EPS_SMALL && AreSamePointXYEpsilon( m_Info[i].IciA[0].ptI, m_Info[j].IciB[1].ptI, 10 * EPS_SMALL) && AreSamePointXYEpsilon( m_Info[i].IciA[1].ptI, m_Info[j].IciB[0].ptI, 10 * EPS_SMALL)) { // elimino la seconda EraseOtherInfo( i, j) ; break ; } } } } } } // sistemazione di intersezioni coincidenti con ordinamento su prima curva A for ( int i = 0 ; i < m_nNumInters ; ++ i) { // precedente int j = i - 1 ; if ( j < 0) { if ( bCrvAClosed && m_nNumInters > 1) j = m_nNumInters - 1 ; else 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 ( AreSamePointXYEpsilon( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI, 10 * EPS_SMALL) && AreSamePointXYEpsilon( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI, 10 * EPS_SMALL) && CompatibleParamA( m_Info[j], m_Info[i], bCrvAClosed, dCrvASpan) && CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan)) { // caso entrambi Overlap ma di tipo opposto e sullo stesso tratto if ( m_Info[i].bOverlap && m_Info[j].bOverlap && m_Info[i].bCBOverEq != m_Info[j].bCBOverEq && abs( m_Info[i].IciA[0].dU - m_Info[j].IciA[0].dU) < EPS_PARAM && abs( m_Info[i].IciA[1].dU - m_Info[j].IciA[1].dU) < EPS_PARAM) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // caso DET-NULL -> NULL-DET per prima curva 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].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], CCompoA) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ; // 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) ; } } // 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], CCompoA) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ; // 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) ; } } // caso DET-NULL -> DET-NULL per prima curva con NULL-NULL -> NULL-NULL su seconda curva 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 && 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) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // caso NULL-DET -> NULL-DET per prima curva con NULL-NULL -> NULL-NULL su seconda curva 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 && 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) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // 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) { m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) EraseCurrentInfo( i, j) ; } // 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) { m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ; // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) EraseOtherInfo( i, j) ; } } } // sistemazione di intersezioni coincidenti con ordinamento su seconda curva B stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ; for ( int i = 0 ; i < m_nNumInters ; ++ i) { // precedente int j = i - 1 ; if ( j < 0) { if ( bCrvAClosed && m_nNumInters > 1) j = m_nNumInters - 1 ; else 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 ( AreSamePointXYEpsilon( m_Info[j].IciA[kj].ptI, m_Info[i].IciA[ki].ptI, 10 * EPS_SMALL) && AreSamePointXYEpsilon( m_Info[j].IciB[kj].ptI, m_Info[i].IciB[ki].ptI, 10 * EPS_SMALL) && CompatibleParamA( m_Info[j], m_Info[i], bCrvAClosed, dCrvASpan) && CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan)) { // caso entrambi Overlap ma di tipo opposto e sullo stesso tratto if ( m_Info[i].bOverlap && m_Info[j].bOverlap && m_Info[i].bCBOverEq != m_Info[j].bCBOverEq && abs( m_Info[i].IciB[0].dU - m_Info[j].IciB[0].dU) < EPS_PARAM && abs( m_Info[i].IciB[1].dU - m_Info[j].IciB[1].dU) < EPS_PARAM) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // 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], CCompoA) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ; // 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) ; } } // 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], CCompoA) ; MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ; // 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) ; } } // caso DET-NULL -> DET-NULL per seconda curva con NULL-NULL -> NULL-NULL su prima 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 && 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) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // caso NULL-DET -> NULL-DET per seconda curva con NULL-NULL -> NULL-NULL su prima 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 && 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) { // cancello entrambe EraseOtherInfo( i, j) ; EraseCurrentInfo( i, j) ; } // caso NULL-NULL per corrente di seconda curva else if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) { m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ; if ( m_Info[i].IciA[ki].dU > m_Info[j].IciA[kj].dU + EPS_PARAM) m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ; // cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente) EraseCurrentInfo( i, j) ; } // caso NULL-NULL per precedente di seconda curva else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL) { m_Info[i].IciB[0].nPrevTy = m_Info[j].IciB[0].nPrevTy ; if ( m_Info[j].IciA[0].dU < m_Info[i].IciA[0].dU - EPS_PARAM) m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ; // cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente) EraseOtherInfo( i, j) ; } } } // ripristino ordinamento su prima curva stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ; // verifico se sono rimaste delle intersezioni di tipo non definito sulla curva A e cerco di risolverle per continuità for ( int i = 0 ; i < m_nNumInters ; ++ i) { // se il tipo di accostamento per la curva A non è definito if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) { if ( i > 0 || ( bCrvAClosed && ! bAutoInters)) { int j = ( i > 0 ? i - 1 : m_nNumInters - 1) ; m_Info[i].IciA[0].nPrevTy = ( m_Info[j].bOverlap ? m_Info[j].IciA[1].nNextTy : m_Info[j].IciA[0].nNextTy) ; } } // se il tipo di allontanamento per la curva A non è definito int ki = ( m_Info[i].bOverlap ? 1 : 0) ; if ( m_Info[i].IciA[ki].nNextTy == ICCT_NULL) { if ( i < m_nNumInters - 1 || ( bCrvAClosed && ! bAutoInters)) { int j = ( i < m_nNumInters - 1 ? i + 1 : 0) ; m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[0].nPrevTy ; } } } // verifico se sono rimaste delle intersezioni di tipo non definito sulla curva B e cerco di risolverle per continuità stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ; for ( int i = 0 ; i < m_nNumInters ; ++ i) { // se il tipo di accostamento per la curva B non è definito if ( m_Info[i].IciB[0].nPrevTy == ICCT_NULL) { if ( i > 0 || ( bCrvBClosed && ! bAutoInters)) { int j = ( i > 0 ? i - 1 : m_nNumInters - 1) ; m_Info[i].IciB[0].nPrevTy = ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq ? m_Info[j].IciB[1].nNextTy : m_Info[j].IciB[0].nNextTy) ; } } // se il tipo di allontanamento per la curva B non è definito if ( m_Info[i].IciB[0].nNextTy == ICCT_NULL) { if ( i < m_nNumInters - 1 || ( bCrvBClosed && ! bAutoInters)) { int j = ( i < m_nNumInters - 1 ? i + 1 : 0) ; m_Info[i].IciB[0].nNextTy = ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq ? m_Info[j].IciB[1].nPrevTy : m_Info[j].IciB[0].nPrevTy) ; } } } // ripristino ordinamento su prima curva stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ; // verifico se sono rimaste delle intersezioni di tipo non definito e cerco di risolverle studiando gli intorni 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)) // 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)) // 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)) // 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)) // 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) { // se autointersezione con spike double dDeltaU = abs( m_Info[i].IciA[0].dU - m_Info[i].IciB[0].dU) ; if ( bAutoInters && ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM))) { // è punta di spike int nType = ICCT_SPK ; // aggiorno il tipo di allontanamento della curva A dalla 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 ; } // caso standard else { // 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)) { // 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) { // se autointersezione con spike double dDeltaU = abs( m_Info[i].IciA[1].dU - m_Info[i].IciB[1].dU) ; if ( bAutoInters && ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM))) { // è punta di spike int nType = ICCT_SPK ; // 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 ; } // caso standard else { // 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)) { // 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 con lo stesso verso, 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].bCBOverEq == m_Info[i].bCBOverEq && 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::IntersSimpleCurves( const ICurve& CurveA, int nA, const ICurve& CurveB, int nB, bool bAutoInters, bool bClosed, int nCurvesNbr) { // se autointersezione, verifico non sia la stessa curva if ( bAutoInters && nA == nB) return true ; // eseguo l'intersezione di queste curve semplici IntersCurveCurve intCC( CurveA, CurveB) ; // ne recupero i risultati int nCurrInters = intCC.GetIntersCount() ; if ( nCurrInters > 0) { m_bOverlaps = ( intCC.GetOverlaps() ? true : m_bOverlaps) ; for ( int j = 0 ; j < nCurrInters ; ++ j) { // recupero e aggiusto i dati dell'intersezione IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( j, aInfo) ; aInfo.IciA[0].dU += nA ; aInfo.IciB[0].dU += nB ; if ( aInfo.bOverlap) { aInfo.IciA[1].dU += nA ; aInfo.IciB[1].dU += nB ; } // se autointersezione, escludo le intersezioni puntuali agli estremi comuni di curve consecutive if ( bAutoInters) { // estremo iniziale if ( ( nB == nA - 1 || ( bClosed && nA == 0 && nB == nCurvesNbr - 1)) && ! aInfo.bOverlap) { Point3d ptStart ; if ( CurveA.GetStartPoint( ptStart) && AreSamePointApprox( ptStart, aInfo.IciA[0].ptI)) continue ; } // estremo finale if ( ( nB == nA + 1 || ( bClosed && nA == nCurvesNbr - 1 && nB == 0)) && ! aInfo.bOverlap) { Point3d ptEnd ; if ( CurveA.GetEndPoint( ptEnd) && AreSamePointApprox( ptEnd, aInfo.IciA[0].ptI)) continue ; } } // aggiungo all'elenco delle intersezioni m_Info.push_back( aInfo) ; ++ m_nNumInters ; } } return true ; } //---------------------------------------------------------------------------- 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 SortGreaterA( 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 SortGreaterB( const IntCrvCrvInfo& aInfo1, const IntCrvCrvInfo& aInfo2) { double dU1, dU2 ; // determino il primo termine del confronto dU1 = aInfo1.IciB[0].dU ; if ( aInfo1.bOverlap) { // caso normale if ( aInfo1.IciB[0].dU < aInfo1.IciB[1].dU) dU1 = 0.5 * ( aInfo1.IciB[0].dU + aInfo1.IciB[1].dU) ; // a cavallo di fine / inizio else dU1 = aInfo1.IciB[0].dU + SPAN_PARAM ; } // determino il secondo termine del confronto dU2 = aInfo2.IciB[0].dU ; if ( aInfo2.bOverlap) { // caso normale if ( aInfo2.IciB[0].dU < aInfo2.IciB[1].dU) dU2 = 0.5 * ( aInfo2.IciB[0].dU + aInfo2.IciB[1].dU) ; // a cavallo di fine / inizio else dU2 = aInfo2.IciB[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) && AreSamePointXYEpsilon( Info[j].IciB[kj].ptI, Info[i].IciB[ki].ptI, 10 * 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 ( abs( Icci1.IciA[k].dU - Icci2.IciA[0].dU) > 0.1 * SPAN_PARAM && ( ! bCrvAClosed || abs( abs( 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 ( abs( Icci1.IciB[k].dU - Icci2.IciB[0].dU) > 0.1 * SPAN_PARAM && ( ! bCrvBClosed || abs( abs( Icci1.IciB[k].dU - Icci2.IciB[0].dU) - dCrvBSpan) > 0.1 * SPAN_PARAM)) return false ; return true ; } //---------------------------------------------------------------------------- static void MediaParamPoints( IntCrvInfo& Ici1, IntCrvInfo& Ici2, const ICurveComposite& crvCompo) { // distanza tra i punti //double dSqDist = SqDist( Ici1.ptI, Ici2.ptI) ; // medio i punti Ici1.ptI = 0.5 * ( Ici1.ptI + Ici2.ptI) ; Ici2.ptI = Ici1.ptI ; // per non mediare i parametri tra gli estremi di curva chiusa if ( abs( Ici1.dU - Ici2.dU) > 0.1 * SPAN_PARAM) return ; // determino il punto della curva che corrisponde al valore medio dei parametri double dUmed = 0.5 * ( Ici1.dU + Ici2.dU) ; //Point3d ptMed ; //if ( ! crvCompo.GetPointD1D2( dUmed, ICurve::FROM_MINUS, ptMed)) // return ; // verifico che non sia più lontano dei punti originali dal loro medio //if ( SqDist( Ici1.ptI, ptMed) > dSqDist / 4) // return ; // medio i parametri Ici1.dU = dUmed ; Ici2.dU = dUmed ; } //---------------------------------------------------------------------------- // 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) ; // se non ci sono variazioni angolari significative, non posso decidere alcunché const double MIN_DEV_ANG = 2 ; if ( abs( DiffAngle( dAngB1pDeg + ANG_STRAIGHT, 0)) < MIN_DEV_ANG && abs( DiffAngle( dAngB2pDeg + ANG_STRAIGHT, dAngB2nDeg)) < MIN_DEV_ANG) return false ; // 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 ; }