EgtGeomKernel 1.6b8 :

- velocizzata chiusura DB con molte entità selezionate
- aggiunta intersezione linea superficie TM (versione semplice)
- migliorata intersezione linea-triangolo
- aggiunto calcolo area di superfici TM
- aggiunto calcolo volume di superfici TM chiuse
- aggiunta gestione facce piane di superficie TM
- aggiunto calcolo punti notevoli di facce di superfici TM.
This commit is contained in:
Dario Sassi
2015-03-11 07:55:53 +00:00
parent 1b85e111dc
commit 6fc5e1f338
12 changed files with 1062 additions and 152 deletions
+313 -75
View File
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// EgalTech 2013-2014
// EgalTech 2014-2015
//----------------------------------------------------------------------------
// File : SurfTriMesh.cpp Data : 15.05.14 Versione : 1.5e5
// Contenuto : Implementazione della classe Superfici TriMesh.
@@ -33,7 +33,7 @@ GEOOBJ_REGISTER( SRF_TRIMESH, NGE_S_TRM, SurfTriMesh) ;
//----------------------------------------------------------------------------
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_bClosed( false), m_nTempProp()
m_dSmoothAng( STM_STD_SMOOTH_ANG), m_bOriented( false), m_bClosed( false), m_bFaceted( false), m_nTimeStamp(), m_nTempProp()
{
m_dCosBndAng = cos( m_dBoundaryAng * DEGTORAD) ;
m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ;
@@ -46,7 +46,7 @@ SurfTriMesh::~SurfTriMesh( void)
//----------------------------------------------------------------------------
bool
SurfTriMesh::Init( int nNumVert, int nNumTria)
SurfTriMesh::Init( int nNumVert, int nNumTria, int nNumFacet)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
@@ -57,6 +57,8 @@ SurfTriMesh::Init( int nNumVert, int nNumTria)
try {
m_vVert.reserve( nNumVert) ;
m_vTria.reserve( nNumTria) ;
if ( nNumFacet > 0)
m_vFacet.reserve( nNumFacet) ;
}
catch (...) {
return false ;
@@ -169,11 +171,115 @@ SurfTriMesh::SetTriangle( int nInd, const StmTria& tT)
m_vTria[i] = tEmpty ;
}
}
// inserisco il vertice
// inserisco il triangolo
m_vTria[nInd] = tT ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetArea( double& dArea) const
{
// controllo parametro di ritorno
if ( &dArea == nullptr)
return false ;
// inizio con area nulla
dArea = 0 ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// sommo l'area di tutti i triangoli
Triangle3d Tria ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
dArea += Tria.GetArea() ;
nId = GetNextTriangle( nId, Tria) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetVolume( double& dVolume) const
{
// controllo parametro di ritorno
if ( &dVolume == nullptr)
return false ;
// inizio con volume nullo
dVolume = 0 ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// la superficie deve essere chiusa
if ( ! IsClosed())
return true ;
// sommo il volume con segno di tutte le piramidi dall'origine ad ogni faccia
Triangle3d Tria ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
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::GetCentroid( Point3d& ptCen) const
{
// controllo parametro di ritorno
if ( &ptCen == nullptr)
return false ;
// inizio con centro nell'origine
ptCen = ORIG ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// se la superficie è chiusa, calcolo il centroide del solido
if ( IsClosed()) {
// applico le formule di R. Nurnberg Imperial College London ad ogni faccia
Triangle3d Tria ;
double dVolume = 0 ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
Vector3d vtA = ( Tria.GetP( 1) - Tria.GetP( 0)) ^ ( Tria.GetP( 2) - Tria.GetP( 0)) ;
dVolume += ( Tria.GetP( 0) - ORIG) * vtA ;
ptCen.x += vtA.x * (( Tria.GetP( 0).x + Tria.GetP( 1).x) * ( Tria.GetP( 0).x + Tria.GetP( 1).x) +
( Tria.GetP( 1).x + Tria.GetP( 2).x) * ( Tria.GetP( 1).x + Tria.GetP( 2).x) +
( Tria.GetP( 2).x + Tria.GetP( 0).x) * ( Tria.GetP( 2).x + Tria.GetP( 0).x)) ;
ptCen.y += vtA.y * (( Tria.GetP( 0).y + Tria.GetP( 1).y) * ( Tria.GetP( 0).y + Tria.GetP( 1).y) +
( Tria.GetP( 1).y + Tria.GetP( 2).y) * ( Tria.GetP( 1).y + Tria.GetP( 2).y) +
( Tria.GetP( 2).y + Tria.GetP( 0).y) * ( Tria.GetP( 2).y + Tria.GetP( 0).y)) ;
ptCen.z += vtA.z * (( Tria.GetP( 0).z + Tria.GetP( 1).z) * ( Tria.GetP( 0).z + Tria.GetP( 1).z) +
( Tria.GetP( 1).z + Tria.GetP( 2).z) * ( Tria.GetP( 1).z + Tria.GetP( 2).z) +
( Tria.GetP( 2).z + Tria.GetP( 0).z) * ( Tria.GetP( 2).z + Tria.GetP( 0).z)) ;
nId = GetNextTriangle( nId, Tria) ;
}
dVolume /= 6 ;
if ( fabs( dVolume) < EPS_SMALL * EPS_SMALL * EPS_SMALL)
return false ;
ptCen /= ( 24 * 2 * dVolume) ;
}
// altrimenti calcolo il centroide della superficie
else {
Triangle3d Tria ;
double dArea = 0 ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
double dTriaArea = Tria.GetArea() ;
dArea += dTriaArea ;
ptCen += Tria.GetCentroid() * dTriaArea ;
nId = GetNextTriangle( nId, Tria) ;
}
if ( fabs( dArea) < EPS_SMALL * EPS_SMALL)
return false ;
ptCen /= dArea ;
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetVertexNum( void) const
@@ -414,8 +520,14 @@ SurfTriMesh::GetTriangleBoundaryEdges( int nId, TriFlags3d& TFlags) const
for ( int i = 0 ; i < 3 ; ++ i) {
// indice triangolo adiacente al lato
int nT = m_vTria[nId].nIdAdjac[i] ;
// se non c'è triangolo adiacente o se forma un angolo oltre il limite, il lato è un contorno
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].vtN * m_vTria[nT].vtN < m_dCosBndAng) ;
// se già definite le facce, verifico indice faccia
if ( m_bFaceted) {
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].nIdFacet != m_vTria[nT].nIdFacet) ;
}
// altrimenti verifico con le normali
else
// se non c'è triangolo adiacente o se forma un angolo oltre il limite, il lato è un contorno
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].vtN * m_vTria[nT].vtN < m_dCosBndAng) ;
}
return true ;
@@ -523,12 +635,16 @@ SurfTriMesh::CopyFrom( const SurfTriMesh& stmSrc)
return false ;
m_vVert = stmSrc.m_vVert ;
m_vTria = stmSrc.m_vTria ;
m_bOriented = stmSrc.m_bOriented ;
m_bClosed = stmSrc.m_bClosed ;
m_dLinTol = stmSrc.m_dLinTol ;
m_dSmoothAng = stmSrc.m_dSmoothAng ;
m_dCosSmAng = stmSrc.m_dCosSmAng ;
m_nStatus = stmSrc.m_nStatus ;
m_nTimeStamp = stmSrc.m_nTimeStamp ;
m_nTempProp = stmSrc.m_nTempProp ;
m_bFaceted = stmSrc.m_bFaceted ;
m_vFacet = stmSrc.m_vFacet ;
return true ;
}
@@ -551,14 +667,29 @@ SurfTriMesh::GetTitle( void) const
bool
SurfTriMesh::Dump( string& sOut, const char* szNewLine) const
{
// se superficie aperta o chiusa
sOut += ( m_bClosed ? "Closed" : "Open") + string( szNewLine) ;
// area
double dArea ;
GetArea( dArea) ;
sOut += "Area=" + ToString( dArea,1) + szNewLine ;
// altri dati per superficie chiusa
if ( m_bClosed) {
double dVolume ;
GetVolume( dVolume) ;
sOut += "Closed Volume=" + ToString( dVolume,1) + szNewLine ;
}
// se segnalo eventuale incongruenza di orientamento
if ( ! m_bOriented)
sOut += string( "Inconsistent Orientation") + szNewLine ;
// numero di vertici
sOut += "Vert : Nbr=" + ToString( GetVertexNum()) +
" Size=" + ToString( GetVertexSize()) + szNewLine ;
// numero di triangoli
sOut += "Tria : Nbr=" + ToString( GetTriangleNum()) +
" Size=" + ToString( GetTriangleSize()) + szNewLine ;
// numero facce, se calcolate
if ( m_bFaceted)
sOut += "Facet : Nbr=" + ToString( GetFacetNum()) +
" Size=" + ToString( GetFacetSize()) + szNewLine ;
return true ;
}
@@ -580,6 +711,9 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
// angolo limite per mediare le normali
if ( ! ngeOut.WriteDouble( m_dSmoothAng, ";", true))
return false ;
// flag orientata
if ( ! ngeOut.WriteBool( m_bOriented, ";"))
return false ;
// flag aperta/chiusa
if ( ! ngeOut.WriteBool( m_bClosed, ";"))
return false ;
@@ -587,7 +721,10 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
if ( ! ngeOut.WriteInt( GetVertexSize(), ";"))
return false ;
// numero di triangoli
if ( ! ngeOut.WriteInt( GetTriangleSize(), ";", true))
if ( ! ngeOut.WriteInt( GetTriangleSize(), ";"))
return false ;
// numero di facce
if ( ! ngeOut.WriteInt( GetFacetSize(), ";", true))
return false ;
// ciclo sui vertici
for ( int i = 0 ; i < int( m_vVert.size()) ; ++ i) {
@@ -607,10 +744,19 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
! ngeOut.WriteInt( m_vTria[i].nIdAdjac[1], ",") ||
! ngeOut.WriteInt( m_vTria[i].nIdAdjac[2], ";") ||
! ngeOut.WriteVector( m_vTria[i].vtN, ";") ||
! ngeOut.WriteInt( m_vTria[i].nIdFacet, ";") ||
! ngeOut.WriteInt( m_vTria[i].nTFlag, ";") ||
! ngeOut.WriteInt( m_vTria[i].nEFlag, ";", true))
return false ;
}
// ciclo sulle facce
int nNumFacet = int( m_vFacet.size()) ;
for ( int i = 0 ; i < nNumFacet ; ++ i) {
bool bEndL = ( ( i + 1) % 10 == 0) || i == ( nNumFacet - 1) ;
if ( ! ngeOut.WriteInt( i, ",") ||
! ngeOut.WriteInt( m_vFacet[i], ";", bEndL))
return false ;
}
return true ;
}
@@ -630,26 +776,46 @@ SurfTriMesh::Load( NgeReader& ngeIn)
double dSmoothAng ;
if ( ! ngeIn.ReadDouble( dSmoothAng, ";", true))
return false ;
// leggo la prossima linea ( 3 parametri : flag chiuso num vertici e num tria)
// recupero il flag
bool bClosed ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
// recupero il numero di vertici
int nNumVert ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
// recupero il numero di triangoli
int nNumTria ;
if ( ! ngeIn.ReadInt( nNumTria, ";", true))
return false ;
// preparo la superficie
if ( ! Init( nNumVert, nNumTria))
return false ;
m_bClosed = bClosed ;
m_dLinTol = dLinTol ;
m_dSmoothAng = dSmoothAng ;
m_dCosSmAng = cos( dSmoothAng * DEGTORAD) ;
// leggo la prossima linea
// prima di versione 1010 3 parametri : flag di chiusa, num vertici, num tria
// da versione 1010 leggo flag di orientata
bool bOriented ;
bool bClosed ;
int nNumVert ;
int nNumTria ;
int nNumFacet ;
if ( ngeIn.GetFileVersion() < NGE_VER_1010) {
bOriented = false ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumTria, ";", true))
return false ;
nNumFacet = 0 ;
}
// da versione 1010 5 parametri : flag di orientata, flag di chiusa, num vertici, num tria, num facet
else {
if ( ! ngeIn.ReadBool( bOriented, ";"))
return false ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumTria, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumFacet, ";", true))
return false ;
}
// preparo la superficie
if ( ! Init( nNumVert, nNumTria, nNumFacet))
return false ;
m_bOriented = bOriented ;
m_bClosed = bClosed ;
m_bFaceted = ( nNumFacet > 0) ;
// lettura dei vertici
int nInd ;
StmVert vV ;
@@ -666,7 +832,7 @@ SurfTriMesh::Load( NgeReader& ngeIn)
// lettura dei triangoli
StmTria tT ;
for ( int i = 0 ; i < nNumTria ; ++ i) {
// leggo la prossima linea ( 6 parametri : Indice, IdVertici, IdAdiacenze, Normale, TFlag, EFlag)
// leggo la prossima linea ( 6 o 7 parametri : Indice, IdVertici, IdAdiacenze, Normale, [Facet,] TFlag, EFlag)
// la interpreto e imposto il vertice
if ( ! ngeIn.ReadInt( nInd, ";") ||
! ngeIn.ReadInt( tT.nIdVert[0], ",") ||
@@ -676,11 +842,21 @@ SurfTriMesh::Load( NgeReader& ngeIn)
! ngeIn.ReadInt( tT.nIdAdjac[1], ",") ||
! ngeIn.ReadInt( tT.nIdAdjac[2], ";") ||
! ngeIn.ReadVector( tT.vtN, ";") ||
( ngeIn.GetFileVersion() >= NGE_VER_1010 && ! ngeIn.ReadInt( tT.nIdFacet, ";")) ||
! ngeIn.ReadInt( tT.nTFlag, ";") ||
! ngeIn.ReadInt( tT.nEFlag, ";", true) ||
! SetTriangle( nInd, tT))
return false ;
}
// lettura delle facce
int nT ;
for ( int i = 0 ; i < nNumFacet ; ++ i) {
bool bEndL = ( ( i + 1) % 10 == 0) || i == ( nNumFacet - 1) ;
if ( ! ngeIn.ReadInt( nInd, ",") ||
! ngeIn.ReadInt( nT, ";", bEndL) ||
! SetFacet( nInd, nT))
return false ;
}
// eseguo validazione
return Validate() ;
}
@@ -720,6 +896,15 @@ SurfTriMesh::Validate( void)
}
}
// Verifico che i triangoli riferiti dalle facce esistano
for ( int i = 0 ; i < GetFacetSize() && m_nStatus == OK && m_bFaceted ; ++ i) {
// verifico validità triangolo riferito
if ( m_vFacet[i] <= SVT_NULL ||
m_vFacet[i] >= GetTriangleSize() ||
m_vTria[ m_vFacet[i]].nIdVert[0] == SVT_DEL)
m_bFaceted = false ;
}
return ( m_nStatus == OK) ;
}
@@ -839,57 +1024,113 @@ SurfTriMesh::AdjustAdjacencies( void)
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustOrientations( int nLev, bool& bSomeWrong)
SurfTriMesh::AdjustOrientations( void)
{
// inizializzo parametro di ritorno
bSomeWrong = false ;
// ciclo sui triangoli
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
// flags
int nNull = 0 ;
int nWrong = 0 ;
// ciclo sui lati del triangolo
for ( int j = 0 ; j < 3 ; ++ j) {
// se non c'è adiacenza
if ( m_vTria[i].nIdAdjac[j] == SVT_NULL)
++ nNull ;
// la verifico
else {
// indice altro triangolo
int nT = m_vTria[i].nIdAdjac[j] ;
// indice altro half-hedge
int nE = 0 ;
if ( m_vTria[nT].nIdAdjac[1] == i)
nE = 1 ;
else if ( m_vTria[nT].nIdAdjac[2] == i)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[i].nIdVert[j] == m_vTria[nT].nIdVert[nE])
++ nWrong ;
}
}
// aggiorno stato
if ( nWrong > 0)
bSomeWrong = true ;
// se almeno uno errato e gli altri nulli, inverto il triangolo
if ( nWrong >= nLev && ( nWrong + nNull) == 3)
InvertTriangle( i) ;
// se non ci sono almeno 2 triangoli è inutile fare test
if ( m_vTria.size() < 2) {
m_bOriented = true ;
return true ;
}
// incremento time stamp di due step (serve un marcatore intermedio)
m_nTimeStamp += 2 ;
// ciclo sui triangoli
TRINTDEQUE S3iQ ;
bool bOk = true ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
// se triangolo non cancellato e senza time stamp
if ( m_vTria[i].nIdVert[0] != SVT_DEL &&
abs( m_vTria[i].nTemp) != m_nTimeStamp) {
S3iQ.emplace_back( i, SVT_NULL, 0) ;
while ( ! S3iQ.empty()) {
if ( ! AdjustTriaOrientation( S3iQ))
bOk = false ;
}
}
}
// salvo il risultato
m_bOriented = bOk ;
// in caso di errore ripristino l'orientamento originale
if ( ! m_bOriented){
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( - m_vTria[i].nTemp == m_nTimeStamp)
InvertTriangle( i) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::TestClosure( void)
SurfTriMesh::AdjustTriaOrientation( TRINTDEQUE& S3iQ)
{
// recupero e tolgo i dati dalla testa della coda
int nT = S3iQ.front().nI1 ;
int nRefT = S3iQ.front().nI2 ;
int nRefE = S3iQ.front().nI3 ;
S3iQ.pop_front() ;
// assegno time stamp al triangolo
m_vTria[nT].nTemp = m_nTimeStamp ;
// se c'è triangolo di riferimento, devo verificare se da invertire
if ( nRefT != SVT_NULL) {
// cerco indice half-edge in comune
int nE = 0 ;
if ( m_vTria[nT].nIdAdjac[1] == nRefT)
nE = 1 ;
else if ( m_vTria[nT].nIdAdjac[2] == nRefT)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[nT].nIdVert[nE] == m_vTria[nRefT].nIdVert[nRefE]) {
m_vTria[nT].nTemp = - m_vTria[nT].nTemp ;
InvertTriangle( nT) ;
}
}
// verifico i triangoli adiacenti
bool bOk = true ;
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
// se non c'è adiacenza o va sul triangolo di provenienza
if ( nAdjT == SVT_NULL || nAdjT == nRefT)
;
// la verifico
else {
// se triangolo adiacente senza timestamp finale e intermedio
if ( abs( m_vTria[nAdjT].nTemp) != m_nTimeStamp &&
m_vTria[nAdjT].nTemp != ( m_nTimeStamp - 1)) {
m_vTria[nAdjT].nTemp = m_nTimeStamp - 1 ;
S3iQ.emplace_back( nAdjT, nT, j) ;
}
// altrimenti verifico che l'orientamento sia congruente
else {
// indice altro half-hedge
int nE = 0 ;
if ( m_vTria[nAdjT].nIdAdjac[1] == nT)
nE = 1 ;
else if ( m_vTria[nAdjT].nIdAdjac[2] == nT)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[nT].nIdVert[j] == m_vTria[nAdjT].nIdVert[nE])
bOk = false ;
}
}
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::TestSealing( void)
{
// ciclo sui triangoli
bool bClosed = true ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( m_vTria[i].nIdAdjac[0] == SVT_NULL ||
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL)
bClosed = false ;
// se triangolo non cancellato
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// 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 ;
}
}
// aggiorno la chiusura della superficie
m_bClosed = bClosed ;
@@ -900,6 +1141,8 @@ SurfTriMesh::TestClosure( void)
bool
SurfTriMesh::AdjustTopology( void)
{
// dichiaro sfaccettatura da ricalcolare
ResetFaceting() ;
// verifica indici
if ( ! Validate())
return false ;
@@ -907,15 +1150,10 @@ SurfTriMesh::AdjustTopology( void)
if ( ! AdjustAdjacencies())
return false ;
// verifica continuità orientazione
int nLev = 3 ;
bool bSomeWrong ;
do {
if ( ! AdjustOrientations( nLev, bSomeWrong))
return false ;
-- nLev ;
} while ( bSomeWrong && nLev > 0) ;
if ( ! AdjustOrientations())
return false ;
// verifica chiusura
if ( ! TestClosure())
if ( ! TestSealing())
return false ;
return true ;