Files
EgtGeomKernel/IntersCurveCurve.cpp
T
Daniele Bariletti c704d94829 EgtGeomKernel :
- piccola aggiunta per la gestione di spike nelle categorizzazioni tra curve.
2026-04-02 15:14:29 +02:00

819 lines
29 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : IntersCurveCurve.cpp Data : 17.08.15 Versione : 1.6h3
// Contenuto : Implementazione della classe intersezione curva/curva.
//
//
//
// Modifiche : 15.06.14 DS Creazione modulo.
// 17.08.15 DS Modifiche per curve approssimate.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "CurveLine.h"
#include "CurveComposite.h"
#include "IntersLineLine.h"
#include "IntersLineArc.h"
#include "IntersArcArc.h"
#include "IntersCrvCompoCrvCompo.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkPlane3d.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments)
{
// Le intersezioni sono calcolate nel piano XY locale.
// Il flag bAreSegments vale solo per intersezione tra due linee e riguarda entrambe.
// inizializzazioni
m_bOverlaps = false ;
m_nIntersCount = 0 ;
m_pCurve[0] = &CurveA ;
m_pCurve[1] = &CurveB ;
// puntatori alle curve usate nei calcoli (originali o temporanee)
const ICurve* pCalcCrv[2] ;
// per eventuale esplosione temporanea delle curve
PtrOwner<ICurve> pTmpCrv[2] ;
// ciclo sulle curve per verificare se da approssimare
for ( int i = 0 ; i < 2 ; ++ i) {
// se curva è arco da approssimare oppure è curva di Bezier
if ( ( m_pCurve[i]->GetType() == CRV_ARC && IsArcToApprox( *m_pCurve[i])) ||
m_pCurve[i]->GetType() == CRV_BEZIER) {
// approssimo con rette
PolyLine PL ;
if ( ! m_pCurve[i]->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return ;
pTmpCrv[i].Set( CreateBasicCurveComposite()) ;
if ( IsNull( pTmpCrv[i]))
return ;
if ( ! GetBasicCurveComposite( pTmpCrv[i])->FromPolyLine( PL))
return ;
pCalcCrv[i] = pTmpCrv[i] ;
}
else
pCalcCrv[i] = m_pCurve[i] ;
}
// chiamo calcolatore opportuno
switch ( pCalcCrv[0]->GetType()) {
case CRV_LINE :
switch ( pCalcCrv[1]->GetType()) {
case CRV_LINE :
LineLineCalculate( *pCalcCrv[0], *pCalcCrv[1], bAreSegments) ;
break ;
case CRV_ARC :
LineArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
case CRV_COMPO :
LineCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
default :
break ;
}
break ;
case CRV_ARC :
switch ( pCalcCrv[1]->GetType()) {
case CRV_LINE :
ArcLineCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
case CRV_ARC :
ArcArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
case CRV_COMPO :
ArcCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
default :
break ;
}
break ;
case CRV_COMPO :
switch ( pCalcCrv[1]->GetType()) {
case CRV_LINE :
CrvCompoLineCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
case CRV_ARC :
CrvCompoArcCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
case CRV_COMPO :
CrvCompoCrvCompoCalculate( *pCalcCrv[0], *pCalcCrv[1]) ;
break ;
default :
break ;
}
break ;
default :
break ;
}
// per curve approssimate, sistemo...
AdjustIntersParams( ( pCalcCrv[0] != m_pCurve[0]), ( pCalcCrv[1] != m_pCurve[1])) ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::IsArcToApprox( const ICurve& Curve)
{
// recupero l'arco
const CurveArc* pArc = GetBasicCurveArc( &Curve) ;
if ( pArc == nullptr)
return false ;
// verifico se non è nel piano XY o ha più di un giro al centro
return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) ||
abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ;
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments)
{
IntersLineLine intLnLn( *GetBasicCurveLine( &CurveA), *GetBasicCurveLine( &CurveB), bAreSegments) ;
if ( intLnLn.m_nNumInters > 0) {
m_bOverlaps = intLnLn.m_bOverlaps ;
m_nIntersCount = intLnLn.m_nNumInters ;
if ( m_nIntersCount == 1)
m_Info.push_back( intLnLn.m_Info) ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
IntersLineArc intLnAr( *GetBasicCurveLine( &CurveA), *GetBasicCurveArc( &CurveB)) ;
if ( intLnAr.m_nNumInters > 0) {
m_bOverlaps = false ;
m_nIntersCount = intLnAr.m_nNumInters ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i)
m_Info.push_back( intLnAr.m_Info[i]) ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::LineCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
// trasformo la linea in curva composita
CurveComposite crvCompo ;
crvCompo.CopyFrom( &CurveA) ;
// eseguo l'intersezione tra curve composite
CrvCompoCrvCompoCalculate( crvCompo, CurveB) ;
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::ArcLineCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
IntersLineArc intLnAr( *GetBasicCurveLine( &CurveB), *GetBasicCurveArc( &CurveA)) ;
if ( intLnAr.m_nNumInters > 0) {
m_bOverlaps = false ;
m_nIntersCount = intLnAr.m_nNumInters ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i)
m_Info.push_back( intLnAr.m_Info[i]) ;
// devo scambiare opportunamente le info di intersezione tra A e B
SwapInfoAB( m_Info, 0) ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::ArcArcCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
IntersArcArc intArAr( *GetBasicCurveArc( &CurveA), *GetBasicCurveArc( &CurveB)) ;
if ( intArAr.m_nNumInters > 0) {
m_bOverlaps = intArAr.m_bOverlaps ;
m_nIntersCount = intArAr.m_nNumInters ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i)
m_Info.push_back( intArAr.m_Info[i]) ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::ArcCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
// trasformo l'arco in curva composita
CurveComposite crvCompo ;
crvCompo.CopyFrom( &CurveA) ;
// eseguo l'intersezione tra curve composite
CrvCompoCrvCompoCalculate( crvCompo, CurveB) ;
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::CrvCompoLineCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
// trasformo la linea in curva composita
CurveComposite crvCompo ;
crvCompo.CopyFrom( &CurveB) ;
// eseguo l'intersezione tra curve composite
CrvCompoCrvCompoCalculate( CurveA, crvCompo) ;
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::CrvCompoArcCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
// trasformo l'arco in curva composita
CurveComposite crvCompo ;
crvCompo.CopyFrom( &CurveB) ;
// eseguo l'intersezione tra curve composite
CrvCompoCrvCompoCalculate( CurveA, crvCompo) ;
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
IntersCrvCompoCrvCompo intCcCc( *GetCurveComposite( &CurveA), *GetCurveComposite( &CurveB)) ;
if ( intCcCc.m_nNumInters > 0) {
m_bOverlaps = intCcCc.m_bOverlaps ;
m_nIntersCount = intCcCc.m_nNumInters ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i)
m_Info.push_back( intCcCc.m_Info[i]) ;
}
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::AdjustIntersParams( bool bAdjCrvA, bool bAdjCrvB)
{
// se non ci sono intersezioni, non va fatto alcunché
if ( m_Info.empty())
return true ;
// se le curve originali non sono state approssimate, non va fatto alcunché
if ( ! bAdjCrvA && ! bAdjCrvB)
return true ;
// procedo ad aggiustare
for ( auto& aInfo : m_Info) {
// se curve originali approssimate, devo ricalcolare i parametri dei punti di intersezione
if ( bAdjCrvA) {
if ( ! m_pCurve[0]->GetParamAtPoint( aInfo.IciA[0].ptI, aInfo.IciA[0].dU, 10 * EPS_SMALL))
return false ;
if ( aInfo.bOverlap && ! m_pCurve[0]->GetParamAtPoint( aInfo.IciA[1].ptI, aInfo.IciA[1].dU, 10 * EPS_SMALL))
return false ;
}
if ( bAdjCrvB) {
if ( ! m_pCurve[1]->GetParamAtPoint( aInfo.IciB[0].ptI, aInfo.IciB[0].dU, 10 * EPS_SMALL))
return false ;
if ( aInfo.bOverlap && ! m_pCurve[1]->GetParamAtPoint( aInfo.IciB[1].ptI, aInfo.IciB[1].dU, 10 * EPS_SMALL))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetOverlaps( void)
{
return m_bOverlaps ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetIntersCount( void)
{
return m_nIntersCount ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetInters3DCount( void)
{
int nCount = 0 ;
for ( int i = 0 ; i < m_nIntersCount ; ++i) {
if ( ! m_Info[i].bOverlap || ( m_Info[i].bOverlap && m_Info[i].bCBOverEq)) {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[0].ptI.z) < EPS_SMALL)
++nCount ;
}
else {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[1].ptI.z) < EPS_SMALL)
++nCount ;
}
}
return nCount ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetCrossIntersCount( void)
{
int nCrossIntersCount = 0 ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// se con sovrapposizione
if ( m_Info[i].bOverlap) {
if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[1].nNextTy &&
m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[1].nNextTy != ICCT_NULL)
++ nCrossIntersCount ;
}
// altrimenti
else {
if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy &&
m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL)
++ nCrossIntersCount ;
}
}
return nCrossIntersCount ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetCrossOrOverlapIntersCount( void)
{
int nCrossOverIntersCount = 0 ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// se con sovrapposizione
if ( m_Info[i].bOverlap)
++ nCrossOverIntersCount ;
// se altrimenti con attraversamento
else if ( m_Info[i].IciA[0].nPrevTy != m_Info[i].IciA[0].nNextTy &&
m_Info[i].IciA[0].nPrevTy != ICCT_NULL && m_Info[i].IciA[0].nNextTy != ICCT_NULL)
++ nCrossOverIntersCount ;
}
return nCrossOverIntersCount ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo)
{
if ( nInd < 0 || nInd >= m_nIntersCount)
return false ;
aInfo = m_Info[nInd] ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetInt3DCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo)
{
if ( nInd < 0 || nInd >= GetInters3DCount())
return false ;
int nCount = - 1 ;
for ( int i = 0 ; i < m_nIntersCount ; ++i) {
if ( ! m_Info[i].bOverlap || ( m_Info[i].bOverlap && m_Info[i].bCBOverEq)) {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[0].ptI.z) < EPS_SMALL)
++nCount ;
}
else {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[1].ptI.z) < EPS_SMALL)
++nCount ;
}
if ( nCount == nInd) {
aInfo = m_Info[nInd] ;
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI)
{
if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1)
return false ;
// ricerca del punto più vicino tra le intersezioni singole
bool bFound = false ;
double dMinSqDist = SQ_INFINITO ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// se è un'intersezione singola
if ( ! m_Info[i].bOverlap) {
// faccio la verifica sul punto
Point3d ptP = ( nCrv == 0 ? m_Info[i].IciA[0].ptI : m_Info[i].IciB[0].ptI) ;
double dSqDist = SqDist( ptNear, ptP) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
ptI = ptP ;
bFound = true ;
}
}
// altrimenti
else {
// recupero il tratto di sovrapposizione
double dUStartTrim, dUEndTrim ;
if ( nCrv == 0) {
dUStartTrim = m_Info[i].IciA[0].dU ;
dUEndTrim = m_Info[i].IciA[1].dU ;
}
else {
dUStartTrim = m_Info[i].IciB[0].dU ;
dUEndTrim = m_Info[i].IciB[1].dU ;
if ( ! m_Info[i].bCBOverEq)
swap( dUStartTrim, dUEndTrim) ;
}
PtrOwner<ICurve> pCrv( m_pCurve[nCrv]->CopyParamRange( dUStartTrim, dUEndTrim)) ;
if ( IsNull( pCrv))
continue ;
// cerco il punto
int nFlag ;
Point3d ptP ;
if ( DistPointCurve( ptNear, *pCrv).GetMinDistPoint( 0.5, ptP, nFlag)) {
// faccio la verifica
double dSqDist = SqDist( ptNear, ptP) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
ptI = ptP ;
bFound = true ;
}
}
}
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetCurveClassification( int nCrv, double dLenMin, CRVCVECTOR& ccClass)
{
// pulisco vettore classificazioni
ccClass.clear() ;
// verifico definizione delle due curve
if ( m_pCurve[0] == nullptr || m_pCurve[1] == nullptr)
return false ;
// se richiesta classificazione della curva A
if ( nCrv == 0) {
// la curva rispetto a cui si classifica deve essere chiusa
if ( ! m_pCurve[1]->IsClosed())
return false ;
// se esiste almeno una intersezione
if ( m_nIntersCount >= 1)
return CalcCurveClassification( m_pCurve[0], m_Info, dLenMin, ccClass) ;
// altrimenti la curva è completamente interna oppure completamente esterna
else
return CalcCurveInOrOut( m_pCurve[0], m_pCurve[1], ccClass) ;
}
// se richiesta classificazione della curva B
else if ( nCrv == 1) {
// la curva rispetto a cui si classifica deve essere chiusa
if ( ! m_pCurve[0]->IsClosed())
return false ;
// devo scambiare opportunamente le info di intersezione tra A e B
// copia temporanea delle info di intersezione
ICCIVECTOR InfoTmp = m_Info ;
// esecuzione scambio e controlli
SwapInfoAB( InfoTmp, 1) ;
// se esiste almeno una intersezione
if ( m_nIntersCount >= 1)
return CalcCurveClassification( m_pCurve[1], InfoTmp, dLenMin, ccClass) ;
// altrimenti la curva è completamente interna oppure completamente esterna
else
return CalcCurveInOrOut( m_pCurve[1], m_pCurve[0], ccClass) ;
}
// altrimenti errore
else
return false ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::SwapInfoAB( ICCIVECTOR& Info, int IndCrvOrd)
{
if ( IndCrvOrd < 0 || IndCrvOrd > 1)
return false ;
// eseguo lo scambio
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// scambio le informazioni tra A e B
swap( Info[i].IciA[0], Info[i].IciB[0]) ;
swap( Info[i].IciA[1], Info[i].IciB[1]) ;
// riordino eventuali sovrapposizioni controverse
if ( Info[i].bOverlap && ! Info[i].bCBOverEq) {
swap( Info[i].IciA[0], Info[i].IciA[1]) ;
swap( Info[i].IciB[0], Info[i].IciB[1]) ;
}
}
// ordino le intersezioni secondo l'ordine crescente del parametro della prima curva
stable_sort( Info.begin(), Info.end(), SortGreaterA) ;
// verifiche su intersezioni in zone non-manifold
OrderNonManifoldInters( Info, *(m_pCurve[IndCrvOrd]), *(m_pCurve[1-IndCrvOrd])) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTOR& Info, double dLenMin, CRVCVECTOR& ccClass)
{
// numero intersezioni
int nNumInters = int( Info.size()) ;
if ( nNumInters < 1)
return false ;
// recupero il dominio parametrico della curva in esame
double dStartPar, dEndPar ;
if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar))
return false ;
// limito lunghezza minima
dLenMin = max( dLenMin, EPS_ZERO) ;
// elimino intersezioni senza attraversamento che giacciono in intervalli di sovrapposizione
ICCIVECTOR InfoCorr ;
InfoCorr.reserve( Info.size()) ;
for ( size_t i = 0 ; i < Info.size() ; ++ i) {
// se intersezione puntuale senza attraversamento
if ( ! Info[i].bOverlap && Info[i].IciA[0].nPrevTy == Info[i].IciA[0].nNextTy) {
// confronto con le intersezioni con sovrapposizione
bool bToSkip = false ;
for ( size_t j = 0 ; j < Info.size() ; ++ j) {
// se coincide o puntuale
if ( j == i || ! Info[j].bOverlap)
continue ;
// determino l'intervallo parametrico tenendo conto di eventuale avvolgimento attorno all'inizio
double dU1 = Info[j].IciA[0].dU ;
double dU2 = Info[j].IciA[1].dU ;
if ( dU2 < dU1 && pCurve->IsClosed())
dU2 += dEndPar ;
// se cade nell'intervallo è da saltare
if ( Info[i].IciA[0].dU >= dU1 && Info[i].IciA[0].dU <= dU2) {
bToSkip = true ;
break ;
}
}
if ( bToSkip)
continue ;
}
// salvo dati intersezione
InfoCorr.emplace_back( Info[i]) ;
}
// aggiorno numero di intersezioni da considerare
nNumInters = int( InfoCorr.size()) ;
// recupero la classificazione all'inizio della curva
int nLastTy = ICCT_NULL ;
double dCurrPar = dStartPar ;
double dCurrLen = 0 ;
double dEndLen ; pCurve->GetLength( dEndLen) ;
// se è chiusa, recupero come finisce
if ( pCurve->IsClosed()) {
if ( ! InfoCorr[nNumInters-1].bOverlap)
nLastTy = InfoCorr[nNumInters-1].IciA[0].nNextTy ;
else {
nLastTy = InfoCorr[nNumInters-1].IciA[1].nNextTy ;
// se attraversa il punto di giunzione (parametro di fine minore di quello di inizio)
if ( InfoCorr[nNumInters-1].IciA[1].dU < InfoCorr[nNumInters-1].IciA[0].dU) {
dCurrPar = InfoCorr[nNumInters-1].IciA[1].dU ;
double dTmpLen ; pCurve->GetLengthAtParam( dCurrPar, dTmpLen) ;
dCurrLen = dTmpLen - dEndLen ;
dEndPar = dCurrPar ;
dEndLen = dTmpLen ;
}
}
}
// costruisco il vettore delle classificazioni
for ( int i = 0 ; i < nNumInters ; ++ i) {
// se è definito un tratto precedente
double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].IciA[0].dU, dLenU) ;
/*int j = i < nNumInters - 1 ? i + 1 : -1 ;
if ( pCurve->IsClosed() && j == - 1)
j = 0 ;*/
int j = i == 0 ? -1 : i - 1 ;
if ( pCurve->IsClosed() && j == - 1)
j = nNumInters - 1 ;
bool bSpike = false ;
if ( j != -1) {
bSpike = InfoCorr[i].bOverlap && InfoCorr[j].bOverlap && InfoCorr[i].bCBOverEq != InfoCorr[j].bCBOverEq ;
if ( bSpike) {
bSpike = abs( InfoCorr[i].IciA[0].dU - InfoCorr[j].IciA[0].dU) < EPS_PARAM ||
abs( InfoCorr[i].IciA[0].dU - InfoCorr[j].IciA[1].dU) < EPS_PARAM ||
abs( InfoCorr[i].IciA[1].dU - InfoCorr[j].IciA[0].dU) < EPS_PARAM ||
abs( InfoCorr[i].IciA[1].dU - InfoCorr[j].IciA[1].dU) < EPS_PARAM ;
}
}
if ( InfoCorr[i].IciA[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) {
// verifico che la definizione sul tratto sia omogenea e valida
int nPrevTy = InfoCorr[i].IciA[0].nPrevTy ;
if ( ( nLastTy != ICCT_NULL && nPrevTy != nLastTy) ||
nPrevTy == ICCT_NULL || nPrevTy == ICCT_ON)
return false ;
// assegno i dati
CrvClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = InfoCorr[i].IciA[0].dU ;
segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = InfoCorr[i].IciA[0].dU ;
dCurrLen = dLenU ;
nLastTy = InfoCorr[i].IciA[0].nNextTy ;
}
// altrimenti, salvo il tipo
else
nLastTy = InfoCorr[i].IciA[0].nNextTy ;
// se è definito un tratto in sovrapposizione
if ( InfoCorr[i].bOverlap) {
// assegno i dati
CrvClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = InfoCorr[i].IciA[1].dU ;
segClass.nClass = ( InfoCorr[i].bCBOverEq ? CRVC_ON_P : CRVC_ON_M) ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = InfoCorr[i].IciA[1].dU ;
dCurrLen = dLenU ;
// se sono in un caso di spike devo trattare l'overlap in modo diverso
if ( ! bSpike)
nLastTy = InfoCorr[i].IciA[1].nNextTy ;
else
nLastTy = InfoCorr[i].IciA[0].nPrevTy ;
}
}
// eventuale tratto finale rimasto
if ( dCurrPar < dEndPar - EPS_PARAM && dEndLen - dCurrLen > dLenMin) {
// verifico che la definizione sul tratto sia valida
if ( nLastTy == ICCT_NULL || nLastTy == ICCT_ON)
return false ;
// assegno i dati
CrvClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = dEndPar ;
segClass.nClass = (( nLastTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB, CRVCVECTOR& ccClass)
{
// recupero il dominio parametrico delle curve A e B
double dStartParA, dEndParA ;
if ( ! pCurveA->GetDomain( dStartParA, dEndParA))
return false ;
double dStartParB, dEndParB ;
if ( ! pCurveB->GetDomain( dStartParB, dEndParB))
return false ;
// se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne
BBox3d boxCrvA, boxCrvB ;
if ( ! pCurveA->GetLocalBBox( boxCrvA) ||
! pCurveB->GetLocalBBox( boxCrvB))
return false ;
bool bAOut = ( ! boxCrvA.OverlapsXY( boxCrvB)) ;
bool bBOut = bAOut ;
for ( double dU = dStartParA ; dU <= dEndParA && ! bAOut ; dU += 1) {
Point3d ptP ;
if ( pCurveA->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) && ! boxCrvB.EnclosesXY( ptP))
bAOut = true ;
}
for ( double dU = dStartParB ; dU <= dEndParB && ! bBOut ; dU += 1) {
Point3d ptP ;
if ( pCurveB->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) && ! boxCrvA.EnclosesXY( ptP))
bBOut = true ;
}
if ( bAOut && bBOut) {
// determino il tipo di esterno
int nClass ;
if ( ! GetCurveOutClass( pCurveB, nClass))
return false ;
// assegno i dati
CrvClass segClass ;
segClass.dParS = dStartParA ;
segClass.dParE = dEndParA ;
segClass.nClass = nClass ;
ccClass.push_back( segClass) ;
return true ;
}
// intersezione tra una semiretta parallela a X dal punto iniziale della curva A e la curva B
// costruisco la linea
Point3d ptStart ;
if ( ! pCurveA->GetStartPoint( ptStart))
return false ;
double dLen = boxCrvB.GetMax().x - boxCrvB.GetMin().x + 1. ;
CurveLine clLine ;
if ( ! clLine.SetPDL( ptStart, 0, dLen))
return false ;
// calcolo l'intersezione
IntersCurveCurve iCC( clLine, *pCurveB) ;
// dichiaro la classe della curva per default
int nClass = CRVC_OUT ;
// se c'è almeno una intersezione
if ( iCC.GetIntersCount() > 0) {
// se quanto precede la prima intersezione è interno, allora la curva è interna
IntCrvCrvInfo aInfo ;
iCC.GetIntCrvCrvInfo( 0, aInfo) ;
if ( aInfo.IciA[0].nPrevTy == ICCT_IN)
nClass = CRVC_IN ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT)
nClass = CRVC_OUT ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_NULL) {
// se il primo punto scelto non va bene allora ne cerco uno che mi dia informazioni sull'essere interno o esterno
CurveLine clLine ;
Point3d ptNewChoice ; pCurveA->GetPointD1D2( 0.25, ICurve::FROM_MINUS, ptNewChoice) ;
if ( ! clLine.SetPDL( ptNewChoice, 0, dLen))
return false ;
// calcolo l'intersezione
IntersCurveCurve iCC( clLine, *pCurveB) ;
if ( iCC.GetIntersCount() > 0) {
// se quanto precede la prima intersezione è interno, allora la curva è interna
IntCrvCrvInfo aInfo ;
iCC.GetIntCrvCrvInfo( 0, aInfo) ;
if ( aInfo.IciA[0].nPrevTy == ICCT_IN)
nClass = CRVC_IN ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT)
nClass = CRVC_OUT ;
else
return false ; // se arrivo qui potrei ritentare la ricerca
}
else
return false ;
}
}
// altrimenti sono esterni tra loro
else {
// determino il tipo di esterno
if ( ! GetCurveOutClass( pCurveB, nClass))
return false ;
}
// assegno i dati
CrvClass segClass ;
segClass.dParS = dStartParA ;
segClass.dParE = dEndParA ;
segClass.nClass = nClass ;
ccClass.push_back( segClass) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetCurveOutClass( const ICurve* pCurve, int& nClass)
{
double dArea ;
if ( ! pCurve->GetAreaXY( dArea))
return false ;
nClass = (( dArea >= 0) ? CRVC_OUT : CRVC_IN) ;
return true ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetRegionCurveClassification( void)
{
// classifico la prima curva rispetto alla seconda
CRVCVECTOR ccClass ;
if ( ! GetCurveClassification( 0, EPS_SMALL, ccClass))
return CCREGC_NULL ;
// derivo la classificazione delle curve come regioni
bool bIn = false ;
bool bOut = false ;
bool bOnP = false ;
bool bOnM = false ;
for ( auto& ccOne : ccClass) {
switch ( ccOne.nClass) {
case CRVC_IN :
bIn = true ;
break ;
case CRVC_OUT :
bOut = true ;
break ;
case CRVC_ON_P :
bOnP = true ;
break ;
case CRVC_ON_M :
bOnM = true ;
break ;
default :
return CCREGC_NULL ;
}
}
if ( bIn) {
if ( bOut)
return CCREGC_INTERS ;
else
return CCREGC_IN1 ;
}
if ( bOut) {
if ( bOnM)
return CCREGC_OUT ;
if ( bOnP)
return CCREGC_IN2 ;
CRVCVECTOR ccClass2 ;
if ( ! GetCurveClassification( 1, EPS_SMALL, ccClass2) || ccClass2.empty())
return CCREGC_NULL ;
if ( ccClass2[0].nClass == CRVC_OUT)
return CCREGC_OUT ;
else
return CCREGC_IN2 ;
}
if ( bOnP)
return CCREGC_SAME ;
if ( bOnM)
return CCREGC_OUT ;
return CCREGC_NULL ;
}