de4165889a
- IntersCurveCurve: eliminata le intersezioni puntuali rimanenti vicine a overlap; corretto scorrimento delle intersezioni durante il merge.
1470 lines
67 KiB
C++
1470 lines
67 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>
|
|
#include <ranges>
|
|
|
|
using namespace std ;
|
|
|
|
//--------------------------- Local functions --------------------------------
|
|
static bool CompatibleParamA( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2,
|
|
bool bCrvAClosed, double dCrvASpan, bool bOrderedOnB = false) ;
|
|
static bool CompatibleParamB( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2,
|
|
bool bCrvBClosed, double dCrvBSpan, bool bOrderedOnB = false) ;
|
|
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
|
|
EraseBothInfo( 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 ;
|
|
}
|
|
else {
|
|
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
|
|
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
|
|
}
|
|
// 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 ;
|
|
}
|
|
else {
|
|
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
|
|
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
|
|
}
|
|
|
|
// 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 ;
|
|
}
|
|
else {
|
|
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
|
|
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
|
|
}
|
|
// 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 ;
|
|
}
|
|
else {
|
|
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
|
|
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
|
|
}
|
|
|
|
// 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
|
|
EraseBothInfo( 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
|
|
EraseBothInfo( 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 = ICCT_NULL ;
|
|
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
|
|
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
|
|
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
|
|
// 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[ki].nPrevTy = ICCT_NULL ;
|
|
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
|
|
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
|
|
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
|
|
// 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 = ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq ? 1 : 0) ;
|
|
int kj = ( m_Info[j].bOverlap && m_Info[j].bCBOverEq ? 1 : 0) ;
|
|
// 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, true) &&
|
|
CompatibleParamB( m_Info[j], m_Info[i], bCrvBClosed, dCrvBSpan, true)) {
|
|
// 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
|
|
EraseBothInfo( 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
|
|
EraseBothInfo( 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
|
|
EraseBothInfo( 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 = ICCT_NULL ;
|
|
if ( m_Info[j].IciA[kj].nNextTy == ICCT_NULL)
|
|
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ;
|
|
if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL)
|
|
m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ;
|
|
// 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[ki].nPrevTy = ICCT_NULL ;
|
|
if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL)
|
|
m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ;
|
|
if ( m_Info[i].IciA[ki].nNextTy == ICCT_NULL)
|
|
m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[kj].nNextTy ;
|
|
// 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
|
|
int ki = ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq ? 1 : 0) ;
|
|
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL) {
|
|
if ( i > 0 || ( bCrvBClosed && ! bAutoInters)) {
|
|
int j = ( i > 0 ? i - 1 : m_nNumInters - 1) ;
|
|
m_Info[i].IciB[ki].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
|
|
ki = ( m_Info[i].bOverlap && m_Info[i].bCBOverEq ? 1 : 0) ;
|
|
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL) {
|
|
if ( i < m_nNumInters - 1 || ( bCrvBClosed && ! bAutoInters)) {
|
|
int j = ( i < m_nNumInters - 1 ? i + 1 : 0) ;
|
|
m_Info[i].IciB[ki].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) {
|
|
// 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) {
|
|
// 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bAutoInters) {
|
|
// controllo l'eventuale presenza di spike
|
|
for ( int i = 0 ; i < m_nNumInters ; ++ i) {
|
|
if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
|
|
// se secondo tratto dello spike
|
|
double dDeltaU = abs( m_Info[i].IciA[0].dU - m_Info[i].IciB[0].dU) ;
|
|
if ( 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 ;
|
|
}
|
|
// se primo tratto dello spike
|
|
dDeltaU = abs( m_Info[i].IciA[1].dU - m_Info[i].IciB[1].dU) ;
|
|
if ( 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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) ;
|
|
}
|
|
|
|
// verifico se una curva ha tutte le info e queste info sono coerenti
|
|
if ( m_nNumInters > 1 && ! bAutoInters) {
|
|
bool bCoherent = true ;
|
|
INTVECTOR vIncoherenceWithPrev ;
|
|
INTVECTOR vNewOverlap ;
|
|
// salvo eventuali incoerenze col precedente
|
|
for ( int i = bCrvAClosed ? 0 : 1 ; i < m_nNumInters ; ++i) {
|
|
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
|
|
int kj = m_Info[j].bOverlap ? 1 : 0 ;
|
|
if ( (m_Info[j].IciA[kj].nNextTy == ICCT_NULL || m_Info[i].IciA[0].nPrevTy == ICCT_NULL || m_Info[j].IciA[kj].nNextTy != m_Info[i].IciA[0].nPrevTy) &&
|
|
m_Info[j].IciA[kj].nNextTy != ICCT_SPK && m_Info[i].IciA[0].nPrevTy != ICCT_SPK) {
|
|
vIncoherenceWithPrev.push_back( i) ;
|
|
bCoherent = false ;
|
|
}
|
|
}
|
|
// incoerenze sulla curva A
|
|
if ( ! bCoherent) {
|
|
for ( int i : vIncoherenceWithPrev) {
|
|
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
|
|
int kj = m_Info[j].bOverlap ? 1 : 0 ;
|
|
int nType = 0 ;
|
|
CalcSide( j, i, &CCompoA, &CCompoB, true, nType) ;
|
|
if ( nType != ICCT_ON) {
|
|
m_Info[i].IciA[0].nPrevTy = nType ;
|
|
m_Info[j].IciA[kj].nNextTy = nType ;
|
|
}
|
|
else
|
|
vNewOverlap.push_back( i) ;
|
|
}
|
|
}
|
|
|
|
// faccio il merge se ho trasformato delle intersezioni in overlap
|
|
for ( int i : views::reverse( vNewOverlap))
|
|
MergeNewOverlap( i, true) ;
|
|
|
|
vNewOverlap.clear() ;
|
|
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ;
|
|
bCoherent = true ;
|
|
vIncoherenceWithPrev.clear() ;
|
|
// salvo eventuali incoerenze col precedente
|
|
for ( int i = bCrvBClosed ? 0 : 1 ; i < m_nNumInters ; ++i) {
|
|
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
|
|
int ki = m_Info[i].bOverlap && ! m_Info[i].bCBOverEq ? 1 : 0 ;
|
|
int kj = m_Info[j].bOverlap && m_Info[j].bCBOverEq ? 1 : 0 ;
|
|
if ( ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL || m_Info[i].IciB[ki].nPrevTy == ICCT_NULL || m_Info[j].IciB[kj].nNextTy != m_Info[i].IciB[ki].nPrevTy) &&
|
|
m_Info[j].IciB[kj].nNextTy != ICCT_SPK && m_Info[i].IciB[ki].nPrevTy != ICCT_SPK) {
|
|
vIncoherenceWithPrev.push_back( i) ;
|
|
bCoherent = false ;
|
|
}
|
|
}
|
|
// incoerenze sulla curva B
|
|
if ( ! bCoherent) {
|
|
for ( int i : vIncoherenceWithPrev) {
|
|
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
|
|
int ki = m_Info[i].bOverlap && ! m_Info[i].bCBOverEq ? 1 : 0 ;
|
|
int kj = m_Info[j].bOverlap && m_Info[j].bCBOverEq ? 1 : 0 ;
|
|
int nType = 0 ;
|
|
CalcSide( j, i, &CCompoB, &CCompoA, false, nType) ;
|
|
if ( nType != ICCT_ON) {
|
|
m_Info[i].IciB[ki].nPrevTy = nType ;
|
|
m_Info[j].IciB[kj].nNextTy = nType ;
|
|
}
|
|
else
|
|
vNewOverlap.push_back( i) ;
|
|
}
|
|
}
|
|
|
|
// faccio il merge se ho trasformato delle intersezioni in overlap
|
|
for ( int i : views::reverse( vNewOverlap))
|
|
MergeNewOverlap( i, false) ;
|
|
}
|
|
else {
|
|
// posso completare A guardando B e viceversa
|
|
}
|
|
|
|
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ;
|
|
// verifiche su intersezioni in zone non-manifold
|
|
OrderNonManifoldInters( m_Info, CCompoA, CCompoB) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCrvCompoCrvCompo::CalcSide( int j, int i,const ICurve* pThisCrv, const ICurve* pOtherCrv, bool bCrvAOrB, int& nType)
|
|
{
|
|
const IntCrvCrvInfo& Icci1 = m_Info[j] ;
|
|
const IntCrvCrvInfo& Icci2 = m_Info[i] ;
|
|
// calcolo tra l'intersezione 1 e 2 se la curva sta dentro o fuori
|
|
int kj = Icci1.bOverlap ? 1 : 0 ;
|
|
double dU = 0 ;
|
|
bool bPrevIsBefore = true ;
|
|
if ( bCrvAOrB) {
|
|
// se precedente minore del successivo faccio la media
|
|
if ( Icci1.IciA[kj].dU < Icci2.IciA[0].dU)
|
|
dU = ( Icci2.IciA[0].dU + Icci1.IciA[kj].dU) / 2 ;
|
|
// altrimenti guardo tra lo start e il successivo
|
|
else {
|
|
bPrevIsBefore = false ;
|
|
dU = ( Icci2.IciA[0].dU + 0.) / 2 ;
|
|
if ( dU < EPS_SMALL) {
|
|
double dStart, dEnd ;
|
|
pThisCrv->GetDomain( dStart, dEnd) ;
|
|
double dUNew = dEnd - Icci1.IciA[kj].dU / 2 ;
|
|
if ( dUNew > dU)
|
|
dU = dUNew ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// se precedente minore del successivo faccio la media
|
|
if ( Icci1.IciB[kj].dU < Icci2.IciB[0].dU)
|
|
dU = ( Icci2.IciB[0].dU + Icci1.IciB[kj].dU) / 2 ;
|
|
// altrimenti guardi tra lo start e il successivo
|
|
else {
|
|
bPrevIsBefore = false ;
|
|
dU = ( Icci2.IciB[0].dU + 0.) / 2 ;
|
|
if ( dU < EPS_SMALL) {
|
|
double dStart, dEnd ;
|
|
pThisCrv->GetDomain( dStart, dEnd) ;
|
|
double dUNew = dEnd - Icci1.IciB[kj].dU / 2 ;
|
|
if ( dUNew > dU)
|
|
dU = dUNew ;
|
|
}
|
|
}
|
|
}
|
|
Point3d ptTest ; pThisCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptTest) ;
|
|
DistPointCurve dpc( ptTest, *pOtherCrv) ;
|
|
dpc.GetSideAtMinDistPoint( 0, Z_AX, nType, EPS_ZERO) ;
|
|
if ( nType == MDS_LEFT)
|
|
nType = ICCT_IN ;
|
|
else if ( nType == MDS_RIGHT)
|
|
nType = ICCT_OUT ;
|
|
// se lo trovo sulla curva controllo se posso definire un tratto overlap
|
|
if ( nType == MDS_ON) {
|
|
double dFactor = 1./3. ;
|
|
DBLVECTOR vdU(2) ;
|
|
bool bIsOn = false ;
|
|
if ( bCrvAOrB) {
|
|
if ( bPrevIsBefore) {
|
|
vdU[0] = ( 1 - dFactor) * Icci2.IciA[0].dU + dFactor * Icci1.IciA[kj].dU ;
|
|
vdU[1] = ( 1 - 2 * dFactor) * Icci2.IciA[0].dU + 2 * dFactor * Icci1.IciA[kj].dU ;
|
|
}
|
|
else if ( Icci2.IciA[0].dU > 2 * EPS_SMALL){
|
|
vdU[0] = ( Icci2.IciA[0].dU + 0.) * dFactor ;
|
|
vdU[1] = ( Icci2.IciA[0].dU + 0.) * 2 * dFactor ;
|
|
}
|
|
else
|
|
bIsOn = true ;
|
|
}
|
|
else {
|
|
if ( bPrevIsBefore) {
|
|
vdU[0] = ( 1 - dFactor) * Icci2.IciB[0].dU + dFactor * Icci1.IciB[kj].dU ;
|
|
vdU[1] = ( 1 - 2 * dFactor) * Icci2.IciB[0].dU + 2 * dFactor * Icci1.IciB[kj].dU ;
|
|
}
|
|
else if ( Icci2.IciB[0].dU > 2 * EPS_SMALL) {
|
|
vdU[0] = ( Icci2.IciB[0].dU + 0.) * dFactor ;
|
|
vdU[1] = ( Icci2.IciB[0].dU + 0.) * 2 * dFactor ;
|
|
}
|
|
else
|
|
bIsOn = true ;
|
|
}
|
|
if ( ! bIsOn) {
|
|
bIsOn = true ;
|
|
for ( int k = 0 ; k < ssize(vdU) && bIsOn ; ++k) {
|
|
Point3d ptTest2 ; pThisCrv->GetPointD1D2( vdU[k], ICurve::FROM_MINUS, ptTest2) ;
|
|
DistPointCurve dpc2( ptTest2, *pOtherCrv) ;
|
|
dpc2.GetSideAtMinDistPoint( 0, Z_AX, nType, EPS_ZERO) ;
|
|
if ( nType != MDS_ON)
|
|
bIsOn = false ;
|
|
}
|
|
}
|
|
if ( bIsOn) {
|
|
m_Info[i].bOverlap = true ;
|
|
Vector3d vtDirThis, vtDirOther ;
|
|
Point3d ptCommon ;
|
|
double dUThis = 0 ;
|
|
if ( bCrvAOrB)
|
|
dUThis = m_Info[i].IciA[0].dU ;
|
|
else
|
|
dUThis = m_Info[i].IciB[0].dU ;
|
|
pThisCrv->GetPointD1D2( dUThis, ICurve::Side::FROM_MINUS, ptCommon, &vtDirThis) ;
|
|
double dUOther = 0 ; pOtherCrv->GetParamAtPoint( ptCommon, dUOther) ;
|
|
pOtherCrv->GetPointD1D2( dUOther, ICurve::Side::FROM_MINUS, ptCommon, &vtDirOther) ;
|
|
m_Info[i].bCBOverEq = vtDirThis * vtDirOther > 0 ;
|
|
if ( m_Info[i].bCBOverEq) {
|
|
m_Info[i].IciA[1] = m_Info[i].IciA[0] ;
|
|
m_Info[i].IciB[1] = m_Info[i].IciB[0] ;
|
|
m_Info[i].IciA[0] = m_Info[j].IciA[kj] ;
|
|
m_Info[i].IciB[0] = m_Info[j].IciB[kj] ;
|
|
m_Info[i].IciA[1].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciB[1].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciA[0].nNextTy = ICCT_ON ;
|
|
m_Info[i].IciB[0].nNextTy = ICCT_ON ;
|
|
}
|
|
else {
|
|
if ( bCrvAOrB) {
|
|
m_Info[i].IciA[1] = m_Info[i].IciA[0] ;
|
|
m_Info[i].IciA[0] = m_Info[j].IciA[kj] ;
|
|
m_Info[i].IciA[1].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciA[0].nNextTy = ICCT_ON ;
|
|
m_Info[i].IciB[1] = m_Info[j].IciB[kj] ;
|
|
m_Info[i].IciB[0].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciB[1].nNextTy = ICCT_ON ;
|
|
}
|
|
else {
|
|
m_Info[i].IciB[1] = m_Info[i].IciB[0] ;
|
|
m_Info[i].IciB[0] = m_Info[j].IciB[kj] ;
|
|
m_Info[i].IciB[1].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciB[0].nNextTy = ICCT_ON ;
|
|
m_Info[i].IciA[1] = m_Info[j].IciA[kj] ;
|
|
m_Info[i].IciA[0].nPrevTy = ICCT_ON ;
|
|
m_Info[i].IciA[1].nNextTy = ICCT_ON ;
|
|
}
|
|
}
|
|
nType = ICCT_ON ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCrvCompoCrvCompo::MergeNewOverlap( int i, bool bCrvAOrB)
|
|
{
|
|
// faccio il merge col precedente
|
|
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
|
|
if ( m_Info[j].bOverlap) {
|
|
m_Info[i].IciA[0] = m_Info[j].IciA[0] ;
|
|
m_Info[i].IciB[0] = m_Info[j].IciB[0] ;
|
|
}
|
|
m_Info.erase( m_Info.begin() + j) ;
|
|
-- j ;
|
|
-- m_nNumInters ;
|
|
return true ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
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) ;
|
|
-- nIndCurr ;
|
|
-- nIndOther ;
|
|
-- m_nNumInters ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
IntersCrvCompoCrvCompo::EraseBothInfo( int& nIndCurr, int& nIndOther)
|
|
{
|
|
m_Info.erase( m_Info.begin() + nIndOther) ;
|
|
-- nIndCurr ;
|
|
-- nIndOther ;
|
|
-- m_nNumInters ;
|
|
m_Info.erase( m_Info.begin() + nIndCurr) ;
|
|
if ( nIndCurr != -1)
|
|
-- nIndCurr ;
|
|
-- 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, bool bOrderedOnB)
|
|
{
|
|
int ki = 0 ;
|
|
int kj = 0 ;
|
|
if ( ! bOrderedOnB) {
|
|
ki = 0 ;
|
|
kj = Icci1.bOverlap ? 1 : 0 ;
|
|
}
|
|
else {
|
|
ki = Icci2.bOverlap && ! Icci2.bCBOverEq ? 1 : 0 ;
|
|
kj = Icci1.bOverlap && Icci1.bCBOverEq ? 1 : 0 ;
|
|
}
|
|
if ( abs( Icci1.IciA[kj].dU - Icci2.IciA[ki].dU) > 0.1 * SPAN_PARAM &&
|
|
( ! bCrvAClosed || abs( abs( Icci1.IciA[kj].dU - Icci2.IciA[ki].dU) - dCrvASpan) > 0.1 * SPAN_PARAM))
|
|
return false ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
CompatibleParamB( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2,
|
|
bool bCrvBClosed, double dCrvBSpan, bool bOrderedOnB)
|
|
{
|
|
int ki = 0 ;
|
|
int kj = 0 ;
|
|
if ( ! bOrderedOnB) {
|
|
ki = 0 ;
|
|
kj = Icci1.bOverlap ? 1 : 0 ;
|
|
}
|
|
else {
|
|
ki = Icci2.bOverlap && ! Icci2.bCBOverEq ? 1 : 0 ;
|
|
kj = Icci1.bOverlap && Icci1.bCBOverEq ? 1 : 0 ;
|
|
}
|
|
|
|
if ( abs( Icci1.IciB[kj].dU - Icci2.IciB[ki].dU) > 0.1 * SPAN_PARAM &&
|
|
( ! bCrvBClosed || abs( abs( Icci1.IciB[kj].dU - Icci2.IciB[ki].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 ;
|
|
}
|