//---------------------------------------------------------------------------- // EgalTech 2025 //---------------------------------------------------------------------------- // File : SurfTriMeshOffset.cpp Data : 07.07.25 Versione : 2.7g1 // Contenuto : Implementazione funzione per Offset di Superfici TriMesh. // // // // Modifiche : 10.06.25 RE Creazione modulo. // 10.06.25 RE Offset di superfici chiuse. // 04.07.25 RE Thickening Offset di superfici generiche. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "VolZmap.h" #include "SurfTriMesh.h" #include "EgtDev/Include/EGkDistPointSurfTm.h" #include "\EgtDev\Include\EGkSurfTriMeshAux.h" #define DEBUG 0 #if DEBUG #include "/EgtDev/Include/EGkGeoObjSave.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EGkStmStandard.h" #include "/EgtDev/Include/EgtPerfCounter.h" std::vector VT ; std::vector VC ; #endif using namespace std ; //---------------------------------------------------------------------------- static ISurfTriMesh* SumStm( const CISURFTMPVECTOR& vStm) { // se vettore vuoto, non faccio nulla if ( vStm.empty()) return nullptr ; // definisco la superficie somma tra tutte ( la prima deve essere valida) PtrOwner pStmAdd( CreateSurfTriMesh()) ; if ( IsNull( pStmAdd)) return nullptr ; // scorro le superfici for ( const ISurfTriMesh* pStm : vStm) { if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0) continue ; if ( ! pStmAdd->IsValid() || pStmAdd->GetTriangleCount() == 0) { if ( ! pStmAdd->CopyFrom( pStm)) return nullptr ; } else pStmAdd->Add( *pStm) ; } // restituisco la superficie ottenuta return ( Release( pStmAdd)) ; } //---------------------------------------------------------------------------- // Funzione che crea l'Offset di una superficie TriMesh //---------------------------------------------------------------------------- ISurfTriMesh* CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) { return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dPrec, nType)) ; } //---------------------------------------------------------------------------- // Funzione che crea il Fat Offset di una superficie TriMesh //---------------------------------------------------------------------------- ISurfTriMesh* CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) { return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dPrec, nType)) ; } //---------------------------------------------------------------------------- // Funzione che crea l'Offset di un insieme di superfici //---------------------------------------------------------------------------- ISurfTriMesh* CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) { // se vettore delle superfici vuoto, non faccio nulla if ( vStm.empty()) return nullptr ; // controllo sul valore di tolleranza lineare double dMyPrec = max( dPrec, 100. * EPS_SMALL) ; // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto) // Nel caso sia minore, restituisco semplicemente la somma delle superfici // ( questo valore serve per rimanere coerente con l'Offset delle curve) if ( abs( dOffs) < 10. * EPS_SMALL) return SumStm( vStm) ; // creo lo Zmap associato alle superfici TriMesh VolZmap OneVolZmap ; if ( ! OneVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType)) return nullptr ; if ( ! OneVolZmap.IsValid()) return nullptr ; // recupero le superfici aperte CISURFTMPVECTOR vStmOpen ; for ( const ISurfTriMesh* pStm : vStm) { if ( pStm != nullptr && pStm->IsValid() && ! pStm->IsClosed()) vStmOpen.emplace_back( pStm) ; } // --- se non ho superfici aperte if ( vStmOpen.empty()) { // restituisco la superficie TriMesh di Offset return ( OneVolZmap.GetSurfTriMesh()) ; } // --- se ho delle superfici aperte // lo Zmap creato è orientato e definisce una superficie chiusa; devo rimuovere i triangoli in eccesso // anzitutto controllo che lo Zmap sia valido if ( ! OneVolZmap.IsValid()) return nullptr ; // inzializzo la superficie TriMesh da restituire PtrOwner pStm( CreateBasicSurfTriMesh()) ; if ( IsNull( pStm) || ! pStm->Init( 3, 1)) return nullptr ; PointGrid3d VertGrid ; VertGrid.Init( 50000) ; // tolleranza di vicinanza alla superficie double dTolDist = 30. * EPS_SMALL ; #if DEBUG VT.emplace_back( OneVolZmap.Clone()) ; VC.emplace_back( BLACK) ; #endif // ciclo lungo i blocchi dello ZMap for ( int nB = 0 ; nB < OneVolZmap.GetBlockCount() ; ++ nB) { // recupero i triangoli TRIA3DEXVECTOR vTria, vTriaSafe ; OneVolZmap.GetBlockTriangles( nB, vTria) ; // un triangolo viene ritenuto valido se è non è troppo vicino ( dOffs) alle superfici aperte for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) { // recupero il triangolo Triangle3dEx& Tria = vTria[nT] ; // scorro le superficie aperte bool bInsert = true ; for ( int nS = 0 ; bInsert && nS < int( vStm.size()) ; ++ nS) { // controllo se posso inserirlo vector vDistPtStm ; for ( int i = 0 ; i < 3 && bInsert ; ++ i) { double dDist = 0. ; vDistPtStm.emplace_back( DistPointSurfTm( Tria.GetP( i), *vStm[nS])) ; bInsert = ( vDistPtStm.back().GetDist( dDist) && dDist > abs( dOffs) - dTolDist) ; } // se il triangolo è al più a distanza di |dOffs| - dTolDist if ( bInsert) { // recupero i triangoli a distanza minima dai vertici del triangolo corrente bool bPerp = true ; for ( int i = 0 ; i < 3 && bPerp ; ++ i) { INTVECTOR vTria ; vDistPtStm[i].GetMinDistTriaIndices( vTria) ; for ( int j = 0 ; j < int( vTria.size()) && bPerp ; ++ j) { Triangle3d TriaCloser ; vStm[nS]->GetTriangle( vTria[j], TriaCloser) ; bPerp = ( abs( Tria.GetN() * TriaCloser.GetN()) < dTolDist) ; } } // se tutti i triangoli a distanza minima sono perpendicolari, allora non lo inserisco bInsert = ( ! bPerp) ; } } // se triangolo da inserire if ( bInsert) vTriaSafe.emplace_back( Tria) ; #if DEBUG ICurveComposite* pCompo = CreateCurveComposite() ; pCompo->AddPoint( Tria.GetP( 0)) ; pCompo->AddLine( Tria.GetP( 1)) ; pCompo->AddLine( Tria.GetP( 2)) ; pCompo->Close() ; Color myCol = ( bInsert ? Color( 0., 1., 0., .5) : Color( 1., 0., 0., .5)) ; VT.emplace_back( CloneCurveComposite( pCompo)) ; VC.emplace_back( myCol) ; ISurfFlatRegion* pSfrTria = CreateSurfFlatRegion() ; pSfrTria->AddExtLoop( pCompo) ; VT.emplace_back( pSfrTria) ; VC.emplace_back( myCol) ; #endif } // inserisco tutti i triangoli validi if ( ! pStm->AddTriaFromZMap( vTriaSafe, VertGrid)) return nullptr ; } #if DEBUG SaveGeoObj( VT, VC, "C:\\Temp\\TriangleSelection.nge") ; #endif // sistemo la topologia if ( ! pStm->AdjustTopologyFromZMap()) return nullptr ; return ( Release( pStm)) ; } //---------------------------------------------------------------------------- //* Funzione che crea il Fat Offset di un insieme di superfici //---------------------------------------------------------------------------- ISurfTriMesh* CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) { // se vettore delle superfici vuoto, non faccio nulla if ( vStm.empty()) return nullptr ; // controllo sul valore di tolleranza lineare double dMyPrec = max( dPrec, 100 * EPS_SMALL) ; // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto) // Nel caso sia minore, restituisco semplicemente la somma delle superfici // ( questo valore serve per rimanere coerente con l'Offset delle curve) if ( abs( dOffs) < 10 * EPS_SMALL) return SumStm( vStm) ; // creo lo Zmap associato alle superfici TriMesh VolZmap OneVolZmap ; if ( ! OneVolZmap.CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyPrec, nType)) return nullptr ; if ( ! OneVolZmap.IsValid()) return nullptr ; // restituisco la superficie TriMesh return ( OneVolZmap.GetSurfTriMesh()) ; }