Files
EgtGeomKernel/IntersCrvCompoCrvCompo.cpp
T
DarioS ffc78b03a7 EgtGeomKernel 2.4l2 :
- corretto riconoscimento topologia intersezioni per autointersezioni di curve.
2022-12-08 10:35:32 +01:00

1167 lines
55 KiB
C++

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