ec6eb3e645
- modifica a Trimming - sistemazioni estetiche varie.
799 lines
28 KiB
C++
799 lines
28 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) ;
|
|
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 ;
|
|
nLastTy = InfoCorr[i].IciA[1].nNextTy ;
|
|
}
|
|
}
|
|
// 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 ;
|
|
}
|