d0521e8f92
- 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.
514 lines
17 KiB
C++
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 ;
|
|
} |