Files
EgtGeomKernel/AdjustLoops.cpp
Daniele Bariletti 9306f5be9d EgtGeomKernel :
- correzioni alla gestione dei loop.
2026-03-31 09:13:21 +02:00

327 lines
13 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2020
//----------------------------------------------------------------------------
// File : AdjustLoops.cpp Data : 14.04.20 Versione : 2.2d2
// Contenuto : Implementazione funzione di sistemazione curve chiuse per
// poter formare loop validi.
//
//
// Modifiche : 02.11.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "CurveComposite.h"
#include "RemoveCurveDefects.h"
#include "AdjustLoops.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <algorithm>
using namespace std ;
//-------------------------------------------------------
static bool
SortCrvCrvInfo( const IntCrvCrvInfo& aInfo1, const IntCrvCrvInfo& aInfo2)
{
// confronto i valori del primo punto della curva A
double dU1 = aInfo1.IciA[0].dU ;
double dU2 = aInfo2.IciA[0].dU ;
if ( abs( dU1 - dU2) < EPS_SMALL)
// se sono uguali confronto i valori del primo punto della curva B
return aInfo1.IciB[0].dU > aInfo2.IciB[0].dU ;
else
return dU1 < dU2 ;
}
//----------------------------------------------------------------------------
static bool
MyAdjustLoops( ICurve* pCurve, ICURVEPLIST& CrvLst)
{
// Pulisco lista di ritorno
CrvLst.clear() ;
// Acquisisco la curva
PtrOwner<ICurve> pMyCrv( pCurve) ;
// Verifico validità curva
if ( IsNull( pMyCrv) || ! pMyCrv->IsValid() || ! pMyCrv->IsClosed())
return false ;
// --- la verifica ed eventuale rimozione va effettuata in un piano perpendicolare al vettore estrusione ---
// verifico il vettore estrusione
Vector3d vtExtr ;
pMyCrv->GetExtrusion( vtExtr) ;
bool bNeedRef = ( ! vtExtr.IsSmall() && ! vtExtr.IsZplus()) ;
// se necessario cambio il riferimento
Frame3d frExtr ;
if ( bNeedRef) {
// calcolo il riferimento OCS con VtExtr come asse Z
if ( ! frExtr.Set( ORIG, vtExtr))
return false ;
// esprimo la curva in questo riferimento
pMyCrv->ToLoc( frExtr) ;
}
// Calcolo le auto intersezioni
SelfIntersCurve sintC( *pMyCrv) ;
// se non ci sono auto-intersezioni che si attraversano o che si toccano (anche con sovrapposizione), non devo fare alcunché
if ( sintC.GetCrossIntersCount() == 0 && sintC.GetTouchIntersCount() == 0) {
// riporto la curva nel riferimento originale
if ( bNeedRef)
pMyCrv->ToGlob( frExtr) ;
// la inserisco in lista
CrvLst.push_back( Release( pMyCrv)) ;
return true ;
}
// Determino intervallo complessivo della curva
double dStart, dEnd ;
if ( ! pMyCrv->GetDomain( dStart, dEnd))
return false ;
Intervals inOk( EPS_PARAM) ;
inOk.Set( dStart, dEnd) ;
// recupero tutte le info delle autointersezioni
IntCrvCrvInfo iccInfo ;
ICCIVECTOR vIccInfo( sintC.GetIntersCount()) ;
for ( int i = 0 ; sintC.GetIntCrvCrvInfo( i, iccInfo) ; ++ i)
vIccInfo[i]= iccInfo ;
// ordino il vettore
sort( vIccInfo.begin(), vIccInfo.end(), SortCrvCrvInfo) ;
// Tolgo le parti da eliminare
int nCross = 0 ;
for ( int i = 0 ; i < int( vIccInfo.size()) ; ++ i) {
if ( i < int( vIccInfo.size()) - 1) {
// se anche l'intersezione successiva è overlap che parte dallo stesso punto
if ( vIccInfo[i].bOverlap && vIccInfo[i+1].bOverlap &&
abs( vIccInfo[i].IciA[0].dU - vIccInfo[i+1].IciA[0].dU) < EPS_SMALL &&
abs( vIccInfo[i].IciB[0].dU - vIccInfo[i+1].IciB[0].dU) < EPS_SMALL) {
// elimino il tratto
inOk.Subtract( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciB[0].dU) ;
// salto le intersezioni successive già considerate rimuovendo questo intervallo
int j = i + 2 ;
while ( j < ( int)vIccInfo.size() && vIccInfo[j].IciA[0].dU > vIccInfo[i].IciA[0].dU - EPS_SMALL &&
vIccInfo[j].IciA[1].dU < vIccInfo[i].IciB[0].dU + EPS_SMALL) {
j ++ ;
}
// aggiorno il contatore
i = j - 1 ;
continue ;
}
}
// se con sovrapposizione
if ( vIccInfo[i].bOverlap) {
// se solo touch
if ( ( vIccInfo[i].IciA[0].nPrevTy == vIccInfo[i].IciA[1].nNextTy ||
vIccInfo[i].IciA[0].nPrevTy == ICCT_SPK || vIccInfo[i].IciA[1].nNextTy == ICCT_SPK) &&
vIccInfo[i].IciA[0].nPrevTy != ICCT_NULL && vIccInfo[i].IciA[1].nNextTy != ICCT_NULL) {
// obbligatoriamente controversi, elimino entrambi i tratti
inOk.Subtract( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciA[1].dU) ;
inOk.Subtract( vIccInfo[i].IciB[0].dU, vIccInfo[i].IciB[1].dU) ;
}
// altrimenti attraversamento
else {
// elimino la parte interna
if ( vIccInfo[i].bCBOverEq)
inOk.Subtract( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciB[0].dU) ;
else
inOk.Subtract( min( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciB[1].dU), max( vIccInfo[i].IciB[0].dU, vIccInfo[i].IciA[1].dU)) ;
}
}
// altrimenti
else {
// se solo touch
if ( vIccInfo[i].IciA[0].nPrevTy == vIccInfo[i].IciA[0].nNextTy &&
vIccInfo[i].IciA[0].nPrevTy != ICCT_NULL && vIccInfo[i].IciA[0].nNextTy != ICCT_NULL) {
inOk.Subtract( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciA[0].dU) ;
inOk.Subtract( vIccInfo[i].IciB[0].dU, vIccInfo[i].IciB[0].dU) ;
}
// altrimenti attraversamento
else {
double dParA = vIccInfo[i].IciA[0].dU ;
double dParB = vIccInfo[i].IciB[0].dU ;
if ( dParA > dParB)
swap( dParA, dParB) ;
// verifico se uno dei due intervalli dà origine ad un tratto trascurabile
PtrOwner<ICurve> pCrv1( pMyCrv->CopyParamRange( dParA, dParB)) ;
PtrOwner<ICurve> pCrv2( pMyCrv->CopyParamRange( dParB, dParA)) ;
double dArea1 = 0, dArea2 = 0 ;
if ( ! IsNull( pCrv1))
pCrv1->GetAreaXY( dArea1) ;
if ( ! IsNull( pCrv2))
pCrv2->GetAreaXY( dArea2) ;
if ( abs( dArea1) > 1e6 * abs( dArea2)) {
// se il tratto dParB->dParA non è significativo
inOk.Subtract( dStart, dParA) ;
inOk.Subtract( dParB, dEnd) ;
}
else if ( abs( dArea2) > 1e6 * abs( dArea1)) {
// se il tratto dParA->dParB non è siginificativo
inOk.Subtract( dParA, dParB) ;
}
else {
// se entrambe le regioni sono significative
if ( IsEven( nCross))
inOk.Subtract( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciB[0].dU) ;
else
inOk.Add( vIccInfo[i].IciA[0].dU, vIccInfo[i].IciB[0].dU) ;
++ nCross ;
}
}
}
}
// Copio le parti da conservare
double dParS, dParE ;
bool bFound = inOk.GetFirst( dParS, dParE) ;
while ( bFound) {
ICurve* pCrv = pMyCrv->CopyParamRange( dParS, dParE) ;
if ( pCrv != nullptr) {
if ( pCrv->GetType() == CRV_COMPO)
CrvLst.push_back( pCrv) ;
else {
CurveComposite* pCrvCo = new( std::nothrow) CurveComposite ;
if ( pCrvCo != nullptr) {
pCrvCo->AddCurve( pCrv) ;
CrvLst.push_back( pCrvCo) ;
}
}
}
bFound = inOk.GetNext( dParS, dParE) ;
}
// Concateno i percorsi risultanti (senza cambiare verso e ignorando le curve già chiuse) :
// primo ciclo con loop di due sole curve
for ( auto iIter = CrvLst.begin() ; iIter != CrvLst.end() ;) {
CurveComposite* pCrvCo = GetBasicCurveComposite( *iIter) ;
// recupero punti iniziale e finale della curva
Point3d ptStart ; pCrvCo->GetStartPoint( ptStart) ;
Point3d ptEnd ; pCrvCo->GetEndPoint( ptEnd) ;
// se aperta, cerco di concatenarla
if ( ! AreSamePointEpsilon( ptStart, ptEnd, 10 * EPS_SMALL)) {
// ciclo sulle curve successive per verificare se possibile concatenamento
for ( auto iIter2 = next( iIter) ; iIter2 != CrvLst.end() ;) {
CurveComposite* pCrvCo2 = GetBasicCurveComposite( *iIter2) ;
// recupero punti iniziale e finale della curva
Point3d ptStart2 ; pCrvCo2->GetStartPoint( ptStart2) ;
Point3d ptEnd2 ; pCrvCo2->GetEndPoint( ptEnd2) ;
// se aperta, verifico se concatenabile alla principale
if ( ! AreSamePointEpsilon( ptStart2, ptEnd2, 10 * EPS_SMALL)) {
if ( AreSamePointEpsilon( ptEnd, ptStart2, 10 * EPS_SMALL) &&
AreSamePointEpsilon( ptEnd2, ptStart, 10 * EPS_SMALL)) {
pCrvCo->AddCurve( pCrvCo2, true, 10 * EPS_SMALL) ;
CrvLst.erase( iIter2) ;
ptEnd = ptEnd2 ;
iIter2 = next( iIter) ;
}
else
++ iIter2 ;
}
else
++ iIter2 ;
}
}
++ iIter ;
}
// secondo ciclo con loop generici
for ( auto iIter = CrvLst.begin() ; iIter != CrvLst.end() ;) {
CurveComposite* pCrvCo = GetBasicCurveComposite( *iIter) ;
// recupero punti iniziale e finale della curva
Point3d ptStart ; pCrvCo->GetStartPoint( ptStart) ;
Point3d ptEnd ; pCrvCo->GetEndPoint( ptEnd) ;
// se aperta, cerco di concatenarla
if ( ! AreSamePointEpsilon( ptStart, ptEnd, 10 * EPS_SMALL)) {
// ciclo sulle curve successive per verificare se possibile concatenamento
for ( auto iIter2 = next( iIter) ; iIter2 != CrvLst.end() ;) {
CurveComposite* pCrvCo2 = GetBasicCurveComposite( *iIter2) ;
// recupero punti iniziale e finale della curva
Point3d ptStart2 ; pCrvCo2->GetStartPoint( ptStart2) ;
Point3d ptEnd2 ; pCrvCo2->GetEndPoint( ptEnd2) ;
// se aperta, verifico se concatenabile alla principale
if ( ! AreSamePointEpsilon( ptStart2, ptEnd2, 10 * EPS_SMALL)) {
if ( AreSamePointEpsilon( ptEnd, ptStart2, 100 * EPS_SMALL)) {
pCrvCo->AddCurve( pCrvCo2, true, 100 * EPS_SMALL) ;
CrvLst.erase( iIter2) ;
ptEnd = ptEnd2 ;
iIter2 = next( iIter) ;
}
else if ( AreSamePointEpsilon( ptEnd2, ptStart, 100 * EPS_SMALL)) {
pCrvCo->AddCurve( pCrvCo2, false, 100 * EPS_SMALL) ;
CrvLst.erase( iIter2) ;
ptStart = ptStart2 ;
iIter2 = next( iIter) ;
}
else
++ iIter2 ;
}
else
++ iIter2 ;
}
}
++ iIter ;
}
// elimino le curve troppo piccole
for ( auto iIter = CrvLst.begin() ; iIter != CrvLst.end() ;) {
CurveComposite* pCrvCo = GetBasicCurveComposite( *iIter) ;
BBox3d b3CrvCo ;
double dDiam ;
if ( ! pCrvCo->GetLocalBBox( b3CrvCo) || b3CrvCo.IsEmpty() ||
! b3CrvCo.GetDiameter( dDiam) || dDiam < 20 * EPS_SMALL) {
delete pCrvCo ;
pCrvCo = nullptr ;
iIter = CrvLst.erase( iIter) ;
}
else {
++ iIter ;
}
}
// riporto le curve nel riferimento originale
if ( bNeedRef) {
for ( auto pCrv : CrvLst)
pCrv->ToGlob( frExtr) ;
}
// assegno il versore estrusione originale
for ( auto pCrv : CrvLst)
pCrv->SetExtrusion( vtExtr) ;
return true ;
}
//----------------------------------------------------------------------------
bool
AdjustLoops( ICurve* pCurve, ICURVEPLIST& CrvLst, bool bNeedSameProp)
{
// elimino eventuali sovrapposizioni e accostamenti
if ( ! MyAdjustLoops( pCurve, CrvLst))
return false ;
// unisco eventuali tratti allineati ed elimino eventuali spikes
for ( auto pCrv : CrvLst) {
// se curva composita
CurveComposite* pCrvCo = GetBasicCurveComposite( pCrv) ;
if ( pCrvCo != nullptr) {
// elimino eventuali Spikes e Small Z
pCrvCo->RemoveSmallDefects( 2 * LIN_TOL_MIN, ANG_TOL_STD_DEG, true) ;
// unisco eventuali tratti allineati
pCrvCo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, bNeedSameProp) ;
// richiudo i loop per sicurezza
pCrvCo->Close() ;
}
}
return true ;
}