41a38fef3b
- aggiunta entità testo (con font Nfe e di sistema) - in tutte le rotate ora l'angolo è in gradi - aggiunta trasformazione Shear (scorrimento) - aggiunta trsformazione LocToLoc - Set/GetInfo specializzate per i diversi tipi di informazioni - Copy e Relocate con possibilità di indicare l'entità di riferimento rispetto a cui inserire - aggiunte trasformazioni a PolyLine.
1915 lines
62 KiB
C++
1915 lines
62 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2014
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfTriMesh.cpp Data : 15.05.14 Versione : 1.5e5
|
|
// Contenuto : Implementazione della classe Superfici TriMesh.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 26.03.14 DS Creazione modulo.
|
|
// 15.05.14 DS Corr. errore CreateByTwoCurves che dava loop infinito.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "GeoObjFactory.h"
|
|
#include "NgeWriter.h"
|
|
#include "NgeReader.h"
|
|
#include "DistPointLine.h"
|
|
#include "Triangulate.h"
|
|
#include "GeoConst.h"
|
|
#include "\EgtDev\Include\EGkStringUtils3d.h"
|
|
#include "\EgtDev\Include\EGkPointGrid3d.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_dLinTol( STM_STD_LIN_TOL), m_dSmoothAng( STM_STD_SMOOTH_ANG), m_bClosed( false)
|
|
{
|
|
m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 siano diversi
|
|
if ( nIdVert[0] == nIdVert[1] ||
|
|
nIdVert[1] == nIdVert[2] ||
|
|
nIdVert[2] == nIdVert[0])
|
|
return SVT_DEL ;
|
|
// verifico che i tre vertici siano ben definiti
|
|
if ( nIdVert[0] < 0 || nIdVert[0] >= int( m_vVert.size()) ||
|
|
m_vVert[nIdVert[0]].nIdTria == SVT_DEL ||
|
|
nIdVert[1] < 0 || nIdVert[1] >= int( m_vVert.size()) ||
|
|
m_vVert[nIdVert[1]].nIdTria == SVT_DEL ||
|
|
nIdVert[2] < 0 || nIdVert[2] >= int( m_vVert.size()) ||
|
|
m_vVert[nIdVert[2]].nIdTria == SVT_DEL)
|
|
return SVT_DEL ;
|
|
// verifico che la normale sia ben definita
|
|
// calcolo vettori come due lati consecutivi del triangolo
|
|
Vector3d vtV1 = m_vVert[nIdVert[1]].ptP - m_vVert[nIdVert[0]].ptP ;
|
|
Vector3d vtV2 = m_vVert[nIdVert[2]].ptP - m_vVert[nIdVert[1]].ptP ;
|
|
// normale da prodotto vettoriale
|
|
Vector3d vtN = vtV1 ^ vtV2 ;
|
|
if ( vtN.IsZero())
|
|
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::GetVertexNum( void) const
|
|
{
|
|
// calcolo il numero dei vertici cancellati
|
|
int nErased = 0 ;
|
|
for ( int nId = 0 ; nId < GetVertexSize() ; ++ nId) {
|
|
if ( m_vVert[nId].nIdTria == SVT_DEL)
|
|
++ nErased ;
|
|
}
|
|
|
|
return ( GetVertexSize() - nErased) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfTriMesh::GetTriangleNum( void) const
|
|
{
|
|
// calcolo il numero dei triangoli cancellati
|
|
int nErased = 0 ;
|
|
for ( int nId = 0 ; nId < GetTriangleSize() ; ++ nId) {
|
|
if ( m_vTria[nId].nIdVert[0] == SVT_DEL)
|
|
++ nErased ;
|
|
}
|
|
|
|
return ( GetTriangleSize() - nErased) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 < GetVertexSize() && m_vVert[nId].nIdTria == SVT_DEL) ;
|
|
// se oltrepassata fine
|
|
if ( nId >= GetVertexSize())
|
|
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 < GetTriangleSize() && m_vTria[nId].nIdVert[0] == SVT_DEL) ;
|
|
// se oltrepassata fine
|
|
if ( nId >= GetTriangleSize())
|
|
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 >= GetTriangleSize() || 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 ;
|
|
// 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 >= m_dCosSmAng)
|
|
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 >= m_dCosSmAng)
|
|
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.GetVertexSize(), stmSrc.GetTriangleSize()))
|
|
return false ;
|
|
m_vVert = stmSrc.m_vVert ;
|
|
m_vTria = stmSrc.m_vTria ;
|
|
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 ;
|
|
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") + string( 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 ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfTriMesh::GetNgeId( void) const
|
|
{
|
|
return GEOOBJ_GETNGEID( SurfTriMesh) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Save( NgeWriter& ngeOut) const
|
|
{
|
|
// tolleranza lineare di costruzione
|
|
ngeOut.WriteDouble( m_dLinTol, ";") ;
|
|
// angolo limite per mediare le normali
|
|
ngeOut.WriteDouble( m_dSmoothAng, ";", true) ;
|
|
// flag aperta/chiusa
|
|
ngeOut.WriteBool( m_bClosed, ";") ;
|
|
// numero di vertici
|
|
ngeOut.WriteInt( GetVertexSize(), ";") ;
|
|
// numero di triangoli
|
|
ngeOut.WriteInt( GetTriangleSize(), ";", 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 ( 2 parametri : dLinTol e dSmoothAng)
|
|
// tolleranza lineare di costruzione
|
|
double dLinTol ;
|
|
if ( ! ngeIn.ReadDouble( dLinTol, ";"))
|
|
return false ;
|
|
// angolo limite per mediare le normali
|
|
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) ;
|
|
// 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 < GetTriangleSize() && 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] >= GetVertexSize() ||
|
|
m_vVert[ m_vTria[i].nIdVert[j]].nIdTria == SVT_DEL)
|
|
m_nStatus = ERR ;
|
|
}
|
|
// calcolo eventuale normale mancante
|
|
if ( m_nStatus == OK && m_vTria[i].vtN.IsSmall())
|
|
CalcTriangleNormal( i) ;
|
|
}
|
|
}
|
|
|
|
// Verifico che i triangoli riferiti dai vertici esistano
|
|
for ( int i = 0 ; i < GetVertexSize() && 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 >= GetTriangleSize() ||
|
|
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 < GetTriangleSize() ; ++ 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 < GetTriangleSize() ; ++ 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 < 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) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::TestClosure( 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 ;
|
|
}
|
|
// 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::CreateByFlatContour( 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)
|
|
{
|
|
// il vettore di estrusione deve essere non nullo
|
|
if ( vtExtr.IsSmall())
|
|
return false ;
|
|
|
|
// la polilinea deve avere almeno 2 punti
|
|
if ( PL.GetPointNbr() < 2)
|
|
return false ;
|
|
|
|
// imposto ricalcolo
|
|
m_nStatus = ERR ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// 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 nV = -1 ;
|
|
Point3d ptP ;
|
|
if ( ! PL.GetFirstPoint( ptP))
|
|
return false ;
|
|
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[4] ;
|
|
while ( PL.GetNextPoint( ptP, bClosed)) {
|
|
// aggiungo due nuovi vertici
|
|
if ( AddVertex( ptP) == SVT_NULL || AddVertex( ptP + vtExtr) == SVT_NULL)
|
|
return false ;
|
|
nV += 2 ;
|
|
// aggiungo i due triangoli relativi
|
|
nIdV[0] = nV - 2 ;
|
|
nIdV[1] = nV - 3 ;
|
|
nIdV[2] = nV - 1 ;
|
|
nIdV[3] = nV ;
|
|
if ( ! AddBiTriangle( nIdV))
|
|
return false ;
|
|
}
|
|
// se curva chiusa, aggiungo gli ultimi due triangoli
|
|
if ( bClosed) {
|
|
// non devo aggiungere i vertici, perchè coincidono con quelli iniziali
|
|
// aggiungo i due triangoli relativi
|
|
nIdV[0] = nV ;
|
|
nIdV[1] = nV - 1 ;
|
|
nIdV[2] = 0 ;
|
|
nIdV[3] = 1 ;
|
|
if ( ! AddBiTriangle( nIdV))
|
|
return false ;
|
|
}
|
|
|
|
// sistemo la topologia
|
|
m_nStatus = TO_VERIFY ;
|
|
return AdjustTopology() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CreateByTwoCurves( const PolyLine& PL1, const PolyLine& PL2)
|
|
{
|
|
// verifico validità polilinee (devono avere almeno 2 punti e non coincidere se non agli estremi aperti)
|
|
if ( ! VerifyPolylinesForTwoCurves( PL1, PL2))
|
|
return false ;
|
|
|
|
// imposto ricalcolo
|
|
m_nStatus = ERR ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// flag di curve chiuse
|
|
bool bClosed = PL1.IsClosed() && PL2.IsClosed() ;
|
|
// recupero i parametri delle due polilinee
|
|
double dU1F ; PL1.GetFirstU( dU1F) ;
|
|
double dU1L ; PL1.GetLastU( dU1L) ;
|
|
double dDeltaU1 = dU1L - dU1F ;
|
|
if ( dDeltaU1 < EPS_SMALL)
|
|
return false ;
|
|
double dU2F ; PL2.GetFirstU( dU2F) ;
|
|
double dU2L ; PL2.GetLastU( dU2L) ;
|
|
double dDeltaU2 = dU2L - dU2F ;
|
|
if ( dDeltaU2 < EPS_SMALL)
|
|
return false ;
|
|
|
|
// costruisco la mesh
|
|
int nPointNbr = PL1.GetPointNbr() + PL2.GetPointNbr() ;
|
|
if ( ! Init( nPointNbr, nPointNbr))
|
|
return false ;
|
|
|
|
// recupero i punti iniziali su curva 1
|
|
int nV1p ; double dU1p ; double dA1p ; Point3d ptP1p ;
|
|
int nV1s ; double dU1s ; double dA1s ; Point3d ptP1s ;
|
|
bool bNext1 = PL1.GetFirstUPoint( &dU1p, &ptP1p) && PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ;
|
|
if ( ! bNext1)
|
|
return false ;
|
|
dA1p = 0 ;
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
if ( ( nV1p = AddVertex( ptP1p)) == SVT_NULL)
|
|
return false ;
|
|
// recupero i punti iniziali su curva 2
|
|
int nV2p ; double dU2p ; double dA2p ; Point3d ptP2p ;
|
|
int nV2s ; double dU2s ; double dA2s ; Point3d ptP2s ;
|
|
bool bNext2 = PL2.GetFirstUPoint( &dU2p, &ptP2p) && PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ;
|
|
if ( ! bNext2)
|
|
return false ;
|
|
dA2p = 0 ;
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
int nIdV[3] ;
|
|
// se i punti iniziali non coincidono, inserisco il vertice iniziale di 2
|
|
if ( ! AreSamePointNear( ptP1p, ptP2p)) {
|
|
if ( ( nV2p = AddVertex( ptP2p)) == SVT_NULL)
|
|
return false ;
|
|
}
|
|
// altrimenti, inserisco un triangolo e mi sposto in avanti su entrambe le curve
|
|
else {
|
|
// inserisco il vertice A1s
|
|
if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il vertice A2s
|
|
if ( ( nV2s = AddVertex( ptP2s)) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il triangolo A1p -> A1s -> A2s
|
|
nIdV[0] = nV1p ;
|
|
nIdV[1] = nV1s ;
|
|
nIdV[2] = nV2s ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
// passo al punto successivo su 1
|
|
nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ;
|
|
bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ;
|
|
if ( bNext1)
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
// passo al punto successivo su 2
|
|
nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ;
|
|
bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ;
|
|
if ( bNext2)
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
}
|
|
// ciclo sui punti
|
|
while ( bNext1 || bNext2) {
|
|
// se c'è nuovo dA1s e la diagonale più corta è dA2p -> dA1s oppure non c'è dA2s
|
|
if ( ( bNext1 && ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) || ! bNext2) {
|
|
// inserisco il vertice A1s
|
|
if ( ( nV1s = AddVertex( ptP1s)) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il triangolo A2p -> A1p -> A1s
|
|
nIdV[0] = nV2p ;
|
|
nIdV[1] = nV1p ;
|
|
nIdV[2] = nV1s ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
// se i punti correnti coincidono passo al successivo anche su 2
|
|
if ( AreSamePointNear( ptP1s, ptP2s)) {
|
|
nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ;
|
|
bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ;
|
|
if ( bNext2)
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
}
|
|
// passo al punto successivo su 1
|
|
nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ;
|
|
bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ;
|
|
if ( bNext1)
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
}
|
|
// altrimenti è dA1p -> dA2s
|
|
else {
|
|
// inserisco il vertice A2s
|
|
if ( ( nV2s = AddVertex( ptP2s)) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il triangolo A2p -> A1p -> A2s
|
|
nIdV[0] = nV2p ;
|
|
nIdV[1] = nV1p ;
|
|
nIdV[2] = nV2s ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
// se i punti correnti coincidono passo al successivo anche su 1
|
|
if ( AreSamePointNear( ptP1s, ptP2s)) {
|
|
nV1p = nV1s ; dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ;
|
|
bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, bClosed) ;
|
|
if ( bNext1)
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
}
|
|
// passo al punto successivo su 2
|
|
nV2p = nV2s ; dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ;
|
|
bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, bClosed) ;
|
|
if ( bNext2)
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
}
|
|
}
|
|
// se curve chiuse, aggiungo gli ultimi due triangoli
|
|
if ( bClosed) {
|
|
dA1s = 1 ;
|
|
dA2s = 1 ;
|
|
// se la diagonale più corta è dA2p -> dA1s = 0
|
|
if ( ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) {
|
|
// inserisco il triangolo A2p -> A1p -> A1s = 0
|
|
nIdV[0] = nV2p ;
|
|
nIdV[1] = nV1p ;
|
|
nIdV[2] = 0 ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il triangolo A2p -> A1s = 0 -> A2s = 1
|
|
nIdV[0] = nV2p ;
|
|
nIdV[1] = 0 ;
|
|
nIdV[2] = 1 ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
}
|
|
// altrimenti è dA1p -> dA2s = 1
|
|
else {
|
|
// inserisco il triangolo A2p -> A1p -> A2s = 1
|
|
nIdV[0] = nV2p ;
|
|
nIdV[1] = nV1p ;
|
|
nIdV[2] = 1 ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
// inserisco il triangolo A1p -> A1s = 0 -> A2s = 1
|
|
nIdV[0] = nV1p ;
|
|
nIdV[1] = 0 ;
|
|
nIdV[2] = 1 ;
|
|
if ( AddTriangle( nIdV) == SVT_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// sistemo la topologia
|
|
m_nStatus = TO_VERIFY ;
|
|
return AdjustTopology() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const
|
|
{
|
|
// recupero se chiusa
|
|
bool bClosed = PL1.IsClosed() && PL2.IsClosed() ;
|
|
// se chiuse, devono avere almeno 3 punti
|
|
if ( bClosed) {
|
|
if ( PL1.GetPointNbr() < 3 || PL2.GetPointNbr() < 3)
|
|
return false ;
|
|
}
|
|
// se aperte, almeno 2
|
|
else {
|
|
if ( PL1.GetPointNbr() < 2 || PL2.GetPointNbr() < 2)
|
|
return false ;
|
|
}
|
|
|
|
// verifico che non ci siano punti interni in comune a pari parametro
|
|
// recupero i parametri delle due polilinee
|
|
double dU1F ; PL1.GetFirstU( dU1F) ;
|
|
double dU1L ; PL1.GetLastU( dU1L) ;
|
|
double dDeltaU1 = dU1L - dU1F ;
|
|
if ( dDeltaU1 < EPS_SMALL)
|
|
return false ;
|
|
double dU2F ; PL2.GetFirstU( dU2F) ;
|
|
double dU2L ; PL2.GetLastU( dU2L) ;
|
|
double dDeltaU2 = dU2L - dU2F ;
|
|
if ( dDeltaU2 < EPS_SMALL)
|
|
return false ;
|
|
// ciclo sui punti
|
|
double dA1p ; double dU1p ; Point3d ptP1p ;
|
|
double dA1s ; double dU1s ; Point3d ptP1s ;
|
|
bool bNext1 = PL1.GetFirstUPoint( &dU1p, &ptP1p) && PL1.GetNextUPoint( &dU1s, &ptP1s, true) ;
|
|
if ( ! bNext1)
|
|
return true ;
|
|
dA1p = 0 ;
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
double dA2p ; double dU2s ; Point3d ptP2s ;
|
|
double dA2s ; double dU2p ; Point3d ptP2p ;
|
|
bool bNext2 = PL2.GetFirstUPoint( &dU2p, &ptP2p) && PL2.GetNextUPoint( &dU2s, &ptP2s, true) ;
|
|
if ( ! bNext2)
|
|
return true ;
|
|
dA2p = 0 ;
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
// se chiuse, verifico la coincidenza dell'inizio delle due curve
|
|
if ( bClosed && AreSamePointNear( ptP1p, ptP2p))
|
|
return false ;
|
|
// verifiche sui punti successivi (non sugli ultimi)
|
|
while ( bNext1 || bNext2) {
|
|
// se c'è nuovo dA1s e la diagonale più corta è dA2p -> dA1s oppure non c'è dA2s
|
|
if ( ( bNext1 && ( dA1s - dA2p) <= ( dA2s - dA1p) + EPS_PARAM) || ! bNext2) {
|
|
// verifico se coincidono
|
|
if ( AreSamePointNear( ptP2p, ptP1s))
|
|
return false ;
|
|
// passo al punto successivo su 1
|
|
dA1p = dA1s ; dU1p = dU1s ; ptP1p = ptP1s ;
|
|
bNext1 = PL1.GetNextUPoint( &dU1s, &ptP1s, true) ;
|
|
if ( bNext1)
|
|
dA1s = ( dU1s - dU1F) / dDeltaU1 ;
|
|
}
|
|
// altrimenti è dA1p -> dA2s = 1
|
|
else {
|
|
// verifico se coincidono
|
|
if ( AreSamePointNear( ptP1p, ptP2s))
|
|
return false ;
|
|
// passo al punto successivo su 2
|
|
dA2p = dA2s ; dU2p = dU2s ; ptP2p = ptP2s ;
|
|
bNext2 = PL2.GetNextUPoint( &dU2s, &ptP2s, true) ;
|
|
if ( bNext2)
|
|
dA2s = ( dU2s - dU2F) / dDeltaU2 ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CreateByRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx,
|
|
double dAngRot, double dStepRot)
|
|
{
|
|
return CreateByScrewing( PL, ptAx, vtAx, dAngRot, dStepRot, 0) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx,
|
|
double dAngRot, double dStepRot, double dMove)
|
|
{
|
|
// verifico che l'asse di rotazione sia non nullo
|
|
if ( vtAx.IsSmall())
|
|
return false ;
|
|
// verifico se solo rivoluzione
|
|
bool bOnlyRev = ( fabs( dMove) < EPS_SMALL) ;
|
|
// verifico che l'angolo di rotazione sia significativo e, se solo rivoluzione, non superi un giro
|
|
if ( fabs( dAngRot) < EPS_ANG_SMALL)
|
|
return false ;
|
|
if ( bOnlyRev && fabs( dAngRot) > ANG_FULL)
|
|
dAngRot = _copysign( ANG_FULL, dAngRot) ;
|
|
// verifico se rotazione completa
|
|
bool bFullRev = bOnlyRev && ( 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) ;
|
|
double dCosStepRot = cos( dAngRot / nStep * DEGTORAD) ;
|
|
double dSinStepRot = sin( dAngRot / nStep * DEGTORAD) ;
|
|
Vector3d vtStepMove = ( dMove / nStep) * vtAx ;
|
|
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 ;
|
|
}
|
|
|
|
// imposto ricalcolo
|
|
m_nStatus = ERR ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// 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 nV = -1 ;
|
|
Point3d ptP ;
|
|
// recupero il punto
|
|
if ( ! PL.GetFirstPoint( ptP))
|
|
return false ;
|
|
// inserisco il primo vertice
|
|
if ( AddVertex( ptP) == SVT_NULL)
|
|
return false ;
|
|
++ nV ;
|
|
// verifico se il punto giace sull'asse e vi sta fisso
|
|
bool bPrevOnAx = bOnlyRev && DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ;
|
|
int nVPrevOnAx = nV ;
|
|
// se non è fisso sull'asse, inserisco le copie ruotate
|
|
if ( ! bPrevOnAx) {
|
|
for ( int i = 1 ; i <= nStep ; ++i) {
|
|
ptP.Rotate( ptAx, vtAx, dCosStepRot, dSinStepRot) ;
|
|
if ( ! bOnlyRev)
|
|
ptP.Translate( vtStepMove) ;
|
|
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, bClosed)) {
|
|
// aggiungo il primo vertice
|
|
if ( AddVertex( ptP) == SVT_NULL)
|
|
return false ;
|
|
++ nV ;
|
|
// verifico se il punto giace sull'asse e vi sta fisso
|
|
bool bOnAx = bOnlyRev && DistPointLine( ptP, ptAx, vtAx, 1, false).IsSmall() ;
|
|
// ciclo sugli step
|
|
for ( int i = 1 ; i <= nStep ; ++i) {
|
|
// se non è fisso sull'asse, inserisco le copie ruotate
|
|
if ( ! bOnAx) {
|
|
ptP.Rotate( ptAx, vtAx, dCosStepRot, dSinStepRot) ;
|
|
if ( ! bOnlyRev)
|
|
ptP.Translate( vtStepMove) ;
|
|
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
|
|
if ( bClosed) {
|
|
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
|
|
m_nStatus = TO_VERIFY ;
|
|
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 è uguale o 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) + EPS_SMALL) {
|
|
// 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::DoCompacting( void)
|
|
{
|
|
// imposto ricalcolo
|
|
m_nStatus = ERR ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// definisco un Grid per i vertici della superficie
|
|
PointGrid3d VertGrid ;
|
|
int nBuckets = GetVertexSize() ;
|
|
VertGrid.Init( nBuckets) ;
|
|
|
|
// inserisco i vertici della trimesh (evitando ripetizioni coi precedenti),
|
|
// salvando in un vettore di reindirizzo i nuovi Id
|
|
INTVECTOR vVId ;
|
|
vVId.reserve( GetVertexSize()) ;
|
|
for ( int nId = 0 ; nId < GetVertexSize() ; ++ nId) {
|
|
// salto i vertici cancellati (ma ne occupo il posto nel vettore di reindirizzo)
|
|
if ( m_vVert[nId].nIdTria == SVT_DEL) {
|
|
vVId.push_back( SVT_DEL) ;
|
|
continue ;
|
|
}
|
|
// recupero la posizione geometrica del vertice
|
|
Point3d ptP = m_vVert[nId].ptP ;
|
|
// se non c'è già un vertice con la stessa posizione lo inserisco nel grid
|
|
int nAliasId ;
|
|
if ( ! VertGrid.Find( ptP, 2 * EPS_SMALL, nAliasId)) {
|
|
VertGrid.InsertPoint( ptP, nId) ;
|
|
// salvo l'Id nel vettore di reindirizzo
|
|
vVId.push_back( nId) ;
|
|
}
|
|
// c'e un vertice coincidente
|
|
else {
|
|
// salvo l'Id alias nel vettore di reindirizzo
|
|
vVId.push_back( nAliasId) ;
|
|
// marco il vertice come cancellato
|
|
m_vVert[nId].nIdTria = SVT_DEL ;
|
|
}
|
|
}
|
|
int nVIdSize = int( vVId.size()) ;
|
|
|
|
// sistemo gli indici dei vertici nei triangoli
|
|
for ( int nId = 0 ; nId < GetTriangleSize() ; ++ nId) {
|
|
// recupero gli indici dei vertici del triangolo
|
|
int vOId[3] ;
|
|
vOId[0] = m_vTria[nId].nIdVert[0] ;
|
|
vOId[1] = m_vTria[nId].nIdVert[1] ;
|
|
vOId[2] = m_vTria[nId].nIdVert[2] ;
|
|
// salto i triangoli cancellati
|
|
if ( vOId[0] == SVT_DEL)
|
|
continue ;
|
|
// verifico la validità degli indici
|
|
if ( vOId[0] < 0 || vOId[0] >= nVIdSize ||
|
|
vOId[1] < 0 || vOId[1] >= nVIdSize ||
|
|
vOId[2] < 0 || vOId[2] >= nVIdSize)
|
|
return false ;
|
|
// aggiorno il triangolo
|
|
m_vTria[nId].nIdVert[0] = vVId[vOId[0]] ;
|
|
m_vTria[nId].nIdVert[1] = vVId[vOId[1]] ;
|
|
m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ;
|
|
}
|
|
|
|
// ricalcolo le adiacenze
|
|
m_nStatus = TO_VERIFY ;
|
|
return AdjustTopology() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::DoSewing( const ISurfTriMesh& stmOther, const Frame3d& frOther)
|
|
{
|
|
// recupero l'altra superficie
|
|
const SurfTriMesh* pOther = dynamic_cast<const SurfTriMesh*>( &stmOther) ;
|
|
if ( pOther == nullptr)
|
|
return false ;
|
|
|
|
// imposto ricalcolo
|
|
m_nStatus = ERR ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// definisco un Grid per i vertici delle due superfici
|
|
PointGrid3d VertGrid ;
|
|
int nBuckets = GetVertexSize() + pOther->GetVertexSize() ;
|
|
VertGrid.Init( nBuckets) ;
|
|
|
|
// inserisco i vertici della trimesh corrente (li considero tutti diversi tra loro)
|
|
for ( int nId = 0 ; nId < GetVertexSize() ; ++ nId) {
|
|
// salto i vertici cancellati
|
|
if ( m_vVert[nId].nIdTria == SVT_DEL)
|
|
continue ;
|
|
// inserisco il vertice nella griglia
|
|
VertGrid.InsertPoint( m_vVert[nId].ptP, nId) ;
|
|
}
|
|
|
|
// inserisco i vertici dell'altra trimesh (evitando ripetizioni coi precedenti),
|
|
// salvando in un vettore di reindirizzo i nuovi Id
|
|
INTVECTOR vVId ;
|
|
vVId.reserve( pOther->GetVertexSize()) ;
|
|
for ( int nOId = 0 ; nOId < pOther->GetVertexSize() ; ++ nOId) {
|
|
// salto i vertici cancellati (ma ne occupo il posto nel vettore di reindirizzo)
|
|
if ( pOther->m_vVert[nOId].nIdTria == SVT_DEL) {
|
|
vVId.push_back( SVT_DEL) ;
|
|
continue ;
|
|
}
|
|
// recupero la posizione geometrica del vertice
|
|
Point3d ptOP = pOther->m_vVert[nOId].ptP ;
|
|
// la porto nel riferimento della prima superficie
|
|
ptOP.ToGlob( frOther) ;
|
|
// se non c'è già un vertice con la stessa posizione lo inserisco
|
|
int nNewId ;
|
|
if ( ! VertGrid.Find( ptOP, 2 * EPS_SMALL, nNewId)) {
|
|
if ( ( nNewId = AddVertex( ptOP)) == SVT_NULL)
|
|
return false ;
|
|
VertGrid.InsertPoint( ptOP, nNewId) ;
|
|
}
|
|
// salvo il nuovo Id nel vettore di reindirizzo
|
|
vVId.push_back( nNewId) ;
|
|
}
|
|
int nVIdSize = int( vVId.size()) ;
|
|
|
|
// inserisco i triangoli dell'altra trimesh
|
|
for ( int nOtId = 0 ; nOtId < pOther->GetTriangleSize() ; ++ nOtId) {
|
|
// recupero gli indici dei vertici del triangolo
|
|
int vOId[3] ;
|
|
vOId[0] = pOther->m_vTria[nOtId].nIdVert[0] ;
|
|
vOId[1] = pOther->m_vTria[nOtId].nIdVert[1] ;
|
|
vOId[2] = pOther->m_vTria[nOtId].nIdVert[2] ;
|
|
// salto i triangoli cancellati
|
|
if ( vOId[0] == SVT_DEL)
|
|
continue ;
|
|
// verifico la validità degli indici
|
|
if ( vOId[0] < 0 || vOId[0] >= nVIdSize ||
|
|
vOId[1] < 0 || vOId[1] >= nVIdSize ||
|
|
vOId[2] < 0 || vOId[2] >= nVIdSize)
|
|
return false ;
|
|
int vId[3] ;
|
|
vId[0] = vVId[vOId[0]] ;
|
|
vId[1] = vVId[vOId[1]] ;
|
|
vId[2] = vVId[vOId[2]] ;
|
|
// inserisco il triangolo
|
|
if ( AddTriangle( vId) == SVT_NULL)
|
|
return false ;
|
|
}
|
|
|
|
// ricalcolo le adiacenze
|
|
m_nStatus = TO_VERIFY ;
|
|
return AdjustTopology() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 < GetVertexSize() ; ++ 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 < GetVertexSize() ; ++ 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 < GetVertexSize() ; ++ 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 < GetVertexSize() ; ++ 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 < GetTriangleSize() ; ++ 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 < GetVertexSize() ; ++ 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 < GetTriangleSize() ; ++ 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] < 0 ||
|
|
m_vTria[nT].nIdVert[0] >= GetVertexSize() ||
|
|
m_vVert[m_vTria[nT].nIdVert[0]].nIdTria == SVT_DEL ||
|
|
m_vTria[nT].nIdVert[1] < 0 ||
|
|
m_vTria[nT].nIdVert[1] >= GetVertexSize() ||
|
|
m_vVert[m_vTria[nT].nIdVert[1]].nIdTria == SVT_DEL ||
|
|
m_vTria[nT].nIdVert[2] < 0 ||
|
|
m_vTria[nT].nIdVert[2] >= GetVertexSize() ||
|
|
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 < GetVertexSize() ; ++ i)
|
|
m_vVert[i].ptP.Mirror( ptOn, vtNorm) ;
|
|
|
|
// inverto le facce
|
|
for ( int i = 0 ; i < GetTriangleSize() ; ++ 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::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità dei parametri
|
|
if ( vtNorm.IsSmall() || vtDir.IsSmall())
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo scorrimento dei vertici
|
|
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
|
|
if ( m_vVert[i].nIdTria != SVT_DEL)
|
|
m_vVert[i].ptP.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
|
|
}
|
|
|
|
// aggiorno le facce
|
|
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
|
|
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
|
|
// 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 ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i vertici
|
|
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
|
|
if ( m_vVert[i].nIdTria != SVT_DEL)
|
|
m_vVert[i].ptP.ToGlob( frRef) ;
|
|
}
|
|
|
|
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 ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i vertici
|
|
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
|
|
if ( m_vVert[i].nIdTria != SVT_DEL)
|
|
m_vVert[i].ptP.ToLoc( frRef) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// verifico validità dei frame
|
|
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se i due riferimenti coincidono, non devo fare alcunché
|
|
if ( AreSameFrame( frOri, frDest))
|
|
return true ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i vertici
|
|
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
|
|
if ( m_vVert[i].nIdTria != SVT_DEL)
|
|
m_vVert[i].ptP.LocToLoc( frOri, frDest) ;
|
|
}
|
|
|
|
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 < GetTriangleSize() ; ++ i)
|
|
InvertTriangle( i) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|