diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj
index 5fe8537..c571c4d 100644
--- a/EgtGeomKernel.vcxproj
+++ b/EgtGeomKernel.vcxproj
@@ -322,6 +322,7 @@ copy $(TargetPath) \EgtProg\Dll64
+
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index e07bdb6..a61acda 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -554,6 +554,9 @@
File di origine\Gdb
+
+
+ File di origine\GeoTrimming
File di origine\GeoDist
diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp
index 789b8a5..16f22f2 100644
--- a/SurfTriMesh.cpp
+++ b/SurfTriMesh.cpp
@@ -4514,3 +4514,21 @@ SurfTriMesh::AdjustTopologyFromZMap( void)
return true ;
}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::GetTriaFromFace( int nF, int& nT) const
+{
+ // la superficie deve essere validata
+ if ( m_nStatus != OK)
+ return false ;
+ // verifico stato sfaccettatura
+ if ( ! VerifyFaceting())
+ return false ;
+ // l'indice della faccia deve essere nei limiti
+ if ( nF < 0 || nF >= int( m_vFacet.size()))
+ return false ;
+ // recupero la normale di un triangolo della faccetta
+ nT = m_vFacet[nF] ;
+ return true ;
+}
diff --git a/SurfTriMesh.h b/SurfTriMesh.h
index 12c886e..49b92a7 100644
--- a/SurfTriMesh.h
+++ b/SurfTriMesh.h
@@ -380,6 +380,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool SetTempInt( int nId, int nTempInt) const ;
bool AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol = 2 * EPS_SMALL) ;
bool AdjustTopologyFromZMap( void) ;
+ bool GetTriaFromFace( int nF, int& nT) const ;
private :
typedef std::vector VERTVECTOR ;
diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp
index dd1841a..f1579f9 100644
--- a/SurfTriMeshOffset.cpp
+++ b/SurfTriMeshOffset.cpp
@@ -733,6 +733,7 @@ CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec)
}
if ( nIndOffsCrv == -1)
return nullptr ;
+ vIndMatched[ nIndOffsCrv] = true ;
// associo le due curve
ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nIndOffsCrv] ;
double dParMinDist = 0. ;
@@ -787,4 +788,4 @@ CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec)
#endif
return ( ( ! IsNull( pStmRef) && pStmRef->IsValid()) ? Release( pStmRef) : nullptr) ;
-}
\ No newline at end of file
+}
diff --git a/Trimming.cpp b/Trimming.cpp
new file mode 100644
index 0000000..bf42b82
--- /dev/null
+++ b/Trimming.cpp
@@ -0,0 +1,3764 @@
+//----------------------------------------------------------------------------
+// EgalTech 2025-2025
+//----------------------------------------------------------------------------
+// File : Trimming.cpp Data : 16.11.23 Versione : 2.7j1
+// Contenuto : Dichiarazione delle funzioni per calcolare una superficie di Bezier
+// Ruled mediante Estrazione di Edge e Selezione di Facce/Superfici
+//
+//
+//
+// Modifiche : 16.11.23 RE Creazione modulo.
+//
+//
+//----------------------------------------------------------------------------
+
+//--------------------------- Include ----------------------------------------
+#include "stdafx.h"
+#include "BiArcs.h"
+#include "GeoConst.h"
+#include "CurveArc.h"
+#include "CurveComposite.h"
+#include "SurfTriMesh.h"
+#include "SurfBezier.h"
+#include "CurveBezier.h"
+#include "/EgtDev/Include/EGkTrimming.h"
+#include "/EgtDev/Include/EGkCurveAux.h"
+#include "/EgtDev/Include/EGkChainCurves.h"
+#include "/EgtDev/Include/EGkDistPointLine.h"
+#include "/EgtDev/Include/EGkDistPointCurve.h"
+#include "/EgtDev/Include/EGkDistPointSurfTm.h"
+#include "/EgtDev/Include/EGkDistPointSurfBz.h"
+#include "/EgtDev/Include/EGkDistPointTria.h"
+#include "/EgtDev/Include/EGkDistLineLine.h"
+#include "/EgtDev/Include/EGkSbzFromCurves.h"
+#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
+#include "/EgtDev/Include/EGkIntersLineBox.h"
+#include "/EgtDev/Include/EGkSurfTriMeshAux.h"
+#include "/EgtDev/Include/EgtNumUtils.h"
+#include
+#include
+
+// -------------------------- Debug --------------------------------------------
+#define DEBUG 0
+#define DEBUG_BASIC_BORDERS 0
+#define DEBUG_CHAIN_CURVES 0
+#define DEBUG_ANG_APPROX 0
+#define DEBUG_BEZIER_INTERP 0
+#define DEBUG_FACE_SEARCH 0
+#define DEBUG_BRK_POINTS 0
+#define DEBUG_BRK_THICK 0
+#define DEBUG_BRK 0
+#define DEBUG_BORDERS_BY_NORMALS 0
+#define DEBUG_SYNC_POINTS 0
+#define DEBUG_BEZIER_RULED 0
+#define DEBUG_CURVATURE 0
+#define DEBUG_SIMPLE_PATCHES 0
+#define DEBUG_SURF_PATCHES 0
+#define DEBUG_EDGES 0
+#define DEBUG_SHAPE_STM 0
+#if DEBUG_BASIC_BORDERS || DEBUG_CHAIN_CURVES || DEBUG_ANG_APPROX || DEBUG_BEZIER_INTERP || \
+ DEBUG_FACE_SEARCH || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || \
+ DEBUG_SYNC_POINTS || DEBUG_BEZIER_RULED || DEBUG_CURVATURE || DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || \
+ DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG
+ #include "CurveLine.h"
+ #include "/EgtDev/Include/EGkGeoObjSave.h"
+ #include "/EgtDev/Include/EgtPerfCounter.h"
+ #include "/EgtDev/Include/EGnStringUtils.h"
+ #include "/EgtDev/Include/EGkGeoPoint3d.h"
+ #include "/EgtDev/Include/EGkGeoVector3d.h"
+ std::vector VT ;
+ std::vector VC ;
+ std::vector VT_Glob ;
+ std::vector VC_Glob ;
+ std::string sFileName = "C:\\Temp\\Debug.nge" ;
+#endif
+
+using namespace std ;
+
+// Vettori e Matrici di curva composite
+typedef vector COMPOVECTOR ;
+typedef vector COMPOMATRIX ;
+// Strutta per Patch semplici, Bordi e insieme di Bordi
+struct SimplePatch {
+ Point3d ptStart ;
+ Point3d ptEnd ;
+ bool bErase ;
+ int nBorder ;
+ SimplePatch()
+ : ptStart( P_INVALID), ptEnd( P_INVALID), bErase( true), nBorder( 0) {} ;
+ SimplePatch( const Point3d& ptS, const Point3d& ptE, int nB, bool bDelete)
+ : ptStart( ptS), ptEnd( ptE), bErase( bDelete), nBorder( nB) {} ;
+} ;
+typedef vector SimpleBorder ;
+typedef vector SimpleBorderVector ;
+typedef vector SimpleBorderMatrix ;
+// Struttura per superficie con relative Patch
+struct SurfPatches {
+ int nIndSurf ;
+ const ISurf* pSurf ;
+ vector vPatches ; // non definiscono per forza un bordo, sono solo patch non ordinate
+ COMPOVECTOR CompoPathces ;
+} ;
+typedef vector SURFPATCHESVECTOR ;
+// Struttura per Calcolo delle Normali su una superficie lungo il suo bordo ( per parallelismo )
+struct BorderInfo {
+ const ISurf* pSurf ;
+ const ICurveComposite* pCompo ;
+ int nInd ;
+ double dParam ;
+ Point3d ptCrv ;
+ Vector3d vtTan ;
+ Vector3d vtNorm ;
+ Point3d ptFinal ;
+ BorderInfo( const ISurf* pS, const ICurveComposite* pC, int nI, double dP)
+ : pSurf( pS), pCompo( pC), nInd( nI), dParam( dP) {}
+} ;
+typedef vector VBORDERINFO ;
+
+//-----------------------------------------------------------------------------
+static const string sCircle{ "circle"} ;
+
+//-----------------------------------------------------------------------------
+//--------------------------- Approssimazione ---------------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Funzione per spezzare una PolyLine in un insieme di Patches, ovvero un insieme di
+// PolyLine dove per ogni punto si discosta da due successivi per non più della tolleranza
+// angolare passata
+static bool
+GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL)
+{
+ // Se PL chiusa, deve contenere almeno 3 punti
+ if ( PL.IsClosed() && PL.GetPointNbr() < 3)
+ return false ;
+ // Se PL aperta, deve contenere almeno 2 punti
+ if ( ! PL.IsClosed() && PL.GetPointNbr() < 2)
+ return false ;
+
+ // Se PL aperta con solo due punti, allora non devo fare nulla
+ if ( ! PL.IsClosed() && PL.GetPointNbr() == 2) {
+ vPL.emplace_back( PL) ;
+ return true ;
+ }
+
+ // Recupero l'insieme di punti associati alla PolyLine
+ PNTVECTOR vPoints ; vPoints.reserve( PL.GetPointNbr()) ;
+ Point3d ptCurr = P_INVALID ;
+ bool bFound = PL.GetFirstPoint( ptCurr) ;
+ while ( bFound) {
+ vPoints.emplace_back( ptCurr) ;
+ bFound = PL.GetNextPoint( ptCurr) ;
+ }
+ #if DEBUG_ANG_APPROX
+ VT.clear() ; VC.clear() ;
+ Color _col = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
+ for ( auto _p : vPoints) {
+ IGeoPoint3d* _pt = CreateGeoPoint3d() ;
+ _pt->Set( _p) ;
+ VT.emplace_back( _pt) ;
+ VC.emplace_back( _col) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\RawPoints.nge") ;
+ #endif
+
+ // Sin della tolleranza angolare massima
+ double dCosTol = cos( dAngTol * DEGTORAD) ;
+
+ // Scorro i punti controllando le loro deviazioni angolari
+ PNTMATRIX vvPoints ;
+ Vector3d vtTanCurr = V_INVALID, vtTanNext = V_INVALID ;
+ bool bNewCurve = true ;
+ int nPoints = int( vPoints.size()) ;
+ for ( int nP = 0 ; nP < nPoints - 2 ; ++ nP) {
+ // Recupero il punto corrente e i due punti successivi
+ Point3d& ptCurr = vPoints[nP] ;
+ Point3d& ptNext = vPoints[nP + 1] ;
+ Point3d& ptNextNext = vPoints[nP + 2] ;
+ // Recupero i versori tangenti definiti dai tre punti ( ptCurr|ptNext e ptNext|ptNextNext)
+ if ( nP == 0) {
+ vtTanCurr = ptNext - ptCurr ;
+ vtTanCurr.Normalize() ;
+ }
+ else
+ vtTanCurr = vtTanNext ;
+ vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ;
+ // Calcolo il Coseno tra i due versori
+ double dCos = vtTanCurr * vtTanNext ;
+ // Se dentro alla tolleranza, allora i punti apparterranno alla stessa curva
+ if ( dCos > dCosTol) {
+ // Se devo definire una curva nuova
+ if ( bNewCurve) {
+ vvPoints.emplace_back( PNTVECTOR()) ;
+ vvPoints.back().emplace_back( ptCurr) ;
+ vvPoints.back().emplace_back( ptNext) ;
+ bNewCurve = false ;
+ }
+ // Aggiungo il punto
+ vvPoints.back().emplace_back( ptNextNext) ;
+ }
+ // Se tratto al di fuori della tolleranza, devo definire una nuova curva
+ else {
+ // Se curva nuova, allora è solamente tratto lineare
+ if ( bNewCurve) {
+ vvPoints.emplace_back( PNTVECTOR()) ;
+ vvPoints.back().emplace_back( ptCurr) ;
+ vvPoints.back().emplace_back( ptNext) ;
+ }
+ bNewCurve = true ;
+ }
+ }
+ // Se PolyLine originale chiusa
+ if ( PL.IsClosed()) {
+ // Se ho più tratti, potrei riuniore il primo con l'ultimo
+ if ( int( vvPoints.size()) > 1) {
+ Point3d& ptCurr = vPoints[int( vPoints.size()) - 2] ;
+ Point3d& ptNext = vPoints[0] ;
+ Point3d& ptNextNext = vPoints[1] ;
+ vtTanCurr = ptNext - ptCurr ; vtTanCurr.Normalize() ;
+ vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ;
+ double dCos = vtTanCurr * vtTanNext ;
+ // Se dentro alla tolleranza
+ if ( dCos > dCosTol) {
+ // Recupero la tangenza del tratto finale dell'ultimo tratto
+ Point3d& ptLast = vvPoints.back()[int( vvPoints.back().size()) - 1] ;
+ Point3d& ptLastLast = vvPoints.back()[int( vvPoints.back().size()) - 2] ;
+ Vector3d vtTanLast = ptLast - ptLastLast ; vtTanLast.Normalize() ;
+ dCos = vtTanLast * vtTanCurr ;
+ // Se nella tolleranza allora posso allacciare il primo e l'ultimo tratto
+ if ( dCos > dCosTol) {
+ for ( int i = bNewCurve ? 1 : 0 ; i < int( vvPoints[0].size()) ; ++ i)
+ vvPoints.back().emplace_back( vvPoints[0][i]) ;
+ vvPoints.erase( vvPoints.begin()) ;
+ }
+ // Altrimenti sposto il punto d'inizio in ptCurr del primo tratto
+ else {
+ PNTVECTOR vPointsFirst ; vPointsFirst.reserve( vvPoints.front().size() + 1) ;
+ vPointsFirst.emplace_back( ptCurr) ;
+ for ( const Point3d& pt : vvPoints.front())
+ vPointsFirst.emplace_back( pt) ;
+ vvPoints.front() = vPointsFirst ;
+ }
+ }
+ // Se fuori dalla tolleranza, e l'ultimo punto non è già stato aggiunto
+ else if ( bNewCurve) {
+ // tratto lineare finale
+ vvPoints.emplace_back( PNTVECTOR{}) ;
+ vvPoints.back().emplace_back( ptCurr) ;
+ vvPoints.back().emplace_back( ptNext) ;
+ }
+ }
+ }
+ // Se invece PolyLine Aperta
+ else {
+ // Se devo creare una curva nuova, aggiungo il tratto finale
+ if ( bNewCurve) {
+ vvPoints.emplace_back( PNTVECTOR{}) ;
+ vvPoints.back().emplace_back( vPoints[int( vPoints.size()) - 2]) ;
+ vvPoints.back().emplace_back( vPoints[int( vPoints.size()) - 1]) ;
+ }
+ }
+ #if DEBUG_ANG_APPROX
+ VT.clear() ; VC.clear() ;
+ for ( auto _v : vvPoints) {
+ Color _col = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
+ for ( auto _p : _v) {
+ IGeoPoint3d* _pt = CreateGeoPoint3d() ;
+ _pt->Set( _p) ;
+ VT.emplace_back( _pt) ;
+ VC.emplace_back( _col) ;
+ }
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\GroupPoints.nge") ;
+ #endif
+
+ // Converto i punti ricavati in PolyLine risultati
+ for ( int i = 0 ; i < int( vvPoints.size()) ; ++ i) {
+ vPL.emplace_back( PolyLine()) ;
+ double dPar = -1. ;
+ for ( int j = 0 ; j < int( vvPoints[i].size()) ; ++ j) {
+ vPL.back().AddUPoint( ++ dPar, vvPoints[i][j]) ;
+ }
+ }
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante
+// Patches di curve di Bezier
+static bool
+ApproxCurveWithBezier( ICurveComposite* pCrvCompo, double dLinTol, double dAngTol)
+{
+ // Controllo dei parametri
+ if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid())
+ return false ;
+
+ // Recupero la PolyLine associata ( senza alcuna approssimazione)
+ PolyLine myPL ;
+ if ( ! pCrvCompo->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL))
+ return false ;
+
+ // Approssimo la curva mediante Set di punti considerando la tolleranza angolare
+ POLYLINEVECTOR vPL ;
+ if ( ! GetPointSetByAngTol( myPL, dAngTol, vPL))
+ return false ;
+ #if DEBUG_BEZIER_INTERP
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( pCrvCompo->Clone()) ;
+ VC.emplace_back( RED) ;
+ for ( PolyLine& PL : vPL) {
+ if ( PL.GetPointNbr() > 1) {
+ Point3d ptCurr ; PL.GetFirstPoint( ptCurr) ;
+ IGeoPoint3d* pt = CreateGeoPoint3d() ;
+ pt->Set( ptCurr) ;
+ VT.emplace_back( pt) ;
+ VC.emplace_back( AQUA) ;
+ PL.GetLastPoint( ptCurr) ;
+ pt->Set( ptCurr) ;
+ VT.emplace_back( pt) ;
+ VC.emplace_back( AQUA) ;
+ }
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\AngBorderApprox.nge") ;
+ VT.clear() ; VC.clear() ;
+ #endif
+
+ // Pulisco la curva originale
+ pCrvCompo->Clear() ;
+
+ // Ogni PolyLine ricavata viene approssimata con un tratto di Bezier
+ const double MAXLEN = 1.5 ;
+ for ( const PolyLine& PL : vPL) {
+ // Se meno di due punti, non la considero ( non dovrebbe mai capitare )
+ if ( PL.GetPointNbr() < 2)
+ continue ;
+ // Recupero i punti
+ PNTVECTOR vPoints ;
+ Point3d ptCurr ;
+ bool bFound = PL.GetFirstPoint( ptCurr) ;
+ while ( bFound) {
+ vPoints.emplace_back( ptCurr) ;
+ bFound = PL.GetNextPoint( ptCurr) ;
+ }
+ #if DEBUG_BEZIER_INTERP
+ Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
+ for ( int i = 0 ; i < int( vPoints.size()) ; ++ i) {
+ IGeoPoint3d* pt = CreateGeoPoint3d() ;
+ pt->Set( vPoints[i]) ;
+ VT.emplace_back( pt) ;
+ VC.emplace_back( myCol) ;
+ }
+ #endif
+ // Approssimo con una Bezier
+ PtrOwner pCrvBz( InterpolatePointSetWithBezier( vPoints, dLinTol, MAXLEN)) ;
+ if ( IsNull( pCrvBz) || ! pCrvBz->IsValid()) {
+ LOG_ERROR( GetEGkLogger(), "Error : Interpolating points to bezier curve failed") ;
+ return false ;
+ }
+ #if DEBUG_BEZIER_INTERP
+ VT.emplace_back( pCrvBz->Clone()) ;
+ myCol.Set( myCol.GetRed() * .95, myCol.GetGreen() * .95, myCol.GetBlue() * .95) ;
+ VC.emplace_back( myCol) ;
+ #endif
+ // Aggiungo il tratto approssimato alla curva finale complessiva
+ if ( ! pCrvCompo->AddCurve( Release( pCrvBz)))
+ return false ;
+ }
+ #if DEBUG_BEZIER_INTERP
+ SaveGeoObj( VT, VC, "C:\\Temp\\InterpolationCurveBezier.nge") ;
+ #endif
+
+ return ( pCrvCompo->IsValid()) ;
+}
+
+//-----------------------------------------------------------------------------
+//-------------------------------- Analisi Bordi ------------------------------
+//-----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Funzione per controllare e sistemare le curve di bordo di una riagata Bezier
+static bool
+ManageRuledBorders( ICurveComposite* pCompoEdge1, ICurveComposite* pCompoEdge2)
+{
+ // Se curve non valide, errore
+ if ( pCompoEdge1 == nullptr || ! pCompoEdge1->IsValid() ||
+ pCompoEdge2 == nullptr || ! pCompoEdge2->IsValid())
+ return false ;
+
+ // Le due curve devono essere entrambe aperte o entrambe chiuse
+ bool bAllClosed = ( pCompoEdge1->IsClosed() && pCompoEdge2->IsClosed()) ;
+ bool bAllOpen = ( ! pCompoEdge1->IsClosed() && ! pCompoEdge2->IsClosed()) ;
+ if ( ! bAllClosed && ! bAllOpen) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Mixed Edges") ;
+ return false ;
+ }
+
+ // Eseguo una copia delle curve composite per non modificare i parametri
+ PtrOwner pCrvEdge1CL( pCompoEdge1->Clone()) ;
+ PtrOwner pCrvEdge2CL( pCompoEdge2->Clone()) ;
+ if ( IsNull( pCrvEdge1CL) || IsNull( pCrvEdge2CL) ||
+ ! pCrvEdge1CL->IsValid() || ! pCrvEdge2CL->IsValid())
+ return false ;
+ PtrOwner pMyCompoEdge1( ConvertCurveToComposite( Release( pCrvEdge1CL))) ;
+ PtrOwner pMyCompoEdge2( ConvertCurveToComposite( Release( pCrvEdge2CL))) ;
+ if ( IsNull( pMyCompoEdge1) || IsNull( pMyCompoEdge2) ||
+ ! pMyCompoEdge1->IsValid() || ! pMyCompoEdge2->IsValid())
+ return false ;
+
+ // Modifico il punto iniziale o oriento le curve allo stesso modo
+ // --- Se entrambe aperte
+ if ( bAllOpen) {
+ // Recupero il punto iniziale della prima curva
+ Point3d ptStart1 ; pMyCompoEdge1->GetStartPoint( ptStart1) ;
+ // Recupero gli estremi della seconda curva
+ Point3d ptStart2 ; pMyCompoEdge2->GetStartPoint( ptStart2) ;
+ Point3d ptEnd2 ; pMyCompoEdge2->GetEndPoint( ptEnd2) ;
+ // Se necessario inverto la seconda curva
+ if ( SqDist( ptStart1, ptEnd2) < SqDist( ptStart1, ptStart2))
+ pMyCompoEdge2->Invert() ;
+ }
+ // --- Se entrambe chiuse
+ else {
+ // Modifico il punto iniziale della prima curva a metà del suo tratto più lungo
+ double dMaxLen = - INFINITO ;
+ int nCrvInd = 0 ;
+ for ( int nCrv = 0 ; nCrv < pMyCompoEdge1->GetCurveCount() ; ++ nCrv) {
+ const ICurve* pCurve = pMyCompoEdge1->GetCurve( nCrv) ;
+ if ( pCurve == nullptr || ! pCurve->IsValid())
+ return false ;
+ double dLen = 0. ;
+ pCurve->GetLength( dLen) ;
+ if ( dLen > dMaxLen) {
+ dMaxLen = dLen ;
+ nCrvInd = nCrv ;
+ }
+ }
+ pMyCompoEdge1->ChangeStartPoint( nCrvInd + 0.5) ;
+ // Recupero il punto iniziale della prima curva
+ Point3d ptStart1 ; pMyCompoEdge1->GetStartPoint( ptStart1) ;
+ // Recupero il punto più vicino sulla seconda curva
+ double dUStart = 0. ;
+ int nFlag = 0 ;
+ DistPointCurve( ptStart1, *pMyCompoEdge2).GetParamAtMinDistPoint( 0., dUStart, nFlag) ;
+ pMyCompoEdge2->ChangeStartPoint( dUStart) ;
+ // Verifico che le tangenti iniziali siano concordi
+ Vector3d vtStart1 ; pMyCompoEdge1->GetStartDir( vtStart1) ;
+ Vector3d vtStart2 ; pMyCompoEdge2->GetStartDir( vtStart2) ;
+ if ( vtStart1 * vtStart2 < - EPS_SMALL)
+ pMyCompoEdge2->Invert() ;
+ }
+
+ // Sostiuisco i risultati
+ pCompoEdge1->Clear() ; pCompoEdge1->CopyFrom( pMyCompoEdge1) ;
+ pCompoEdge2->Clear() ; pCompoEdge2->CopyFrom( pMyCompoEdge2) ;
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per determinare la normale di una superficie generica in un punto
+static bool
+GetNormalAtPoint( const ISurf* pSurf, const Point3d& pt, Vector3d& vtN)
+{
+ // Verifico che le due superfici siano valide
+ if ( pSurf == nullptr || ! pSurf->IsValid())
+ return false ;
+ const double dMinLen = 20. * EPS_SMALL ;
+ const double dMinArea = dMinLen * dMinLen ;
+
+ // Se è Trimesh, recupero la normale del triangolo più vicino al punto scelto
+ if ( pSurf->GetType() == SRF_TRIMESH) {
+ const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ;
+ if ( pStm == nullptr || ! pStm->IsValid())
+ return false ;
+ int nTria = 0 ;
+ DistPointSurfTm( pt, *pStm).GetMinDistTriaIndex( nTria) ;
+ Triangle3d Tria ;
+ if ( ! pStm->GetTriangle( nTria, Tria))
+ return false ;
+ // se il triangolo è rappresentativo, recupero la sua normale
+ if ( Tria.GetArea() > dMinArea)
+ vtN = Tria.GetN() ;
+ else {
+ BBox3d BBoxPt ;
+ BBoxPt.Add( pt) ;
+ BBoxPt.Expand( dMinLen + 2. * EPS_SMALL) ;
+ INTVECTOR vT ;
+ pStm->GetAllTriaOverlapBox( BBoxPt, vT) ;
+ int nBestTria = -1 ;
+ double dMaxArea = dMinArea ;
+ for ( const int& nT : vT) {
+ if ( pStm->GetTriangle( nT, Tria)) {
+ double dCurrArea = Tria.GetArea() ;
+ if ( dCurrArea > dMaxArea) {
+ dMaxArea = dCurrArea ;
+ nBestTria = nT ;
+ }
+ }
+ }
+ if ( nBestTria == -1) // recupero lo stesso il più vicino ( calcolato prima)
+ nBestTria = nTria ;
+ if ( ! pStm->GetTriangle( nBestTria, Tria))
+ return false ;
+ vtN = Tria.GetN() ;
+ }
+ }
+ // Se è Bezier, la normale è calcolata automaticamente
+ else if ( pSurf->GetType() == SRF_BEZIER) {
+ const ISurfBezier* pSbz = GetSurfBezier( pSurf) ;
+ if ( pSbz == nullptr || ! pSbz->IsValid())
+ return false ;
+ if ( ! DistPointSurfBz( pt, *pSbz).GetNorm( vtN))
+ return false ;
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per Splittare una Patch con un'altra
+static bool
+SplitPatchWithPatch( SurfPatches& SurfPatchA, SurfPatches& SurfPatchB, double dLinTol)
+{
+ // Definisco la tolleranza di parametro
+ const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- euristica, modificabile
+
+ // Scorro le Patch della superficie A
+ for ( int nPatchA = 0 ; nPatchA < int( SurfPatchA.CompoPathces.size()) ; ++ nPatchA) {
+ // Recupero la PatchA
+ CurveComposite& PatchA = SurfPatchA.CompoPathces[nPatchA] ;
+ Point3d& ptStartA = SurfPatchA.vPatches[nPatchA].ptStart ;
+ Point3d& ptEndA = SurfPatchA.vPatches[nPatchA].ptEnd ;
+ // Scorro le Patch della supericie B
+ for ( int nPatchB = 0 ; nPatchB < int( SurfPatchB.CompoPathces.size()) ; ++ nPatchB) {
+ // Recupero la PatchB
+ CurveComposite& PatchB = SurfPatchB.CompoPathces[nPatchB] ;
+ Point3d& ptStartB = SurfPatchB.vPatches[nPatchB].ptStart ;
+ Point3d& ptEndB = SurfPatchB.vPatches[nPatchB].ptEnd ;
+
+ // Verifico se gli estremi giaciono sulle linee
+ double dDist = 0. ;
+ double dPar = 0., dParS = 0., dParE = 0. ;
+ int nFlag = 0 ;
+ bool bSplit = false ;
+ Point3d ptInters ;
+
+ // Estremi B su PatchA ( sono tutti tratti lineari, quindi nel 3d va bene)
+ DistPointCurve DLL0( ptStartB, PatchA) ;
+ bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol &&
+ DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ PatchA.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ if ( ! bSplit) {
+ DistPointCurve DLL1( ptEndB, PatchA) ;
+ bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol &&
+ DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ PatchA.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ }
+ // Se Split della PatchA richiesto
+ if ( bSplit) {
+ // Split della Patch
+ PatchA.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ;
+ SimplePatch NextPatch( ptInters, ptEndA, 0, false) ;
+ SurfPatchA.vPatches.insert( SurfPatchA.vPatches.begin() + nPatchA + 1, NextPatch) ;
+ ptEndA = ptInters ;
+ // Split della curva composita associata
+ CurveComposite* pCompoAfter( PatchA.Clone()) ;
+ PatchA.TrimEndAtParam( dPar) ;
+ pCompoAfter->TrimStartAtParam( dPar) ;
+ SurfPatchA.CompoPathces.insert( SurfPatchA.CompoPathces.begin() + nPatchA + 1, *pCompoAfter) ;
+ // Aggiorno i contatori
+ -- nPatchA ;
+ break ;
+ }
+
+ // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene)
+ DistPointCurve DLL2( ptStartA, PatchB) ;
+ bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol &&
+ DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ PatchB.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ if ( ! bSplit) {
+ DistPointCurve DLL3( ptEndA, PatchB) ;
+ bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol &&
+ DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ PatchB.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ }
+ // Se Split della PatchB richiesto
+ if ( bSplit) {
+ // Split della Patch
+ PatchB.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ;
+ SimplePatch NextPatch( ptInters, ptEndB, 0, false) ;
+ SurfPatchB.vPatches.insert( SurfPatchB.vPatches.begin() + nPatchB + 1, NextPatch) ;
+ ptEndB = ptInters ;
+ // Split della curva composita associata
+ CurveComposite* pCompoAfter( PatchB.Clone()) ;
+ PatchB.TrimEndAtParam( dPar) ;
+ pCompoAfter->TrimStartAtParam( dPar) ;
+ SurfPatchB.CompoPathces.insert( SurfPatchB.CompoPathces.begin() + nPatchB + 1, *pCompoAfter) ;
+ // Aggiorno i contatori
+ -- nPatchB ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per ottenere le Patch dei bordi di una superficie
+static bool
+CalcPatches( const POLYLINEVECTOR& vPLBorders, double dAngTol, POLYLINEMATRIX& matPLPatches)
+{
+ // Ogni PolyLine di bordo viene vista come un insieme di Patches
+ matPLPatches.reserve( vPLBorders.size()) ;
+ for ( const PolyLine& PL : vPLBorders) {
+ // Approssimo mediante tolleranza angolare ricavando l'insieme delle Patches
+ matPLPatches.emplace_back( POLYLINEVECTOR{}) ;
+ if ( ! GetPointSetByAngTol( PL, dAngTol, matPLPatches.back()))
+ return false ;
+ // Trasferisco le TempProps
+ for ( PolyLine newPL : matPLPatches.back())
+ newPL.SetTempProp( 0, PL.GetTempProp( 0)) ;
+ }
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione per scremare le curve di Bordo tenendo solo i tratti utili concatenabili
+static bool
+ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol,
+ ICRVCOMPOPOVECTOR& vCompoResult)
+{
+ // Se non ho Polyline non faccio nulla
+ if ( vPLBorders.empty())
+ return true ;
+ vCompoResult.clear() ;
+
+ // Approssimo le curve
+ // NB. Per Patch si intende un tratto di PolyLine dove la tangenza di ogni punto con i suoi 2 successivi
+ // rimane all'interno della tolleranza angolare definita
+ // Ogni curva di bordo viene quindi vista come un insieme di Patches
+ POLYLINEMATRIX matPLPatches ;
+ if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatches))
+ return false ;
+ // Tengo anche la curva composita rispettiva per ogni Patch ( serve più avanti) [*]
+ COMPOMATRIX matCompoPatches ; matCompoPatches.reserve( vPLBorders.size()) ;
+ for ( const POLYLINEVECTOR& PLBorder : matPLPatches) {
+ matCompoPatches.emplace_back( COMPOVECTOR{}) ;
+ for ( const PolyLine& PLPatch : PLBorder) {
+ matCompoPatches.back().emplace_back( CurveComposite()) ;
+ matCompoPatches.back().back().FromPolyLine( PLPatch) ;
+ }
+ }
+
+ // Ogni curva Patch diventa un insieme di tratti attivi definiti dagli estremi calcolati
+ // NB. In questo modo si salvano solo gli estremi della curva Patch, mentre la sua geometria
+ // è rimasta memorizzata in precedenza [*]
+ // Ogni bordo viene quindi visto come un insieme di Patch semplici ( per adesso tutte attive)
+ SimpleBorderVector vvSimpleBorder ; vvSimpleBorder.reserve( matPLPatches.size()) ;
+ for ( int i = 0 ; i < int( matPLPatches.size()) ; ++ i) {
+ vvSimpleBorder.emplace_back( SimpleBorder()) ;
+ for ( int j = 0 ; j < int( matPLPatches[i].size()) ; ++ j) {
+ Point3d ptS ; matPLPatches[i][j].GetFirstPoint( ptS) ;
+ Point3d ptE ; matPLPatches[i][j].GetLastPoint( ptE) ;
+ vvSimpleBorder.back().emplace_back( ptS, ptE, i, false) ;
+ }
+ }
+ #if DEBUG_CHAIN_CURVES
+ VC.clear() ; VT.clear() ;
+ for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) {
+ for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) {
+ VT.emplace_back( matCompoPatches[i][j].Clone()) ;
+ VC.emplace_back( RED) ;
+ IGeoPoint3d* ptS = CreateGeoPoint3d() ;
+ ptS->Set( vvSimpleBorder[i][j].ptStart) ;
+ VT.emplace_back( ptS) ;
+ VC.emplace_back( AQUA) ;
+ IGeoPoint3d* ptE = CreateGeoPoint3d() ;
+ ptE->Set( vvSimpleBorder[i][j].ptEnd) ;
+ VT.emplace_back( ptE) ;
+ VC.emplace_back( AQUA) ;
+ }
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\EdgesAndPoints.nge") ;
+ #endif
+
+ // In generale se sono state selezionate più superfici, non è garantito che tutti gli estremi
+ // delle Patch coicidano solo con altri estremi di altre Patches ( può capitare che un estremo di
+ // una Patch cada ad esempio a metà di un'altra Patch e non nei suoi estremi )
+ // Soluzione : si spezzano le Patch ulteriormente in modo che ogni estremo di patch sia o nell'intorno
+ // di un altro estremo di patch o isolato ( ad esempio nei bordi più esterni )
+ const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- eursitica, modificabile
+ for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) {
+ // Recupero la curva corrente
+ SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ;
+ // Scorro i suoi Edges
+ for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) {
+ // Recupero il tratto di curva corrente
+ CurveComposite& CurrCompo = matCompoPatches[nCurrCrv][nCurrEdge] ;
+ // Scorro le curve successive
+ for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) {
+ // Recupero la curva successiva
+ SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ;
+ // Scorro i suoi Edges
+ for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) {
+ // Se appartiene allo stesso bordo, passo alla seguente
+ if ( NextCurve[nNextEdge].nBorder == CurrCurve[nCurrEdge].nBorder)
+ continue ;
+ // Recupero il tratto di curva corrente
+ CurveComposite& NextCompo = matCompoPatches[nNextCrv][nNextEdge] ;
+ // Verifico se gli estremi giaciono sulle linee
+ double dDist = 0. ;
+ double dPar = 0., dParS = 0., dParE = 0. ;
+ int nFlag = 0 ;
+ bool bSplit = false ;
+ Point3d ptInters ;
+
+ // Estremi Next su LineCurr ( sono tutti tratti lineari, quindi nel 3d va bene)
+ DistPointCurve DLL0( NextCurve[nNextEdge].ptStart, CurrCompo) ;
+ bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol &&
+ DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ CurrCompo.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ if ( ! bSplit) {
+ DistPointCurve DLL1( NextCurve[nNextEdge].ptEnd, CurrCompo) ;
+ bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol &&
+ DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ CurrCompo.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ }
+ // Split dell'Edge se richiesto
+ if ( bSplit) {
+ #if DEBUG_CHAIN_CURVES
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( NextCompo.Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ VT.emplace_back( CurrCompo.Clone()) ;
+ VC.emplace_back( LIME) ;
+ SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ;
+ #endif
+ // Aggiorno gli Edges
+ CurrCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ;
+ SimplePatch NextEdge( ptInters, CurrCurve[nCurrEdge].ptEnd,
+ CurrCurve[nCurrEdge].nBorder, false) ;
+ CurrCurve.insert( CurrCurve.begin() + nCurrEdge + 1, NextEdge) ;
+ CurrCurve[nCurrEdge].ptEnd = ptInters ;
+ // Aggiorno le Curve
+ CurveComposite* pCompoAfter( CurrCompo.Clone()) ;
+ CurrCompo.TrimEndAtParam( dPar) ;
+ pCompoAfter->TrimStartAtParam( dPar) ;
+ matCompoPatches[nCurrCrv].insert( matCompoPatches[nCurrCrv].begin() + nCurrEdge + 1, *pCompoAfter) ;
+ // Aggiorno i contatori
+ -- nCurrEdge ;
+ nNextCrv = int( vvSimpleBorder.size()) ;
+ break ;
+ }
+
+ // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene)
+ DistPointCurve DLL2( CurrCurve[nCurrEdge].ptStart, NextCompo) ;
+ bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol &&
+ DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ NextCompo.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ if ( ! bSplit) {
+ DistPointCurve DLL3( CurrCurve[nCurrEdge].ptEnd, NextCompo) ;
+ bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol &&
+ DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) &&
+ NextCompo.GetDomain( dParS, dParE) &&
+ dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ;
+ }
+ // Split dell'Edge se richiesto
+ if ( bSplit) {
+ #if DEBUG_CHAIN_CURVES
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( NextCompo.Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ VT.emplace_back( CurrCompo.Clone()) ;
+ VC.emplace_back( LIME) ;
+ SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ;
+ #endif
+ // Aggiorno gli Edges
+ NextCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ;
+ SimplePatch NextEdge( ptInters, NextCurve[nNextEdge].ptEnd,
+ NextCurve[nNextEdge].nBorder, false) ;
+ NextCurve.insert( NextCurve.begin() + nNextEdge + 1, NextEdge) ;
+ NextCurve[nNextEdge].ptEnd = ptInters ;
+ // Aggiorno le curve
+ CurveComposite* pCompoAfter( NextCompo.Clone()) ;
+ NextCompo.TrimEndAtParam( dPar) ;
+ pCompoAfter->TrimStartAtParam( dPar) ;
+ matCompoPatches[nNextCrv].insert( matCompoPatches[nNextCrv].begin() + nNextEdge + 1, *pCompoAfter) ;
+ // Aggiorno i contatori
+ -- nNextEdge ;
+ }
+ }
+ }
+ }
+ }
+ #if DEBUG_CHAIN_CURVES
+ VC.clear() ; VT.clear() ;
+ for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) {
+ for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) {
+ VT.emplace_back( matCompoPatches[i][j].Clone()) ;
+ VC.emplace_back( RED) ;
+ IGeoPoint3d* pt = CreateGeoPoint3d() ;
+ pt->Set( vvSimpleBorder[i][j].ptStart) ;
+ VT.emplace_back( pt) ;
+ VC.emplace_back( AQUA) ;
+ pt = CreateGeoPoint3d() ;
+ pt->Set( vvSimpleBorder[i][j].ptEnd) ;
+ VT.emplace_back( pt) ;
+ VC.emplace_back( AQUA) ;
+ }
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\BordersWithOverlaps.nge") ;
+ #endif
+
+ // Si eliminano ora tutte le Patch che si sovrappongono, in modo da ottenere solo un
+ // le Patch che rappresentano il bordo esterno
+ const double MAXPOINT = 10 ;
+ for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) {
+ // Recupero la curva corrente
+ SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ;
+ // Scorro i suoi Edges
+ for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) {
+ // Se Edge cancellato, passo al successivo
+ if ( CurrCurve[nCurrEdge].bErase)
+ continue ;
+ // Recupero i due estremi dell'Edge
+ Point3d& ptCurrStart = CurrCurve[nCurrEdge].ptStart ;
+ Point3d& ptCurrEnd = CurrCurve[nCurrEdge].ptEnd ;
+ // Scorro le curve successive
+ for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) {
+ // Recupero la curva successiva
+ SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ;
+ // Scorro i suoi Edges
+ for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) {
+ // Se Edge cancellato, passo al successivo
+ #if 0
+ // Se pezze si superficie piccolissime, si rischia di eliminare tutti i
+ // tratti Next con il primo tratto Curr e lasciare poi il Secondo Curr senza
+ // elementi da eliminare ( TrimTractor.nge)
+ if ( NextCurve[nNextEdge].bErase)
+ continue ;
+ #endif
+ // Recupero i due estremi di riferimento
+ Point3d& ptNextStart = NextCurve[nNextEdge].ptStart ;
+ Point3d& ptNextEnd = NextCurve[nNextEdge].ptEnd ;
+ // Controllo se i due estremi coincidono
+ if ( ( AreSamePointEpsilon( ptCurrStart, ptNextStart, dLinTol) &&
+ AreSamePointEpsilon( ptCurrEnd, ptNextEnd, dLinTol)) ||
+ ( AreSamePointEpsilon( ptCurrStart, ptNextEnd, dLinTol) &&
+ AreSamePointEpsilon( ptCurrEnd, ptNextStart, dLinTol))) {
+ // Controllo che i punti coincidano
+ CurveComposite* pCompoCurr = &matCompoPatches[nCurrCrv][nCurrEdge] ;
+ CurveComposite* pCompoNext = &matCompoPatches[nNextCrv][nNextEdge] ;
+ if ( pCompoCurr == nullptr || pCompoNext == nullptr)
+ return false ;
+ double dLenCurr ; pCompoCurr->GetLength( dLenCurr) ;
+ bool bErase = true ;
+ for ( int nP = 1 ; bErase && nP <= MAXPOINT ; ++ nP) {
+ double dPar = 0. ;
+ pCompoCurr->GetParamAtLength( ( dLenCurr / MAXPOINT) * nP, dPar) ;
+ Point3d ptCurr ;
+ pCompoCurr->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptCurr) ;
+ double dSqDist = 0. ;
+ DistPointCurve( ptCurr, *pCompoNext).GetSqDist( dSqDist) ;
+ bErase = ( dSqDist < dLinTol * dLinTol + SQ_EPS_SMALL) ;
+ }
+ // Disabilito i rispettivi Edges se necessario
+ if ( bErase) {
+ CurrCurve[nCurrEdge].bErase = true ;
+ NextCurve[nNextEdge].bErase = true ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Dalle PolyLine recupero delle curve composite ( quindi anch'esse come insieme di tratti linari)
+ ICRVCOMPOPOVECTOR vCompoPatches ; vCompoPatches.reserve( vvSimpleBorder.size()) ;
+ for ( const PolyLine& PL : vPLBorders) {
+ if ( ! vCompoPatches.emplace_back( CreateCurveComposite()) ||
+ ! vCompoPatches.back()->FromPolyLine( PL))
+ return false ;
+ vCompoPatches.back()->SetTempProp( PL.GetTempProp( 0), 0) ;
+ }
+
+ // Recupero solo i sottotratti di curva validi ( quindi che non fanno overlap tra loro)
+ for ( int nCrv = 0 ; nCrv < int( vvSimpleBorder.size()) ; ++ nCrv) {
+ // Recupero la curva
+ SimpleBorder& CrvEdge = vvSimpleBorder[nCrv] ;
+ // Scorro i suoi edges
+ for ( int nEdge = 0 ; nEdge < int( CrvEdge.size()) ; ++ nEdge) {
+ // Se edge non attivo, passo al successivo
+ if ( CrvEdge[nEdge].bErase)
+ continue ;
+ // Se punto iniziale finale uguali
+ // [ Se pezze di superficie piccolissime, si rischia di eliminare tutti i
+ // tratti Next con il primo tratto Curr e lasciare poi il Secondo Curr senza
+ // elementi da eliminare ( TrimTractor.nge) ]
+ if ( AreSamePointApprox( CrvEdge[nEdge].ptStart, CrvEdge[nEdge].ptEnd))
+ vCompoResult.emplace_back( Release( vCompoPatches[nCrv])) ;
+ else {
+ // Recupero il tratto di curva e lo memorizzo
+ double dUStart = 0., dUEnd = 0. ;
+ vCompoPatches[nCrv]->GetParamAtPoint( CrvEdge[nEdge].ptStart, dUStart, dLinTol) ;
+ vCompoPatches[nCrv]->GetParamAtPoint( CrvEdge[nEdge].ptEnd, dUEnd, dLinTol) ;
+ vCompoResult.emplace_back( ConvertCurveToComposite( vCompoPatches[nCrv]->CopyParamRange( dUStart, dUEnd))) ;
+ vCompoResult.back()->SetTempProp( vCompoPatches[nCrv]->GetTempProp( 0), 0) ;
+ }
+ }
+ }
+ // Conservo solo le curve valide
+ for ( int nCrv = 0 ; nCrv < int( vCompoResult.size()) ; ++ nCrv) {
+ if ( IsNull( vCompoResult[nCrv]) || ! vCompoResult[nCrv]->IsValid()) {
+ vCompoResult.erase( vCompoResult.begin() + nCrv) ;
+ -- nCrv ;
+ }
+ }
+ #if DEBUG_CHAIN_CURVES // Debug per le Patch risultanti
+ VT.clear() ; VC.clear() ;
+ for ( int i = 0 ; i < int( vCompoResult.size()) ; ++ i) {
+ VT.emplace_back( vCompoResult[i]->Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\FinalChainedBorders.nge") ;
+ #endif
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione per concatenare nello spazio 3d le Curve Patches.
+// NB. Tutte le vCompoPathes sono formate da tratti lineari.
+static bool
+ChainCompoPatches( ICRVCOMPOPOVECTOR& vCompoPatches, double dChainTol,
+ ICRVCOMPOPOVECTOR& vCompoChained)
+{
+ // Controllo dei parametri
+ if ( vCompoPatches.empty())
+ return false ;
+ vCompoChained.clear() ;
+
+ // Controllo la validità delle curve
+ for ( const ICurveComposite* pCrvCompo : vCompoPatches) {
+ if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid())
+ return false ;
+ }
+
+ // La concatenazione parte dalla curva più lunga
+ double dMaxLen = - INFINITO ;
+ int nInd = 0 ;
+ for ( int i = 0 ; i < int( vCompoPatches.size()) ; ++ i) {
+ double dLen = 0. ;
+ vCompoPatches[i]->GetLength( dLen) ;
+ if ( dLen > dMaxLen) {
+ dMaxLen = dLen ;
+ nInd = i ;
+ }
+ }
+ swap( vCompoPatches[0], vCompoPatches[nInd]) ;
+
+ // [ TODO : Algoritmo migliorabile nei controlli ]
+ // Scorro le curve
+ vCompoChained.reserve( vCompoPatches.size()) ;
+ BOOLVECTOR vbCrvChained( vCompoPatches.size(), false) ;
+ for ( int nCurrCrv = 0 ; nCurrCrv < int( vCompoPatches.size()) ; ++ nCurrCrv) {
+ // Se curva già concatenata, passo alla successiva ( no biforcazioni ammesse -> errore )
+ if ( vbCrvChained[nCurrCrv])
+ continue ;
+ // Definisco una nuova curva di concatenazione e recupero il suo estremo finale
+ Point3d ptEnd ;
+ if ( ! vCompoChained.emplace_back( CloneCurveComposite( vCompoPatches[nCurrCrv])) ||
+ ! vCompoChained.back()->GetEndPoint( ptEnd))
+ return false ;
+ // Trasferisco le TempProps alle sottocurve
+ for ( int nU = 0 ; nU < vCompoChained.back()->GetCurveCount() ; ++ nU)
+ vCompoChained.back()->SetCurveTempProp( nU, vCompoPatches[nCurrCrv]->GetTempProp( 0), 0) ;
+ // Cerco tra le altre curve disponibili una candidata alla concatenazione
+ for ( int nNextCrv = 0 ; nNextCrv < int( vCompoPatches.size()) ; ++ nNextCrv) {
+ if ( nNextCrv == nCurrCrv || vbCrvChained[nNextCrv])
+ continue ;
+ // Recupero i suoi estremi [ sono tratti lineari, la ricerca è immediata ]
+ Point3d ptStartN ; vCompoPatches[nNextCrv]->GetStartPoint( ptStartN) ;
+ Point3d ptEndN ; vCompoPatches[nNextCrv]->GetEndPoint( ptEndN) ;
+ // Se estremi distanti, passo alla successiva
+ bool bChain = AreSamePointEpsilon( ptEnd, ptStartN, dChainTol) ;
+ bool bChainInv = ( ( ! bChain) && AreSamePointEpsilon( ptEnd, ptEndN, dChainTol)) ;
+ if ( ! bChain && ! bChainInv)
+ continue ;
+ // Recupero la lunghezza della curva
+ double dLenN = 0. ; vCompoPatches[nNextCrv]->GetLength( dLenN) ;
+ // Se la lunghezza della curva è più piccola della tolleranza
+ if ( dLenN < dChainTol + EPS_ZERO) {
+ // La curva corrente non viene aggiunta, ma viene modificato l'estremo finale corrente
+ // nel punto medio
+ vCompoChained.back()->ModifyEnd( Media( ptEndN, ptEnd)) ;
+ }
+ // Se la lunghezza è maggiore della tolleranza
+ else {
+ // Recupero la curva successiva
+ PtrOwner pCrv( CloneCurveComposite( vCompoPatches[nNextCrv])) ;
+ if ( IsNull( pCrv) || ! pCrv->IsValid())
+ return false ;
+ // Se necessario inverto ( potrebbe capitare per triangoli male orientati)
+ if ( bChainInv)
+ pCrv->Invert() ;
+ // Trasferisco le TempProps alle sottocurve
+ for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU)
+ pCrv->SetCurveTempProp( nU, pCrv->GetTempProp( 0), 0) ;
+ // Concateno
+ if ( ! vCompoChained.back()->AddCurve( pCrv->Clone(), true, dChainTol))
+ return false ;
+ }
+ // Aggiornamento dei parametri
+ vbCrvChained[nNextCrv] = true ; // curva in una concatenazione
+ nNextCrv = 0 ; // reset contatore per curva next
+ if ( ! vCompoChained.back()->GetEndPoint( ptEnd)) // aggiornamento punto finale della concatenazione
+ return false ;
+ }
+ }
+ // Verifico la validità delle curve ottenute
+ for ( int i = 0 ; i < int( vCompoChained.size()) ; ++ i) {
+ if ( IsNull( vCompoChained[i]) || ! vCompoChained[i]->IsValid())
+ return false ;
+ // Se curva al di sotto della tolleranza, la scarto
+ // ( Capita se ci sono facce/superfici molto strette. La concatenazione chiude in automatico
+ // la curva complessiva isolando quindi queste entità)
+ double dLen = 0. ;
+ if ( ! vCompoChained[i]->GetLength( dLen) || dLen < dChainTol) {
+ vCompoChained.erase( vCompoChained.begin() + i) ;
+ -- i ;
+ }
+ }
+ #if DEBUG_CHAIN_CURVES // Debug curve concatenate grezze
+ VT.clear() ; VC.clear() ;
+ for ( const ICurveComposite* pCompo : vCompoChained) {
+ VT.emplace_back( pCompo->Clone()) ;
+ VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\ChainedCurves.nge") ;
+ #endif
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione che restituisce una prima semplificazione e concatenazione delle curve
+// di bordi definiti mediante PolyLines
+static bool
+GetRawEdges( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol,
+ ICRVCOMPOPOVECTOR& vCompoChained)
+{
+ // Se non o curve di bordo, allora non faccio nulla
+ if ( vPLBorders.empty())
+ return true ;
+ vCompoChained.clear() ;
+
+ // Recupero le curve di Bordo che non effettuano Overlap tra loro ( sempre solo tratti lineari)
+ ICRVCOMPOPOVECTOR vCompoPatches ;
+ if ( ! ManagePatches( vPLBorders, dLinTol, dAngTol, vCompoPatches))
+ return false ;
+
+ // Concateno le curve risultanti
+ const double CHAIN_TOL = 50. * EPS_SMALL ;
+ if ( ! ChainCompoPatches( vCompoPatches, CHAIN_TOL, vCompoChained))
+ return false ;
+
+ // Se le curve risultano aperte con estremi entro la tolleranza, le chiudo
+ for ( int i = 0 ; i < int( vCompoChained.size()) ; ++ i) {
+ if ( vCompoChained[i] == nullptr || ! vCompoChained[i]->IsValid())
+ return false ;
+ Point3d ptS ; vCompoChained[i]->GetStartPoint( ptS) ;
+ Point3d ptE ; vCompoChained[i]->GetEndPoint( ptE) ;
+ if ( AreSamePointEpsilon( ptS, ptE, dLinTol)) {
+ vCompoChained[i]->Close() ;
+ // Riporto la Temp Prop
+ int nTmpProp0 = vCompoChained[i]->GetFirstCurve()->GetTempProp( 0) ;
+ vCompoChained[i]->SetCurveTempProp( vCompoChained[i]->GetCurveCount() - 1, nTmpProp0, 0) ;
+ }
+ }
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione per calcolare le Edge Curves per la creazione della superficie di Bezier Ruled
+// mediante spessore e tolleranza associata
+static bool
+BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol,
+ double dThick, double dThickTol)
+{
+ // Se non ho curve, non faccio nulla
+ if ( vCompoChained.empty())
+ return true ;
+ const double ANG_SPLIT = 65. ;
+
+ // Scorro le curve
+ ICRVCOMPOPOVECTOR vCrvResult ;
+ for ( const ICurveComposite* pCompoChained : vCompoChained) {
+ // Verifico la sua validità
+ if ( pCompoChained == nullptr || ! pCompoChained->IsValid())
+ return false ;
+ // Recupero la PolyLine associata ( senza alcuna approssimazione)
+ PolyLine myPL ;
+ if ( ! pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL))
+ return false ;
+ // Approssimo la curva mediante Set di punti considerando la tolleranza angolare
+ POLYLINEVECTOR vPL ;
+ if ( ! GetPointSetByAngTol( myPL, ANG_SPLIT, vPL))
+ return false ;
+ // Scorro le PolyLine ricavate e recupero i punti di Split ( tratti da rimuovere)
+ BIPNTVECTOR vBiPntSplit ; vBiPntSplit.reserve( 2) ;
+ for ( const PolyLine& PL : vPL) {
+ double dLen ; PL.GetLength( dLen) ;
+ if ( abs( dLen - dThick) < dThickTol) {
+ Point3d ptStart ; PL.GetFirstPoint( ptStart) ;
+ Point3d ptEnd ; PL.GetLastPoint( ptEnd) ;
+ vBiPntSplit.emplace_back( make_pair( ptStart, ptEnd)) ;
+ }
+ }
+ // Se non ho ottenuto esattamente due tratti, non analizzo più la curva corrente
+ if ( int( vBiPntSplit.size()) != 2) {
+ LOG_INFO( GetEGkLogger(), "Warning in Trimming : Detected more Curves by Thick values") ;
+ break ; // lascio la curva invariata
+ }
+ if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained)))
+ return false ;
+ double dU0 = 0., dU1 = 0. ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].second, dU0) ;
+ vCrvResult.back()->ChangeStartPoint( dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].first, dU1) ;
+ vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( 0., dU1))) ;
+ if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained)))
+ return false ;
+ vCrvResult.back()->ChangeStartPoint( dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].second, dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].first, dU1) ;
+ vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( dU0, dU1))) ;
+ }
+
+ swap( vCrvResult, vCompoChained) ;
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+// Funzione per calcolare le Edge Curves per la creazione della superficie di Bezier Ruled
+// mediante punti di rottura
+static bool
+BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol,
+ const BIPNTVECTOR& vBreakingPts)
+{
+ // Se non ho curve, non faccio nulla
+ if ( vCompoChained.empty())
+ return true ;
+ // Se non ho punti di rottura, non faccio nulla
+ if ( vBreakingPts.empty())
+ return true ;
+ // Se ho punti di rottura in comune, errore
+ for ( int i = 0 ; i < int( vBreakingPts.size()) ; ++ i) {
+ if ( AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[i].second, dLinTol))
+ return false ;
+ for ( int j = i + 1 ; j < int( vBreakingPts.size()) ; ++ j) {
+ if ( AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[j].first, dLinTol) ||
+ AreSamePointEpsilon( vBreakingPts[i].first, vBreakingPts[j].second, dLinTol) ||
+ AreSamePointEpsilon( vBreakingPts[i].second, vBreakingPts[j].first, dLinTol) ||
+ AreSamePointEpsilon( vBreakingPts[i].second, vBreakingPts[j].second, dLinTol))
+ return false ;
+ }
+ }
+
+ #if DEBUG_BRK_POINTS
+ VC.clear() ; VT.clear() ;
+ for ( const ICurveComposite* _pCompoChained : vCompoChained) {
+ VT.emplace_back( _pCompoChained->Clone()) ;
+ VC.emplace_back( RED) ;
+ }
+ for ( const BIPOINT& _Bipt : vBreakingPts) {
+ IGeoPoint3d* _ptS = CreateGeoPoint3d() ; _ptS->Set( _Bipt.first) ;
+ IGeoPoint3d* _ptE = CreateGeoPoint3d() ; _ptE->Set( _Bipt.second) ;
+ VT.emplace_back( _ptS) ;
+ VT.emplace_back( _ptE) ;
+ VC.emplace_back( AQUA) ;
+ VC.emplace_back( LIME) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\Brk.nge") ;
+ #endif
+
+ // Scorro le curve
+ ICRVCOMPOPOVECTOR vCrvResult ;
+ for ( const ICurveComposite* pCompoChained : vCompoChained) {
+ // Verifico che sia valida
+ if ( pCompoChained == nullptr || ! pCompoChained->IsValid())
+ return false ;
+ // Copio la curva, dato che potrei spezzarla
+ ICRVCOMPOPOVECTOR vCompoParts ; vCompoParts.reserve( vBreakingPts.size()) ;
+ if ( ! vCompoParts.emplace_back( CloneCurveComposite( pCompoChained)))
+ return false ;
+ for ( const BIPOINT& BiPnts : vBreakingPts) {
+ // Scorro i tratti ( inizialmente la curva stessa)
+ for ( int i = 0 ; i < int( vCompoParts.size()) ; ++ i) {
+ // Controllo che la coppia di punti giacia su quella curva
+ if ( ! vCompoParts[i]->IsPointOn( BiPnts.first, dLinTol) ||
+ ! vCompoParts[i]->IsPointOn( BiPnts.second, dLinTol))
+ continue ;
+ // Se entrambi sulla curva, recupero il tratto più lungo da loro definito
+ double dUS = 0. ; vCompoParts[i]->GetParamAtPoint( BiPnts.first, dUS, dLinTol) ;
+ double dUE = 0. ; vCompoParts[i]->GetParamAtPoint( BiPnts.second, dUE, dLinTol) ;
+ PtrOwner pCrvA( vCompoParts[i]->CopyParamRange( dUS, dUE)) ;
+ PtrOwner pCrvB( vCompoParts[i]->CopyParamRange( dUE, dUS)) ;
+ // Se la curva corrente è chiusa
+ if ( vCompoParts[i]->IsClosed()) {
+ if ( IsNull( pCrvA) || IsNull( pCrvB))
+ return false ;
+ double dLenA = 0. ; pCrvA->GetLength( dLenA) ;
+ double dLenB = 0. ; pCrvB->GetLength( dLenB) ;
+ if ( dLenA > dLenB)
+ vCompoParts[i].Set( ConvertCurveToComposite( Release( pCrvA))) ;
+ else
+ vCompoParts[i].Set( ConvertCurveToComposite( Release( pCrvB))) ;
+ }
+ // Se la curva è aperta
+ else {
+ double dUDomS = 0., dUDomE = 0. ;
+ vCompoParts[i]->GetDomain( dUDomS, dUDomE) ;
+ PtrOwner pCompoTmp( CloneCurveComposite( vCompoParts[i])) ;
+ if ( IsNull( pCompoTmp) || ! pCompoTmp->IsValid())
+ return false ;
+ if ( IsNull( pCrvA)) {
+ pCompoTmp->TrimStartAtParam( dUS) ;
+ vCompoParts.emplace_back( Release( pCompoTmp)) ;
+ vCompoParts[i]->TrimEndAtParam( dUE) ;
+ }
+ else if ( IsNull( pCrvB)) {
+ pCompoTmp->TrimStartAtParam( dUE) ;
+ vCompoParts.emplace_back( Release( pCompoTmp)) ;
+ vCompoParts[i]->TrimEndAtParam( dUS) ;
+ }
+ }
+ }
+ }
+ // Memorizzo tutte le curve valide ottenute dai punti di rottura
+ for ( int i = 0 ; i < int( vCompoParts.size()) ; ++ i) {
+ if ( ! IsNull( vCompoParts[i]) && vCompoParts[i]->IsValid())
+ vCrvResult.emplace_back( Release( vCompoParts[i])) ;
+ }
+ }
+
+ swap( vCrvResult, vCompoChained) ;
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+static bool
+BreakCompoPathces( ICRVCOMPOPOVECTOR& vCompoChained, double dLinTol, double dAngTol)
+{
+ // Se non ho curve, non faccio nulla
+ if ( vCompoChained.empty())
+ return true ;
+ const double ANG_SPLIT = 65. ;
+
+ // Scorro le curve
+ ICRVCOMPOPOVECTOR vCrvResult ;
+ for ( const ICurveComposite* pCompoChained : vCompoChained) {
+ // Verifico la sua validità
+ if ( pCompoChained == nullptr || ! pCompoChained->IsValid())
+ return false ;
+ // Recupero la PolyLine associata ( senza alcuna approssimazione)
+ PolyLine myPL ;
+ if ( ! pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, myPL))
+ return false ;
+ // Approssimo la curva mediante Set di punti considerando la tolleranza angolare
+ POLYLINEVECTOR vPL ;
+ if ( ! GetPointSetByAngTol( myPL, ANG_SPLIT, vPL))
+ return false ;
+ // Se meno di 4 PolyLine non faccio nulla
+ if ( int( vPL.size()) < 4) {
+ LOG_INFO( GetEGkLogger(), "Warning in Trimming : Not Detected 2 Curves") ;
+ return true ;
+ }
+ // Scorro le PolyLine e ricavo le due più corte
+ INTDBLVECTOR vIndPLLen ; vIndPLLen.reserve( vPL.size()) ;
+ for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
+ double dLen ; vPL[i].GetLength( dLen) ;
+ vIndPLLen.emplace_back( make_pair( i, dLen)) ;
+ }
+ sort( vIndPLLen.begin(), vIndPLLen.end(), []( const INTDBL& IndA, const INTDBL& IndB){
+ return ( IndA.second < IndB.second) ;
+ }) ;
+ BIPNTVECTOR vBiPntSplit ; vBiPntSplit.reserve( 2) ;
+ for ( int i = 0 ; i < 2 ; ++ i) {
+ Point3d ptS ; vPL[vIndPLLen[i].first].GetFirstPoint( ptS) ;
+ Point3d ptE ; vPL[vIndPLLen[i].first].GetLastPoint( ptE) ;
+ vBiPntSplit.emplace_back( make_pair( ptS, ptE)) ;
+ }
+
+ #if DEBUG_BRK
+ VT.emplace_back( pCompoChained->Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ for ( PolyLine& _PL : vPL) {
+ IGeoPoint3d* _ptS = CreateGeoPoint3d() ;
+ Point3d _ptStart ; _PL.GetFirstPoint( _ptStart) ; _ptS->Set( _ptStart) ;
+ VT.emplace_back( _ptS) ;
+ VC.emplace_back( YELLOW) ;
+ IGeoPoint3d* _ptE = CreateGeoPoint3d() ;
+ Point3d _ptEnd ; _PL.GetLastPoint( _ptEnd) ; _ptE->Set( _ptEnd) ;
+ VT.emplace_back( _ptE) ;
+ VC.emplace_back( YELLOW) ;
+ }
+ for ( BIPOINT& BiPt : vBiPntSplit) {
+ ICurveLine* pLine = CreateCurveLine() ;
+ pLine->Set( BiPt.first, BiPt.second) ;
+ VT.emplace_back( pLine) ;
+ VC.emplace_back( FUCHSIA) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\SplitRawEdges.nge") ;
+ #endif
+
+ if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained)))
+ return false ;
+ double dU0 = 0., dU1 = 0. ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].second, dU0) ;
+ vCrvResult.back()->ChangeStartPoint( dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].first, dU1) ;
+ vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( 0., dU1))) ;
+ if ( ! vCrvResult.emplace_back( CloneCurveComposite( pCompoChained)))
+ return false ;
+ vCrvResult.back()->ChangeStartPoint( dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[1].second, dU0) ;
+ vCrvResult.back()->GetParamAtPoint( vBiPntSplit[0].first, dU1) ;
+ vCrvResult.back().Set( ConvertCurveToComposite( vCrvResult.back()->CopyParamRange( dU0, dU1))) ;
+ }
+
+ swap( vCrvResult, vCompoChained) ;
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+//---------------------------- Estrazione dei Bordi ---------------------------
+//-----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// Funzione che restituisce l'insieme dei Bordi di una Superficie ( TriMesh o Bezier)
+static bool
+InsertLoopsOfSurf( const ISurf* pSurf, POLYLINEVECTOR& vPL)
+{
+ // Se superficie TriMesh
+ if ( pSurf->GetType() == SRF_TRIMESH) {
+ // Recupero la superficie, verificandone la validità
+ const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ;
+ if ( pStm == nullptr || ! pStm->IsValid())
+ return false ;
+ // verifico che tutte le parti siano valide
+ // ( nel recupero dei Loop alcune superfici presentano delle Part non valide)
+ double dPartArea = 0. ;
+ bool bValidParts = true ;
+ BOOLVECTOR vValidParts ; vValidParts.reserve( pStm->GetPartCount()) ;
+ for ( int nP = 0 ; nP < pStm->GetPartCount() ; ++ nP) {
+ vValidParts.emplace_back( pStm->GetPartArea( nP, dPartArea) && dPartArea > SQ_EPS_SMALL) ;
+ bValidParts = bValidParts && ( vValidParts.back()) ;
+ }
+ // Recupero le PolyLine di bordo
+ if ( bValidParts) {
+ if ( ! pStm->GetLoops( vPL))
+ return false ;
+ }
+ else {
+ for ( int nP = 0 ; nP < pStm->GetPartCount() ; ++ nP) {
+ if ( vValidParts[nP]) {
+ POLYLINEVECTOR vPLPart ;
+ if ( ! pStm->GetPartLoops( nP, vPLPart))
+ return false ;
+ for ( const PolyLine& PL : vPLPart)
+ vPL.emplace_back( PL) ;
+ }
+ }
+ }
+ }
+
+ // Se superficie di Bezier
+ else if ( pSurf->GetType() == SRF_BEZIER) {
+ // Recupero la superficie, verificandone la validità
+ const ISurfBezier* pSbz = GetSurfBezier( pSurf) ;
+ if ( pSbz == nullptr || ! pSbz->IsValid())
+ return false ;
+ // Recupero i Bordi ( questa funzione restituisce dei tratti lineari)
+ ICRVCOMPOPOVECTOR vLoops ;
+ if ( ! pSbz->GetLoops( vLoops, true))
+ return false ;
+ // Li inserisco nel vettore ( come insieme di tratti lineari)
+ // NB. Tengo le tolleranze molto basse per ottenere dei loop rappresentativi della geometria
+ for ( int nL = 0 ; nL < int( vLoops.size()) ; ++ nL) {
+ if ( ! IsNull( vLoops[nL]) && vLoops[nL]->IsValid()) {
+ vPL.emplace_back( PolyLine()) ;
+ if ( ! vLoops[nL]->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, vPL.back()))
+ return false ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per ottenere il bordo di una superficie TriMesh definito da un insieme di facce
+static bool
+GetSurfTmBordersByFaces( const SurfTriMesh* pStm, const INTVECTOR& vFaces,
+ double dLinTol, POLYLINEVECTOR& vPL)
+{
+ // Controllo che la superficie sia valida
+ if ( pStm == nullptr || ! pStm->IsValid())
+ return false ;
+
+ // Inserisco il primo triangolo valido di ogni faccia
+ INTVECTOR vTria ;
+ for ( const int& nF : vFaces) {
+ int nT = SVT_NULL ;
+ if ( pStm->GetTriaFromFace( nF, nT))
+ vTria.emplace_back( nT) ;
+ }
+
+ // Definisco un vettore di concatenamento delle curve ( in questo caso segmenti, lati di triangoli)
+ ICRVCOMPOPOVECTOR vCompoChain ; vCompoChain.reserve( 3 * pStm->GetTriangleCount()) ;
+
+ // Collezione di triangoli già visitati
+ unordered_set SetTria ; SetTria.reserve( pStm->GetTriangleCount()) ;
+ // Collezione di Edges come coppia di punti
+ BIPNTVECTOR vEdges ; vEdges.reserve( 3 * pStm->GetTriangleCount()) ;
+
+ // Finchè ho triangoli di adiacenza non ancora visitati
+ while ( ! vTria.empty()) {
+ // Recupero il triangolo corrente
+ int nCurrTria = vTria.back() ;
+ // Elimino il triangolo corrente
+ vTria.pop_back() ;
+ // Se triangolo non presente, lo aggiungo come visitato
+ auto IterTria = SetTria.find( nCurrTria) ;
+ if ( IterTria == SetTria.end())
+ SetTria.insert( nCurrTria) ;
+ // Se triangolo già visitato, passo al successivo
+ else
+ continue ;
+
+ // Recupero il triangolo corrente ( definito dai suoi 3 vertici )
+ int nTriaVertices[3] ;
+ pStm->GetTriangle( nCurrTria, nTriaVertices) ;
+
+ // Recupero i tre triangoli adiacenti al triangolo corrente
+ int nIdAdjTriaId[3] ;
+ if ( ! pStm->GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId))
+ return false ;
+ // Scorro le adiacenze
+ for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) {
+ // Recupero l'indice del triangolo adiacente
+ int nTriaAdj = nIdAdjTriaId[nAdj] ;
+ // Inserisco il lato orientato del triangolo se :
+ // - Non ho adiacenze
+ // - L'adiacenza avviene su una faccia da non considerare
+ bool bInsertEdge = false ;
+ if ( nTriaAdj == SVT_NULL)
+ bInsertEdge = true ;
+ else {
+ // Recupero la faccia del triangolo adiacente
+ int nFaceAdj = pStm->GetFacetFromTria( nTriaAdj) ;
+ // Se appartiene ad una faccia da inserire
+ if ( find( vFaces.begin(), vFaces.end(), nFaceAdj) != vFaces.end())
+ vTria.push_back( nTriaAdj) ;
+ // Se appartiene ad una faccia da non considerare, memorizzo il suo Edge orientato
+ else
+ bInsertEdge = true ;
+ }
+
+ // Se richiesto, memorizzo l'Edge
+ if ( bInsertEdge) {
+ Point3d ptS ; pStm->GetVertex( nTriaVertices[nAdj % 3], ptS) ;
+ Point3d ptE ; pStm->GetVertex( nTriaVertices[( nAdj + 1) % 3], ptE) ;
+ if ( vCompoChain.emplace_back( CreateCurveComposite())) {
+ vCompoChain.back()->AddPoint( ptS) ;
+ vCompoChain.back()->AddLine( ptE) ;
+ }
+ }
+ }
+ }
+
+ // Recupero i tratti di PolyLine dei triangoli
+ ICRVCOMPOPOVECTOR vCompoChained ;
+ if ( ! ChainCompoPatches( vCompoChain, dLinTol, vCompoChained))
+ return false ;
+ for ( const ICurveComposite* pCompoChained : vCompoChain) {
+ if ( pCompoChained != nullptr && pCompoChained->IsValid()) {
+ vPL.emplace_back( PolyLine()) ;
+ pCompoChained->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, vPL.back()) ;
+ }
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per il calcolo dei bordi delle superfici
+static bool
+GetSurfBorders( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace, double dLinTol,
+ POLYLINEVECTOR& vPLBorders)
+{
+ // Verifico che tutte le superfici siano valide e ben definite
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf == nullptr || ! pSurf->IsValid())
+ return false ;
+ }
+ vPLBorders.clear() ;
+
+ // Definisco l'insieme delle PolyLine ricavate dai bordi
+ // NB. I bordi possono derivare da :
+ // - Loop di una Bezier
+ // - Loop di una Superficie TriMesh
+ // - Insieme di facce di una supericie TriMesh
+ // Scorro il vettore delle superfici
+ for ( int nS = 0 ; nS < int( vSurf.size()) ; ++ nS) {
+ // Recupero la superficie
+ const ISurf* pSurf = vSurf[nS] ;
+ if ( pSurf == nullptr)
+ return false ;
+ // Recupero le facce associate a quella superficie dal vettore di selezione
+ INTVECTOR vFaces ;
+ for ( const SelData& SurfFace : vSurfFace) {
+ if ( SurfFace.nId == nS &&
+ find( vFaces.begin(), vFaces.end(), SurfFace.nSub) == vFaces.end())
+ vFaces.push_back( SurfFace.nSub) ;
+ }
+ // Recupero la dimensione del vettore delle PolyLine risultati attuale
+ int nSize = int( vPLBorders.size()) ;
+ // Se non ho nessuna faccia e nessun triangolo da scartare, estraggo i bordi complessivi della superficie
+ if ( int( vFaces.size()) == 1 && vFaces[0] == SEL_SUB_ALL) {
+ if ( ! InsertLoopsOfSurf( pSurf, vPLBorders))
+ return false ;
+ }
+ // Se ho più facce da inserire
+ else {
+ // Se TriMesh
+ if ( pSurf->GetType() == SRF_TRIMESH) {
+ // Recupero la regione TriMesh di base
+ const SurfTriMesh* pStm = GetBasicSurfTriMesh( pSurf) ;
+ if ( pStm == nullptr)
+ return false ;
+ // Aggiungo i tratti di curva necessari
+ if ( ! GetSurfTmBordersByFaces( pStm, vFaces, dLinTol, vPLBorders))
+ return false ;
+ }
+ // Se Bezier, errore, non ho facce per la superficie
+ if ( pSurf->GetType() == SRF_BEZIER)
+ return false ;
+ }
+ // Associo alle nuove PolyLine ricavate l'indice della superficie corrispondente
+ for ( int i = nSize ; i < int( vPLBorders.size()) ; ++ i)
+ vPLBorders[i].SetTempProp( nS, 0) ;
+ }
+
+ #if DEBUG_BASIC_BORDERS // Debug per Bordi
+ VT.clear() ; VC.clear() ;
+ for ( const PolyLine& _PL : vPLBorders) {
+ ICurveComposite* _pCrv = CreateCurveComposite() ;
+ _pCrv->FromPolyLine( _PL) ;
+ VT.emplace_back( _pCrv->Clone()) ;
+ VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\BasicBorders.nge") ;
+ #endif
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// ---------------------------------- Analisi Adiacenze -----------------------
+// ----------------------------------------------------------------------------
+static bool
+ClassifyTriangles( const SurfTriMesh& Stm, const INTVECTOR& vTBox, int nFirstTria, double dAngTol,
+ unordered_set& setAvoidTria, unordered_set& setNewTria)
+{
+ // Collezione di triangoli già visitati
+ unordered_set setTria ; setTria.reserve( vTBox.size()) ;
+ // Collezioni di triangoli da analizzare
+ INTVECTOR vTria ; vTria.reserve( int( vTBox.size()) + 1) ;
+ vTria.push_back( nFirstTria) ;
+
+ // Finchè ho triangoli da visitare
+ while ( ! vTria.empty()) {
+ // Recupero il triangolo corrente
+ int nCurrTria = vTria.back() ;
+ // Elimino il triangolo corente
+ vTria.pop_back() ;
+
+ // Se triangolo da evitare, passo al successivo
+ if ( setAvoidTria.find( nCurrTria) != setAvoidTria.end())
+ continue ;
+
+ // Se triangolo mai visitato lo aggiungo tra quelli visitati, altrimenti passo al successivo
+ if ( setTria.find( nCurrTria) != setTria.end())
+ continue ;
+ setTria.insert( nCurrTria) ;
+
+ // Inserisco il triangolo corrente
+ setNewTria.insert( nCurrTria) ;
+
+ // Recupero il triangolo corrente e le sue adiacenze
+ int nTriaVertices[3] ;
+ if ( ! Stm.GetTriangle( nCurrTria, nTriaVertices))
+ return false ;
+ Triangle3d Tria ;
+ if ( ! Stm.GetTriangle( nCurrTria, Tria))
+ return false ;
+ int nIdAdjTriaId[3] ;
+ if ( ! Stm.GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId))
+ return false ;
+
+ // Scorro le adiacenze
+ for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) {
+ // Recupero l'indice del triangolo corrente
+ int nTriaAdj = nIdAdjTriaId[nAdj] ;
+ // Se non ho adiacenza, non faccio nulla
+ if ( nTriaAdj == SVT_NULL)
+ continue ;
+ // Recupero il triangolo adiacente
+ Triangle3d TriaAdj ;
+ if ( ! Stm.GetTriangle( nTriaAdj, TriaAdj))
+ return false ;
+ // Se l'adiacenza non è interna al Box corrente, il triangolo rimane visitato
+ if ( find( vTBox.begin(), vTBox.end(), nTriaAdj) == vTBox.end())
+ setTria.insert( nTriaAdj) ;
+ // Se la normale è fuori dalla tolleranza
+ if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dAngTol + EPS_ANG_SMALL) * DEGTORAD)) {
+ // Se tale non è già stato scartato
+ if ( find( setAvoidTria.begin(), setAvoidTria.end(), nTriaAdj) == setAvoidTria.end()) {
+ // Azzero i triangoli correnti e ricomincio l'algoritmo
+ setAvoidTria.insert( nTriaAdj) ;
+ vTria.clear() ;
+ vTria.push_back( nFirstTria) ;
+ setTria.clear() ;
+ break ;
+ }
+ continue ;
+ }
+ // Inserisco il triangolo per la ricerca futura
+ vTria.push_back( nTriaAdj) ;
+ }
+ }
+
+ #if DEBUG_FACE_SEARCH
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) {
+ VT.emplace_back( Stm.CloneTriangle( *Iter)) ;
+ VC.emplace_back( GREEN) ;
+ }
+ for ( auto Iter = setAvoidTria.begin() ; Iter != setAvoidTria.end() ; ++ Iter) {
+ VT.emplace_back( Stm.CloneTriangle( *Iter)) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ //SaveGeoObj( VT, VC, "C:\\Temp\\2.nge") ;
+ #endif
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per il recupero delle curve concatenate di bordo dai triangoli classificati
+static bool
+GetBordersByTriaInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, double dLinTol,
+ const unordered_set& setNewTria, COMPOVECTOR& vCompoChain,
+ bool& bAmbiguous)
+{
+ // I bordi Locali sono definiti dall'insieme degli Edges dei triangoli trovati come validi
+ BIPNTVECTOR vBiPnts ;
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) {
+ int nIdVert[3] ;
+ if ( ! Stm.GetTriangle( *Iter, nIdVert))
+ return false ;
+ int nIdAdjTriaId[3] ;
+ if ( ! Stm.GetTriangleAdjacencies( *Iter, nIdAdjTriaId))
+ return false ;
+ for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) {
+ int nTriaAdj = nIdAdjTriaId[nAdj] ;
+ if ( nTriaAdj == SVT_NULL ||
+ find( setNewTria.begin(), setNewTria.end(), nTriaAdj) == setNewTria.end()) {
+ vBiPnts.emplace_back( BIPOINT()) ;
+ if ( ! Stm.GetVertex( nIdVert[nAdj], vBiPnts.back().first) ||
+ ! Stm.GetVertex( nIdVert[( nAdj + 1) % 3], vBiPnts.back().second))
+ return false ;
+ }
+ }
+ }
+
+ // Per ogni Edge ricavato, conservo solo le parti interne al Box corrente
+ INTVECTOR vEdgeToSave ; vEdgeToSave.reserve( vBiPnts.size()) ;
+ for ( int nEdge = 0 ; nEdge < int( vBiPnts.size()) ; ++ nEdge) {
+ Point3d& ptL1 = vBiPnts[nEdge].first ;
+ Point3d& ptL2 = vBiPnts[nEdge].second ;
+ Vector3d vtDir = ptL2 - ptL1 ;
+ vtDir.Normalize() ;
+ INTDBLVECTOR vInters ;
+ if ( IntersLineBox( ptL1, ptL2, BBoxCurr, vInters, true)) {
+ if ( int( vInters.size()) == 2) {
+ vEdgeToSave.push_back( nEdge) ;
+ // Se edge sul bordo, lo spezzo
+ if ( vInters[1].first == ILBT_OUT)
+ ptL2 = ptL1 + ( vtDir * vInters[1].second) ;
+ if ( vInters[0].first == ILBT_IN)
+ ptL1 = ptL1 + ( vtDir * vInters[0].second) ;
+ }
+ }
+ }
+ unordered_set setBiPntsToSave( vEdgeToSave.begin(), vEdgeToSave.end()) ;
+ int nCurr = 0 ;
+ for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) {
+ if ( setBiPntsToSave.count( i))
+ vBiPnts[nCurr ++] = vBiPnts[i] ;
+ }
+ vBiPnts.resize( nCurr) ;
+
+ #if DEBUG_FACE_SEARCH
+ for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) {
+ ICurveLine* pLine = CreateCurveLine() ;
+ pLine->Set( vBiPnts[i].first, vBiPnts[i].second) ;
+ VT.emplace_back( pLine) ;
+ VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ;
+ }
+ // SaveGeoObj( VT, VC, "C:\\Temp\\3.nge") ;
+ #endif
+
+ // Concateno i Segmenti interni al Box corrente
+ BOOLVECTOR vIndInChain ; vIndInChain.resize( vBiPnts.size(), false) ;
+ vCompoChain.reserve( vBiPnts.size()) ;
+ for ( int i = 0 ; i < int( vBiPnts.size()) ; ++ i) {
+ // Se già in Chain, passo al successivo
+ if ( vIndInChain[i])
+ continue ;
+ vIndInChain[i] = true ;
+ // Recupero gli estremi correnti
+ Point3d ptCurrStart = vBiPnts[i].first ;
+ Point3d ptCurrEnd = vBiPnts[i].second ;
+ // Definisco la nuova curve composita di concatenamento
+ vCompoChain.emplace_back( CurveComposite()) ;
+ vCompoChain.back().AddPoint( ptCurrStart) ;
+ vCompoChain.back().AddLine( ptCurrEnd) ;
+ // Punti di controllo per Biforcazioni
+ PNTVECTOR vPtForks ; vPtForks.reserve( vBiPnts.size()) ;
+ for ( int j = 0 ; j < int( vBiPnts.size()) ; ++ j) {
+ // Controllo un altro Edge non in Chain, recuperando i suoi estremi
+ if ( i == j || vIndInChain[j])
+ continue ;
+ Point3d& ptOtherStart = vBiPnts[j].first ;
+ Point3d& ptOtherEnd = vBiPnts[j].second ;
+ // Se concatenamento ammissibile
+ if ( AreSamePointEpsilon( ptCurrEnd, ptOtherStart, dLinTol)) {
+ // Se su un punto di Biforcazione, sono in un caso ambiguo
+ for ( const Point3d& ptFork : vPtForks) {
+ if ( AreSamePointApprox( ptFork, ptCurrEnd)) {
+ bAmbiguous = true ;
+ return true ;
+ }
+ }
+ vPtForks.emplace_back( ptCurrEnd) ;
+ // Altrimenti aggiorno i parametri di ricerca
+ vCompoChain.back().AddLine( ptOtherEnd) ;
+ ptCurrEnd = ptOtherEnd ;
+ vIndInChain[j] = true ;
+ j = 0 ;
+ }
+ else if ( AreSamePointEpsilon( ptCurrEnd, ptOtherEnd, dLinTol)) {
+ // Se su un punto di Biforcazione, sono in un caso ambiguo
+ for ( const Point3d& ptFork : vPtForks) {
+ if ( AreSamePointApprox( ptFork, ptCurrEnd)) {
+ bAmbiguous = true ;
+ return true ;
+ }
+ }
+ vPtForks.emplace_back( ptCurrEnd) ;
+ // Altrimenti aggiorno i parametri di ricerca
+ vCompoChain.back().AddLine( ptOtherStart) ;
+ ptCurrEnd = ptOtherStart ;
+ vIndInChain[j] = true ;
+ j = 0 ;
+ }
+ else if ( AreSamePointEpsilon( ptCurrStart, ptOtherEnd, dLinTol)) {
+ // Se su un punto di Biforcazione, sono in un caso ambiguo
+ for ( const Point3d& ptFork : vPtForks) {
+ if ( AreSamePointApprox( ptFork, ptCurrStart)) {
+ bAmbiguous = true ;
+ return true ;
+ }
+ }
+ vPtForks.emplace_back( ptCurrStart) ;
+ // Altrimenti aggiorno i parametri di ricerca
+ vCompoChain.back().AddLine( ptOtherStart, false) ;
+ ptCurrStart = ptOtherStart ;
+ vIndInChain[j] = true ;
+ j = 0 ;
+ }
+ else if ( AreSamePointEpsilon( ptCurrStart, ptOtherStart, dLinTol)) {
+ // Se su un punto di Biforcazione, sono in un caso ambiguo
+ for ( const Point3d& ptFork : vPtForks) {
+ if ( AreSamePointApprox( ptFork, ptCurrStart)) {
+ bAmbiguous = true ;
+ return true ;
+ }
+ }
+ vPtForks.emplace_back( ptCurrStart) ;
+ // Altrimenti aggiorno i parametri di ricerca
+ vCompoChain.back().AddLine( ptOtherEnd, false) ;
+ ptCurrStart = ptOtherEnd ;
+ vIndInChain[j] = true ;
+ j = 0 ;
+ }
+ }
+ }
+
+ #if DEBUG_FACE_SEARCH
+ for ( int i = 0 ; i < int( vCompoChain.size()) ; ++ i) {
+ VT.emplace_back( vCompoChain[i].Clone()) ;
+ VC.emplace_back( FUCHSIA) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\4.nge") ;
+ #endif
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per il calcolo dei punti medi tra due curve di Bordo
+static bool
+CalcMidPointForBorders( const CurveComposite& CompoA, const CurveComposite& CompoB,
+ const SurfTriMesh& Stm, const unordered_set& setNewTria,
+ Point3d& ptMid, Point3d& ptMid1, int& nTria, int& nTria1)
+{
+ // Se entrambe le curve non sono valide, errore
+ if ( ! CompoA.IsValid() && ! CompoB.IsValid())
+ return false ;
+
+ // Se entrambe le curve sono valide
+ if ( CompoA.IsValid() && CompoB.IsValid()) {
+ // Recupero ptMid1 e ptMid2 e i rispettivi triangoli di ricerca
+ Point3d ptA ; CompoA.GetStartPoint( ptA) ;
+ Point3d ptB ; CompoA.GetEndPoint( ptB) ;
+ Point3d ptC ; CompoB.GetStartPoint( ptC) ;
+ Point3d ptD ; CompoB.GetEndPoint( ptD) ;
+ if ( SqDist( ptA, ptD) < SqDist( ptA, ptC))
+ swap( ptC, ptD) ;
+ ptMid = Media( ptB, ptD) ;
+ ptMid1 = Media( ptA, ptC) ;
+ }
+ // Se una sola valida
+ else {
+ const CurveComposite& CurveX = ( CompoA.IsValid() ? CompoA : CompoB) ;
+ Point3d ptA ; CurveX.GetStartPoint( ptA) ;
+ Point3d ptD ; CurveX.GetEndPoint( ptD) ;
+ ptMid = Media( ptA, ptD) ;
+ ptMid1 = P_INVALID ;
+ nTria1 = SVT_NULL ;
+ }
+ // Recupero il triangolo a distanza minima dai due punti ricavati
+ double dSqDistMin = INFINITO ;
+ double dSqDistMin1 = INFINITO ;
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) {
+ Triangle3d Tria ;
+ if ( ! Stm.GetTriangle( *Iter, Tria))
+ return false ;
+ double dSqDist = 0., dSqDist1 = 0. ;
+ DistPointTriangle( ptMid, Tria).GetSqDist( dSqDist) ;
+ if ( dSqDist < dSqDistMin) {
+ dSqDistMin = dSqDist ;
+ nTria = *Iter ;
+ }
+ if ( ptMid1.IsValid()) {
+ DistPointTriangle( ptMid1, Tria).GetSqDist( dSqDist1) ;
+ if ( dSqDist1 < dSqDistMin1) {
+ dSqDistMin1 = dSqDist1 ;
+ nTria1 = *Iter ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per l'analisi locale delle curve di bordo
+static bool
+CheckCurvesInBox( const SurfTriMesh& Stm, const COMPOVECTOR& vCompoChain, const Point3d& ptSel,
+ const unordered_set& setNewTria, CurveComposite& CompoA,CurveComposite& CompoB,
+ Point3d& ptMid, Point3d& ptMid1, int& nTria, int& nTria1)
+{
+ const double HALF_LEN = .5 ;
+ const double ANG_SPLIT = 50. ;
+
+ // Se non ho curve, errore
+ if ( vCompoChain.empty())
+ return false ;
+
+ #if DEBUG_FACE_SEARCH
+ for ( int _i = 0 ; _i < int( vCompoChain.size()) ; ++ _i) {
+ VT.emplace_back( vCompoChain[_i].Clone()) ;
+ VC.emplace_back( PURPLE) ;
+ }
+ #endif
+
+ // Recupero le due curve di riferimento
+ CurveComposite CompoATmp, CompoBTmp ;
+
+ // Se ho una sola curva, allora i bordi si sono uniti
+ if ( int( vCompoChain.size()) == 1) {
+ // Approssimo la curva in Patches
+ PolyLine PL ;
+ if ( ! vCompoChain[0].ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL))
+ return false ;
+ POLYLINEMATRIX matPL ;
+ if ( ! CalcPatches( { PL}, ANG_SPLIT, matPL) && ! matPL.empty() && ! matPL[0].empty())
+ return false ;
+ CompoATmp.FromPolyLine( matPL[0].front()) ;
+ CompoBTmp.FromPolyLine( matPL[0].back()) ;
+ }
+ // Se due curve di bordo
+ else if ( int( vCompoChain.size()) == 2) {
+ CompoATmp = vCompoChain[0] ;
+ CompoBTmp = vCompoChain[1] ;
+ }
+ // Se più di due, cerco le due curve più vicine
+ else if ( int( vCompoChain.size()) > 2) {
+ INTDBLVECTOR vIndSqDist ; vIndSqDist.reserve( vCompoChain.size()) ;
+ for ( int nCrv = 0 ; nCrv < int( vCompoChain.size()) ; ++ nCrv) {
+ vIndSqDist.emplace_back( make_pair( nCrv, 0.)) ;
+ if ( ! DistPointCurve( ptSel, vCompoChain[nCrv]).GetSqDist( vIndSqDist.back().second))
+ return false ;
+ }
+ sort( vIndSqDist.begin(), vIndSqDist.end(), []( const INTDBL& A, const INTDBL& B) {
+ return ( A.second < B.second) ;
+ }) ;
+ CompoATmp = vCompoChain[vIndSqDist[0].first] ;
+ CompoBTmp = vCompoChain[vIndSqDist[1].first] ;
+ }
+
+ // Entrambe le curve sono chiuse, non devo fare nulla
+ if ( CompoATmp.IsClosed() && CompoBTmp.IsClosed()) {
+ CompoA = CompoATmp ;
+ CompoB = CompoBTmp ;
+ return true ;
+ }
+
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoATmp.Clone()) ;
+ VC.emplace_back( WHITE) ;
+ VT.emplace_back( CompoBTmp.Clone()) ;
+ VC.emplace_back( WHITE) ;
+ #endif
+
+ // Definisco le due curve di riferimento
+ double dUA = 0., dUB = 0. ;
+ int nFlag = 0 ;
+ if ( ! DistPointCurve( ptSel, CompoATmp).GetParamAtMinDistPoint( 0., dUA, nFlag) ||
+ ! DistPointCurve( ptSel, CompoBTmp).GetParamAtMinDistPoint( 0., dUB, nFlag))
+ return false ;
+ // Se le curve sono chiuse devo fare attenzione
+ if ( CompoATmp.IsClosed()) {
+ // Se lunghezza inferiore del doppio della semilunghezza, errore ( curva troppo piccola per essere lavorata)
+ double dLenA ;
+ if ( ! CompoATmp.GetLength( dLenA) || dLenA < 2. * HALF_LEN + EPS_SMALL)
+ return false ;
+ // Cambio il punto inziale della curva
+ CompoATmp.ChangeStartPoint( dUA) ;
+ double dUS, dUE ;
+ if ( ! CompoATmp.GetDomain( dUS, dUE))
+ return false ;
+ CompoATmp.ChangeStartPoint( ( dUS + dUE) / 2.) ;
+ if ( ! DistPointCurve( ptSel, CompoATmp).GetParamAtMinDistPoint( 0., dUA, nFlag))
+ return false ;
+ }
+ if ( CompoBTmp.IsClosed()) {
+ // Se lunghezza inferiore del doppio della semilunghezza, errore ( curva troppo piccola per essere lavorata)
+ double dLenB ;
+ if ( ! CompoBTmp.GetLength( dLenB) || dLenB < 2. * HALF_LEN + EPS_SMALL)
+ return false ;
+ CompoBTmp.ChangeStartPoint( dUB) ;
+ double dUS, dUE ;
+ if ( ! CompoBTmp.GetDomain( dUS, dUE))
+ return false ;
+ CompoBTmp.ChangeStartPoint( ( dUS + dUE) / 2.) ;
+ if ( ! DistPointCurve( ptSel, CompoBTmp).GetParamAtMinDistPoint( 0., dUB, nFlag))
+ return false ;
+ }
+ // Recupero la lunghezza della curva e la lunghezza in tali parametri
+ double dULenA, dULenB, dLenA, dLenB ;
+ if ( ! CompoATmp.GetLengthAtParam( dUA, dULenA) ||
+ ! CompoBTmp.GetLengthAtParam( dUB, dULenB) ||
+ ! CompoATmp.GetLength( dLenA) ||
+ ! CompoBTmp.GetLength( dLenB))
+ return false ;
+ // Recupero i due tratti di curva per l'analisi
+ double dLenMinA = Clamp( dULenA - HALF_LEN, 0., dLenA) ;
+ double dLenMaxA = Clamp( dULenA + HALF_LEN, 0., dLenA) ;
+ double dLenMinB = Clamp( dULenB - HALF_LEN, 0., dLenB) ;
+ double dLenMaxB = Clamp( dULenB + HALF_LEN, 0., dLenB) ;
+ // Recupero i parametri e le curve
+ double dUAS, dUAE, dUBS, dUBE ;
+ if ( ! CompoATmp.GetParamAtLength( dLenMinA, dUAS) ||
+ ! CompoATmp.GetParamAtLength( dLenMaxA, dUAE) ||
+ ! CompoBTmp.GetParamAtLength( dLenMinB, dUBS) ||
+ ! CompoBTmp.GetParamAtLength( dLenMaxB, dUBE))
+ return false ;
+ CompoA.CopyFrom( ConvertCurveToBasicComposite( CompoATmp.CopyParamRange( dUAS, dUAE))) ;
+ CompoB.CopyFrom( ConvertCurveToBasicComposite( CompoBTmp.CopyParamRange( dUBS, dUBE))) ;
+
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoA.Clone()) ;
+ VC.emplace_back( RED) ;
+ VT.emplace_back( CompoB.Clone()) ;
+ VC.emplace_back( RED) ;
+ #endif
+
+ // Recupero ptMid1 e ptMid2 e i rispettivi triangoli di ricerca
+ if ( ! CalcMidPointForBorders( CompoA, CompoB, Stm, setNewTria, ptMid, ptMid1, nTria, nTria1))
+ return false ;
+
+ #if DEBUG_FACE_SEARCH
+ IGeoPoint3d* _ptMid = CreateGeoPoint3d() ; _ptMid->Set( ptMid) ;
+ VT.emplace_back( _ptMid) ;
+ VC.emplace_back( AQUA) ;
+ if ( ptMid1.IsValid()) {
+ IGeoPoint3d* _ptMid1 = CreateGeoPoint3d() ; _ptMid1->Set( ptMid1) ;
+ VT.emplace_back( _ptMid1) ;
+ VC.emplace_back( AQUA) ;
+ }
+ VT.emplace_back( Stm.CloneTriangle( nTria)) ;
+ VC.emplace_back( LIME) ;
+ if ( nTria1 != SVT_NULL) {
+ VT.emplace_back( Stm.CloneTriangle( nTria1)) ;
+ VC.emplace_back( LIME) ;
+ }
+ //SaveGeoObj( VT, VC, "C:\\Temp\\5.nge") ;
+ #endif
+
+ // I punti, le curve e i triangoli ricavati, devono essere validi
+ return ( CompoA.IsValid() && CompoB.IsValid() && ptMid.IsValid() && ptMid1.IsValid() &&
+ nTria != SVT_NULL && nTria1 != SVT_NULL) ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per aggiornare il Bordo mediante adiacenze di triangoli
+static bool
+UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& vCompoChain,
+ bool& bUpdate)
+{
+ bUpdate = false ;
+ // Se Curva corrente non valida, non devo aggiornare nulla
+ if ( ! Compo.IsValid())
+ return true ;
+ // Se le Compo di concatenazione non sono valide, errore
+ for ( const CurveComposite& CompoChain : vCompoChain) {
+ if ( ! CompoChain.IsValid())
+ return false ;
+ }
+
+ // Recupero gli estremi della curva corrente
+ Point3d ptStart ; Compo.GetStartPoint( ptStart) ;
+ Point3d ptEnd ; Compo.GetEndPoint( ptEnd) ;
+
+ #if DEBUG_FACE_SEARCH
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( Compo.Clone()) ;
+ VC.emplace_back( RED) ;
+ for ( const CurveComposite& CompoChain : vCompoChain) {
+ VT.emplace_back( CompoChain.Clone()) ;
+ VC.emplace_back( AQUA) ;
+ }
+ #endif
+
+ // Scorro le curve di concatenazione
+ bool bUpdateStart = false ;
+ bool bUpdateEnd = false ;
+ for ( const CurveComposite& CompoChain : vCompoChain) {
+ // Verifico gli estremi della curva corrente
+ bool bMyUpdateStart = ( CompoChain.IsPointOn( ptStart, dLinTol)) ;
+ bool bMyUpdateEnd = ( CompoChain.IsPointOn( ptEnd, dLinTol)) ;
+ if ( bMyUpdateStart || bMyUpdateEnd) {
+ // Recupero il dominio della curva di concatenzione
+ double dUS = 0., dUE = 0. ;
+ if ( ! CompoChain.GetDomain( dUS, dUE))
+ return false ;
+ // Recupero gli Estremi della curva di concatenazione
+ Point3d ptS ; CompoChain.GetStartPoint( ptS) ;
+ Point3d ptE ; CompoChain.GetEndPoint( ptE) ;
+ // Se solo tratto antecedente valido
+ if ( bMyUpdateStart && ! bMyUpdateEnd) {
+ double dUBreak = 0. ;
+ if ( ! CompoChain.GetParamAtPoint( ptStart, dUBreak, dLinTol))
+ return false ;
+ CurveComposite CompoPrev ;
+ if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) {
+ CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ;
+ CompoPrev.Invert() ;
+ }
+ else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS))
+ CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ;
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoPrev.Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif
+ bUpdateStart = ( Compo.AddCurve( CompoPrev, false, dLinTol)) ;
+ }
+ // Se solo tratto successivo valido
+ else if ( ! bMyUpdateStart && bMyUpdateEnd) {
+ double dUBreak = 0. ;
+ if ( ! CompoChain.GetParamAtPoint( ptEnd, dUBreak, dLinTol))
+ return false ;
+ CurveComposite CompoAft ;
+ if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE))
+ CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ;
+ else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) {
+ CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ;
+ CompoAft.Invert() ;
+ }
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoAft.Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif
+ bUpdateEnd = Compo.AddCurve( CompoAft, true, dLinTol) ;
+ }
+ // Se entrambi i tratti sono validi
+ else {
+ double dUBreak = 0., dUBreak1 = 0. ;
+ if ( ! CompoChain.GetParamAtPoint( ptStart, dUBreak, dLinTol) ||
+ ! CompoChain.GetParamAtPoint( ptEnd, dUBreak1, dLinTol))
+ return false ;
+ if ( ! Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) {
+ CurveComposite CompoPrev ;
+ CurveComposite CompoAft ;
+ if ( dUBreak < dUBreak1) {
+ CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ;
+ CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUE))) ;
+ }
+ else {
+ CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ;
+ CompoPrev.Invert() ;
+ CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak1))) ;
+ CompoAft.Invert() ;
+ }
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoPrev.Clone()) ;
+ VC.emplace_back( LIME) ;
+ VT.emplace_back( CompoAft.Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif
+ bUpdateStart = ( Compo.AddCurve( CompoPrev, false, dLinTol)) ;
+ bUpdateEnd = ( Compo.AddCurve( CompoAft, true, dLinTol)) ;
+ }
+ else if ( Compo.IsPointOn( ptS) && Compo.IsPointOn( ptE)) {
+ CurveComposite CompoSingle ;
+ if ( dUBreak < dUBreak1) {
+ CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUBreak1))) ;
+ CompoSingle.Invert() ;
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoSingle.Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif // false
+ if ( Compo.AddCurve( CompoSingle, true, dLinTol)) {
+ bUpdateStart = true ;
+ bUpdateEnd = true ;
+ }
+ }
+ else {
+ CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUBreak))) ;
+ #if DEBUG_FACE_SEARCH
+ VT.emplace_back( CompoSingle.Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif // false
+ if ( Compo.AddCurve( CompoSingle, true, dLinTol)) {
+ bUpdateStart = true ;
+ bUpdateEnd = true ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ #if DEBUG_FACE_SEARCH
+ //SaveGeoObj( VT, VC, "C:\\Temp\\6.nge") ;
+ #endif
+ bUpdate = ( bUpdateStart || bUpdateEnd) ;
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per controllare le curve di Bordo all'interno del Box
+static bool
+CheckBordersInBox( CurveComposite& CompoA, CurveComposite& CompoB,
+ const SurfTriMesh& Stm, const unordered_set& setAvoidTria,
+ double dAngTol, double dLinTol, double dSize, double dSizeTol, bool& bBreak)
+{
+ bBreak = false ;
+ // Verifico la validità delle Curve
+ bool bValidA = ( CompoA.IsValid()) ;
+ bool bValidB = ( CompoB.IsValid()) ;
+
+ // Se nessuna curva valida, errore
+ if ( ! bValidA && ! bValidB)
+ return false ;
+
+ // Recupero i due tratti di curva in analisi e le loro proprietà
+ CurveComposite myCompoA, myCompoB ;
+ // NB. la parametrizzazione deve avvenire per lunghezza, non per parametro
+ double dLenA = 0., dLenB = 0. ;
+ double dLenStartA = 0., dLenStartB = 0., dLenEndA = 0., dLenEndB = 0. ;
+
+ // Se entrambe le curve sono valide
+ if ( bValidA && bValidB) {
+ myCompoA = CompoA ;
+ myCompoB = CompoB ;
+ // Recupero la lunghezza delle due curve
+ if ( ! myCompoA.GetLength( dLenA) || ! myCompoB.GetLength( dLenB))
+ return false ;
+ // Recupero la lunghezza di Analisi scorrendo le curve :
+ // - per CompoA devo indietreggiare
+ // - per CompoB devo avanzare
+ dLenStartA = Clamp( dLenA - dSize - dSizeTol, 0., dLenA) ;
+ dLenEndB = Clamp( dSize + dSizeTol, 0., dLenB) ;
+ // Se curve troppo corte non le analizzo
+ if ( dLenA - dLenStartA < dSizeTol || dLenEndB < dSizeTol)
+ return true ;
+ dLenEndA = dLenA ;
+ dLenStartB = 0. ;
+ }
+ // Se una delle due valida
+ else {
+ // Recupero la myCompoA come estremo finale e myCompoB come estremo iniziale
+ const CurveComposite& CompoX = ( CompoA.IsValid() ? CompoA : CompoB) ;
+ double dLen ;
+ if ( ! CompoX.GetLength( dLen))
+ return false ;
+ if ( dLen < 2. * ( dSize + dSizeTol) + 5. * EPS_SMALL)
+ return true ;
+ double dUS, dUE, dUStartA, dUEndB ;
+ if ( ! CompoX.GetDomain( dUS, dUE) ||
+ ! CompoX.GetParamAtLength( dLen - dSize - dSizeTol - 2. * EPS_SMALL, dUStartA) ||
+ ! CompoX.GetParamAtLength( dSize + dSizeTol + 2. * EPS_SMALL, dUEndB))
+ return false ;
+ // Per sicurezza [ migliorabile se stabile]
+ if ( ! myCompoA.CopyFrom( CompoX.CopyParamRange( dUStartA, dUE)) ||
+ ! myCompoB.CopyFrom( CompoX.CopyParamRange( dUS, dUEndB)))
+ return false ;
+ dLenStartA = 0. ;
+ dLenStartB = 0. ;
+ if ( ! myCompoA.GetLength( dLenEndA) || ! myCompoB.GetLength( dLenEndB))
+ return false ;
+ dLenA = dLenEndA ;
+ dLenB = dLenEndB ;
+ }
+
+ #if DEBUG_FACE_SEARCH
+ VT.clear() ; VC.clear() ;
+ // Disegno simbolico
+ if ( CompoA.IsValid()) {
+ VT.emplace_back( CompoA.Clone()) ;
+ VC.emplace_back( AQUA) ;
+ }
+ if ( CompoB.IsValid()) {
+ VT.emplace_back( CompoB.Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ //SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ;
+ #endif
+
+ // Campiono le Curve alla ricerca di restrizioni
+ const int MAX_SAMPLE = 5 ;
+ const int MAX_OUT_SAMPLE = 2 ; // Per ignorare le piccole imperfezioni
+ int nCountOut = 0 ;
+ bool bExpandBox = false ;
+ for ( int i = 0 ; i <= MAX_SAMPLE ; ++ i) {
+ // Recupero i parametri su tale Curva
+ double dLenUA = Clamp( ( dLenStartA + i * ( dLenEndA - dLenStartA) / MAX_SAMPLE), EPS_SMALL, dLenA - EPS_SMALL) ;
+ double dLenUB = Clamp( ( dLenEndB - i * ( dLenEndB - dLenStartB) / MAX_SAMPLE), EPS_SMALL, dLenB - EPS_SMALL) ;
+ // Recupero i punti associati e la loro distanza
+ double dUA, dUB ;
+ if ( ! myCompoA.GetParamAtLength( dLenUA, dUA) || ! myCompoB.GetParamAtLength( dLenUB, dUB))
+ return false ;
+ Point3d ptA, ptB ;
+ if ( ! myCompoA.GetPointD1D2( dUA, ICurve::FROM_MINUS, ptA) ||
+ ! myCompoB.GetPointD1D2( dUB, ICurve::FROM_PLUS, ptB))
+ return false ;
+ if ( SqDist( ptA, ptB) < ( dSize - dSizeTol) * ( dSize - dSizeTol))
+ ++ nCountOut ;
+ else
+ nCountOut = 0 ;
+ #if DEBUG_FACE_SEARCH
+ CurveLine _Line ; _Line.Set( ptA, ptB) ;
+ VT.emplace_back( _Line.Clone()) ;
+ VC.emplace_back( nCountOut == 0 ? LIME : RED) ;
+ #endif
+ if ( nCountOut >= MAX_OUT_SAMPLE) {
+ bExpandBox = true ;
+ break ;
+ }
+ }
+
+ #if DEBUG_FACE_SEARCH
+ //SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ;
+ #endif
+
+ // Se rilevata restrizione
+ if ( bExpandBox) {
+ // Recupero i due tratti lineari in tangenza
+ Vector3d vtA, vtB ;
+ if ( ! myCompoA.GetEndDir( vtA) || ! myCompoB.GetStartDir( vtB))
+ return false ;
+ Point3d ptA, ptB ;
+ if ( ! myCompoA.GetEndPoint( ptA) || ! myCompoB.GetStartPoint( ptB))
+ return false ;
+ // Cerco il punto a minima distanza tra esse ( suppongo che le linee tendano a convergere
+ // verso lo spigolo della striscia in analisi)
+ Point3d ptMinDistA, ptMinDistB ;
+ if ( ! DistLineLine( ptA, vtA, 1., ptB, - vtB, 1., false, false).GetMinDistPoints( ptMinDistA, ptMinDistB))
+ return false ;
+ Point3d ptInt = Media( ptMinDistA, ptMinDistB) ;
+ // Definisco un Box centrato nel punto medio di taglio tra CompoA e CompoB sul Box
+ BBox3d BBoxCheck ;
+ Point3d ptCenter = Media( ptA, ptB) ;
+ BBoxCheck.Add( ptCenter) ; // dSize / cos( 60deg)
+ BBoxCheck.Expand( dSizeTol + min( Dist( ptCenter, ptInt), 2. * dSize)) ;
+
+ #if DEBUG_FACE_SEARCH
+ CurveLine _LineA, _LineB ;
+ _LineA.Set( ptA, ptA + 1e2 * vtA) ;
+ _LineB.Set( ptB, ptB - 1e2 * vtB) ;
+ VT.emplace_back( _LineA.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ VT.emplace_back( _LineB.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ CurveComposite pCompoBox ;
+ pCompoBox.AddPoint( BBoxCheck.GetMin()) ;
+ pCompoBox.AddLine( BBoxCheck.GetMin() + BBoxCheck.GetDimX() * X_AX) ;
+ pCompoBox.AddLine( BBoxCheck.GetMax() - BBoxCheck.GetDimZ() * Z_AX) ;
+ pCompoBox.AddLine( BBoxCheck.GetMin() + BBoxCheck.GetDimY() * Y_AX) ;
+ pCompoBox.Close() ;
+ pCompoBox.SetExtrusion( Z_AX) ;
+ pCompoBox.SetThickness( BBoxCheck.GetDimZ()) ;
+ VT.emplace_back( pCompoBox.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ;
+ #endif
+
+ // Determino le due curve all'interno di questo Box
+ INTVECTOR vTBox ;
+ if ( ! Stm.GetAllTriaOverlapBox( BBoxCheck, vTBox) || vTBox.empty())
+ return false ;
+ double dMinSqDist = INFINITO ;
+ int nTria = 0 ;
+ for ( int nT = 0 ; nT < int( vTBox.size()) ; ++ nT) {
+ Triangle3d Tria ;
+ if ( ! Stm.GetTriangle( vTBox[nT], Tria))
+ return false ;
+ double dSqDist = 0. ;
+ if ( DistPointTriangle( ptCenter, Tria).GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
+ dMinSqDist = dSqDist ;
+ nTria = vTBox[nT] ;
+ }
+ }
+ unordered_set MysetAvoidTria( setAvoidTria) ;
+ unordered_set MysetNewTria ;
+ if ( ! ClassifyTriangles( Stm, vTBox, nTria, dAngTol, MysetAvoidTria, MysetNewTria))
+ return false ;
+ COMPOVECTOR vCompoChain ;
+ if ( ! GetBordersByTriaInBox( Stm, BBoxCheck, dLinTol, MysetNewTria, vCompoChain, bBreak))
+ return false ;
+
+ #if DEBUG_FACE_SEARCH
+ for ( CurveComposite& Compo : vCompoChain) {
+ VT.emplace_back( Compo.Clone()) ;
+ VC.emplace_back( FUCHSIA) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\Divergent.nge") ;
+ #endif
+
+ // Se ottengo una sola curva, allora la striscia si è chiusa
+ if ( int( vCompoChain.size()) <= 1)
+ return true ;
+ // Se ottengo ancora due curve, allora la striscia non rispetta lo spessore minimo
+ bBreak = ( int( vCompoChain.size()) >= 2) ;
+ if ( bBreak) {
+ // Se devo fermare la ricerca e ho ancora CompoA e CompoB valide
+ if ( bValidA && bValidB) {
+ // Collego CompoA con CompoB e pulisco CompoB
+ Point3d ptStartB ;
+ if ( ! CompoB.GetStartPoint( ptStartB))
+ return false ;
+ CompoA.AddLine( ptStartB) ;
+ if ( ! CompoA.AddCurve( CompoB, dLinTol))
+ return false ;
+ CompoB.Clear() ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per analisi locale della superficie all'interno di un Box
+static bool
+GetBordersInBox( const SurfTriMesh& Stm, const BBox3d& BBoxCurr, int nFirstTria, const Point3d& ptSel,
+ double dSize, double dSizeTol, bool bAbsFirst, bool bRelFirst, double dAngTol,
+ double dLinTol, unordered_set& setAvoidTria, unordered_set& setNewTria,
+ CurveComposite& CompoA, CurveComposite& CompoB, Point3d& ptMid, Point3d& ptMid1,
+ int& nTria, int& nTria1, bool& bBreak, bool& bStop)
+{
+ // Controllo dei parametri
+ if ( ! Stm.IsValid())
+ return false ;
+ bBreak = false ;
+ bStop = false ;
+ setNewTria.clear() ;
+
+ // Recupero tutti i Triangoli all'interno del Box
+ INTVECTOR vTBox ;
+ if ( ! Stm.GetAllTriaOverlapBox( BBoxCurr, vTBox) || vTBox.empty()) {
+ // [Non devo mai capitare qui, non ha senso]
+ bStop = true ;
+ return true ;
+ }
+
+ #if DEBUG_FACE_SEARCH
+ VT.clear() ; VC.clear() ;
+ CurveComposite pCompoBox ;
+ pCompoBox.AddPoint( BBoxCurr.GetMin()) ;
+ pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimX() * X_AX) ;
+ pCompoBox.AddLine( BBoxCurr.GetMax() - BBoxCurr.GetDimZ() * Z_AX) ;
+ pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimY() * Y_AX) ;
+ pCompoBox.Close() ;
+ pCompoBox.SetExtrusion( Z_AX) ;
+ pCompoBox.SetThickness( BBoxCurr.GetDimZ()) ;
+ VT.emplace_back( pCompoBox.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ VT.emplace_back( Stm.CloneTriangle( nFirstTria)) ;
+ VC.emplace_back( YELLOW) ;
+ IGeoPoint3d* _ptSel = CreateGeoPoint3d() ; _ptSel->Set( ptSel) ;
+ VT.emplace_back( _ptSel) ;
+ VC.emplace_back( RED) ;
+ //if ( bAbsFirst)
+ //SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ;
+ #endif
+
+ // Classifico i triangoli
+ if ( ! ClassifyTriangles( Stm, vTBox, nFirstTria, dAngTol, setAvoidTria, setNewTria))
+ return false ;
+
+ // Recupero solo i bordi validi interni al Box dai triangoli classificati
+ COMPOVECTOR vCompoChain ;
+ if ( ! GetBordersByTriaInBox( Stm, BBoxCurr, dLinTol, setNewTria, vCompoChain, bBreak))
+ return false ;
+
+ // Se primo triangolo in assoluto, ricavo i due tratti di interesse
+ if ( bAbsFirst) {
+ if ( ! CheckCurvesInBox( Stm, vCompoChain, ptSel, setNewTria, CompoA, CompoB, ptMid, ptMid1, nTria, nTria1))
+ return false ;
+ // Se entrambe chiuse, ho finito
+ if ( CompoA.IsClosed() && CompoB.IsClosed()) {
+ bStop = true ;
+ return true ;
+ }
+ }
+ // Se non sono il primo triangolo
+ else {
+
+ // Se primo triangolo relativo, tengo i punti di Trimming
+ if ( bRelFirst) {
+ // TODO -> non estendere le curve e tenerere i punti di Trim
+ }
+
+ // Aggiorno la CompoA con il nuovo tratto trovato
+ bool bUpdateA = false ;
+ if ( ! UpdateBorderByTriaAdj( CompoA, dLinTol, vCompoChain, bUpdateA))
+ return false ;
+ // Se CompoA si è aggiornata
+ if ( bUpdateA) {
+ // Se si è chiusa su se stessa, ho individuato il bordo
+ if ( CompoA.IsClosed()) {
+ bStop = true ;
+ return true ;
+ }
+ // Verifico se si è unita alla CompoB
+ if ( CompoB.IsValid()) {
+ CurveComposite CompoBTest ;
+ CompoBTest.CopyFrom( &CompoB) ;
+ bool bUpdateBTmp = false ;
+ if ( ! UpdateBorderByTriaAdj( CompoBTest, dLinTol, { CompoA}, bUpdateBTmp))
+ return false ;
+ if ( bUpdateBTmp) {
+ CompoB.Clear() ;
+ CompoA.CopyFrom( &CompoBTest) ;
+ bUpdateA = true ;
+ bBreak = true ;
+ }
+ }
+ }
+ // Aggiorno la Compo B con il nuovo tratto trovato
+ bool bUpdateB = false ;
+ if ( CompoB.IsValid()) {
+ if ( ! UpdateBorderByTriaAdj( CompoB, dLinTol, vCompoChain, bUpdateB))
+ return false ;
+ // Se CompoB si è aggiornata
+ if ( bUpdateB) {
+ // Se si è chiusa su se stessa, ho individuato il bordo
+ if ( CompoB.IsClosed()) {
+ bStop = true ;
+ return true ;
+ }
+ // Verifico se si è unita alla CompoA
+ if ( CompoA.IsValid()) {
+ CurveComposite CompoATest ;
+ CompoATest.CopyFrom( &CompoA) ;
+ bool bUpdateATmp = false ;
+ if ( ! UpdateBorderByTriaAdj( CompoATest, dLinTol, { CompoB}, bUpdateATmp))
+ return false ;
+ if ( bUpdateATmp) {
+ CompoA.Clear() ;
+ CompoB.CopyFrom( &CompoATest) ;
+ bUpdateA = true ;
+ bBreak = true ;
+ }
+ }
+ }
+ }
+
+ // Se sono il primo triangolo Relativo
+ if ( bRelFirst) {
+ // Accorcio le curve originarie
+ }
+
+ // Se non ho aggiornato nessuna delle due curve, sono in caso di divergenza
+ if ( ! bUpdateA && ! bUpdateB) {
+ // Può capitare con il primo Cubetto per triangoli grandi !
+ // ( da capire che cosa fare...)
+ // serve ????
+ }
+
+ // Verifico che le curve siano tra loro alla distanza stabilita
+ if ( dSizeTol > EPS_SMALL) {
+ if ( ! CheckBordersInBox( CompoA, CompoB, Stm, setAvoidTria, dAngTol, dLinTol, dSize, dSizeTol, bBreak))
+ return false ;
+ }
+ if ( bBreak) {
+ // Se caso ambiguo nel cubetto corrente, non aggiungo i triangoli trovati
+ setNewTria.clear() ;
+ return true ;
+ }
+
+ // Se CompoA e CompoB sono due curve distinte, calcolo i 2 punti medi e i 2 triangoli di ricerca,
+ // altrimenti ptMid1 sarà invalido e nTria1 sarà un triangolo nullo
+ if ( ! CalcMidPointForBorders( CompoA, CompoB, Stm, setNewTria, ptMid, ptMid1, nTria, nTria1))
+ return false ;
+ }
+
+ #if DEBUG_FACE_SEARCH
+ VT.clear() ; VC.clear() ;
+ pCompoBox.Clear() ;
+ pCompoBox.AddPoint( BBoxCurr.GetMin()) ;
+ pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimX() * X_AX) ;
+ pCompoBox.AddLine( BBoxCurr.GetMax() - BBoxCurr.GetDimZ() * Z_AX) ;
+ pCompoBox.AddLine( BBoxCurr.GetMin() + BBoxCurr.GetDimY() * Y_AX) ;
+ pCompoBox.Close() ;
+ pCompoBox.SetExtrusion( Z_AX) ;
+ pCompoBox.SetThickness( BBoxCurr.GetDimZ()) ;
+ VT.emplace_back( pCompoBox.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ VT.emplace_back( Stm.CloneTriangle( nFirstTria)) ;
+ VC.emplace_back( YELLOW) ;
+ _ptSel = CreateGeoPoint3d() ; _ptSel->Set( ptSel) ;
+ VT.emplace_back( _ptSel) ;
+ VC.emplace_back( RED) ;
+ if ( CompoA.IsValid()) {
+ VT.emplace_back( CompoA.Clone()) ;
+ VC.emplace_back( AQUA) ;
+ }
+ if ( CompoB.IsValid()) {
+ VT.emplace_back( CompoB.Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\1.nge") ;
+ #endif
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per muovere il BoxLocale lungo le curve di Bordo
+static bool
+MarchAlongPath( const BBox3d& BBoxCurr, const SurfTriMesh& Stm,
+ unordered_set& setAvoidTria, unordered_set& setValidTria,
+ bool bFollowA, const Point3d& ptMid, int nTria, double dSize, double dSizeTol,
+ double dAngTol, bool& bRelFirst, CurveComposite& CompoA, CurveComposite& CompoB, bool& bStop)
+{
+ // Variabili di controllo per la ricerca
+ BBox3d BBoxLast = BBoxCurr ;
+ Point3d ptRef = ptMid ;
+ int nTriaRef = nTria ;
+ bool bBreak = false ;
+
+ // Costanti di ricerca e contatori associati
+ const double EXPAND_EXTRA_TOL = 10. * EPS_SMALL ;
+ const int MAX_TRY = 4 ;
+ int nCount = 0 ;
+
+ // Inizio della ricerca
+ BBox3d MyBBoxCurr ;
+ while ( ! bBreak) {
+ // Definisco il nuovo Box
+ MyBBoxCurr.Reset() ;
+ MyBBoxCurr.Add( ptRef) ;
+ MyBBoxCurr.Expand( dSize + dSizeTol + EXPAND_EXTRA_TOL) ;
+ // Ricerco i triangoli
+ unordered_set setNewTria ; setNewTria.reserve( Stm.GetTriangleCount()) ;
+ Point3d myPtMid, myPtMid1 ;
+ int nMyTria = 0, nMyTria1 = 0 ;
+ if ( ! GetBordersInBox( Stm, MyBBoxCurr, nTriaRef, ptRef, dSize, dSizeTol, false, bRelFirst,
+ dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB,
+ myPtMid, myPtMid1, nMyTria, nMyTria1, bBreak, bStop))
+ return false ;
+ bRelFirst = false ;
+ // Memorizzo i triangoli validi ricavati
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter)
+ setValidTria.insert( *Iter) ;
+ // Se Direzione terminata o Curva chiusa
+ if ( bBreak || bStop)
+ break ;
+ // Ho determinato due curve distinte, il nuovo punto è quello più distante dal Box precedente
+ Point3d ptLast = ptRef ;
+ if ( myPtMid.IsValid() && myPtMid1.IsValid()) {
+ if ( bFollowA) {
+ ptRef = myPtMid ;
+ nTriaRef = nMyTria ;
+ }
+ else {
+ ptRef = myPtMid1 ;
+ nTriaRef = nMyTria1 ;
+ }
+ }
+ else {
+ if ( myPtMid.IsValid()) {
+ ptRef = myPtMid ;
+ nTriaRef = nMyTria ;
+ }
+ else {
+ ptRef = myPtMid1 ;
+ nTriaRef = nMyTria1 ;
+ }
+ }
+ // Se il nuovo punto è vicino al precedente, aggiorno il contatore
+ if ( SqDist( ptLast, ptRef) < ( ( dSize + dSizeTol) * ( dSize + dSizeTol) / 16.))
+ ++ nCount ;
+ else
+ nCount = 0 ;
+ // Se troppi punti vicini tra loro, blocco la ricerca per sicurezza
+ if ( nCount >= MAX_TRY)
+ bBreak = true ;
+ // Il Box Corrente diventa il Box precedente
+ BBoxLast = MyBBoxCurr ;
+
+ #if DEBUG_FACE_SEARCH
+ VT.clear() ; VC.clear() ;
+ CurveComposite CompoBox ;
+ CompoBox.AddPoint( MyBBoxCurr.GetMin()) ;
+ CompoBox.AddLine( MyBBoxCurr.GetMin() + MyBBoxCurr.GetDimX() * X_AX) ;
+ CompoBox.AddLine( MyBBoxCurr.GetMax() - MyBBoxCurr.GetDimZ() * Z_AX) ;
+ CompoBox.AddLine( MyBBoxCurr.GetMin() + MyBBoxCurr.GetDimY() * Y_AX) ;
+ CompoBox.Close() ;
+ CompoBox.SetExtrusion( Z_AX) ;
+ CompoBox.SetThickness( MyBBoxCurr.GetDimZ()) ;
+ VT.emplace_back( CompoBox.Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ IGeoPoint3d* _ptRef = CreateGeoPoint3d() ; _ptRef->Set( ptRef) ;
+ VT.emplace_back( _ptRef) ;
+ VC.emplace_back( RED) ;
+ if ( CompoA.IsValid()) {
+ VT.emplace_back( CompoA.Clone()) ;
+ VC.emplace_back( AQUA) ;
+ }
+ if ( CompoB.IsValid()) {
+ VT.emplace_back( CompoB.Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ //SaveGeoObj( VT, VC, "C:\\Temp\\CurveUpdate.nge") ;
+ #endif
+
+ }
+
+ return true ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per definire se il bordo di una TriMesh è una circonferenza
+static bool
+IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d& vtN, double& dRad)
+{
+ // Se PolyLine aperta o non piana, non è un cerchio
+ Plane3d PlanePL ;
+ if ( ! PL.IsClosed() || ! PL.IsFlat( PlanePL, dShapeLinTol))
+ return false ;
+
+ // Creo un sistema di riferimento centrato nella PolyLine
+ Point3d ptCentroid ;
+ Frame3d frCurr ;
+ CurveComposite CurveCompo ; CurveCompo.FromPolyLine( PL) ;
+ if ( ! CurveCompo.GetCentroid( ptCentroid) ||
+ ! frCurr.Set( ptCentroid, PlanePL.GetVersN()))
+ return false ;
+
+ // Porto una copia della PL in questo frame
+ PolyLine PLLoc = PL ; PLLoc.ToLoc( frCurr) ;
+
+ // Per ogni tratto salvo i suoi estremi e il punto medio in successione ( senza ripetizioni)
+ PNTVECTOR vPts ;
+ Point3d ptNext ;
+ PLLoc.GetFirstPoint( ptNext) ;
+ vPts.push_back( ptNext) ;
+ while ( PLLoc.GetNextPoint( ptNext)) {
+ vPts.push_back( Media( vPts.back(), ptNext)) ;
+ vPts.push_back( ptNext) ;
+ }
+
+ // Per ogni coppia di punti calcolo la Distanza Massima e Minima dal centro del cerchio locale ( ORIG)
+ double dSqMaxDist = 0. ;
+ double dSqMinDist = INFINITO ;
+ for ( int i = 0 ; i < int( floor( 0.5 * int( vPts.size()))) ; i = i + 2) {
+ double dSqLineDist = INFINITO ;
+ DistPointLine( ORIG, vPts[i], vPts[i + 1]).GetSqDist( dSqLineDist) ;
+ if ( dSqLineDist < dSqMinDist)
+ dSqMinDist = dSqLineDist ;
+ double dSqPtDist = SqDist( ORIG, vPts[i]) ;
+ if ( dSqPtDist > dSqMaxDist)
+ dSqMaxDist = dSqPtDist ;
+ }
+
+ // Se distanza minima e massima entro tolleranza, allora è una circonferenza
+ if ( abs( dSqMaxDist - dSqMinDist) < dShapeLinTol * dShapeLinTol) {
+ ptC = ptCentroid ;
+ vtN = PlanePL.GetVersN() ;
+ dRad = 0.5 * ( sqrt( dSqMaxDist) + sqrt( dSqMinDist)) ;
+ return true ;
+ }
+
+ return false ;
+}
+
+// ----------------------------------------------------------------------------
+// Funzione per estrarre Geometrie note da una sola TriMesh
+static bool
+GetShapesFromSurf( const ISurf* pSurf, double dShapeLinTol, double dShapeAngTol, double dLinTol,
+ double dEdgeLinTol, double dAngTol, double dFaceAngTol, const STRVECTOR& vsShapes,
+ ISURFPOVECTOR& vSurfSel, ICRVCOMPOPOMATRIX& matCompoBorders)
+{
+ vSurfSel.clear() ;
+ matCompoBorders.clear() ;
+ // Verifico la validità della superficie
+ if ( pSurf == nullptr || ! pSurf->IsValid())
+ return false ;
+
+ // Recupero il Tipo
+ int nType = pSurf->GetType() ;
+
+ ISURFTMPOVECTOR vSurfTmSelTmp ;
+ // Se superficie di Besier, non faccio nulla (?)
+ if ( nType == SRF_BEZIER)
+ return true ;
+ // Se superficie TriMesh
+ else if ( nType == SRF_TRIMESH) {
+ // Recupero la TriMesh
+ const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pSurf) ;
+ if ( pStmBasic == nullptr || ! pStmBasic->IsValid())
+ return false ;
+ // Ciclo di Analisi Triangoli
+ const int MAXTRY = 1000 ;
+ int nCount = 0 ;
+ int nTriaCheck = 0 ;
+ BOOLVECTOR vbTria( pStmBasic->GetTriangleCount(), false) ;
+ while ( nCount < MAXTRY && nTriaCheck < pStmBasic->GetTriangleCount()) {
+ // Recupero il primo triangolo valido disponibile non ancora analizzato
+ int nFirstTria = 0 ;
+ for ( int nT = 0 ; nT < ssize( vbTria) ; ++ nT) {
+ if ( ! vbTria[nT]) {
+ nFirstTria = nT ;
+ break ;
+ }
+ }
+ unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ;
+ unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ;
+ // Collezioni di triangoli da analizzare
+ INTVECTOR vTria ; vTria.reserve( pStmBasic->GetTriangleCount()) ;
+ vTria.push_back( nFirstTria) ;
+ // Finchè ho triangoli da visitare
+ while ( ! vTria.empty()) {
+ // Recupero il triangolo corrente
+ int nCurrTria = vTria.back() ;
+ // Elimino il triangolo corente
+ vTria.pop_back() ;
+
+ // Se triangolo da evitare, passo al successivo
+ if ( setAvoidTria.find( nCurrTria) != setAvoidTria.end())
+ continue ;
+ // Se triangolo mai visitato lo aggiungo tra quelli visitati, altrimenti passo al successivo
+ if ( vbTria[nCurrTria])
+ continue ;
+ vbTria[nCurrTria] = true ;
+ ++ nTriaCheck ;
+
+ // Inserisco il triangolo corrente
+ setNewTria.insert( nCurrTria) ;
+
+ // Recupero il triangolo corrente e le sue adiacenze
+ int nTriaVertices[3] ;
+ if ( ! pStmBasic->GetTriangle( nCurrTria, nTriaVertices))
+ return false ;
+ Triangle3d Tria ;
+ if ( ! pStmBasic->GetTriangle( nCurrTria, Tria))
+ return false ;
+ int nIdAdjTriaId[3] ;
+ if ( ! pStmBasic->GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId))
+ return false ;
+
+ // Scorro le adiacenze
+ for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) {
+ // Recupero l'indice del triangolo corrente
+ int nTriaAdj = nIdAdjTriaId[nAdj] ;
+ // Se non ho adiacenza, non faccio nulla
+ if ( nTriaAdj == SVT_NULL)
+ continue ;
+ // Recupero il triangolo adiacente
+ Triangle3d TriaAdj ;
+ if ( ! pStmBasic->GetTriangle( nTriaAdj, TriaAdj))
+ return false ;
+ // Se la normale è fuori dalla tolleranza, memorizzo il triangolo tra quelli da scartare
+ if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dFaceAngTol + EPS_ANG_SMALL) * DEGTORAD)) {
+ setAvoidTria.insert( nTriaAdj) ;
+ continue ;
+ }
+ // Inserisco il triangolo per la ricerca futura
+ vTria.push_back( nTriaAdj) ;
+ }
+ }
+ ++ nCount ;
+ // Se ho nuovi triangoli, definisco una superficie da essi
+ if ( ! setNewTria.empty()) {
+
+ #if DEBUG_SHAPE_STM
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( pStmBasic->Clone()) ;
+ VC.emplace_back( BLACK) ;
+ StmFromTriangleSoup _TriaSoup ; _TriaSoup.Start() ;
+ for ( auto _Iter = setNewTria.begin() ; _Iter != setNewTria.end() ; ++ _Iter) {
+ Triangle3d _Tria ;
+ if ( ! pStmBasic->GetTriangle( *_Iter, _Tria))
+ return false ;
+ _TriaSoup.AddTriangle( _Tria) ;
+ }
+ _TriaSoup.End() ;
+ VT.emplace_back( _TriaSoup.GetSurf()) ;
+ VC.emplace_back( LIME) ;
+ //SaveGeoObj( VT, VC, "C:\\Temp\\MyShape.nge") ;
+ VT.clear() ; VC.clear() ;
+ #endif
+
+ StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ;
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) {
+ Triangle3d Tria ;
+ if ( ! pStmBasic->GetTriangle( *Iter, Tria))
+ return false ;
+ TriaSoup.AddTriangle( Tria) ;
+ }
+ TriaSoup.End() ;
+ PtrOwner pStmTmp( TriaSoup.GetSurf()) ;
+ if ( ! IsNull( pStmTmp) && pStmTmp->IsValid() && pStmTmp->GetTriangleCount() > 0) {
+ if ( ! vSurfTmSelTmp.emplace_back( Release( pStmTmp)))
+ return false ;
+ }
+ }
+ }
+ }
+
+ // Se non ho ricavato superfici, esco
+ if ( vSurfTmSelTmp.empty())
+ return true ;
+
+ // Per ognuna di esse ricerco le geometrie compatibili
+ for ( int i = 0 ; i < ssize( vSurfTmSelTmp) ; ++ i) {
+ // Recupero i Loops
+ POLYLINEVECTOR vPL ;
+ vSurfTmSelTmp[i]->GetLoops( vPL) ;
+ // Elimino i Loop che non sono chiusi
+ vPL.erase(
+ remove_if( vPL.begin(), vPL.end(), []( const PolyLine& PL) {
+ return ( ! PL.IsClosed()) ;
+ }),
+ vPL.end()
+ ) ;
+ // Se non ho esattamente due Loops, passo alla superficie successiva
+ if ( ssize( vPL) != 2)
+ continue ;
+ // Se devo ricercare Circonferenze
+ if ( find_if( vsShapes.begin(), vsShapes.end(), [&]( const string& sStr) {
+ return ( sStr.compare( sCircle) == 0) ;
+ }) != vsShapes.end()) {
+ // Verifico che le due PolyLine siano circonferenze
+ Point3d ptCA, ptCB ; Vector3d vtNA, vtNB ; double dRadA, dRadB ;
+ if ( IsBorderACircle( vPL[0], dShapeLinTol, ptCA, vtNA, dRadA) &&
+ IsBorderACircle( vPL[1], dShapeAngTol, ptCB, vtNB, dRadB)) {
+ // Definisco le due circonferenze
+ PtrOwner pCirA( CreateCurveArc()) ;
+ PtrOwner pCirB( CreateCurveArc()) ;
+ if ( ! IsNull( pCirA) && ! IsNull( pCirB) &&
+ pCirA->Set( ptCA, vtNA, dRadA) &&
+ pCirB->Set( ptCB, vtNB, dRadB)) {
+ vSurfSel.emplace_back( GetSurf( Release( vSurfTmSelTmp[i]))) ;
+ matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ;
+ matCompoBorders.back().resize( 2) ;
+ matCompoBorders.back()[0].Set( ConvertCurveToComposite( Release( pCirA))) ;
+ matCompoBorders.back()[1].Set( ConvertCurveToComposite( Release( pCirB))) ;
+ // l'Approssimazione delle curve prevede che io usi sempre tratti lineari, quindi approssimo
+ PolyLine PLA ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLA) ;
+ PolyLine PLB ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLB) ;
+ matCompoBorders.back()[0]->Clear() ; matCompoBorders.back()[0]->FromPolyLine( PLA) ;
+ matCompoBorders.back()[1]->Clear() ; matCompoBorders.back()[1]->FromPolyLine( PLB) ;
+ }
+ }
+
+ #if DEBUG_SHAPE_STM
+ CurveComposite _CompoA ; _CompoA.FromPolyLine( vPL[0]) ;
+ CurveComposite _CompoB ; _CompoB.FromPolyLine( vPL[1]) ;
+ VT.emplace_back( _CompoA.Clone()) ;
+ VT.emplace_back( _CompoB.Clone()) ;
+ Color _cCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
+ VC.emplace_back( _cCol) ;
+ VC.emplace_back( _cCol) ;
+ #endif
+ }
+ }
+
+ // #if DEBUG_SHAPE_STM
+ // SaveGeoObj( VT, VC, "C:\\Temp\\myAutoBorders.nge") ;
+ // #endif
+
+ return true ;
+}
+
+//-----------------------------------------------------------------------------
+//-------------------------------- Funzioni Export ----------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Funzione per il calcolo degli Edges Grezzi
+bool
+GetTrimmingRawEdges( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace,
+ double dLinTol, double dAngTol,
+ ICRVCOMPOPOVECTOR& vCompoRawEdges)
+{
+ // Controllo la validità delle superfici
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf == nullptr || ! pSurf->IsValid()) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Detected invalid Surf") ;
+ return false ;
+ }
+ }
+ // Pulizia dei parametri di ritorno
+ vCompoRawEdges.clear() ;
+ // Se non ho elementi di selezione, non faccio nulla
+ if ( vSurfFace.empty())
+ return true ;
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ // Controllo sulla tolleranza angolare
+ double dMyAngTol = Clamp( dAngTol, 1., 45.) ;
+
+ // Recupero i bordi semplici definiti dalle superfici e dalle loro eventuali facce selezionate
+ POLYLINEVECTOR vPLBorders ;
+ if ( ! GetSurfBorders( vSurf, vSurfFace, dMyLinTol, vPLBorders)) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Borders extraction failed") ;
+ return false ;
+ }
+
+ // Recupero le curve di bordo grezze
+ if ( ! GetRawEdges( vPLBorders, dMyLinTol, dMyAngTol, vCompoRawEdges)) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Border simplification failed") ;
+ return false ;
+ }
+
+ return true ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per il calcolo automatico degli Edge finali
+// Se c'è la necessità di spezzare le curve di bordo si procede in questo modo :
+// 1) Si controlla l'esistenza di eventuali punti di rottura
+// 2) Se non ci sono punti di rottura, si cerca un valore di Thick e ThickTol
+// 3) Se non c'è una valore di Thick e ThickTol si procede per una rottura generica
+// Valori di Default dei parametri per evitare i rispettivi controlli :
+// - vBreakingPts = {}
+// - dThick = 0., dThickTol = 0.
+bool
+GetTrimmingFinalBorders( ICRVCOMPOPOVECTOR& vCompoBezierEdges, double dLinTol, double dAngTol,
+ BIPNTVECTOR& vBreakingPts, double dThick, double dThickTol)
+{
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ // Controllo sulla tolleranza angolare
+ double dMyAngTol = Clamp( dAngTol, 1., 45.) ;
+
+ // Se non ho curve, errore
+ if ( vCompoBezierEdges.empty()) {
+ LOG_INFO( GetEGkLogger(), "Warning in Trimming : No Edges detected") ;
+ return false ;
+ }
+ // Se ho 1 curva, allora cerco di spezzarla
+ else if ( int( vCompoBezierEdges.size()) == 1) {
+ // Se sono presenti dei punti di rottura
+ bool bOk = true ;
+ if ( ! vBreakingPts.empty())
+ bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol, vBreakingPts) ;
+ // Se invece è presente il valore di Thick
+ else if ( dThick > EPS_SMALL)
+ bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol, dThick, dThickTol) ;
+ else
+ // Se generica
+ bOk = BreakCompoPathces( vCompoBezierEdges, dMyLinTol, dMyAngTol) ;
+ if ( ! bOk)
+ LOG_INFO( GetEGkLogger(), "Warning in Trimming : Breaking curves failed") ;
+ }
+ // Se ho 2 curve, perfetto !
+ else if ( int( vCompoBezierEdges.size()) == 2)
+ return true ;
+ // Se più curve, errore
+ else {
+ LOG_INFO( GetEGkLogger(), "Warning in Trimming : More than 2 Edges detected") ;
+ return false ;
+ }
+
+ return true ;
+}
+
+// -----------------------------------------------------------------------------
+// Funzione per ricavare i bordi a partire da un insieme di superfici; questi vengono
+// calcolati mediante analisi delle normali lungo il bordo delle Patches di Surfs
+bool
+GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, double dLinTol, double dAngTol, double dThick,
+ ICRVCOMPOPOVECTOR& vCompoBezierEdges)
+{
+ // Pulizia dei parametri di ritorno
+ vCompoBezierEdges.clear() ;
+ // Se non ho elementi di selezione, non faccio nulla
+ if ( vSurfFaces.empty())
+ return true ;
+ // Lo spessore deve essere positivo
+ if ( dThick < 10. * EPS_SMALL) // coerente con Offset minimo
+ return false ;
+
+ // Verifico che le superfici siano tutte valide ed aperte
+ for ( const ISurf* pSurf : vpSurf) {
+ if ( pSurf == nullptr || ! pSurf->IsValid() || pSurf->IsClosed())
+ return false ;
+ }
+
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ // Controllo sulla tolleranza angolare
+ double dMyAngTol = Clamp( dAngTol, 1., 45.) ;
+
+ // Recupero la superficie TriMesh di cui fare l'Offset
+ PtrOwner pStm( nullptr) ;
+ if ( int( vpSurf.size()) == 1) {
+ const ISurf* pSurf = vpSurf[0] ;
+ if ( pSurf == nullptr)
+ return false ;
+ int nType = pSurf->GetType() ;
+ if ( nType == SRF_TRIMESH)
+ pStm.Set( CloneBasicSurfTriMesh( pSurf)) ;
+ else if ( nType == SRF_BEZIER) {
+ const ISurfBezier* pSurfBz = GetSurfBezier( pSurf) ;
+ if ( pSurfBz != nullptr)
+ pStm.Set( CloneBasicSurfTriMesh( pSurfBz->GetApproxSurf( dMyLinTol))) ;
+ }
+ }
+ else {
+ // [ Soluzione temporanea ]
+ StmFromTriangleSoup mySoup ; mySoup.Start() ;
+ for ( const ISurf* pSurf : vpSurf) {
+ if ( pSurf == nullptr)
+ return false ;
+ int nType = pSurf->GetType() ;
+ if ( nType == SRF_TRIMESH)
+ mySoup.AddSurfTriMesh( *GetSurfTriMesh( pSurf)) ;
+ else if ( nType == SRF_BEZIER) {
+ const ISurfBezier* pSrfBz = GetSurfBezier( pSurf) ;
+ if ( pSrfBz == nullptr)
+ return false ;
+ PtrOwner pStmTmp( pSrfBz->GetApproxSurf( dMyLinTol)) ;
+ if ( ! IsNull( pStmTmp) && pStmTmp->IsValid())
+ mySoup.AddSurfTriMesh( *pStmTmp) ;
+ }
+ }
+ mySoup.End() ;
+ pStm.Set( GetBasicSurfTriMesh( mySoup.GetSurf())) ;
+ }
+ if ( IsNull( pStm) || ! pStm->IsValid() || pStm->IsClosed())
+ return false ;
+
+ // Eseguo l'Offset in negativo della superficie passando per lo ZMap
+ double dPrec = max( min( dThick / 4., 10. * max( dMyLinTol, EPS_SMALL)), 0.5) ;
+ PtrOwner pStmOffs( CreateSurfTriMeshesOffset( { pStm}, - dThick, dPrec)) ;
+ if ( IsNull( pStmOffs) || ! pStmOffs->IsValid())
+ return false ;
+
+ // Recupero i Loop dalla superficie originaria e i Loop della superficie di Offset
+ POLYLINEVECTOR vPL, vPLOffs ;
+ if ( ! pStm->GetLoops( vPL) || ! pStmOffs->GetLoops( vPLOffs))
+ return false ;
+
+ #if DEBUG_BORDERS_BY_NORMALS
+ for ( const ISurf* _pSurf : vpSurf) {
+ VT.emplace_back( _pSurf->Clone()) ;
+ VC.emplace_back( LIME) ;
+ }
+ VT.emplace_back( pStmOffs->Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ;
+ #endif
+
+ // Trasformo ogni Loop in curva composita
+ ICRVCOMPOPOVECTOR vCompoLoops ; vCompoLoops.reserve( vPL.size()) ;
+ for ( const PolyLine& PL : vPL) {
+ if ( PL.IsClosed()) {
+ if ( ! vCompoLoops.emplace_back( CreateBasicCurveComposite()) ||
+ ! vCompoLoops.back()->FromPolyLine( PL) ||
+ ! vCompoLoops.back()->IsValid())
+ return false ;
+ }
+ }
+ ICRVCOMPOPOVECTOR vCompoOffsLoops ; vCompoOffsLoops.reserve( vPLOffs.size()) ;
+ for ( const PolyLine& PLOffs : vPLOffs) {
+ if ( PLOffs.IsClosed()) {
+ if ( ! vCompoOffsLoops.emplace_back( CreateCurveComposite()) ||
+ ! vCompoOffsLoops.back()->FromPolyLine( PLOffs) ||
+ ! vCompoOffsLoops.back()->IsValid())
+ return false ;
+ }
+ }
+
+ #if DEBUG_BORDERS_BY_NORMALS
+ for ( ICurveComposite* pCompo : vCompoLoops) {
+ VT.emplace_back( pCompo->Clone()) ;
+ VC.emplace_back( GREEN) ;
+ }
+ for ( ICurveComposite* pCompoOffs : vCompoOffsLoops) {
+ VT.emplace_back( pCompoOffs->Clone()) ;
+ VC.emplace_back( BLUE) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\TwoSurfs.nge") ;
+ #endif
+
+ // Per ogni curva della superficie originale cerco la sua associata
+ BOOLVECTOR vIndMatched( vCompoOffsLoops.size(), false) ;
+ for ( const ICurveComposite* pCompoLoop : vCompoLoops) {
+ // sposto il punto iniziale della curva nel tratto più lungo
+ double dMaxLen = - INFINITO ;
+ int nIndCrv = 0 ;
+ for ( int nCrv = 0 ; nCrv < pCompoLoop->GetCurveCount() ; ++ nCrv) {
+ const ICurve* pCurve = pCompoLoop->GetCurve( nCrv) ;
+ if ( pCurve != nullptr && pCurve->IsValid()) {
+ double dCurrLen = 0. ;
+ pCurve->GetLength( dCurrLen) ;
+ if ( dCurrLen > dMaxLen) {
+ dMaxLen = dCurrLen ;
+ nIndCrv = nCrv ;
+ }
+ }
+ }
+ Point3d ptRef ;
+ pCompoLoop->GetPointD1D2( nIndCrv + 0.5, ICurve::FROM_MINUS, ptRef) ;
+ // dalle altre curve derivanti dalla superficie di Offset cerco quella più vicina al punto inziale
+ double dMinSqDist = INFINITO ;
+ int nIndOffsCrv = -1 ;
+ for ( int nOffsCrv = 0 ; nOffsCrv < int( vCompoOffsLoops.size()) ; ++ nOffsCrv) {
+ if ( vIndMatched[nOffsCrv])
+ continue ;
+ // recupero la curva e calcolo la distanza
+ const ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nOffsCrv] ;
+ int nFlag = 0 ;
+ Point3d ptCurrMinDist ;
+ if ( DistPointCurve( ptRef, *pCompoOffsLoop).GetMinDistPoint( 0., ptCurrMinDist, nFlag)) {
+ double dCurrSqDist = SqDist( ptRef, ptCurrMinDist) ;
+ if ( dCurrSqDist < dMinSqDist) {
+ dMinSqDist = dCurrSqDist ;
+ nIndOffsCrv = nOffsCrv ;
+ }
+ }
+ }
+ if ( nIndOffsCrv == -1)
+ return false ;
+ vIndMatched[ nIndOffsCrv] = true ;
+ // associo le due curve ( quindi consecutive nel vettore delle curve risultanti)
+ vCompoBezierEdges.emplace_back( CloneCurveComposite( pCompoLoop)) ;
+ if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol))
+ return false ;
+ vCompoBezierEdges.emplace_back( CloneCurveComposite( vCompoOffsLoops[nIndOffsCrv])) ;
+ if ( ! ApproxCurveWithBezier( vCompoBezierEdges.back(), dMyLinTol, dMyAngTol))
+ return false ;
+ }
+
+ return true ;
+}
+
+// -----------------------------------------------------------------------------
+// Funzione per approssimare le curve di Bordo grezze ( tratti lineari) in
+// Patch di curve di Bezier
+bool
+GetTrimmingBezierEdges( ICRVCOMPOPOVECTOR& vCompoRawEdges, double dLinTol, double dAngTol,
+ ICRVCOMPOPOVECTOR& vBezierEdges)
+{
+ // Pulizia del parametro di ritorno
+ vBezierEdges.clear() ;
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ // Controllo sulla tolleranza angolare
+ double dMyAngTol = Clamp( dAngTol, 1., 45.) ;
+
+ #if DEBUG_EDGES
+ VC.clear() ; VT.clear() ;
+ for ( int _i = 0 ; _i < int( vCompoRawEdges.size()) ; ++ _i) {
+ VT.emplace_back( vCompoRawEdges[_i]->Clone()) ;
+ VC.emplace_back( RED) ;
+ }
+ #endif
+
+ // Approssimo i bordi grezzi
+ vBezierEdges.reserve( vCompoRawEdges.size()) ;
+ for ( int i = 0 ; i < int( vCompoRawEdges.size()) ; ++ i) {
+ PtrOwner pCompoTmp( CloneCurveComposite( vCompoRawEdges[i])) ;
+ if ( IsNull( pCompoTmp) ||
+ ! ApproxCurveWithBezier( pCompoTmp, dMyLinTol, dMyAngTol) ||
+ ! vBezierEdges.emplace_back( Release( pCompoTmp))) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Approxing edge failed") ;
+ return false ;
+ }
+ }
+
+ #if DEBUG_EDGES
+ VC.clear() ; VT.clear() ;
+ for ( int _i = 0 ; _i < int( vCompoTmpEdges.size()) ; ++ _i) {
+ VT.emplace_back( vCompoTmpEdges[_i]->Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\ApproxBorder.nge") ;
+ #endif
+
+ return true ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per ottenere i punti di sincronizzazione tra due curve di Bezier per
+// la costruzione della superficie rigata stessa
+bool
+GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
+ double dLinTol, BIPNTVECTOR& vSyncPoints)
+{
+ // Verifica validità delle curve per la creazione della Bezier rigata
+ PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ;
+ PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ;
+ if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2))
+ return false ;
+ vSyncPoints.clear() ;
+
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+
+ #if DEBUG_SYNC_POINTS
+ VT.clear() ; VC.clear() ;
+ VT.emplace_back( pCompoEdge1->Clone()) ;
+ VC.emplace_back( AQUA) ;
+ VT.emplace_back( pCompoEdge2->Clone()) ;
+ VC.emplace_back( ORANGE) ;
+ #endif
+
+ // Definisco la superficie di Bezier rigata
+ PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ;
+ if ( IsNull( pSBzRuled) || ! pSBzRuled->IsValid())
+ return false ;
+
+ // Recupero i punti di sincronizzazione e li restituisco
+ ICURVEPOVECTOR vCrv ;
+ pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ;
+ vSyncPoints.reserve( vCrv.size()) ;
+ for ( int i = 0 ; i < int( vCrv.size()) ; ++ i) {
+ if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) {
+ #if DEBUG_SYNC_POINTS
+ VT.emplace_back( vCrv[i]->Clone()) ;
+ VC.emplace_back( LIME) ;
+ #endif
+ Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ;
+ Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ;
+ if ( ! AreSamePointApprox( ptStart, ptEnd))
+ vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ;
+ }
+ }
+
+ #if DEBUG_SYNC_POINTS
+ SaveGeoObj( VT, VC, "C:\\Temp\\BorderSyncPoints.nge") ;
+ #endif
+
+ return true ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per il calcolo della superficie di Bezier rigata
+// NB. Possono essere passati dei parametri opzionali come vIndPriority e vIndVisible :
+// - Se non presenti, la superficie Ruled Bezier viene costruita in modo standard
+// - Se sono presenti degli indici di priorità e/o degli indici di visibilità, significa che
+// si vuole costruire una superficie diversa da quella standard, dove i tratti prioritari
+// sono quelli che più determinano il cambiamento della superficie ( in quanto diversi da quelli
+// originali) e i tratti visibili servono per determinare l'intervallo di influenza della modifica
+// alla superficie nei pressi dei tratti lineari di sincronizzazione prioritari
+ISurfBezier*
+GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1,
+ const ICurve* pCrvEdge2, double dLinTol, const BIPNTVECTOR& vSyncPoints,
+ const INTVECTOR& vIndPriority, const INTVECTOR& vIndVisible)
+{
+ // Verifica validità delle curve per la creazione della Bezier rigata
+ PtrOwner pCompoEdge1( ConvertCurveToComposite( pCrvEdge1->Clone())) ;
+ PtrOwner pCompoEdge2( ConvertCurveToComposite( pCrvEdge2->Clone())) ;
+ if ( ! ManageRuledBorders( pCompoEdge1, pCompoEdge2))
+ return nullptr ;
+ // Controllo sulla tolleranza lineare
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+
+ #if DEBUG_BEZIER_RULED
+ VT_Glob.emplace_back( pCompoEdge1->Clone()) ;
+ VT_Glob.emplace_back( pCompoEdge2->Clone()) ;
+ VC_Glob.emplace_back( ORANGE) ;
+ VC_Glob.emplace_back( AQUA) ;
+ #endif
+
+ // Creo la superficie di Bezier
+ PtrOwner pSurfBz( CreateSurfBezier()) ;
+ if ( IsNull( pSurfBz))
+ return nullptr ;
+
+ // Se non ho punti di controllo forzati
+ if ( vSyncPoints.empty()) {
+ pSurfBz.Set( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol)) ;
+ if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier invalid") ;
+ return nullptr ;
+ }
+ }
+ // Se ho punti di controllo forzati
+ else {
+ // Recupero i tratti lineari di sincronizzazione
+ ICURVEPOVECTOR vCrv ; vCrv.reserve( vSyncPoints.size()) ;
+ for ( const BIPOINT& PtSPtE : vSyncPoints) {
+ PtrOwner pLine( CreateCurveLine()) ;
+ if ( IsNull( pLine) || ! pLine->Set( PtSPtE.first, PtSPtE.second))
+ return nullptr ;
+ vCrv.emplace_back( Release( pLine)) ;
+ }
+ #if DEBUG_BEZIER_RULED
+ for ( int _i = 0 ; _i < int( vCrv.size()) ; ++ _i) {
+ VT_Glob.emplace_back( vCrv[_i]) ;
+ VC_Glob.emplace_back( LIME) ;
+ }
+ #endif
+ // Definisco la superficie
+ pSurfBz.Set( GetSurfBezierRuledGuided( pCompoEdge1, pCompoEdge2, vCrv, dMyLinTol)) ;
+ if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) {
+ LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier with Sync Points invalid") ;
+ return nullptr ;
+ }
+ }
+
+ #if DEBUG_BEZIER_RULED
+ VT_Glob.emplace_back( pSurfBz->Clone()) ;
+ VC_Glob.emplace_back( LIME) ;
+ SaveGeoObj( VT_Glob, VC_Glob, "C:\\Temp\\TestBz.nge") ;
+ #endif
+
+ // La superficie deve essere orientata correttamente con le geometrie iniziali ( privilegio le TriMesh)
+ if ( ! vSurf.empty()) {
+ bool bOk = true ;
+ Point3d ptPos ;
+ Vector3d vtN ;
+ if ( pSurfBz->GetPointNrmD1D2( 0.1, 0.1, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPos, vtN)) {
+ Point3d ptCheck = ptPos + 10. * EPS_SMALL * vtN ;
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf->GetType() == SRF_TRIMESH) {
+ if ( DistPointSurfTm( ptCheck, *GetSurfTriMesh( pSurf)).IsPointOnLeftSide())
+ pSurfBz->Invert() ;
+ bOk = true ;
+ break ;
+ }
+ }
+ if ( ! bOk) {
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf->GetType() == SRF_BEZIER) {
+ if ( DistPointSurfBz( ptCheck, *GetSurfBezier( pSurf)).IsPointOnLeftSide())
+ pSurfBz->Invert() ;
+ bOk = true ;
+ break ;
+ }
+ }
+ }
+ }
+ }
+
+ return ( IsNull( pSurfBz) || ! pSurfBz->IsValid() ? nullptr : Release( pSurfBz)) ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per la ricerca di facce adiacenti su una superficie TriMesh.
+// Dato un insieme iniziale di facce, per ciascuna di esse vengono analizzate le facce adiacenti.
+// Se la normale di una faccia adiacente forma un angolo entro la tolleranza specificata,
+// quella faccia viene memorizzata e considerata come nuovo punto di partenza per la ricerca
+// di ulteriori adiacenze.
+bool
+GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const PNTVECTOR& vPts,
+ double dAngTol, double dSize, double dSizeTol, INTVECTOR& vOtherTria)
+{
+ // Verifico la validità della superficie TriMesh e l'esistenza di triangoli di riferimento
+ if ( ! pStm->IsValid() || vTria.empty())
+ return false ;
+
+ // Recupero la superficie di base
+ const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pStm) ;
+ if ( pStmBasic == nullptr || ! pStmBasic->IsValid())
+ return false ;
+
+ // Definisco un Box3d nel punto di Selezione di dimensioni pari al doppio della dimensione della
+ // striscia di ricerca considerando la tolleranza
+ Triangle3d firstTria ;
+ if ( ! pStmBasic->GetTriangle( vTria[0], firstTria))
+ return false ;
+ BBox3d BBoxCurr ;
+ BBoxCurr.Add( vPts[0]) ;
+ const double EXPAND_EXTRA_TOL = 10. * EPS_SMALL ;
+ BBoxCurr.Expand( ( dSize + dSizeTol + EXPAND_EXTRA_TOL)) ;
+
+ // Recupero i triangoli validi all'interno del Box e definisco i primi due tratti lineari
+ // per le curve di Bordo
+ bool bBreak = false, bStop = false ;
+ unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ;
+ unordered_set setValidTria ; setValidTria.reserve( pStmBasic->GetTriangleCount()) ;
+ unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ;
+ Point3d ptMid, ptMid1 ;
+ int nTria = 0, nTria1 = 0 ;
+ CurveComposite CompoA, CompoB ;
+ if ( ! GetBordersInBox( *pStmBasic, BBoxCurr, vTria[0], vPts[0], dSize, dSizeTol, true, true,
+ dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, CompoA, CompoB,
+ ptMid, ptMid1, nTria, nTria1, bBreak, bStop))
+ return false ;
+
+ // Se triangolo iniziale non significativo, devo sceglierne un altro
+ if ( bBreak) {
+ return true ; // ??? come lo comunico all'utente
+ }
+ // Se ho già ricavato tutto, ho finito
+ else if ( bStop) {
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter)
+ vOtherTria.push_back( *Iter) ;
+ return true ;
+ }
+
+ // I nuovi triangoli della striscia vengono memorizzati
+ for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter)
+ setValidTria.insert( *Iter) ;
+
+ // Ricerco nella direzione di ptMid1
+ bool bRelFirst = true ;
+ if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, true, ptMid1, nTria1,
+ dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop))
+ return false ;
+
+ // Se Non ho ricavato un'intera striscia chiusa, allora avvio la ricerca in direzione di ptMid
+ if ( ! bStop) {
+ if ( ! MarchAlongPath( BBoxCurr, *pStmBasic, setAvoidTria, setValidTria, false, ptMid, nTria,
+ dSize, dSizeTol, dAngTol, bRelFirst, CompoA, CompoB, bStop))
+ return false ;
+ }
+
+ // Per ogni triangolo recuperato, cerco le facce a cui appartiene
+ unordered_set setValidFace ;
+ for ( auto Iter = setValidTria.begin() ; Iter != setValidTria.end() ; ++ Iter)
+ vOtherTria.push_back( *Iter) ;
+
+ return true ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per la ricerca di Superfici in tangenza ( Simile a quanto descritto nella funzione sopra)
+bool
+GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf, double dLinTol,
+ double dAngTol, double dFaceAngTol, INTVECTOR& vIndOtherSurf)
+{
+ // Verifica dei parametri
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf == nullptr || ! pSurf->IsValid())
+ return false ;
+ }
+ for ( const ISurf* pOtherSurf : vOtherSurf) {
+ if ( pOtherSurf == nullptr || ! pOtherSurf->IsValid())
+ return false ;
+ }
+
+ // creo l'insieme delle curve di bordo in continuità
+ SURFPATCHESVECTOR vSurfPatches ; vSurfPatches.reserve( vSurf.size() + vOtherSurf.size()) ;
+ BOXVECTOR vBBox3d ; vBBox3d.reserve( vSurf.size() + vOtherSurf.size()) ;
+ for ( int nS = 0 ; nS < int( vSurf.size()) ; ++ nS) {
+ vSurfPatches.emplace_back( SurfPatches()) ;
+ vSurfPatches.back().pSurf = vSurf[nS] ;
+ vSurfPatches.back().nIndSurf = nS ;
+ vBBox3d.emplace_back( BBox3d()) ;
+ POLYLINEVECTOR vPLBorders ;
+ if ( ! InsertLoopsOfSurf( vSurf[nS], vPLBorders))
+ return false ;
+ for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL)
+ vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ;
+ vBBox3d.back().Expand( 2. * dLinTol) ;
+ POLYLINEMATRIX matPLPatchBorders ;
+ if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders))
+ return false ;
+ for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) {
+ for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) {
+ Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ;
+ Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ;
+ vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ;
+ vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ;
+ vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ;
+ }
+ }
+ }
+ for ( int nS = 0 ; nS < int( vOtherSurf.size()) ; ++ nS) {
+ vSurfPatches.emplace_back( SurfPatches()) ;
+ vSurfPatches.back().pSurf = vOtherSurf[nS] ;
+ vSurfPatches.back().nIndSurf = int( vSurf.size()) + nS ;
+ vBBox3d.emplace_back( BBox3d()) ;
+ POLYLINEVECTOR vPLBorders ;
+ if ( ! InsertLoopsOfSurf( vOtherSurf[nS], vPLBorders))
+ continue ;
+ for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL)
+ vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ;
+ vBBox3d.back().Expand( 2. * dLinTol) ;
+ POLYLINEMATRIX matPLPatchBorders ;
+ if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders))
+ return false ;
+ for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) {
+ for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) {
+ Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ;
+ Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ;
+ vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ;
+ vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ;
+ vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ;
+ }
+ }
+ }
+
+ // Se necessario, Splitto le Patch per far combiaciare gli estremi
+ for ( int i = 0 ; i < int( vSurfPatches.size()) - 1 ; ++ i) {
+ for ( int j = i + 1 ; j < int( vSurfPatches.size()) ; ++ j) {
+ if ( vBBox3d[i].Overlaps( vBBox3d[j])) {
+ if ( ! SplitPatchWithPatch( vSurfPatches[i], vSurfPatches[j], dLinTol))
+ return false ;
+ }
+ }
+ }
+
+ #if DEBUG_SIMPLE_PATCHES
+ VT.clear() ; VC.clear() ;
+ for ( int i = 0 ; i < int( vSurfPatches.size()) ; ++ i) {
+ Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
+ for ( int j = 0 ; j < int( vSurfPatches[i].CompoPathces.size()) ; ++ j) {
+ VT.emplace_back( vSurfPatches[i].CompoPathces[j].Clone()) ;
+ VC.emplace_back( myCol) ;
+ IGeoPoint3d* _pt = CreateGeoPoint3d() ; _pt->Set( vSurfPatches[i].vPatches[j].ptStart) ;
+ VT.emplace_back( _pt) ;
+ VC.emplace_back( AQUA) ;
+ IGeoPoint3d* _pt1 = CreateGeoPoint3d() ; _pt1->Set( vSurfPatches[i].vPatches[j].ptEnd) ;
+ VT.emplace_back( _pt1) ;
+ VC.emplace_back( AQUA) ;
+ }
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\SimplePatch.nge") ;
+ #endif
+
+ // Verifico ora se le tangenze nei punti di giunzione sono al di sotto della tolleranza angolare
+ INTVECTOR vSurfToCheck ;
+ INTSET setSurf ;
+ for ( int i = 0 ; i < int( vSurf.size()) ; ++ i)
+ vSurfToCheck.push_back( i) ;
+
+ // Finchè ho una superficie da analizzare
+ while ( ! vSurfToCheck.empty()) {
+ // Recupero l'indice della superficie corrente
+ int nSurf = vSurfToCheck.back() ;
+ // Elimino l'indice corrente
+ vSurfToCheck.pop_back() ;
+ // Se superficie non analizzata, la aggiungo come visitata
+ auto IterSurf = setSurf.find( nSurf) ;
+ if ( IterSurf == setSurf.end())
+ setSurf.insert( nSurf) ;
+ // Se già visitata, passo alla successiva
+ else
+ continue ;
+
+ // Recupero la superficie corrente
+ const ISurf* pCurrSurf = vSurfPatches[nSurf].pSurf ;
+
+ // Scorro le sua Patches
+ for ( int nCurrPatch = 0 ; nCurrPatch < int( vSurfPatches[nSurf].vPatches.size()) ; ++ nCurrPatch) {
+ // Recupero la Patch attuale
+ SimplePatch& currPatch = vSurfPatches[nSurf].vPatches[nCurrPatch] ;
+ // Se Patch già analizzata, passo alla successiva
+ if ( currPatch.bErase)
+ continue ;
+ currPatch.bErase = true ;
+ // Scorro le altre Patches
+ for ( int nOtherSurf = 0 ; nOtherSurf < int( vSurfPatches.size()) ; ++ nOtherSurf) {
+ // Se stessa superficie, passo alla successiva
+ if ( nOtherSurf == nSurf)
+ continue ;
+ // Se superficie già analizzata, passo alla successiva
+ if ( setSurf.find( nOtherSurf) != setSurf.end())
+ continue ;
+ // Recupero la superficie di confronto
+ const ISurf* pOtherSurf = vSurfPatches[nOtherSurf].pSurf ;
+ // Scorro le sua Patches
+ for ( int nOtherPatch = 0 ; nOtherPatch < int( vSurfPatches[nOtherSurf].vPatches.size()) ; ++ nOtherPatch) {
+ // Recupero la Patch di confronto
+ SimplePatch& nextPatch = vSurfPatches[nOtherSurf].vPatches[nOtherPatch] ;
+ // Se Patch già analizzata, passo alla successiva
+ if ( nextPatch.bErase)
+ continue ;
+ // Se gli estremi coincidono
+ if ( ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptStart, dLinTol) &&
+ AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptEnd, dLinTol)) ||
+ ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptEnd, dLinTol) &&
+ AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptStart, dLinTol))) {
+ // Controllo se le tangenze rimangono nella tolleranza
+ bool bTangent = true ;
+ // Campiono la Patch corrente
+ const int MAX_POINTS = 5 ;
+ BIPNTVECTOR vPtAPtB ; vPtAPtB.reserve( MAX_POINTS + 1) ;
+ CurveComposite& currCompoPatch = vSurfPatches[nSurf].CompoPathces[nCurrPatch] ;
+ CurveComposite& otherCompoPatch = vSurfPatches[nOtherSurf].CompoPathces[nOtherPatch] ;
+ double dLen = 0.;
+ currCompoPatch.GetLength( dLen) ;
+ for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) {
+ double dU = 0. ;
+ currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ;
+ Point3d ptCurr ;
+ currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ;
+ Point3d ptOther ;
+ int nFlag = 0 ;
+ DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag) ;
+ // Recupero le due normali sulle curva patch campionate
+ Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ;
+ if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) ||
+ ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther))
+ return false ;
+ bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ;
+ }
+ // Se superficie in tangenza, aggiorno i parametri
+ if ( bTangent) {
+ vSurfToCheck.emplace_back( nOtherSurf) ;
+ nextPatch.bErase = true ;
+ if ( nOtherSurf >= int( vSurf.size()) &&
+ find( vIndOtherSurf.begin(), vIndOtherSurf.end(), nOtherSurf - int( vSurf.size())) == vIndOtherSurf.end())
+ vIndOtherSurf.push_back( nOtherSurf - int( vSurf.size())) ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ #if DEBUG_SURF_PATCHES
+ VT.clear() ; VC.clear() ;
+ for ( const int& nInd : vIndOtherSurf) {
+ VT.emplace_back( vOtherSurf[nInd]->Clone()) ;
+ VC.emplace_back( GRAY) ;
+ }
+ for ( const ISurf* pSurf : vSurf) {
+ VT.emplace_back( pSurf->Clone()) ;
+ VC.emplace_back( YELLOW) ;
+ }
+ SaveGeoObj( VT, VC, "C:\\Temp\\SurfPatches.nge") ;
+ #endif
+
+ return true ;
+}
+
+//------------------------------------------------------------------------------
+// Funzione per la ricerca automatica delle Geometrie di Trimming
+bool
+GetTrimmingAutoEntities( const CISURFPVECTOR& vSurf, double dShapeLinTol, double dShapeAngTol,
+ double dLinTol, double dEdgeLinTol, double dAngTol, double dAngFaceTol,
+ const STRVECTOR& vsShapes, ISURFPOMATRIX& matSelSurf,
+ ICRVCOMPOPOMATRIX& matCompoBorders, ISURFBEZPOVECTOR& vSurfBz)
+{
+ // Pulizia dei parametri di ingresso
+ matSelSurf.clear() ;
+ matCompoBorders.clear() ;
+ vSurfBz.clear() ;
+
+ // Se non ho superfici non devo fare nulla
+ if ( vSurf.empty())
+ return true ;
+ // Verifico che le superfici presenti siano ben definite
+ for ( const ISurf* pSurf : vSurf) {
+ if ( pSurf == nullptr || ! pSurf->IsValid())
+ return false ;
+ }
+
+ // Controllo sulla tolleranza lineare
+ double dMyShapeLinTol = Clamp( dShapeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ double dMyEdgeLinTol = Clamp( dEdgeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
+ // Controllo sulla tolleranza angolare
+ double dMyShapeAngTol = Clamp( dShapeAngTol, 1., 60.) ;
+ double dMyAngTol = Clamp( dAngTol, 1., 45.) ;
+ double dMyFaceAngTol = Clamp( dAngFaceTol, 1., 60.) ;
+
+ ICRVCOMPOPOMATRIX matCompoBordersTmp ;
+ // Se una sola superficie, effettuo la ricerca per triangoli
+ if ( ssize( vSurf) == 1) {
+ ISURFPOVECTOR vSurfTmp ;
+ if ( ! GetShapesFromSurf( vSurf[0], dMyShapeLinTol, dMyShapeAngTol, dMyLinTol, dMyEdgeLinTol,
+ dMyAngTol, dMyFaceAngTol, vsShapes, vSurfTmp, matCompoBordersTmp))
+ return false ;
+ for ( int i = 0 ; i < ssize( vSurfTmp) ; ++ i) {
+ matSelSurf.emplace_back( ISURFPOVECTOR{}) ;
+ matSelSurf.back().emplace_back( Release( vSurfTmp[i])) ;
+ }
+ }
+ // Se più superfici eseguo la ricerca per Patches
+ else {
+
+ }
+
+ // Se non ho alcuna Geometria voluta, esco
+ if ( matSelSurf.empty())
+ return true ;
+
+ // Per ogni Geometria, approssimo le Curve mediante delle Bezier e calolo la Rigata
+ for ( int i = 0 ; i < ssize( matSelSurf) ; ++ i) {
+ matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ; matCompoBorders.back().reserve( 2) ;
+ if ( ! GetTrimmingBezierEdges( matCompoBordersTmp[i], dLinTol, dAngTol, matCompoBorders.back()))
+ return false ;
+ vSurfBz.emplace_back( GetTrimmingRuledBezier( vSurf, matCompoBorders.back()[0], matCompoBorders.back()[1],
+ dMyLinTol, BIPNTVECTOR{}, INTVECTOR{}, INTVECTOR{})) ;
+ }
+
+ return true ;
+}