Files
EgtGeomKernel/IntersCurveCurve.cpp
T
Dario Sassi d0521e8f92 EgtGeomKernel 1.5h5 :
- sistemata approssimazione di curve di Bezier con archi
- aggiunta a CurveBezier metodo per sapere se è collassata in un punto
- in PolyArc e PolyLine sostituite Splice con Join e aggiunte Split
- in TSC non si accetta più la creazione di una curva di Bezier collassata in un punto.
2014-08-19 20:19:17 +00:00

514 lines
17 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : IntersCurveCurve.cpp Data : 20.06.14 Versione : 1.5f6
// Contenuto : Implementazione della classe intersezione linea/linea.
//
//
//
// Modifiche : 15.06.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "IntersLineLine.h"
#include "IntersLineArc.h"
#include "IntersArcArc.h"
#include "IntersCrvCompoCrvCompo.h"
#include "CurveLine.h"
#include "CurveComposite.h"
#include "/EgtDev/Include/EGkIntersCurveCurve.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_nNumInters = 0 ;
m_pCurve[0] = &CurveA ;
m_pCurve[1] = &CurveB ;
// chiamo calcolatore opportuno
switch ( CurveA.GetType()) {
case CRV_LINE :
switch ( CurveB.GetType()) {
case CRV_LINE :
LineLineCalculate( CurveA, CurveB, bAreSegments) ;
break ;
case CRV_ARC :
LineArcCalculate( CurveA, CurveB) ;
break ;
case CRV_BEZ :
break ;
case CRV_COMPO :
LineCrvCompoCalculate( CurveA, CurveB) ;
break ;
}
break ;
case CRV_ARC :
switch ( CurveB.GetType()) {
case CRV_LINE :
ArcLineCalculate( CurveA, CurveB) ;
break ;
case CRV_ARC :
ArcArcCalculate( CurveA, CurveB) ;
break ;
case CRV_BEZ :
break ;
case CRV_COMPO :
ArcCrvCompoCalculate( CurveA, CurveB) ;
break ;
}
break ;
case CRV_BEZ :
break ;
case CRV_COMPO :
switch ( CurveB.GetType()) {
case CRV_LINE :
CrvCompoLineCalculate( CurveA, CurveB) ;
break ;
case CRV_ARC :
CrvCompoArcCalculate( CurveA, CurveB) ;
break ;
case CRV_BEZ :
break ;
case CRV_COMPO :
CrvCompoCrvCompoCalculate( CurveA, CurveB) ;
break ;
}
break ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::LineLineCalculate( const ICurve& CurveA, const ICurve& CurveB, bool bAreSegments)
{
IntersLineLine intLnLn( *GetCurveLine( &CurveA), *GetCurveLine( &CurveB), bAreSegments) ;
if ( intLnLn.m_nNumInters > 0) {
m_bOverlaps = intLnLn.m_bOverlaps ;
m_nNumInters = intLnLn.m_nNumInters ;
if ( m_nNumInters == 1)
m_Info.push_back( intLnLn.m_Info) ;
}
}
//----------------------------------------------------------------------------
void
IntersCurveCurve::LineArcCalculate( const ICurve& CurveA, const ICurve& CurveB)
{
IntersLineArc intLnAr( *GetCurveLine( &CurveA), *GetCurveArc( &CurveB)) ;
if ( intLnAr.m_nNumInters > 0) {
m_bOverlaps = false ;
m_nNumInters = intLnAr.m_nNumInters ;
for ( int i = 0 ; i < m_nNumInters ; ++ 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( *GetCurveLine( &CurveB), *GetCurveArc( &CurveA)) ;
if ( intLnAr.m_nNumInters > 0) {
m_bOverlaps = false ;
m_nNumInters = intLnAr.m_nNumInters ;
for ( int i = 0 ; i < m_nNumInters ; ++ 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( *GetCurveArc( &CurveA), *GetCurveArc( &CurveB)) ;
if ( intArAr.m_nNumInters > 0) {
m_bOverlaps = intArAr.m_bOverlaps ;
m_nNumInters = intArAr.m_nNumInters ;
for ( int i = 0 ; i < m_nNumInters ; ++ 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_nNumInters = intCcCc.m_nNumInters ;
for ( int i = 0 ; i < m_nNumInters ; ++ i)
m_Info.push_back( intCcCc.m_Info[i]) ;
}
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetOverlaps( void)
{
return m_bOverlaps ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetNumInters( void)
{
return m_nNumInters ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo)
{
if ( nInd < 0 || nInd >= m_nNumInters)
return false ;
aInfo = m_Info[nInd] ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI)
{
if ( m_nNumInters == 0 || nCrv < 0 || nCrv > 1)
return false ;
// ricerca del punto più vicino tra le intersezioni singole
bool bFound = false ;
double dMinSqDist = INFINITO * INFINITO ;
for ( int i = 0 ; i < m_nNumInters ; ++ 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, 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_nNumInters >= 1)
return CalcCurveClassification( m_pCurve[0], m_Info, 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_nNumInters >= 1)
return CalcCurveClassification( m_pCurve[1], InfoTmp, 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_nNumInters ; ++ 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(), SortGreater) ;
// 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, 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 ;
// recupero la classificazione all'inizio della curva
int nLastTy = ICCT_NULL ;
double dCurrPar = dStartPar ;
// se è chiusa, recupero come finisce
if ( pCurve->IsClosed()) {
if ( ! Info[nNumInters-1].bOverlap)
nLastTy = Info[nNumInters-1].IciA[0].nNextTy ;
else {
nLastTy = Info[nNumInters-1].IciA[1].nNextTy ;
// se attraversa il punto di giunzione (parametro di fine minore di quello di inizio)
if ( Info[nNumInters-1].IciA[1].dU < Info[nNumInters-1].IciA[0].dU) {
dCurrPar = Info[nNumInters-1].IciA[1].dU ;
dEndPar = dCurrPar ;
}
}
}
// costruisco il vettore delle classificazioni
for ( int i = 0 ; i < nNumInters ; ++ i) {
// se è definito un tratto precedente
if ( Info[i].IciA[0].dU > dCurrPar + EPS_PARAM) {
// verifico che la definizione sul tratto sia omogenea e valida
int nPrevTy = Info[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 = Info[i].IciA[0].dU ;
segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = Info[i].IciA[0].dU ;
nLastTy = Info[i].IciA[0].nNextTy ;
}
// altrimenti, salvo il tipo
else
nLastTy = Info[i].IciA[0].nNextTy ;
// se è definito un tratto in sovrapposizione
if ( Info[i].bOverlap) {
// assegno i dati
CrvClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = Info[i].IciA[1].dU ;
segClass.nClass = ( Info[i].bCBOverEq ? CRVC_ON_P : CRVC_ON_M) ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = Info[i].IciA[1].dU ;
nLastTy = Info[i].IciA[1].nNextTy ;
}
}
// eventuale tratto finale rimasto
if ( dCurrPar < dEndPar - EPS_PARAM) {
// 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 della curva A
double dStartPar, dEndPar ;
if ( ! pCurveA->GetDomain( dStartPar, dEndPar))
return false ;
// se i box delle due curve non interferiscono è sicuramente default
BBox3d boxCrvA, boxCrvB ;
if ( ! pCurveA->GetLocalBBox( boxCrvA) ||
! pCurveB->GetLocalBBox( boxCrvB))
return false ;
if ( ! boxCrvA.OverlapsXY( boxCrvB)) {
// determino il tipo di esterno
int nClass ;
if ( ! GetCurveOutClass( pCurveB, nClass))
return false ;
// assegno i dati
CrvClass segClass ;
segClass.dParS = dStartPar ;
segClass.dParE = dEndPar ;
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.GetNumInters() > 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 ;
}
// altrimenti sono esterni tra loro
else {
// determino il tipo di esterno
if ( ! GetCurveOutClass( pCurveB, nClass))
return false ;
}
// assegno i dati
CrvClass segClass ;
segClass.dParS = dStartPar ;
segClass.dParE = dEndPar ;
segClass.nClass = nClass ;
ccClass.push_back( segClass) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetCurveOutClass( const ICurve* pCurve, int& nClass)
{
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( LIN_TOL_APPROX, ANG_TOL_APPROX_DEG, PL))
return false ;
double dArea ;
if ( ! PL.GetAreaXY( dArea))
return false ;
nClass = (( dArea > 0) ? CRVC_OUT : CRVC_IN) ;
return true ;
}