From 121abf5864e2f12b9edbd2220cb61127f87ed050 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Wed, 26 Jun 2024 08:41:57 +0200 Subject: [PATCH] EgtGeomKernel 2.6f4 : - miglioramenti alla gestione di shell e part nelle superfici Trimesh. --- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes SurfTriMesh.cpp | 609 +++++++++++++++++++++++++--------------- SurfTriMesh.h | 44 ++- SurfTriMeshBooleans.cpp | 33 --- 4 files changed, 412 insertions(+), 274 deletions(-) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 1a6ea85b8348f36ec332b24c794bf4c8266f8cb9..a41876e3ede8db5fb6592c083bf40655f7003380 100644 GIT binary patch delta 94 zcmdlNy)SyhFE&P#&A-_cnHfzcD{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-WjGrO delta 94 zcmdlNy)SyhFE&Qw&A-_cnHh~ID{|{@_Trkr0u;H;XNwSVW8B;$>;>dw2zN+>g;Df- LFmBFL4&ed-W11TR diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index b400e3a..c7dabd0 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -33,8 +33,8 @@ #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EgtPointerOwner.h" -#include #include +#include using namespace std ; @@ -46,7 +46,7 @@ SurfTriMesh::SurfTriMesh( void) : m_nStatus( TO_VERIFY), m_dLinTol( STM_STD_LIN_TOL), m_dBoundaryAng( STM_STD_BOUNDARY_ANG), m_dSmoothAng( STM_STD_SMOOTH_ANG), m_bShowEdges( false), m_bOriented( false), m_bClosed( false), m_bFaceted( false), m_bFacEdged( false), m_nTimeStamp( 0), m_nTempProp{0,0}, m_dTempParam{0,0}, - m_nMaxTFlag( 0), m_nParts( -1), m_nShells( -1), m_pHGrd3d( nullptr) + m_nMaxTFlag( 0), m_nShells( -1), m_pHGrd3d( nullptr) { m_dCosBndAng = cos( m_dBoundaryAng * DEGTORAD) ; m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ; @@ -85,8 +85,8 @@ SurfTriMesh::Init( int nNumVert, int nNumTria, int nNumFacet) m_nStatus = OK ; m_bClosed = false ; m_nMaxTFlag = 0 ; - m_nParts = -1 ; m_nShells = -1 ; + m_vPart.clear() ; return true ; } @@ -117,8 +117,8 @@ SurfTriMesh::Clear( void) m_dTempParam[0] = 0 ; m_dTempParam[1] = 0 ; m_nMaxTFlag = 0 ; - m_nParts = -1 ; m_nShells = -1 ; + m_vPart.clear() ; return true ; } @@ -128,8 +128,8 @@ SurfTriMesh::AddVertex( const Point3d& ptVert, double dU, double dV) { // imposto ricalcolo m_nStatus = TO_VERIFY ; - m_nParts = - 1 ; m_nShells = -1 ; + m_vPart.clear() ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; // inserisco il vertice @@ -160,8 +160,8 @@ SurfTriMesh::MoveVertex( int nInd, const Point3d& ptNewVert) m_vVert[nInd].ptP = ptNewVert ; // imposto ricalcolo m_nStatus = TO_VERIFY ; - m_nParts = - 1 ; m_nShells = - 1 ; + m_vPart.clear() ; m_bFaceted = false ; m_bFacEdged = false ; m_OGrMgr.Reset() ; @@ -230,8 +230,8 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag) return SVT_DEL ; // imposto ricalcolo m_nStatus = TO_VERIFY ; - m_nParts = - 1 ; m_nShells = -1 ; + m_vPart.clear() ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; // inserisco il triangolo @@ -322,8 +322,8 @@ SurfTriMesh::RemoveTriangle( int nId) m_bFaceted = false ; m_bFacEdged = false ; // invalido calcolo connettività - m_nParts = - 1 ; m_nShells = -1 ; + m_vPart.clear() ; return true ; } @@ -912,8 +912,6 @@ SurfTriMesh::CloneTriangle( int nT) const pSurfTM->m_dCosBndAng = m_dCosBndAng ; pSurfTM->m_dSmoothAng = m_dSmoothAng ; pSurfTM->m_dCosSmAng = m_dCosSmAng ; - pSurfTM->m_nParts = 1 ; - pSurfTM->m_nShells = 1 ; // Copio il triangolo int nNewInd[3] = { pSurfTM->AddVertex( m_vVert[m_vTria[nT].nIdVert[0]].ptP), @@ -1311,8 +1309,8 @@ SurfTriMesh::CopyFrom( const SurfTriMesh& stmSrc) m_nTempProp[0] = stmSrc.m_nTempProp[0] ; m_nTempProp[1] = stmSrc.m_nTempProp[1] ; m_nMaxTFlag = stmSrc.m_nMaxTFlag ; - m_nParts = stmSrc.m_nParts ; m_nShells = stmSrc.m_nShells ; + m_vPart = stmSrc.m_vPart ; m_dTempParam[0] = stmSrc.m_dTempParam[0] ; m_dTempParam[1] = stmSrc.m_dTempParam[1] ; return true ; @@ -1350,12 +1348,10 @@ SurfTriMesh::Dump( string& sOut, bool bMM, const char* szNewLine) const // segnalo eventuale incongruenza di orientamento if ( ! m_bOriented) sOut += string( "Inconsistent Orientation") + szNewLine ; - // segnalo numero di parti + // segnalo numero di parti e di gusci int nParts = GetPartCount() ; - sOut += string( "Parts=") + ToString( nParts) + szNewLine ; - // segnalo numero di gusci int nShells = GetShellCount() ; - sOut += string( "Shells=") + ToString( nShells) + szNewLine ; + sOut += string( "Parts=") + ToString( nParts) + string( " Shells=") + ToString( nShells) + szNewLine ; // numero di vertici sOut += "Vert : Nbr=" + ToString( GetVertexCount()) + " Size=" + ToString( GetVertexSize()) + szNewLine ; @@ -1465,8 +1461,8 @@ SurfTriMesh::Load( NgeReader& ngeIn) // imposto ricalcolo della grafica, della connessione e di hashgrids3d m_OGrMgr.Clear() ; m_nMaxTFlag = 0 ; - m_nParts = -1 ; m_nShells = -1 ; + m_vPart.clear() ; ResetHashGrids3d() ; // leggo la prossima linea ( 2 parametri : dLinTol e dSmoothAng) // tolleranza lineare di costruzione @@ -1626,8 +1622,8 @@ SurfTriMesh::Validate( bool bCorrect) } // invalido calcolo connessione - m_nParts = - 1 ; m_nShells = -1 ; + m_vPart.clear() ; return ( m_nStatus == OK) ; } @@ -1902,8 +1898,8 @@ SurfTriMesh::AdjustTopology( void) m_bFaceted = false ; m_bFacEdged = false ; // invalido calcolo connessione - m_nParts = - 1 ; m_nShells = - 1 ; + m_vPart.clear() ; // verifica indici if ( ! Validate( true)) return false ; @@ -3572,7 +3568,10 @@ SurfTriMesh::Invert( void) if ( m_nStatus != OK) return false ; - // imposto ricalcolo della grafica e di hashgrids3d + // imposto ricalcolo numero delle parti (le shell non cambiano) + m_vPart.clear() ; + + // imposto ricalcolo della grafica e di hashgrids3d m_OGrMgr.Reset() ; ResetHashGrids3d() ; @@ -3645,14 +3644,187 @@ SurfTriMesh::GetAllTriaBox( void) const } //---------------------------------------------------------------------------- -int -SurfTriMesh::GetPartCount( void) const +bool +SurfTriMesh::VerifyConnection( bool bShellsAndParts) const { if ( ! IsValid()) - return 0 ; - if ( m_nParts == - 1 && ! VerifyConnection()) - return 0 ; - return m_nParts ; + return false ; + + // se non sono già note le shell + if ( m_nShells == -1) { + // reset connessione + for ( auto& Tria : m_vTria) + Tria.nShell = SVT_NULL ; + // ciclo sui triangoli per determinare le shells + m_nShells = 0 ; + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + // salto triangoli cancellati o già assegnati + if ( m_vTria[i].nIdVert[0] == SVT_DEL || + m_vTria[i].nShell != SVT_NULL) + continue ; + // assegno indice di shell connessa al triangolo + m_vTria[i].nShell = m_nShells ; + ++ m_nShells ; + // set di triangoli da aggiornare + set stTria ; + stTria.insert( i) ; + while ( ! stTria.empty()) { + // tolgo un triangolo dal set + const auto iIt = stTria.begin() ; + int nT = *iIt ; + stTria.erase( iIt) ; + // aggiorno i triangoli adiacenti + for ( int j = 0 ; j < 3 ; ++ j) { + int nAdjT = m_vTria[nT].nIdAdjac[j] ; + if ( nAdjT != SVT_NULL && m_vTria[nAdjT].nShell == SVT_NULL) { + m_vTria[nAdjT].nShell = m_vTria[nT].nShell ; + stTria.insert( nAdjT) ; + } + } + } + } + } + + // reset delle parti + m_vPart.clear() ; + + // se richiesta solo la determinazione delle shell, esco + if ( ! bShellsAndParts) + return true ; + + // Se superficie vuota, allora non ho parti + if ( m_nShells == 0) + return true ; + + // Se ho solo una shell, allora ho una sola parte + if ( m_nShells == 1) { + m_vPart.emplace_back( m_bClosed, INTVECTOR{ 0}) ; + return true ; + } + + // Ho più shell devo controllare la loro posizione relativa + struct SHELLINFO { + SHELLINFO( int nI, double dVol, const BBox3d& b3B, ISurfTriMesh* pStm) + : nInd( nI), dVolume( dVol), b3Box( b3B), pStmShell( pStm) {} + int nInd ; + double dVolume ; + BBox3d b3Box ; + PtrOwner pStmShell ; + } ; + vector vOuterShells ; + vector vInnerShells ; + INTVECTOR vOpenShells ; + for ( int nSh = 0 ; nSh < m_nShells ; ++ nSh) { + // se la shell è chiusa + if ( IsShellClosed( nSh)) { + // creo una superficie clonata dalla shell + PtrOwner pStmShell( CloneShell( nSh)) ; + if ( IsNull( pStmShell) || ! pStmShell->IsValid()) + return false ; + // ne calcolo il volume (con segno) + double dVol = 0. ; + pStmShell->GetVolume( dVol) ; + // ne calcolo il bounding box + BBox3d b3Box ; + pStmShell->GetLocalBBox( b3Box, BBF_STANDARD) ; + // la inserisco nel vettore opportuno + if ( dVol > 0) + vOuterShells.emplace_back( nSh, dVol, b3Box, Release( pStmShell)) ; + else + vInnerShells.emplace_back( nSh, dVol, b3Box, Release( pStmShell)) ; + } + // altrimenti aperta + else { + // la inserisco nel vettore delle shell aperte + vOpenShells.push_back( nSh) ; + } + } + + // ordino il vettore delle shell esterne in senso crescente di volume (crescenti anche in valore assoluto) + sort( vOuterShells.begin(), vOuterShells.end(), + []( const SHELLINFO& a, const SHELLINFO& b) { + return ( a.dVolume < b.dVolume) ; + }) ; + // ordino il vettore delle shell interne in senso crescente di volume (decrescenti in valore assoluto) + sort( vInnerShells.begin(), vInnerShells.end(), + []( const SHELLINFO& a, const SHELLINFO& b) { + return ( a.dVolume < b.dVolume) ; + }) ; + + // classifico le shell esterne + for ( int i = 0 ; i < int( vOuterShells.size()) ; ++ i) { + // inserisco nel vettore delle parti + m_vPart.emplace_back( true, INTVECTOR{ vOuterShells[i].nInd}) ; + // cerco eventuali interne che vi appartengono + CISURFTMPVECTOR vStmTest{ vOuterShells[i].pStmShell} ; + for ( int j = 0 ; j < int( vInnerShells.size()) ; ++ j) { + // se libera e il box è incluso, verifico se realmente interna + if ( vInnerShells[j].nInd >= 0 && vOuterShells[i].b3Box.Encloses( vInnerShells[j].b3Box)) { + Point3d ptCheck ; + vInnerShells[j].pStmShell->GetFirstVertex( ptCheck) ; + bool bIsInside = true ; + for ( const auto& pStmTest : vStmTest) { + BBox3d b3Test = pStmTest->GetAllTriaBox() ; + if ( b3Test.Overlaps( vInnerShells[j].b3Box)) { + DistPointSurfTm distCalculator( ptCheck, *pStmTest) ; + if ( ! distCalculator.IsPointInside()) { + bIsInside = false ; + break ; + } + } + } + if ( bIsInside) { + m_vPart.back().vShell.push_back( vInnerShells[j].nInd) ; + vInnerShells[j].nInd = -1 ; + vStmTest.push_back( vInnerShells[j].pStmShell) ; + } + } + } + } + + // classifico le shell interne rimaste libere + bool bNewInner = true ; + CISURFTMPVECTOR vStmTest ; + for ( int i = 0 ; i < int( vInnerShells.size()) ; ++ i) { + if ( vInnerShells[i].nInd >= 0) { + // se non è nuova interna verifico sia interna alle altre correnti + if ( ! bNewInner) { + bool bIsInside = true ; + Point3d ptCheck ; + vInnerShells[i].pStmShell->GetFirstVertex( ptCheck) ; + // se il box interferisce con altri, verifico se realmente interna + for ( const auto& pStmTest : vStmTest) { + BBox3d b3Test = pStmTest->GetAllTriaBox() ; + if ( b3Test.Overlaps( vInnerShells[i].b3Box)) { + DistPointSurfTm distCalculator( ptCheck, *pStmTest) ; + if ( ! distCalculator.IsPointInside()) { + bIsInside = false ; + break ; + } + } + } + if ( bIsInside) + m_vPart.back().vShell.push_back( vInnerShells[i].nInd) ; + else + bNewInner = true ; + } + // se nuova interna + if ( bNewInner) { + bNewInner = false ; + m_vPart.emplace_back( true, INTVECTOR{ -1, vInnerShells[i].nInd}) ; + vStmTest.clear() ; + } + vInnerShells[i].nInd = -1 ; + vStmTest.push_back( vInnerShells[i].pStmShell) ; + } + } + + // aggiungo all'elenco delle parti le shell aperte + for ( int i = 0 ; i < int( vOpenShells.size()) ; ++ i) { + m_vPart.emplace_back( false, INTVECTOR{ vOpenShells[i]}) ; + } + + return true ; } //---------------------------------------------------------------------------- @@ -3661,209 +3833,67 @@ SurfTriMesh::GetShellCount( void) const { if ( ! IsValid()) return 0 ; - if ( m_nShells == - 1 && ! VerifyConnection()) + if ( m_nShells == -1 && ! VerifyConnection()) return 0 ; return m_nShells ; } //---------------------------------------------------------------------------- bool -SurfTriMesh::VerifyConnection( void) const +SurfTriMesh::GetShellArea( int nShell, double& dArea) const { + // Controllo parametro di ritorno + if ( &dArea == nullptr) + return false ; + // Imposto area nulla + dArea = 0 ; + // Verifiche sull'oggetto if ( ! IsValid()) return false ; - - // reset connessione - for ( auto& Tria : m_vTria) { - Tria.nPart = SVT_NULL ; - Tria.nShell = SVT_NULL ; + if ( m_nShells == -1 && ! VerifyConnection()) + return false ; + // Se la componente non esiste, errore + if ( nShell < 0 || nShell >= m_nShells) + return false ; + // sommo l'area di tutti i triangoli della shell + Triangle3d Tria ; + int nId = GetFirstTriangle( Tria) ; + while ( nId != SVT_NULL) { + if ( m_vTria[nId].nShell == nShell) + dArea += Tria.GetArea() ; + nId = GetNextTriangle( nId, Tria) ; } - - // ciclo sui triangoli per determinare le shells - m_nShells = 0 ; - for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { - // salto triangoli cancellati o già assegnati - if ( m_vTria[i].nIdVert[0] == SVT_DEL || - m_vTria[i].nShell != SVT_NULL) - continue ; - // assegno indice di parte connessa al triangolo - m_vTria[i].nShell = m_nShells ; - ++ m_nShells ; - // set di triangoli da aggiornare - set stTria ; - stTria.insert( i) ; - while ( ! stTria.empty()) { - // tolgo un triangolo dal set - const auto iIt = stTria.begin() ; - int nT = *iIt ; - stTria.erase( iIt) ; - // aggiorno i triangoli adiacenti - for ( int j = 0 ; j < 3 ; ++ j) { - int nAdjT = m_vTria[nT].nIdAdjac[j] ; - if ( nAdjT != SVT_NULL && m_vTria[nAdjT].nShell == SVT_NULL) { - m_vTria[nAdjT].nShell = m_vTria[nT].nShell ; - stTria.insert( nAdjT) ; - } - } - } - } - - // identifico le parti - m_nParts = 0 ; - if ( m_nShells == 1) { // se ho solo una shell allora ho una sola parte - m_nParts = 1 ; - for ( auto& Tria : m_vTria) - Tria.nPart = Tria.nShell ; - } - else { // se ho più shells devo controllare la loro posizione - // salvo solo le Shells chiuse e per ognuna di esse il loro volume e l'indice della shell - // < stmShell, ( nShellInd, dVol) > - // NB. I Volumi sono sempre finiti, il segno del volume mi dice solo se sto considerando - // la parte interna o esterna della superficie - typedef pair, pair> SHELLINFO ; - vector vClosedShells ; - vClosedShells.reserve( m_nShells) ; - INTVECTOR vOpenShells ; // vettore di indici di Shell aperte - for ( int s = 0 ; s < GetShellCount() ; ++ s) { - // recupero la Shell - PtrOwner pStmShell( CloneShell( s)) ; - if ( IsNull( pStmShell) || ! pStmShell->IsValid()) - return false ; - double dVol = 0. ; - // se chiusa calcolo il suo volume con segno - if ( pStmShell->IsClosed()) { - pStmShell->GetVolume( dVol) ; - vClosedShells.emplace_back( make_pair( Release( pStmShell), make_pair( s, dVol))) ; - } - // se aperta, non rientra nella classficazione ( sarà coincidente ad una Part) - else - vOpenShells.push_back( s) ; - } - - // ordino il vettore in senso decrescente per volume, in valore assoluto - // NB. tutte le shell con volume negativo sono state invertite ! - sort( vClosedShells.begin(), vClosedShells.end(), - []( const SHELLINFO& a, const SHELLINFO& b) { - return abs( a.second.second) > abs( b.second.second) ; - }) ; - - // se la superficie in prima posizione è negativa, allora le inverto tutte; il numero di - // Parts non cambia nel conto - if ( ! vClosedShells.empty() && vClosedShells.front().second.second < - EPS_SMALL) - for ( auto& Shell : vClosedShells) - Shell.first->Invert() ; - - // creo una matrice di interi ; ogni riga corrisponde ad una Parte, dove in posizione 0 c'è - // la shell esterna e nelle successive le rispettiva shells interne - INTMATRIX vnShellIndMat ; - - bool bFirstShell ; // flag per indicare se la shell corrente è esterna - int nIndExtShell = -1 ; // indice del vettore di shell chiuse della shell esterna - INTVECTOR vIndIntShells ; // vettore di indici di shell chiuse interne alla shell esterna corrente - do { - bFirstShell = true ; - for ( int i = 0 ; i < int( vClosedShells.size()) ; ++ i) { - // recupero l'indice della shell e verifico che sia valido - int j = vClosedShells[i].second.first ; - if ( j < 0) - continue ; - // lo inserisco come esterno... - if ( bFirstShell) { - vnShellIndMat.push_back({ j}) ; - vClosedShells[i].second.first = -1 ; - bFirstShell = false ; - nIndExtShell = i ; - vIndIntShells.clear() ; - } - // altrimento verifico se la shell è interna o no - else { - // la shell è interna se è sia interna alla shell esterna corrente ( della riga di - // vnShellIndMat ) e allo stesso tempo esterna a tutte le shell già inserite nella riga - // attuale. - Point3d ptCheck ; - vClosedShells[i].first->GetFirstVertex( ptCheck) ; - - // 1) verifica rispetto alla shell esterna - DistPointSurfTm distCalculator( ptCheck, *vClosedShells[nIndExtShell].first) ; - if ( ! distCalculator.IsPointInside()) - continue ; - - // 2) verifica rispetto a tutte la shell già trovate interne - bool bOk = true ; - for ( int k = 1 ; k < int( vIndIntShells.size()) ; ++ k) { - DistPointSurfTm distCalculator( ptCheck, *vClosedShells[vIndIntShells[k]].first) ; - // NB. tutte le shell hanno volume negativo ! - if ( ! distCalculator.IsPointInside()) { - bOk = false ; - break ; - } - } - if ( bOk) { - // inserisco nella matrice - vnShellIndMat.back().push_back( j) ; - vClosedShells[i].second.first = - 1 ; - vIndIntShells.push_back( i) ; - } - } - } - } while ( ! bFirstShell) ; - - // scorro le righe della matrice e assegno la Part ( ovvero la riga ) - int nPart = 0 ; - for ( nPart = 0 ; nPart < int( vnShellIndMat.size()) ; ++ nPart) { - ++ m_nParts ; - for ( int j = 0 ; j < int( vnShellIndMat[nPart].size()) ; ++ j) { - for ( auto& Tria : m_vTria) { - if ( Tria.nShell == j) - Tria.nPart = nPart ; - } - } - } - - // per tutte le superfici aperte, assegno loro una Parte - for ( int i = 0 ; i < int( vOpenShells.size()) ; ++ i) { - ++ m_nParts ; - for ( auto& Tria : m_vTria) { - if ( Tria.nShell == i) - Tria.nPart = i + ( nPart ++ ) ; - } - } - - } - return true ; } //---------------------------------------------------------------------------- -bool -SurfTriMesh::RemovePart( int nPart) +bool +SurfTriMesh::IsShellClosed( int nShell) const { + // Verifiche sull'oggetto if ( ! IsValid()) return false ; - - // Il numero delle componenti deve essere maggiore di zero o calcolabile - if ( m_nParts == -1 && ! VerifyConnection()) + if ( m_nShells == -1 && ! VerifyConnection( false)) return false ; - // Se la componente non esiste, errore - if ( m_nParts <= 0 || nPart < 0 || nPart >= m_nParts) + if ( nShell < 0 || nShell >= m_nShells) return false ; - - int nPartsOld = m_nParts ; - // Rimuovo i triangoli della componente nPart - for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { - if ( m_vTria[i].nPart == nPart) - RemoveTriangle( i) ; + // ciclo sui triangoli della shell + bool bClosed = true ; + for ( int i = 0 ; i < GetTriangleSize() ; ++ i) { + // se triangolo non cancellato e della shell + if ( m_vTria[i].nIdVert[0] != SVT_DEL && m_vTria[i].nShell == nShell) { + // verifico le adiacenze + if ( m_vTria[i].nIdAdjac[0] == SVT_NULL || + m_vTria[i].nIdAdjac[1] == SVT_NULL || + m_vTria[i].nIdAdjac[2] == SVT_NULL) { + bClosed = false ; + break ; + } + } } - - // Aggiorno il numero di componenti - m_nParts = nPartsOld - 1 ; - - // imposto ricalcolo della grafica e di hashgrids3d - m_OGrMgr.Reset() ; - ResetHashGrids3d() ; - - return true ; + // restituisco il risultato + return bClosed ; } //---------------------------------------------------------------------------- @@ -3878,18 +3908,18 @@ SurfTriMesh::RemoveShell( int nShell) return false ; // Se la componente non esiste, errore - if ( m_nShells <= 0 || nShell < 0 || nShell >= m_nShells) + if ( nShell < 0 || nShell >= m_nShells) return false ; - int nShellsOld = m_nShells ; - // Rimuovo i triangoli della componente nPart + int nOldShells = m_nShells ; + // Rimuovo i triangoli della componente nShell for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { if ( m_vTria[i].nShell == nShell) RemoveTriangle( i) ; } - // Aggiorno il numero di componenti - m_nShells = nShellsOld - 1 ; + // Aggiorno il numero di shell + m_nShells = nOldShells - 1 ; // imposto ricalcolo della grafica e di hashgrids3d m_OGrMgr.Reset() ; @@ -3899,18 +3929,18 @@ SurfTriMesh::RemoveShell( int nShell) } //---------------------------------------------------------------------------- -SurfTriMesh* -SurfTriMesh::ClonePart( int nPart) const +SurfTriMesh* +SurfTriMesh::CloneShell( int nShell) const { if ( ! IsValid()) return nullptr ; // Il numero delle componenti deve essere maggiore di zero o calcolabile - if ( m_nParts == -1 && ! VerifyConnection()) + if ( m_nShells == -1 && ! VerifyConnection()) return nullptr ; // Se la componente non esiste, errore - if ( m_nParts <= 0 || nPart < 0 || nPart >= m_nParts) + if ( nShell < 0 || nShell >= m_nShells) return nullptr ; // Creo nuovo oggetto SurfTriMesh @@ -3924,12 +3954,10 @@ SurfTriMesh::ClonePart( int nPart) const pSurfTM->m_dCosBndAng = m_dCosBndAng ; pSurfTM->m_dSmoothAng = m_dSmoothAng ; pSurfTM->m_dCosSmAng = m_dCosSmAng ; - pSurfTM->m_nParts = 1 ; - pSurfTM->m_nShells = 1 ; // Copio i triangoli for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { - if ( m_vTria[i].nIdVert[0] != SVT_DEL && m_vTria[i].nPart == nPart) { + if ( m_vTria[i].nIdVert[0] != SVT_DEL && m_vTria[i].nShell == nShell) { int nNewInd[3] = { pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[0]].ptP), pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[1]].ptP), pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[2]].ptP)} ; @@ -3946,18 +3974,143 @@ SurfTriMesh::ClonePart( int nPart) const } //---------------------------------------------------------------------------- -SurfTriMesh* -SurfTriMesh::CloneShell( int nShell) const +int +SurfTriMesh::GetPartCount( void) const +{ + if ( ! IsValid()) + return 0 ; + if ( m_vPart.empty() && ! VerifyConnection()) + return 0 ; + return int( m_vPart.size()) ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartArea( int nPart, double& dArea) const +{ + // Controllo parametro di ritorno + if ( &dArea == nullptr) + return false ; + // Imposto area nulla + dArea = 0 ; + // Verifiche sull'oggetto + if ( ! IsValid()) + return false ; + if ( m_vPart.empty() && ! VerifyConnection()) + return false ; + // Se la componente non esiste, errore + if ( nPart < 0 || nPart >= int( m_vPart.size())) + return false ; + // sommo l'area di tutti i triangoli della parte + Triangle3d Tria ; + int nId = GetFirstTriangle( Tria) ; + while ( nId != SVT_NULL) { + const auto& vShell = m_vPart[nPart].vShell ; + if ( find( vShell.begin(), vShell.end(), m_vTria[nId].nShell) != vShell.end()) + dArea += Tria.GetArea() ; + nId = GetNextTriangle( nId, Tria) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::IsPartClosed( int nPart) const +{ + // Verifiche sull'oggetto + if ( ! IsValid()) + return false ; + if ( m_vPart.empty() && ! VerifyConnection()) + return false ; + // Se la componente non esiste, errore + if ( nPart < 0 || nPart >= int( m_vPart.size())) + return false ; + return m_vPart[nPart].bClosed ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartVolume( int nPart, double& dVolume) const +{ + // Controllo parametro di ritorno + if ( &dVolume == nullptr) + return false ; + // Imposto volume nullo + dVolume = 0 ; + // Verifiche sull'oggetto + if ( ! IsValid()) + return false ; + if ( m_vPart.empty() && ! VerifyConnection()) + return false ; + // Se la componente non esiste, errore + if ( nPart < 0 || nPart >= int( m_vPart.size())) + return false ; + // la parte deve essere chiusa + if ( ! m_vPart[nPart].bClosed) + return true ; + // sommo il volume con segno di tutte le piramidi della parte dall'origine ad ogni faccia + Triangle3d Tria ; + int nId = GetFirstTriangle( Tria) ; + while ( nId != SVT_NULL) { + const auto& vShell = m_vPart[nPart].vShell ; + if ( find( vShell.begin(), vShell.end(), m_vTria[nId].nShell) != vShell.end()) { + Vector3d vtA = ( Tria.GetP( 1) - Tria.GetP( 0)) ^ ( Tria.GetP( 2) - Tria.GetP( 0)) ; + dVolume += ( Tria.GetP( 0) - ORIG) * vtA ; + } + nId = GetNextTriangle( nId, Tria) ; + } + dVolume /= 6 ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::RemovePart( int nPart) +{ + if ( ! IsValid()) + return false ; + + // Il numero delle componenti deve essere maggiore di zero o calcolabile + if ( m_vPart.empty() && ! VerifyConnection()) + return false ; + + // Se la componente non esiste, errore + if ( nPart < 0 || nPart >= int( m_vPart.size())) + return false ; + + int nOldShells = m_nShells ; + // Rimuovo i triangoli della componente nPart (ovvero delle sue shell) + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + const auto& vShell = m_vPart[nPart].vShell ; + if ( find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { + RemoveTriangle( i) ; + } + } + + // Aggiorno il numero di componenti + m_nShells = nOldShells - m_vPart[nPart].GetShellCount() ; + m_vPart.erase( m_vPart.begin() + nPart) ; + + // imposto ricalcolo della grafica e di hashgrids3d + m_OGrMgr.Reset() ; + ResetHashGrids3d() ; + + return true ; +} + +//---------------------------------------------------------------------------- +SurfTriMesh* +SurfTriMesh::ClonePart( int nPart) const { if ( ! IsValid()) return nullptr ; - // Il numero delle componenti deve essere maggiore di zero o calcolabile - if ( m_nShells == -1 && ! VerifyConnection()) + // Il numero delle parti deve essere maggiore di zero o calcolabile + if ( m_vPart.empty() && ! VerifyConnection()) return nullptr ; - // Se la componente non esiste, errore - if ( m_nShells <= 0 || nShell < 0 || nShell >= m_nShells) + // Se la parte non esiste, errore + if ( nPart < 0 || nPart >= int( m_vPart.size())) return nullptr ; // Creo nuovo oggetto SurfTriMesh @@ -3971,12 +4124,12 @@ SurfTriMesh::CloneShell( int nShell) const pSurfTM->m_dCosBndAng = m_dCosBndAng ; pSurfTM->m_dSmoothAng = m_dSmoothAng ; pSurfTM->m_dCosSmAng = m_dCosSmAng ; - pSurfTM->m_nParts = 1 ; - pSurfTM->m_nShells = 1 ; // Copio i triangoli for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { - if ( m_vTria[i].nIdVert[0] != SVT_DEL && m_vTria[i].nShell == nShell) { + const auto& vShell = m_vPart[nPart].vShell ; + if ( m_vTria[i].nIdVert[0] != SVT_DEL && + find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { int nNewInd[3] = { pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[0]].ptP), pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[1]].ptP), pSurfTM->AddVertex( m_vVert[m_vTria[i].nIdVert[2]].ptP)} ; diff --git a/SurfTriMesh.h b/SurfTriMesh.h index b601646..5b3c803 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -52,16 +52,16 @@ class StmTria public : StmTria( void) : nIdVert{ SVT_NULL, SVT_NULL, SVT_NULL}, nIdAdjac{ SVT_NULL, SVT_NULL, SVT_NULL}, nETempFlag{ 0, 0, 0}, - vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nShell( SVT_NULL), nPart( SVT_NULL), nTemp( 0), nTempShell{ 0}, nTempPart{ 0} {} + vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nShell( SVT_NULL), nTemp( 0), nTempShell{ 0} {} StmTria( const int nIdV[3]) : nIdVert{ nIdV[0], nIdV[1], nIdV[2]}, nIdAdjac{ SVT_NULL, SVT_NULL, SVT_NULL}, nETempFlag{ 0, 0, 0}, - vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nShell( SVT_NULL), nPart( SVT_NULL), nTemp( 0), nTempShell{ 0}, nTempPart{ 0} {} + vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nShell( SVT_NULL), nTemp( 0), nTempShell{ 0} {} StmTria( const int nIdV[3], int nTF) : nIdVert{ nIdV[0], nIdV[1], nIdV[2]}, nIdAdjac{ SVT_NULL, SVT_NULL, SVT_NULL}, nETempFlag{ 0, 0, 0}, - vtN(), nIdFacet( SVT_NULL), nTFlag( nTF), nEFlag( 0), nShell( SVT_NULL), nPart( SVT_NULL), nTemp( 0), nTempShell{ 0}, nTempPart{ 0} {} + vtN(), nIdFacet( SVT_NULL), nTFlag( nTF), nEFlag( 0), nShell( SVT_NULL), nTemp( 0), nTempShell{ 0} {} StmTria( const int nIdV[3], const int nIdA[3], const Vector3d& vtV, int nTF, int nEF) : nIdVert{ nIdV[0], nIdV[1], nIdV[2]}, nIdAdjac{ nIdA[0], nIdA[1], nIdA[2]}, nETempFlag{ 0, 0, 0}, - vtN( vtV), nIdFacet( SVT_NULL), nTFlag( nTF), nEFlag( nEF), nShell( SVT_NULL), nPart( SVT_NULL), nTemp( 0), nTempShell{ 0}, nTempPart{ 0} {} + vtN( vtV), nIdFacet( SVT_NULL), nTFlag( nTF), nEFlag( nEF), nShell( SVT_NULL), nTemp( 0), nTempShell{ 0} {} public : int nIdVert[3] ; int nIdAdjac[3] ; @@ -71,11 +71,24 @@ class StmTria int nTFlag ; int nEFlag ; mutable int nShell ; - mutable int nPart ; mutable int nTemp ; mutable int nTempShell ; - mutable int nTempPart ; +} ; +//---------------------------------------------------------------------------- +// Classe Part +class StmPart +{ + public : + StmPart( void) + : bClosed( false) {} + StmPart( bool bClo, const INTVECTOR& vSh) + : bClosed( bClo), vShell( vSh) {} + int GetShellCount( void) + { return ( vShell.empty() ? 0 : int( vShell.size()) - ( vShell[0] == -1 ? 1 : 0)) ; } + public : + bool bClosed ; + INTVECTOR vShell ; } ; //---------------------------------------------------------------------------- @@ -319,12 +332,15 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool Repair( double dMaxEdgeLen = MAX_EDGE_LEN_STD) override ; bool GetAllTriaOverlapBox( const BBox3d& b3Box, INTVECTOR& vT) const override ; const BBox3d& GetAllTriaBox( void) const override ; - int GetPartCount( void) const override ; - int GetShellCount( void) const override ; - bool RemovePart( int nPart) override ; + int GetShellCount( void) const override ; + bool GetShellArea( int nShell, double& dArea) const override ; bool RemoveShell( int nShell) override ; - SurfTriMesh* ClonePart( int nPart) const override ; SurfTriMesh* CloneShell( int nShell) const override ; + int GetPartCount( void) const override ; + bool RemovePart( int nPart) override ; + bool GetPartArea( int nPart, double& dArea) const override ; + bool GetPartVolume( int nPart, double& dVolume) const override ; + SurfTriMesh* ClonePart( int nPart) const override ; bool SetTFlag( int nId, int nTFlag) override ; bool GetTFlag( int nId, int& nFlag) const override ; int GetMaxTFlag( void) const override @@ -359,6 +375,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW private : typedef std::vector VERTVECTOR ; typedef std::vector TRIAVECTOR ; + typedef std::vector PARTVECTOR ; typedef std::vector FACEDGEVECTOR ; typedef std::deque TRINTDEQUE ; @@ -403,14 +420,15 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool UpdateFacetEdging( void) ; void ResetHashGrids3d( void) const ; bool VerifyHashGrids3d( void) const ; - bool VerifyConnection( void) const ; + bool VerifyConnection( bool bShellsAndParts = true) const ; + bool IsShellClosed( int nShell) const ; + bool IsPartClosed( int nPart) const ; bool CutTriangleByPlane( int nTriaId, const Plane3d& plPlane, bool bSaveOnEq, bool& bModif) ; bool CutByTriangles( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif) ; bool DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMATRIX& cvBoundClosedLoopVec, BOOLVECTOR& vbInOut) ; bool RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Surf, bool& bModif) ; bool AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Surf) ; bool IntersectTriMeshTriangle( SurfTriMesh& Other) ; - bool IdentifyParts( void) const ; bool IdentifyShells( void) const ; bool RemoveDoubleTriangles( bool& bModified) ; bool RemoveTJunctions( bool& bModified) ; @@ -442,8 +460,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW int m_nTempProp[2] ; // vettore proprietà temporanee double m_dTempParam[2] ; // vettore parametri temporanei int m_nMaxTFlag ; // massimo valore dei TFlag dei triangoli - mutable int m_nParts ; // numero di parti intese come volumi (-1 se da calcolare) mutable int m_nShells ; // numero di gusci connessi (-1 se da calcolare) + mutable PARTVECTOR m_vPart ; // vettore delle parti (flag chiusura e elenco shell, prima sempre esterna o infinita) mutable HashGrids3d* m_pHGrd3d ; // Hash Grid 3d nel suo riferimento mutable BBox3d m_b3HGrd3d ; // Box3d collegato a Hash Grid 3d } ; diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index 2a0a975..c8a2e8c 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -1403,39 +1403,6 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) return true ; } -//---------------------------------------------------------------------------- -bool -SurfTriMesh::IdentifyParts( void) const -{ - for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { - // salto triangoli cancellati o già assegnati - if ( m_vTria[i].nIdVert[0] == SVT_DEL || - abs( m_vTria[i].nTempPart) != 1) - continue ; - // set di triangoli da aggiornare - set stTria ; - stTria.insert( i) ; - while ( ! stTria.empty()) { - // tolgo un triangolo dal set - const auto iIt = stTria.begin() ; - int nT = *iIt ; - stTria.erase( iIt) ; - // aggiorno i triangoli adiacenti - for ( int j = 0 ; j < 3 ; ++ j) { - if ( m_vTria[nT].nETempFlag[j] != 0) - continue ; - int nAdjT = m_vTria[nT].nIdAdjac[j] ; - if ( nAdjT != SVT_NULL && m_vTria[nAdjT].nTempPart == 0) { - m_vTria[nAdjT].nTempPart = m_vTria[nT].nTempPart ; - stTria.insert( nAdjT) ; - } - } - } - } - - return true ; -} - //---------------------------------------------------------------------------- bool SurfTriMesh::IdentifyShells( void) const