3e8e7e2e2a
- 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).
764 lines
35 KiB
C++
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 ;
|
|
}
|