Files
EgtGeomKernel/IntersCrvCompoCrvCompo.cpp
T
Dario Sassi 3e8e7e2e2a EgtGeomKernel 1.5l1 :
- aggiornamento a VS2013
- migliorato SimpleOffset e implementato anche per CurveComposite
- il lato di offset ora viene dal segno dello spostamento ( + a destra, - a sinistra)
- il vettore estrusione ora è la normale al piano di offset (se non c'è uso Z+)
- aggiunto a tutte le entità geometriche membro m_nTempProp intero temporaneo
- migliorata DistPointCrvBezier e DistPointArc
- corretta IntersLineArc con linee che non giacciono nel piano XY
- corretta ModifyStart di CurveArc
- a PolyArc aggiunto metodo ParamLinearTransform
- aggiunta gestione riferimento di griglia (CPlane).
2014-12-17 15:03:29 +00:00

764 lines
35 KiB
C++

//----------------------------------------------------------------------------
// 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 <algorithm>
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 ;
}