Files
EgtGeomKernel/SurfTriMeshFaceting.cpp
T
Dario Sassi 6c14e51ef6 EgtGeomKernel 1.6c2 :
- aggiunte funzioni per circonferenze e archi tangenti.
2015-03-16 07:38:43 +00:00

535 lines
20 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : SurfTriMeshFaceting.cpp Data : 25.02.15 Versione : 1.6b
// 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 "GeoConst.h"
#include "PolygonPlane.h"
using namespace std ;
//----------------------------------------------------------------------------
bool
SurfTriMesh::ResetFaceting( void)
{
m_bFaceted = false ;
m_vFacet.clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::VerifyFaceting( void) const
{
if ( m_bFaceted)
return true ;
return (const_cast<SurfTriMesh*>(this))->UpdateFaceting() ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::UpdateFaceting( void)
{
// reset faceting
m_bFaceted = false ;
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i)
m_vTria[i].nIdFacet = SVT_NULL ;
// ricostruisco le sfaccettature
int nFacet = 0 ;
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL &&
m_vTria[i].nIdFacet == SVT_NULL) {
// assegno indice di faccia al triangolo
m_vTria[i].nIdFacet = nFacet ;
m_vFacet.push_back( i) ;
++ nFacet ;
// piano del triangolo
Plane3d plPlane ;
if ( ! SetPlane( m_vVert[m_vTria[i].nIdVert[0]].ptP, m_vTria[i].vtN, plPlane))
return false ;
// aggiorno i triangoli adiacenti
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[i].nIdAdjac[j] ;
if ( nAdjT != SVT_NULL &&
m_vTria[nAdjT].nIdFacet == SVT_NULL) {
if ( ! UpdateTriaFaceting( i, m_vTria[i].nIdFacet, plPlane, nAdjT))
return false ;
}
}
}
}
// calcolo facce piane riuscito
m_bFaceted = true ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::UpdateTriaFaceting( int nRefT, int nFacet, const Plane3d& plPlane, int nT)
{
// verifica scostamento della normale da quella del piano
if ( plPlane.vtN * m_vTria[nT].vtN < m_dCosBndAng)
return true ;
// verifica scostamento del vertice opposto al lato in comune dal piano
int nV = SVT_NULL ;
for ( int i = 0 ; i < 3 ; ++i) {
if ( m_vTria[nT].nIdAdjac[i] == nRefT) {
nV = Prev( i) ;
break ;
}
}
if ( nV == SVT_NULL)
return false ;
if ( ! PointInPlaneApprox( m_vVert[m_vTria[nT].nIdVert[nV]].ptP, plPlane))
return true ;
// il triangolo fa parte della faccia
m_vTria[nT].nIdFacet = nFacet ;
// aggiorno i triangoli adiacenti
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
if ( nAdjT != SVT_NULL &&
m_vTria[nAdjT].nIdFacet == SVT_NULL) {
if ( ! UpdateTriaFaceting( nT, nFacet, plPlane, nAdjT))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetFacetNum( void) const
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return 0 ;
// verifico stato sfaccettatura
if ( ! VerifyFaceting())
return 0 ;
// restituisco il numero
return int( m_vFacet.size()) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::SetFacet( int nInd, int nT)
{
// recupero la dimensione originale
int nPrevSize = int( m_vFacet.size()) ;
// determino la dimensione necessaria
int nNewSize = max( nInd + 1, nPrevSize) ;
// se necessaria dimensione maggiore
if ( nNewSize > nPrevSize) {
// espando vettore
try { m_vFacet.resize( nNewSize) ; }
catch (...) { return false ; }
// inizializzo a cancellate le eventuali facce intermedie
if ( ( nNewSize - nPrevSize) > 1) {
for ( int i = nPrevSize ; i < nNewSize ; ++ i)
m_vFacet[i] = SVT_DEL ;
}
}
// inserisco la faccia
m_vFacet[nInd] = nT ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetFacetFromTria( int nT) const
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return SVT_NULL ;
// verifico stato sfaccettatura
if ( ! VerifyFaceting())
return SVT_NULL ;
// l'indice del triangolo deve essere nei limiti
if ( nT < 0 || nT >= int( m_vTria.size()) || m_vTria[nT].nIdVert[0] == SVT_DEL)
return SVT_NULL ;
// restituisco l'indice di faccia
return m_vTria[nT].nIdFacet ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetAllTriaInFacet( int nF, INTVECTOR& vT) const
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico stato sfaccettatura
if ( ! VerifyFaceting())
return false ;
// l'indice della faccia deve essere nei limiti
if ( nF < 0 || nF >= int( m_vFacet.size()))
return false ;
// recupero l'indice del primo triangolo della faccia
int nT = m_vFacet[nF] ;
// incremento time stamp
++ m_nTimeStamp ;
// recupero i triangoli della faccia
vT.clear() ;
vT.reserve( 10) ;
vT.push_back( nT) ;
m_vTria[nT].nTemp = m_nTimeStamp ;
return VerifyAdjacTriaFacet( nT, vT) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::VerifyAdjacTriaFacet( int nT, INTVECTOR& vT) const
{
// verifico i triangoli adiacenti
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
if ( nAdjT != SVT_NULL &&
m_vTria[nAdjT].nTemp != m_nTimeStamp &&
m_vTria[nAdjT].nIdFacet == m_vTria[nT].nIdFacet) {
vT.push_back( nAdjT) ;
m_vTria[nAdjT].nTemp = m_nTimeStamp ;
if ( ! VerifyAdjacTriaFacet( nAdjT, vT))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetFacetNearestEndPoint( int nF, const Point3d& ptNear, Point3d& ptEnd, Vector3d& vtN) const
{
// recupero l'elenco dei triangoli della faccia
INTVECTOR vTria ;
if ( ! GetAllTriaInFacet( nF, vTria))
return false ;
// ciclo sui triangoli e sui loro lati di bordo
bool bFound = false ;
double dMinSqDist = INFINITO * INFINITO ;
for ( int i = 0 ; i < int( vTria.size()) ; ++i) {
int nT = vTria[i] ;
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
if ( nAdjT == SVT_NULL ||
m_vTria[nAdjT].nIdFacet != nF) {
Point3d ptTest = m_vVert[m_vTria[nT].nIdVert[j]].ptP ;
double dSqDist = SqDist( ptTest, ptNear) ;
if ( dSqDist < dMinSqDist) {
// salvo i dati del punto
dMinSqDist = dSqDist ;
ptEnd = ptTest ;
bFound = true ;
// recupero la normale della faccia (non quella mediata del vertice)
vtN = m_vTria[nT].vtN ;
//Vector3d vtN1, vtN2 ;
//if ( ! GetTriangleSmoothNormal( nT, j, vtN))
// vtN = m_vTria[nT].vtN ;
}
}
}
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetFacetNearestMidPoint( int nF, const Point3d& ptNear, Point3d& ptMid, Vector3d& vtN) const
{
// recupero l'elenco dei triangoli della faccia
INTVECTOR vTria ;
if ( ! GetAllTriaInFacet( nF, vTria))
return false ;
// ciclo sui triangoli e sui loro lati di bordo
bool bFound = false ;
double dMinSqDist = INFINITO * INFINITO ;
for ( int i = 0 ; i < int( vTria.size()) ; ++i) {
int nT = vTria[i] ;
for ( int j = 0 ; j < 3 ; ++ j) {
int k = Next( j) ;
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
if ( nAdjT == SVT_NULL ||
m_vTria[nAdjT].nIdFacet != nF) {
Point3d ptTest = Media( m_vVert[m_vTria[nT].nIdVert[j]].ptP,
m_vVert[m_vTria[nT].nIdVert[k]].ptP, 0.5) ;
double dSqDist = SqDist( ptTest, ptNear) ;
if ( dSqDist < dMinSqDist) {
// salvo i dati del punto
dMinSqDist = dSqDist ;
ptMid = ptTest ;
bFound = true ;
// recupero la normale della faccia (non quella mediata del vertice)
vtN = m_vTria[nT].vtN ;
//Vector3d vtN1, vtN2 ;
//if ( GetTriangleSmoothNormal( nT, j, vtN1) &&
// GetTriangleSmoothNormal( nT, k, vtN2)) {
// vtN = Media( vtN1, vtN2, 0.5) ;
// vtN.Normalize() ;
//}
//else
// vtN = m_vTria[nT].vtN ;
}
}
}
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
{
// recupero l'elenco dei triangoli della faccia
INTVECTOR vTria ;
if ( ! GetAllTriaInFacet( nF, vTria))
return false ;
// incremento time stamp
++ m_nTimeStamp ;
// ciclo sui triangoli
for ( int i = 0 ; i < int( vTria.size()) ; ++ i) {
int nT = vTria[i] ;
// se triangolo non ancora visitato
if ( m_vTria[nT].nTemp != m_nTimeStamp) {
// determino i triangoli adiacenti
int nAdjT[3] ;
for ( int j = 0 ; j < 3 ; ++ j)
nAdjT[j] = m_vTria[nT].nIdAdjac[j] ;
// se tutti e tre i lati sono di contorno
if ( ( nAdjT[0] == SVT_NULL || m_vTria[nAdjT[0]].nIdFacet != nF) &&
( nAdjT[1] == SVT_NULL || m_vTria[nAdjT[1]].nIdFacet != nF) &&
( nAdjT[2] == SVT_NULL || m_vTria[nAdjT[2]].nIdFacet != nF)) {
// ho trovato un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
}
// se i due lati 0 e 1 sono di contorno
else if ( ( nAdjT[0] == SVT_NULL || m_vTria[nAdjT[0]].nIdFacet != nF) &&
( nAdjT[1] == SVT_NULL || m_vTria[nAdjT[1]].nIdFacet != nF)) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 2, m_nTimeStamp, vPL.back()))
return false ;
}
// se i due lati 1 e 2 sono di contorno
else if ( ( nAdjT[1] == SVT_NULL || m_vTria[nAdjT[1]].nIdFacet != nF) &&
( nAdjT[2] == SVT_NULL || m_vTria[nAdjT[2]].nIdFacet != nF)) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 0, m_nTimeStamp, vPL.back()))
return false ;
}
// se i due lati 2 e 0 sono di contorno
else if ( ( nAdjT[2] == SVT_NULL || m_vTria[nAdjT[2]].nIdFacet != nF) &&
( nAdjT[0] == SVT_NULL || m_vTria[nAdjT[0]].nIdFacet != nF)) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 1, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 0 è di contorno
else if ( nAdjT[0] == SVT_NULL || m_vTria[nAdjT[0]].nIdFacet != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 1, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 1 è di contorno
else if ( nAdjT[1] == SVT_NULL || m_vTria[nAdjT[1]].nIdFacet != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 2, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 2 è di contorno
else if ( nAdjT[2] == SVT_NULL || m_vTria[nAdjT[2]].nIdFacet != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
// cammino lungo il loop fino a chiuderlo
if ( ! MarchAlongLoop( nF, nT, 0, m_nTimeStamp, vPL.back()))
return false ;
}
// altrimenti non c'è contorno
else {
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
}
}
}
// normale di riferimento della faccia
Vector3d vtN = m_vTria[vTria[0]].vtN ;
// in prima posizione ci deve essere il loop esterno
bool bOutFirst = false ;
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
Plane3d plPlane ;
double dArea ;
if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea))
return false ;
// se loop esterno
if ( vtN * plPlane.vtN > 0) {
// se non c'è ancora loop esterno in prima posizione
if ( ! bOutFirst) {
// lo sposto in prima posizione
if ( i != 0)
swap( vPL[0], vPL[i]) ;
bOutFirst = true ;
}
// altrimenti errore
else
return false ;
}
}
return bOutFirst ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::MarchAlongLoop( int nF, int nT, int nV, int nTimeStamp, PolyLine& PL) const
{
// mi muovo lungo il loop, un triangolo alla volta
bool bEnd = false ;
while ( ! bEnd) {
if ( ! MarchOneTria( nF, nT, nV, nTimeStamp, PL, bEnd))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::MarchOneTria( int nF, int& nT, int& nV, int nTimeStamp,
PolyLine& PL, bool& bEnd) const
{
// verifico esistenza triangolo adiacente, sul lato dopo il vertice
if ( m_vTria[nT].nIdAdjac[nV] == SVT_NULL)
return false ;
int nAdjT = m_vTria[nT].nIdAdjac[nV] ;
// verifico appartenga alla stessa faccia
if ( m_vTria[nAdjT].nIdFacet != nF)
return false ;
// recupero il suo lato di adiacenza
int nAdjS = SVT_NULL ;
for ( int i = 0 ; i < 3 ; ++ i) {
if ( m_vTria[nAdjT].nIdAdjac[i] == nT) {
nAdjS = i ;
break ;
}
}
if ( nAdjS == SVT_NULL)
return false ;
// vertice di fine adiacenza e indice del successivo lato
int nAdjV = Next( nAdjS) ;
// verifico se il lato successivo è un bordo
int nNextT = m_vTria[nAdjT].nIdAdjac[nAdjV] ;
if ( nNextT == SVT_NULL || m_vTria[nNextT].nIdFacet != nF) {
// se già recuperato
if ( m_vTria[nAdjT].nTemp == nTimeStamp) {
bEnd = true ;
return true ;
}
// dichiaro triangolo analizzato
m_vTria[nAdjT].nTemp = nTimeStamp ;
// aggiungo il lato al loop
nAdjV = Next( nAdjV) ;
PL.AddUPoint( nAdjT, m_vVert[m_vTria[nAdjT].nIdVert[nAdjV]].ptP) ;
// verifico anche il successivo
nNextT = m_vTria[nAdjT].nIdAdjac[nAdjV] ;
if ( nNextT == SVT_NULL || m_vTria[nNextT].nIdFacet != nF) {
// aggiungo il lato al loop
nAdjV = Next( nAdjV) ;
PL.AddUPoint( nAdjT, m_vVert[m_vTria[nAdjT].nIdVert[nAdjV]].ptP) ;
}
}
// devo passare al triangolo adiacente
nT = nAdjT ;
nV = nAdjV ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetFacetCenter( int nF, Point3d& ptCen, Vector3d& vtN) const
{
// recupero i loop della faccia
POLYLINEVECTOR vPL ;
if ( ! GetFacetLoops( nF, vPL) || vPL.size() == 0)
return false ;
// calcolo il centro del loop esterno (è il primo)
PolygonPlane PolyPlane ;
Point3d ptP ;
for ( bool bFound = vPL[0].GetFirstPoint( ptP) ; bFound ; bFound = vPL[0].GetNextPoint( ptP))
PolyPlane.AddPoint( ptP) ;
if ( ! PolyPlane.GetCentroid( ptCen))
return false ;
// recupero la normale di un triangolo della faccetta
vtN = m_vTria[m_vFacet[nF]].vtN ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetFacetNormal( int nF, Vector3d& vtN) const
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico stato sfaccettatura
if ( ! VerifyFaceting())
return false ;
// l'indice della faccia deve essere nei limiti
if ( nF < 0 || nF >= int( m_vFacet.size()))
return false ;
// recupero la normale di un triangolo della faccetta
vtN = m_vTria[m_vFacet[nF]].vtN ;
return true ;
}