Files
EgtGeomKernel/SurfTriMesh.cpp
T
Dario Sassi 1b767fe58e EgtGeomKernel 1.5e1 :
- in TriMesh migliorato lo smooth delle normali
- in TriMesh aggiunta generazione per rivoluzione
- migliorati gestione e aggiornamento materiali.
2014-05-02 06:57:24 +00:00

1387 lines
44 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2014
//----------------------------------------------------------------------------
// File : SurfTriMesh.cpp Data : 26.03.14 Versione : 1.5c9
// Contenuto : Implementazione della classe Superfici TriMesh.
//
//
//
// Modifiche : 26.03.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "SurfTriMesh.h"
#include "GeoObjFactory.h"
#include "NgeWriter.h"
#include "NgeReader.h"
#include "DistPointLine.h"
#include "Triangulate.h"
#include "\EgtDev\Include\EGkStringUtils3d.h"
#include "\EgtDev\Include\EGkPolyLine.h"
#include <new>
using namespace std ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( SRF_TRIMESH, NGE_S_TRM, SurfTriMesh) ;
//----------------------------------------------------------------------------
SurfTriMesh::SurfTriMesh( void)
: m_nStatus( TO_VERIFY), m_bClosed( false)
{
}
//----------------------------------------------------------------------------
SurfTriMesh::~SurfTriMesh( void)
{
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Init( int nNumVert, int nNumTria)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// verifico validità parametri
if ( nNumVert < 3 || nNumTria < 1)
return false ;
// prealloco la memoria
try {
m_vVert.reserve( nNumVert) ;
m_vTria.reserve( nNumTria) ;
}
catch (...) {
return false ;
}
// completo inizializzazione
m_nStatus = OK ;
m_bClosed = false ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::AddVertex( const Point3d& ptVert)
{
// imposto ricalcolo
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// inserisco il vertice
try { m_vVert.push_back( StmVert( ptVert)) ;}
catch(...) { return SVT_NULL ;}
// ne determino l'indice
return int( m_vVert.size() - 1) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::SetVertex( int nInd, const StmVert& vV)
{
// imposto ricalcolo
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// recupero la dimensione originale
int nPrevSize = int( m_vVert.size()) ;
// determino la dimensione necessaria
int nNewSize = max( nInd + 1, nPrevSize) ;
// se necessaria dimensione maggiore
if ( nNewSize > nPrevSize) {
// espando vettore
try { m_vVert.resize( nNewSize) ; }
catch (...) { return false ; }
// inizializzo a cancellati gli eventuali vertici intermedi
if ( ( nNewSize - nPrevSize) > 1) {
StmVert vEmpty( Point3d(), SVT_DEL, 0) ;
for ( int i = nPrevSize ; i < nNewSize ; ++ i)
m_vVert[i] = vEmpty ;
}
}
// inserisco il vertice
m_vVert[nInd] = vV ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::AddTriangle( const int nIdVert[3])
{
// verifico che i tre indici diano diversi
if ( nIdVert[0] == nIdVert[1] ||
nIdVert[1] == nIdVert[2] ||
nIdVert[2] == nIdVert[0])
return SVT_DEL ;
// imposto ricalcolo
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// inserisco il triangolo
try { m_vTria.push_back( StmTria( nIdVert)) ;}
catch(...) { return SVT_NULL ;}
// ne determino l'indice
return int( m_vTria.size() - 1) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::SetTriangle( int nInd, const StmTria& tT)
{
// imposto ricalcolo
m_nStatus = TO_VERIFY ;
m_OGrMgr.Reset() ;
// recupero la dimensione originale
int nPrevSize = int( m_vTria.size()) ;
// determino la dimensione necessaria
int nNewSize = max( nInd + 1, nPrevSize) ;
// se necessaria dimensione maggiore
if ( nNewSize > nPrevSize) {
// espando vettore
try { m_vTria.resize( nNewSize) ; }
catch (...) { return false ; }
// inizializzo a cancellati gli eventuali triangoli intermedi
if ( ( nNewSize - nPrevSize) > 1) {
StmTria tEmpty ;
tEmpty.nIdVert[0] = SVT_DEL ;
for ( int i = nPrevSize ; i < nNewSize ; ++ i)
m_vTria[i] = tEmpty ;
}
}
// inserisco il vertice
m_vTria[nInd] = tT ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetFirstVertex( Point3d& ptP) const
{
return GetNextVertex( SVT_NULL, ptP) ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetNextVertex( int nId, Point3d& ptP) const
{
// cerco il primo successivo valido
do {
nId ++ ;
} while ( nId < GetVertexNum() && m_vVert[nId].nIdTria == SVT_DEL) ;
// se oltrepassata fine
if ( nId >= GetVertexNum())
return SVT_NULL ;
// recupero i dati
ptP = m_vVert[nId].ptP ;
// ritorno indice triangolo corrente
return nId ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetFirstTriangle( Triangle3d& Tria) const
{
return GetNextTriangle( SVT_NULL, Tria) ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetNextTriangle( int nId, Triangle3d& Tria) const
{
// cerco il primo successivo valido
do {
nId ++ ;
} while ( nId < GetTriangleNum() && m_vTria[nId].nIdVert[0] == SVT_DEL) ;
// se oltrepassata fine
if ( nId >= GetTriangleNum())
return SVT_NULL ;
// recupero i dati
Tria.Set( m_vVert[m_vTria[nId].nIdVert[0]].ptP,
m_vVert[m_vTria[nId].nIdVert[1]].ptP,
m_vVert[m_vTria[nId].nIdVert[2]].ptP,
m_vTria[nId].vtN) ;
// ritorno indice triangolo corrente
return nId ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const
{
// verifico esistenza del triangolo
if ( nId >= GetTriangleNum() || m_vTria[nId].nIdVert[0] == SVT_DEL)
return false ;
// recupero le normali di ciascun vertice
for ( int i = 0 ; i < 3 ; ++ i) {
if ( ! GetTriangleSmoothNormal( nId, i, TNrms.vtN[i]))
TNrms.vtN[i] = m_vTria[nId].vtN ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const
{
// recupero tutti i triangoli attorno al vertice
bool bCirc ;
INTVECTOR vT ;
int nTria = GetAllTriaAroundVertex( m_vTria[nT].nIdVert[nV], vT, bCirc) ;
if ( nTria < 1)
return false ;
// cerco indice del triangolo corrente
int nPos = - 1 ;
for ( int i = 0 ; i < int( vT.size()) ; ++ i) {
if ( vT[i] == nT) {
nPos = i ;
break ;
}
}
if ( nPos == -1)
return false ;
// medio le normali, finché non incontro degli spigoli
vtN = m_vTria[nT].vtN ;
const double COS_DEV_LIM = cos( 22.5 * DEGTORAD) ;
// parto dal triangolo e vado in direzione positiva
int nLim = nPos ;
for ( int i = NextIndAroundVertex( nPos, nTria, bCirc) ;
i != nPos && i < int( vT.size()) ;
i = NextIndAroundVertex( i, nTria, bCirc)) {
if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM)
vtN += m_vTria[vT[i]].vtN ;
else
break ;
nLim = i ;
}
// parto dal triangolo e vado in direzione negativa
for ( int i = PrevIndAroundVertex( nPos, nTria, bCirc) ;
i != nLim && i >= 0 ;
i = PrevIndAroundVertex( i, nTria, bCirc)) {
if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM)
vtN += m_vTria[vT[i]].vtN ;
else
break ;
}
//// parto dal triangolo e vado in direzione positiva
//for ( int i = nPos + 1 ; i < int( vT.size()) ; ++ i) {
// if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM)
// vtN += m_vTria[vT[i]].vtN ;
// else
// break ;
//}
//// parto dal triangolo e vado in direzione negativa
//for ( int i = nPos - 1 ; i >= 0 ; -- i) {
// if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= COS_DEV_LIM)
// vtN += m_vTria[vT[i]].vtN ;
// else
// break ;
//}
vtN.Normalize() ;
return true ;
}
//----------------------------------------------------------------------------
SurfTriMesh*
SurfTriMesh::Clone( void) const
{
// alloco oggetto
SurfTriMesh* pStm = new(nothrow) SurfTriMesh ;
if ( pStm != nullptr) {
if ( ! pStm->Copy( *this)) {
delete pStm ;
return nullptr ;
}
}
return pStm ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Copy( const IGeoObj* pGObjSrc)
{
const SurfTriMesh* pStm = dynamic_cast<const SurfTriMesh*>( pGObjSrc) ;
if ( pStm == nullptr)
return false ;
return Copy( *pStm) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Copy( const SurfTriMesh& stmSrc)
{
if ( &stmSrc == this)
return true ;
if ( ! Init( stmSrc.GetVertexNum(), stmSrc.GetTriangleNum()))
return false ;
m_vVert = stmSrc.m_vVert ;
m_vTria = stmSrc.m_vTria ;
m_bClosed = stmSrc.m_bClosed ;
m_nStatus = stmSrc.m_nStatus ;
return true ;
}
//----------------------------------------------------------------------------
GeoObjType
SurfTriMesh::GetType( void) const
{
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( SurfTriMesh)) ;
}
//----------------------------------------------------------------------------
const string&
SurfTriMesh::GetTitle( void) const
{
static const string sTitle = "TriMesh" ;
return sTitle ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Dump( string& sOut, const char* szNewLine) const
{
// se superficie aperta o chiusa
sOut += ( m_bClosed ? "Closed" : "Open") ;
// numero di vertici
sOut += " VertNbr=" + ToString( GetVertexNum()) ;
// numero di triangoli
sOut += " TriaNbr=" + ToString( GetTriangleNum()) ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetNgeId( void) const
{
return GEOOBJ_GETNGEID( SurfTriMesh) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Save( NgeWriter& ngeOut) const
{
// flag aperta/chiusa
ngeOut.WriteBool( m_bClosed, ";") ;
// numero di vertici
ngeOut.WriteInt( GetVertexNum(), ";") ;
// numero di triangoli
ngeOut.WriteInt( GetTriangleNum(), ";", true) ;
// ciclo sui vertici
for ( int i = 0 ; i < int( m_vVert.size()) ; ++ i) {
ngeOut.WriteInt( i, ";") ;
ngeOut.WritePoint( m_vVert[i].ptP, ";") ;
ngeOut.WriteInt( m_vVert[i].nIdTria, ";") ;
ngeOut.WriteInt( m_vVert[i].nFlag, ";", true) ;
}
// ciclo sui triangoli
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
ngeOut.WriteInt( i, ";") ;
ngeOut.WriteInt( m_vTria[i].nIdVert[0], ",") ;
ngeOut.WriteInt( m_vTria[i].nIdVert[1], ",") ;
ngeOut.WriteInt( m_vTria[i].nIdVert[2], ";") ;
ngeOut.WriteInt( m_vTria[i].nIdAdjac[0], ",") ;
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].nTFlag, ";") ;
ngeOut.WriteInt( m_vTria[i].nEFlag, ";", true) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Load( NgeReader& ngeIn)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// 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 ;
// inizializzo la superficie TriMesh
if ( ! Init( nNumVert, nNumTria))
return false ;
m_bClosed = bClosed ;
// lettura dei vertici
int nInd ;
StmVert vV ;
for ( int i = 0 ; i < nNumVert ; ++ i) {
// leggo la prossima linea ( 4 parametri : Indice, Punto, IdTria, Flag)
// la interpreto e imposto il vertice
if ( ! ngeIn.ReadInt( nInd, ";") ||
! ngeIn.ReadPoint( vV.ptP, ";") ||
! ngeIn.ReadInt( vV.nIdTria, ";") ||
! ngeIn.ReadInt( vV.nFlag, ";", true) ||
! SetVertex( nInd, vV))
return false ;
}
// lettura dei triangoli
StmTria tT ;
for ( int i = 0 ; i < nNumTria ; ++ i) {
// leggo la prossima linea ( 6 parametri : Indice, IdVertici, IdAdiacenze, Normale, TFlag, EFlag)
// la interpreto e imposto il vertice
if ( ! ngeIn.ReadInt( nInd, ";") ||
! ngeIn.ReadInt( tT.nIdVert[0], ",") ||
! ngeIn.ReadInt( tT.nIdVert[1], ",") ||
! ngeIn.ReadInt( tT.nIdVert[2], ";") ||
! ngeIn.ReadInt( tT.nIdAdjac[0], ",") ||
! ngeIn.ReadInt( tT.nIdAdjac[1], ",") ||
! ngeIn.ReadInt( tT.nIdAdjac[2], ";") ||
! ngeIn.ReadVector( tT.vtN, ";") ||
! ngeIn.ReadInt( tT.nTFlag, ";") ||
! ngeIn.ReadInt( tT.nEFlag, ";", true) ||
! SetTriangle( nInd, tT))
return false ;
}
// eseguo validazione
return Validate() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Validate( void)
{
if ( m_nStatus == OK)
return true ;
// Verifico che i vertici riferiti dai triangoli esistano
m_nStatus = OK ;
for ( int i = 0 ; i < GetTriangleNum() && m_nStatus == OK ; ++ i) {
// se triangolo non cancellato
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
for ( int j = 0 ; j < 3 && m_nStatus == OK ; ++ j) {
if ( m_vTria[i].nIdVert[j] < 0 ||
m_vTria[i].nIdVert[j] >= GetVertexNum() ||
m_vVert[ m_vTria[i].nIdVert[j]].nIdTria == SVT_DEL)
m_nStatus = ERR ;
}
// calcolo eventuali normale mancante
if ( m_vTria[i].vtN.IsSmall())
CalcTriangleNormal( i) ;
}
}
// Verifico che i triangoli riferiti dai vertici esistano
for ( int i = 0 ; i < GetVertexNum() && m_nStatus == OK ; ++ i) {
// se vertice non cancellato e con riferimento assegnato
if ( m_vVert[i].nIdTria != SVT_DEL && m_vVert[i].nIdTria != SVT_NULL) {
if ( m_vVert[i].nIdTria < SVT_DEL ||
m_vVert[i].nIdTria >= GetTriangleNum() ||
m_vTria[ m_vVert[i].nIdTria].nIdVert[0] == SVT_DEL)
m_nStatus = ERR ;
}
}
return ( m_nStatus == OK) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::FindVertexInTria( int nV, int nT, int& nK) const
{
nK = - 1 ;
for ( int k = 0 ; k < 3 ; k ++) {
if ( nV == m_vTria[nT].nIdVert[k]) {
nK = k ;
break ;
}
}
return ( nK != -1) ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetAllTriaAroundVertex( int nV, INTVECTOR& vT, bool& bCirc) const
{
const int MAX_VT_SIZE = 512 ;
// pulisco il vettore risultato
vT.clear() ;
// recupero il triangolo puntato dal vertice
int nT = m_vVert[nV].nIdTria ;
if ( nT == SVT_NULL)
return 0 ;
vT.push_back( nT) ;
// cerco i triangoli adiacenti con lo stesso vertice in CCW
int k ;
int nTa = nT ;
do {
if ( FindVertexInTria( nV, nTa, k))
nTa = m_vTria[nTa].nIdAdjac[Prev(k)] ;
else
nTa = SVT_NULL ;
// per evitare cicli infiniti dovuti a triangoli invertiti
if ( vT.size() >= 2 && nTa == vT[vT.size()-2])
break ;
// se valido
if ( nTa != nT && nTa != SVT_NULL)
vT.push_back( nTa) ;
} while ( nTa != nT && nTa != SVT_NULL && vT.size() < MAX_VT_SIZE) ;
// se sono ritornato al triangolo di partenza ho fatto un giro e concluso la ricerca
if ( nTa == nT) {
bCirc = true ;
return int( vT.size()) ;
}
// altrimenti, devo cercare i triangoli adiacenti con lo stesso vertice in CW
nTa = nT ;
do {
if ( FindVertexInTria( nV, nTa, k))
nTa = m_vTria[nTa].nIdAdjac[k] ;
else
nTa = SVT_NULL ;
// per evitare cicli infiniti dovuti a triangoli invertiti
if ( vT.size() >= 2 && nTa == vT[vT.size()-2])
break ;
// se valido
if ( nTa != nT && nTa != SVT_NULL)
vT.insert( vT.begin(), nTa) ;
} while ( nTa != nT && nTa != SVT_NULL && vT.size() < MAX_VT_SIZE) ;
bCirc = ( nTa == nT) ;
return int( vT.size()) ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::NextIndAroundVertex( int nInd, int nSize, bool bCirc) const
{
nInd = nInd + 1 ;
if ( bCirc && nInd >= nSize)
nInd = nInd % nSize ;
return nInd ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::PrevIndAroundVertex( int nInd, int nSize, bool bCirc) const
{
nInd = nInd - 1 ;
if ( bCirc && nInd < 0)
nInd = ( nInd + nSize) % nSize ;
return nInd ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustAdjacencies( void)
{
// sistemo i puntatori dai vertici ai triangoli
for ( int i = 0 ; i < GetTriangleNum() ; ++ i) {
// se triangolo non cancellato
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
for ( int j = 0 ; j < 3 ; ++ j) {
if ( m_vVert[ m_vTria[i].nIdVert[j]].nIdTria == SVT_NULL)
m_vVert[ m_vTria[i].nIdVert[j]].nIdTria = i ;
}
}
}
// sistemo i puntatori tra triangoli
bool bModif ;
do {
bModif = false ;
for ( int i = 0 ; i < GetTriangleNum() ; ++ i) {
// se triangolo non cancellato
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
for ( int j = 0 ; j < 3 ; ++ j) {
// se adiacenza non risolta
if ( m_vTria[i].nIdAdjac[j] == SVT_NULL) {
// vertici all'estremo dello half-edge di indice j
int nVi = m_vTria[i].nIdVert[j] ;
int nVf = m_vTria[i].nIdVert[Next(j)] ;
// indice altro vertice in altro triangolo
int k ;
int nN ;
bool bCirc ;
INTVECTOR vT ;
// triangoli con il vertice all'inizio dello half-edge
nN = GetAllTriaAroundVertex( nVi, vT, bCirc) ;
for ( int l = 0 ; l < nN ; ++ l) {
int nTi = vT[l] ;
if ( nTi != i) {
// se altro vertice in comune, aggiusto le adiacenze dei due triangoli
if ( FindVertexInTria( nVf, nTi, k)) {
m_vTria[i].nIdAdjac[j] = nTi ;
// se half-hedge con orientazione opposta (come dovrebbe essere)
// il successivo di k deve coincidere con j
if ( m_vTria[nTi].nIdVert[Next(k)] == m_vTria[i].nIdVert[j])
m_vTria[nTi].nIdAdjac[k] = i ;
else
m_vTria[nTi].nIdAdjac[Prev(k)] = i ;
bModif = true ;
continue ;
}
}
}
// triangoli con il vertice alla fine dello half-edge
nN = GetAllTriaAroundVertex( nVf, vT, bCirc) ;
for ( int l = 0 ; l < nN ; ++ l) {
int nTf = vT[l] ;
if ( nTf != i) {
// se altro vertice in comune, aggiusto le adiacenze dei due triangoli
if ( FindVertexInTria( nVi, nTf, k)) {
m_vTria[i].nIdAdjac[j] = nTf ;
// se half-hedge con orientazione opposta (come dovrebbe essere)
// il precedente di k deve coincidere con il successivo j
if ( m_vTria[nTf].nIdVert[Prev(k)] == m_vTria[i].nIdVert[Next(j)])
m_vTria[nTf].nIdAdjac[Prev(k)] = i ;
else
m_vTria[nTf].nIdAdjac[k] = i ;
bModif = true ;
continue ;
}
}
}
}
}
}
}
} while ( bModif) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustOrientations( int nLev, bool& bSomeWrong)
{
// inizializzo parametro di ritorno
bSomeWrong = false ;
// ciclo sui triangoli
for ( int i = 0 ; i < GetTriangleNum() ; ++ 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) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::TestClosure( void)
{
// ciclo sui triangoli
bool bClosed = true ;
for ( int i = 0 ; i < GetTriangleNum() ; ++ 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 ;
}
// aggiorno la chiusura della superficie
m_bClosed = bClosed ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustTopology( void)
{
// verifica indici
if ( ! Validate())
return false ;
// verifica adiacenze
if ( ! AdjustAdjacencies())
return false ;
// verifica continuità orientazione
int nLev = 3 ;
bool bSomeWrong ;
do {
if ( ! AdjustOrientations( nLev, bSomeWrong))
return false ;
-- nLev ;
} while ( bSomeWrong && nLev > 0) ;
// verifica chiusura
if ( ! TestClosure())
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CreateByTriangulation( const PolyLine& PL)
{
// eseguo la triangolazione
PNTVECTOR vPnt ;
INTVECTOR vTria ;
Triangulate Tri ;
if ( ! Tri.Make( PL, vPnt, vTria))
return false ;
// inizializzo la superficie
int nVert = int( vPnt.size()) ;
int nTria = int( vTria.size()) / 3 ;
if ( ! Init( nVert, nTria))
return false ;
// inserisco i vertici nella superficie
for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) {
if ( AddVertex( vPnt[i]) == SVT_NULL)
return false ;
}
// recupero i triangoli e li inserisco nella superficie
int vV[3] ;
for ( int i = 0 ; i < nTria ; ++i) {
vV[0] = vTria[3*i] ;
vV[1] = vTria[3*i+1] ;
vV[2] = vTria[3*i+2] ;
if ( AddTriangle( vV) == SVT_NULL)
return false ;
}
// sistemo la topologia
return AdjustTopology() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CreateByExtrusion( const PolyLine& PL, const Vector3d& vtExtr)
{
// verifico che il vettore di estrusione sia non nullo
if ( vtExtr.IsSmall())
return false ;
// verifico se la polilinea è chiusa
bool bClosed = PL.IsClosed() ;
// costruisco la mesh
int nPointNbr = PL.GetPointNbr() ;
if ( ! Init( 2 * nPointNbr, 2 * nPointNbr))
return false ;
// inserisco il primo vertice della polilinea e il suo estruso
int nP = 0 ;
int nV = -1 ;
Point3d ptP ;
if ( ! PL.GetFirstPoint( ptP))
return false ;
++ nP ;
if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL)
return false ;
nV += 2 ;
// ciclo sui punti della polilinea (per inserire vertice e suo estruso + 2 triangoli per ogni punto)
int nIdV[3] ;
while ( PL.GetNextPoint( ptP)) {
// incremento numero punto
++ nP ;
// se polilinea aperta o non è l'ultimo punto
if ( ! bClosed || nP < nPointNbr) {
// aggiungo due nuovi vertici
if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL)
return false ;
nV += 2 ;
// aggiungo triangolo in basso a sinistra
nIdV[0] = nV - 3 ; nIdV[1] = nV - 1 ; nIdV[2] = nV - 2 ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// aggiungo triangolo in alto a destra
nIdV[0] = nV - 2 ; nIdV[1] = nV - 1 ; nIdV[2] = nV ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// altrimenti ultimo punto di polilinea chiusa
else {
// non devo aggiungere i vertici, perchè coincidono con quelli iniziali
// aggiungo triangolo in basso a sinistra
nIdV[0] = nV - 1 ; nIdV[1] = 0 ; nIdV[2] = nV ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// aggiungo triangolo in alto a destra
nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = 1 ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
}
// sistemo la topologia
return AdjustTopology() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx,
double dAngRot, double dStepRot)
{
// verifico che l'asse di rotazione sia non nullo
if ( vtAx.IsSmall())
return false ;
// verifico che l'angolo di rotazione sia significativo e non superi un giro
if ( fabs( dAngRot) < EPS_ANG_SMALL)
return false ;
if ( fabs( dAngRot) > ANG_FULL)
dAngRot = _copysign( ANG_FULL, dAngRot) ;
// verifico se rotazione completa
bool bFullRev = ( fabs( fabs( dAngRot) - ANG_FULL) < EPS_ANG_SMALL) ;
// aggiusto il valore dell'angolo di step
const double MIN_STEP_ROT = 1 ;
const double MAX_STEP_ROT = 90 ;
if ( fabs( dStepRot) < MIN_STEP_ROT)
dStepRot = _copysign( MIN_STEP_ROT, dAngRot) ;
else if ( fabs( dStepRot) > MAX_STEP_ROT)
dStepRot = _copysign( MAX_STEP_ROT, dAngRot) ;
else
dStepRot = _copysign( dStepRot, dAngRot) ;
// calcolo il numero di step
int nStep = int( dAngRot / dStepRot) ;
nStep = max( nStep, 1) ;
dStepRot = dAngRot / nStep ;
if ( bFullRev)
-- nStep ;
// verifico che la polilinea non attraversi l'asse di rivoluzione o lo tocchi in punti interni
if ( ! VeryfyPolylineForRevolution( PL, ptAx, vtAx)) {
LOG_ERROR( GetEGkLogger(), "StmCreateByRevolution : polyline inside meets axis")
return false ;
}
// verifico se la polilinea è chiusa
bool bClosed = PL.IsClosed() ;
// costruisco la mesh
int nPointNbr = PL.GetPointNbr() ;
if ( ! Init( ( 1 + nStep) * nPointNbr, ( 1 + nStep) * nPointNbr))
return false ;
// inserisco il primo punto della polilinea e i suoi ruotati
int nP = 0 ;
int nV = -1 ;
Point3d ptP ;
// recupero il punto
if ( ! PL.GetFirstPoint( ptP))
return false ;
++ nP ;
// inserisco il primo vertice
if ( AddVertex( ptP) == SVT_NULL)
return false ;
++ nV ;
// verifico se il punto giace sull'asse
bool bPrevOnAx = DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ;
int nVPrevOnAx = nV ;
// se non è sull'asse, inserisco le copie ruotate
if ( ! bPrevOnAx) {
for ( int i = 1 ; i <= nStep ; ++i) {
ptP.Rotate( ptAx, vtAx, dStepRot * DEGTORAD) ;
if ( AddVertex( ptP) == SVT_NULL)
return false ;
++ nV ;
}
}
// ciclo sui punti della polilinea (per inserire vertice e suoi ruotati + 2 triangoli per ogni punto)
int nIdV[4] ;
while ( PL.GetNextPoint( ptP)) {
// incremento numero punto
++ nP ;
// se polilinea aperta o non è l'ultimo punto
if ( ! bClosed || nP < nPointNbr) {
// aggiungo il primo vertice
if ( AddVertex( ptP) == SVT_NULL)
return false ;
++ nV ;
// verifico se il punto giace sull'asse
bool bOnAx = DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ;
// ciclo sugli step
for ( int i = 1 ; i <= nStep ; ++i) {
// se non è sull'asse, inserisco le copie ruotate
if ( ! bOnAx) {
ptP.Rotate( ptAx, vtAx, dStepRot * DEGTORAD) ;
if ( AddVertex( ptP) == SVT_NULL)
return false ;
++ nV ;
}
// per i controlli già fatti non è possibile avere contemp. prec e corr su asse
// se il precedente è sull'asse, aggiungo un solo triangolo
if ( bPrevOnAx) {
nIdV[0] = nVPrevOnAx ;
nIdV[1] = nV ;
nIdV[2] = nV - 1 ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// se il corrente è sull'asse, aggiungo un solo triangolo
else if ( bOnAx) {
nIdV[0] = nV - ( nStep + 2) + i ;
nIdV[1] = nIdV[0] + 1 ;
nIdV[2] = nV ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// altrimenti aggiungo due triangoli
else {
nIdV[0] = nV - ( nStep + 2) ;
nIdV[1] = nIdV[0] + 1 ;
nIdV[2] = nV ;
nIdV[3] = nV - 1 ;
if ( ! AddBiTriangle( nIdV))
return false ;
}
}
// se rivoluzione completa, aggiungo i due triangoli di chiusura
if ( bFullRev) {
// per i controlli già fatti non è possibile avere contemp. prec e corr su asse
// se il precedente è sull'asse, aggiungo un solo triangolo
if ( bPrevOnAx) {
nIdV[0] = nVPrevOnAx ;
nIdV[1] = nV - nStep ;
nIdV[2] = nV ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// se il corrente è sull'asse, aggiungo un solo triangolo
else if ( bOnAx) {
nIdV[0] = nV - 1 ;
nIdV[1] = nV - ( nStep + 1) ;
nIdV[2] = nV ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// altrimenti aggiungo due triangoli
else {
nIdV[0] = nV - ( nStep + 1) ;
nIdV[1] = nV - ( 2 * nStep + 1) ;
nIdV[2] = nV - nStep ;
nIdV[3] = nV ;
if ( ! AddBiTriangle( nIdV))
return false ;
}
}
bPrevOnAx = false ;
}
// altrimenti ultimo punto di polilinea chiusa
else {
for ( int i = 1 ; i <= nStep ; ++i) {
// non devo aggiungere i vertici, perchè coincidono con quelli iniziali
// aggiungo triangolo in basso a sinistra
nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = nV - nStep + i ; nIdV[2] = i ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// aggiungo triangolo in alto a destra
nIdV[0] = nV - nStep + i - 1 ; nIdV[1] = i ; nIdV[2] = i - 1 ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// se rivoluzione completa, aggiungo i due triangoli di chiusura
if ( bFullRev) {
// aggiungo triangolo in basso a sinistra
nIdV[0] = nV ; nIdV[1] = nV - nStep ; nIdV[2] = 0 ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// aggiungo triangolo in alto a destra
nIdV[0] = nV ; nIdV[1] = 0 ; nIdV[2] = nStep ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
}
}
// sistemo la topologia
return AdjustTopology() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) const
{
// calcolo un riferimento con origine ptAx e asseZ vtAx
Frame3d frAx ;
if ( ! frAx.Set( ptAx, vtAx))
return false ;
// numero di segmenti della polilinea
int nTotSeg = PL.GetLineNbr() ;
// flag di chiusa
bool bClosed = PL.IsClosed() ;
// recupero il primo punto e lo porto nel riferimento Ax e quindi lo proietto su XY
Point3d ptPp ;
if ( ! PL.GetFirstPoint( ptPp))
return false ;
ptPp.ToLoc( frAx) ;
ptPp.z = 0 ;
// calcolo la distanza tra i segmenti della polilinea portati nel piano XY del rif Ax e l'origine
int nSeg = 0 ;
Point3d ptPc ;
while ( PL.GetNextPoint( ptPc)) {
// punto corrente
ptPc.ToLoc( frAx) ;
ptPc.z = 0 ;
++ nSeg ;
// verifico distanza
if ( DistPointLine( ORIG, ptPp, ptPc).IsSmall()) {
if ( bClosed ||
( ! ( nSeg == 1 && AreSamePointNear( ORIG, ptPp)) &&
! ( nSeg == nTotSeg && AreSamePointNear( ORIG, ptPc))))
return false ;
}
// salvo punto
ptPp = ptPc ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AddBiTriangle( const int nIdVert[4])
{
// 0 <- 3
// | |
// 1 -> 2
int nIdV[3] ;
// se la diagonale 0->2 è più corta della 1->3
if ( SqDist( m_vVert[nIdVert[0]].ptP, m_vVert[nIdVert[2]].ptP) <=
SqDist( m_vVert[nIdVert[1]].ptP, m_vVert[nIdVert[3]].ptP)) {
// triangolo 0->1->2
nIdV[0] = nIdVert[0] ;
nIdV[1] = nIdVert[1] ;
nIdV[2] = nIdVert[2] ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// triangolo 0->2->3
nIdV[0] = nIdVert[0] ;
nIdV[1] = nIdVert[2] ;
nIdV[2] = nIdVert[3] ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
// altrimenti uso la 1->3
else {
// triangolo 0->1->3
nIdV[0] = nIdVert[0] ;
nIdV[1] = nIdVert[1] ;
nIdV[2] = nIdVert[3] ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
// triangolo 1->2->3
nIdV[0] = nIdVert[1] ;
nIdV[1] = nIdVert[2] ;
nIdV[2] = nIdVert[3] ;
if ( AddTriangle( nIdV) == SVT_NULL)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetLocalBBox( BBox3d& b3Loc) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il box in locale
b3Loc.Reset() ;
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
b3Loc.Add( m_vVert[i].ptP) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetBBox( const Frame3d& frRef, BBox3d& b3Ref) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// assegno il box nel riferimento
b3Ref.Reset() ;
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL) {
Point3d ptTemp = m_vVert[i].ptP ;
ptTemp.ToGlob( frRef) ;
b3Ref.Add( ptTemp) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Translate( const Vector3d& vtMove)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// traslo i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
m_vVert[i].ptP.Translate( vtMove) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// ruoto i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
m_vVert[i].ptP.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
}
// ruoto le normali delle facce
for ( int i = 0 ; i < GetTriangleNum() ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL)
m_vTria[i].vtN.Rotate( vtAx, dCosAng, dSinAng) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico non sia nulla
if ( fabs( dCoeffX) < EPS_ZERO && fabs( dCoeffY) < EPS_ZERO && fabs( dCoeffZ) < EPS_ZERO)
return false ;
// determino se contiene anche un mirror (numero dispari di coefficienti negativi)
bool bMirror = ( dCoeffX < 0) ;
bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ;
bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// scalo i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
m_vVert[i].ptP.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
}
// aggiorno le facce
for ( int i = 0 ; i < GetTriangleNum() ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// se c'è mirror, devo invertire la faccia
if ( bMirror && ! InvertTriangle( i))
return false ;
// aggiorno la normale
if ( ! CalcTriangleNormal( i))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::InvertTriangle( int nT)
{
// controllo validità triangolo
if ( m_vTria[nT].nIdVert[0] == SVT_DEL)
return false ;
// scambio di due vertici
swap( m_vTria[nT].nIdVert[1], m_vTria[nT].nIdVert[2]) ;
// scambio delle conseguenti due adiacenze
swap( m_vTria[nT].nIdAdjac[0], m_vTria[nT].nIdAdjac[2]) ;
// inversione della normale
m_vTria[nT].vtN *= - 1 ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::CalcTriangleNormal( int nT)
{
// controllo validità triangolo
if ( m_vTria[nT].nIdVert[0] == SVT_DEL)
return false ;
// controllo validità vertici riferiti dal triangolo
if ( m_vTria[nT].nIdVert[0] >= GetVertexNum() ||
m_vVert[m_vTria[nT].nIdVert[0]].nIdTria == SVT_DEL ||
m_vTria[nT].nIdVert[1] >= GetVertexNum() ||
m_vVert[m_vTria[nT].nIdVert[1]].nIdTria == SVT_DEL ||
m_vTria[nT].nIdVert[2] >= GetVertexNum() ||
m_vVert[m_vTria[nT].nIdVert[2]].nIdTria == SVT_DEL)
return false ;
// calcolo vettori come due lati consecutivi del triangolo
Vector3d vtV1 = m_vVert[m_vTria[nT].nIdVert[1]].ptP - m_vVert[m_vTria[nT].nIdVert[0]].ptP ;
Vector3d vtV2 = m_vVert[m_vTria[nT].nIdVert[2]].ptP - m_vVert[m_vTria[nT].nIdVert[1]].ptP ;
Vector3d vtN = vtV1 ^ vtV2 ;
// normale da prodotto vettoriale
if ( ! vtN.Normalize( EPS_ZERO))
return false ;
m_vTria[nT].vtN = vtN ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// specchio i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i)
m_vVert[i].ptP.Mirror( ptOn, vtNorm) ;
// inverto le facce
for ( int i = 0 ; i < GetTriangleNum() ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// inverto la faccia
if ( ! InvertTriangle( i))
return false ;
// aggiorno la normale
if ( ! CalcTriangleNormal( i))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::ToGlob( const Frame3d& frRef)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
m_vVert[i].ptP.ToGlob( frRef) ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::ToLoc( const Frame3d& frRef)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo i vertici
for ( int i = 0 ; i < GetVertexNum() ; ++ i) {
if ( m_vVert[i].nIdTria != SVT_DEL)
m_vVert[i].ptP.ToLoc( frRef) ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::Invert( void)
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// inverto i triangoli
for ( int i = 0 ; i < GetTriangleNum() ; ++ i)
InvertTriangle( i) ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}