//---------------------------------------------------------------------------- // 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 "RemoveCurveSpikes.h" #include "AdjustLoops.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //---------------------------------------------------------------------------- static bool MyAdjustLoops( ICurve* pCurve, ICURVEPLIST& CrvLst) { // Pulisco lista di ritorno CrvLst.clear() ; // Acquisisco la curva PtrOwner 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) ; // Tolgo le parti da eliminare IntCrvCrvInfo iccInfo ; for ( int i = 0 ; sintC.GetIntCrvCrvInfo( i, iccInfo) ; ++ i) { // se con sovrapposizione if ( iccInfo.bOverlap) { // se solo touch if ( ( iccInfo.IciA[0].nPrevTy == iccInfo.IciA[1].nNextTy || iccInfo.IciA[0].nPrevTy == ICCT_SPK || iccInfo.IciA[1].nNextTy == ICCT_SPK) && iccInfo.IciA[0].nPrevTy != ICCT_NULL && iccInfo.IciA[1].nNextTy != ICCT_NULL) { // obbligatoriamente controversi, elimino entrambi i tratti inOk.Subtract( iccInfo.IciA[0].dU, iccInfo.IciA[1].dU) ; inOk.Subtract( iccInfo.IciB[0].dU, iccInfo.IciB[1].dU) ; } // altrimenti attraversamento else { // elimino la parte interna if ( iccInfo.bCBOverEq) inOk.Subtract( iccInfo.IciA[0].dU, iccInfo.IciB[0].dU) ; else inOk.Subtract( min( iccInfo.IciA[0].dU, iccInfo.IciB[1].dU), max( iccInfo.IciB[0].dU, iccInfo.IciA[1].dU)) ; } } // altrimenti else { // se solo touch if ( iccInfo.IciA[0].nPrevTy == iccInfo.IciA[0].nNextTy && iccInfo.IciA[0].nPrevTy != ICCT_NULL && iccInfo.IciA[0].nNextTy != ICCT_NULL) { inOk.Subtract( iccInfo.IciA[0].dU, iccInfo.IciA[0].dU) ; inOk.Subtract( iccInfo.IciB[0].dU, iccInfo.IciB[0].dU) ; } // altrimenti attraversamento else { inOk.Subtract( iccInfo.IciA[0].dU, iccInfo.IciB[0].dU) ; } } } // 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, 10 * EPS_SMALL)) { pCrvCo->AddCurve( pCrvCo2, true, 10 * EPS_SMALL) ; CrvLst.erase( iIter2) ; ptEnd = ptEnd2 ; iIter2 = next( iIter) ; } else if ( AreSamePointEpsilon( ptEnd2, ptStart, 10 * EPS_SMALL)) { pCrvCo->AddCurve( pCrvCo2, false, 10 * EPS_SMALL) ; CrvLst.erase( iIter2) ; ptStart = ptStart2 ; iIter2 = next( iIter) ; } else ++ iIter2 ; } else ++ iIter2 ; } } ++ 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) { // 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) { // unisco eventuali tratti allineati pCrvCo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; // elimino eventuali spikes RemoveCurveSpikes( pCrvCo) ; } } return true ; }