EgtGeomKernel 1.6b8 :

- velocizzata chiusura DB con molte entità selezionate
- aggiunta intersezione linea superficie TM (versione semplice)
- migliorata intersezione linea-triangolo
- aggiunto calcolo area di superfici TM
- aggiunto calcolo volume di superfici TM chiuse
- aggiunta gestione facce piane di superficie TM
- aggiunto calcolo punti notevoli di facce di superfici TM.
This commit is contained in:
Dario Sassi
2015-03-11 07:55:53 +00:00
parent 1b85e111dc
commit 6fc5e1f338
12 changed files with 1062 additions and 152 deletions
BIN
View File
Binary file not shown.
+2
View File
@@ -295,6 +295,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="IntersLineSurfTm.cpp" />
<ClCompile Include="IntersLineTria.cpp" />
<ClCompile Include="IterManager.cpp" />
<ClCompile Include="LinePerpTwoCurves.cpp" />
@@ -325,6 +326,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="StmFromTriangleSoup.cpp" />
<ClCompile Include="StringUtils3d.cpp" />
<ClCompile Include="SurfTriMesh.cpp" />
<ClCompile Include="SurfTriMeshFaceting.cpp" />
<ClCompile Include="Triangulate.cpp" />
<ClCompile Include="Vector3d.cpp" />
<ClCompile Include="NgeWriter.cpp" />
+6
View File
@@ -258,6 +258,12 @@
<ClCompile Include="IntersLineTria.cpp">
<Filter>File di origine\GeoInters</Filter>
</ClCompile>
<ClCompile Include="SurfTriMeshFaceting.cpp">
<Filter>File di origine\Geo</Filter>
</ClCompile>
<ClCompile Include="IntersLineSurfTm.cpp">
<Filter>File di origine\GeoInters</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
+2
View File
@@ -93,6 +93,8 @@ GeomDB::Init( void)
bool
GeomDB::Clear( void)
{
// deseleziono tutto (velocizza, perchè segue ordine lista selezione)
ClearSelection() ;
// disalloco i gruppi e gli oggetti
m_GrpRadix.Clear() ;
// pulisco lista dei selezionati
+3
View File
@@ -54,10 +54,13 @@ IntersLinePlane( const Point3d& ptL, const Vector3d& vtL, double dLen, const Pla
// intersezione sul primo estremo
if ( fabs( dDistI) < EPS_SMALL)
return ILPT_START ;
// intersezione sul secondo estremo
else if ( fabs( dDistI - dLen) < EPS_SMALL)
return ILPT_END ;
// intersezione interna
else if ( dDistI > 0 && dDistI < dLen)
return ILPT_YES ;
// nessuna intersezione
else
return ILPT_NO ;
}
+59
View File
@@ -0,0 +1,59 @@
//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : IntersLineSurfTm.cpp Data : 09.03.15 Versione : 1.6b8
// Contenuto : Implementazione della intersezione linea/superficie trimesh.
//
//
//
// Modifiche : 09.03.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "ProjPlane.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
using namespace std ;
//----------------------------------------------------------------------------
bool
IntersLineSurfTm( const Point3d& ptL, const Vector3d& vtL, double dLen, const ISurfTriMesh& Stm,
ILSIVECTOR& vInfo)
{
// verifico linea
Vector3d vtDir = vtL ;
if ( ! vtDir.Normalize( EPS_ZERO))
return false ;
// verifico superficie
if ( &Stm == nullptr)
return false ;
// verifico parametro di ritorno
if ( &vInfo == nullptr)
return false ;
// cerco i triangoli intersecati dalla linea
Triangle3d Tria ;
int nT = Stm.GetFirstTriangle( Tria) ;
while ( nT != SVT_NULL) {
Point3d ptInt, ptInt2 ;
int nRes = IntersLineTria( ptL, vtDir, dLen, Tria, ptInt, ptInt2) ;
if ( nRes == ILTT_IN || nRes == ILTT_EDGE || nRes == ILTT_VERT) {
double dU = ( ptInt - ptL) * vtDir ;
vInfo.emplace_back( dU, nT, ptInt) ;
}
nT = Stm.GetNextTriangle( nT, Tria) ;
}
// se non trovati, esco
if ( vInfo.size() == 0)
return true ;
// ordino il vettore delle intersezioni secondo il senso crescente del parametro di linea
sort( vInfo.begin(), vInfo.end(),
[]( const IntLinStmInfo& a, const IntLinStmInfo&b) { return a.dU < b.dU ; }) ;
return true ;
}
+6 -4
View File
@@ -19,7 +19,8 @@
//----------------------------------------------------------------------------
int
IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTria, Point3d& ptInt)
IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTria,
Point3d& ptInt, Point3d& ptInt2)
{
Vector3d vtL = ptL2 - ptL1 ;
double dLen = vtL.Len() ;
@@ -27,12 +28,13 @@ IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTr
vtL /= dLen ;
else
vtL = V_NULL ;
return IntersLineTria( ptL1, vtL, dLen, trTria, ptInt) ;
return IntersLineTria( ptL1, vtL, dLen, trTria, ptInt, ptInt2) ;
}
//----------------------------------------------------------------------------
int
IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt)
IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria,
Point3d& ptInt, Point3d& ptInt2)
{
// determino il piano del triangolo
Plane3d plPlane ;
@@ -45,7 +47,7 @@ IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Tria
return ILTT_NO ;
// se c'è una intersezione
else if ( nRes == ILPT_START || nRes == ILPT_END || nRes == ILPT_YES) {
int nPTT = PointInTria( ptInt, trTria.GetP(0), trTria.GetP(1), trTria.GetP(2), trTria.GetN()) ;
int nPTT = PointInTria( ptInt, trTria) ;
switch ( nPTT) {
case PTT_OUT :
return ILTT_NO ;
+3 -1
View File
@@ -29,7 +29,9 @@ const int NGE_VER_1008 = 1008 ;
// 1008 : aggiunge vtExtr e dThick a tutte le curve
const int NGE_VER_1009 = 1009 ;
// 1009 : aggiunto solido ZMAP e cambiato Id di TEXT
const int NGE_VER_LAST = NGE_VER_1009 ;
const int NGE_VER_1010 = 1010 ;
// 1010 : aggiunto flag orientata e elenco facce a SurfTm
const int NGE_VER_LAST = NGE_VER_1010 ;
// Indici KeyWord
const int NGE_START = 0 ;
const int NGE_END = 1 ;
+82 -59
View File
@@ -16,46 +16,67 @@
#include "/EgtDev/Include/EGkTriangle3d.h"
//-----------------------------------------------------------------------------
enum PlaneType { PL_NULL = 0,
PL_XY = 1,
PL_YZ = 2,
PL_ZX = 3} ;
enum PntTriaPos { PTT_OUT = 0, // punto esterno al triangolo
PTT_VERT = 1, // punto su un vertice
PTT_EDGE = 2, // punto interno ad un lato
PTT_IN = 3} ; // punto interno
//----------------------------------------------------------------------------
// Piano canonico di miglior proiezione (perpendicolare alla componente maggiore della normale)
#define UpdateMin( dMin, dVal) if ( dVal < dMin) dMin = dVal ;
#define UpdateMax( dMax, dVal) if ( dVal > dMax) dMax = dVal ;
//----------------------------------------------------------------------------
// Verifica se un punto è compreso nel box del triangolo.
inline bool
CalcProjPlane( const Vector3d& vtN, int& nPlane, bool& bCCW)
PointInTriaBox( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
// verifico che la normale non sia nulla
if ( vtN.IsZero())
double Xmin = ptA.x ; UpdateMin( Xmin, ptB.x) UpdateMin( Xmin, ptC.x)
if ( ptP.x < Xmin - EPS_SMALL)
return false ;
double Ymin = ptA.y ; UpdateMin( Ymin, ptB.y) UpdateMin( Ymin, ptC.y)
if ( ptP.y < Ymin - EPS_SMALL)
return false ;
double Zmin = ptA.z ; UpdateMin( Zmin, ptB.z) UpdateMin( Zmin, ptC.z)
if ( ptP.z < Zmin - EPS_SMALL)
return false ;
double Xmax = ptA.x ; UpdateMax( Xmax, ptB.x) UpdateMax( Xmax, ptC.x)
if ( ptP.x > Xmax + EPS_SMALL)
return false ;
double Ymax = ptA.y ; UpdateMax( Ymax, ptB.y) UpdateMax( Ymax, ptC.y)
if ( ptP.y > Ymax + EPS_SMALL)
return false ;
double Zmax = ptA.z ; UpdateMax( Zmax, ptB.z) UpdateMax( Zmax, ptC.z)
if ( ptP.z > Zmax + EPS_SMALL)
return false ;
// proiezione sul piano XY (Nz con valore maggiore)
if ( fabs( vtN.z) > fabs( vtN.x) &&
fabs( vtN.z) > fabs( vtN.y)) {
nPlane = PL_XY ;
bCCW = ( vtN.z > 0) ;
}
// proiezione sul piano YZ (Nx con valore maggiore)
else if ( fabs( vtN.x) > fabs( vtN.y)) {
nPlane = PL_YZ ;
bCCW = ( vtN.x > 0) ;
}
// proiezione sul piano ZX (Ny con valore maggiore)
else {
nPlane = PL_ZX ;
bCCW = ( vtN.y > 0) ;
}
return true ;
}
//----------------------------------------------------------------------------
// Coincidenza approssimata di punti nel piano di proiezione
inline bool
AreSamePointApproxInPlane( int nPlane, const Point3d& ptP1, const Point3d& ptP2)
{
double dX, dY, dZ ;
switch ( nPlane) {
default : // PL_XY
dX = ptP1.x - ptP2.x ;
dY = ptP1.y - ptP2.y ;
return ( ( dX * dX + dY * dY) < EPS_SMALL * EPS_SMALL) ;
case PL_YZ :
dY = ptP1.y - ptP2.y ;
dZ = ptP1.z - ptP2.z ;
return ( ( dY * dY + dZ * dZ) < EPS_SMALL * EPS_SMALL) ;
case PL_ZX :
dZ = ptP1.z - ptP2.z ;
dX = ptP1.x - ptP2.x ;
return ( ( dZ * dZ + dX * dX) < EPS_SMALL * EPS_SMALL) ;
}
}
//----------------------------------------------------------------------------
// Lunghezza del segmento nel piano di proiezione
inline double
LenSegment( int nPlane, const Point3d& ptA, const Point3d& ptB)
LenSegmentInPlane( int nPlane, const Point3d& ptA, const Point3d& ptB)
{
switch ( nPlane) {
default : // PL_XY
@@ -68,53 +89,55 @@ LenSegment( int nPlane, const Point3d& ptA, const Point3d& ptB)
}
//----------------------------------------------------------------------------
// Prodotto vettoriale nel piano di proiezione ( positivo se i 3 punti in ordine CCW)
inline double
TwoArea( int nPlane, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
switch ( nPlane) {
default : // PL_XY
return ( ptB.x - ptA.x) * ( ptC.y - ptB.y) - ( ptB.y - ptA.y) * ( ptC.x - ptB.x) ;
case PL_YZ :
return ( ptB.y - ptA.y) * ( ptC.z - ptB.z) - ( ptB.z - ptA.z) * ( ptC.y - ptB.y) ;
case PL_ZX :
return ( ptB.z - ptA.z) * ( ptC.x - ptB.x) - ( ptB.x - ptA.x) * ( ptC.z - ptB.z) ;
}
}
//----------------------------------------------------------------------------
// Verifica se un punto giacente nel piano del triangolo è compreso nello stesso.
inline int
PointInTria( const Point3d& ptP,
const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, const Vector3d& vtN)
PointInTria( const Point3d& ptP, const Triangle3d& Tria)
{
// verifico che il punto stia nel box del triangolo
if ( ! PointInTriaBox( ptP, Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2)))
return PTT_OUT ;
// calcolo il piano ottimale di proiezione
int nPlane ;
bool bCCW ;
if ( ! CalcProjPlane( vtN, nPlane, bCCW))
if ( ! CalcProjPlane( Tria.GetN(), nPlane, bCCW))
return PTT_OUT ;
// verifico se il punto sta su un vertice
if ( AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 0)) ||
AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 1)) ||
AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 2)))
return PTT_VERT ;
// calcolo la lunghezza dei lati
double dLenAB = LenSegment( nPlane, ptA, ptB) ;
double dLenBC = LenSegment( nPlane, ptB, ptC) ;
double dLenCA = LenSegment( nPlane, ptC, ptA) ;
double dLenAB = LenSegmentInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1)) ;
double dLenBC = LenSegmentInPlane( nPlane, Tria.GetP( 1), Tria.GetP( 2)) ;
double dLenCA = LenSegmentInPlane( nPlane, Tria.GetP( 2), Tria.GetP( 0)) ;
if ( dLenAB < EPS_SMALL || dLenBC < EPS_SMALL || dLenCA < EPS_SMALL)
return PTT_OUT ;
// determino la posizione del punto rispetto ai lati del triangolo
double dPosAB = TwoArea( nPlane, ptP, ptA, ptB) / dLenAB ;
double dPosBC = TwoArea( nPlane, ptP, ptB, ptC) / dLenBC ;
double dPosCA = TwoArea( nPlane, ptP, ptC, ptA) / dLenCA ;
double dPosAB = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 0), Tria.GetP( 1)) / dLenAB ;
double dPosBC = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) / dLenBC ;
double dPosCA = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 2), Tria.GetP( 0)) / dLenCA ;
// se tre valori nulli, triangolo non definito correttamente
if ( fabs( dPosAB) < EPS_SMALL && fabs( dPosBC) < EPS_SMALL && fabs( dPosCA) < EPS_SMALL)
return PTT_OUT ;
// se due valori nulli, sta su un vertice
if ( ( fabs( dPosAB) < EPS_SMALL && fabs( dPosBC) < EPS_SMALL) ||
( fabs( dPosBC) < EPS_SMALL && fabs( dPosCA) < EPS_SMALL) ||
( fabs( dPosCA) < EPS_SMALL && fabs( dPosAB) < EPS_SMALL))
return PTT_VERT ;
// se un valore nullo e gli altri due con lo stesso segno, sta su un lato
if ( ( fabs( dPosAB) < EPS_SMALL && ( dPosBC * dPosCA > 0)) ||
( fabs( dPosBC) < EPS_SMALL && ( dPosCA * dPosAB > 0)) ||
( fabs( dPosCA) < EPS_SMALL && ( dPosAB * dPosBC > 0)))
return PTT_EDGE ;
// se un valore nullo e gli altri due con lo stesso segno
if ( fabs( dPosAB) < EPS_SMALL && ( dPosBC * dPosCA) > 0) {
// se la proiezione del punto sta sul lato AB
double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 0), Tria.GetP( 1)) / dLenAB ;
if ( dPro > 0 && dPro < dLenAB)
return PTT_EDGE ;
}
if ( fabs( dPosBC) < EPS_SMALL && ( dPosCA * dPosAB) > 0) {
// se la proiezione del punto sta sul lato BC
double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) / dLenBC ;
if ( dPro > 0 && dPro < dLenBC)
return PTT_EDGE ;
}
if ( fabs( dPosCA) < EPS_SMALL && ( dPosAB * dPosBC) > 0) {
// se la proiezione del punto sta sul lato CA
double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 2), Tria.GetP( 0)) / dLenCA ;
if ( dPro > 0 && dPro < dLenCA)
return PTT_EDGE ;
}
// se tre valori con lo stesso segno, sta dentro
if ( ( dPosAB > EPS_SMALL && dPosBC > EPS_SMALL && dPosCA > EPS_SMALL) ||
( dPosAB < - EPS_SMALL && dPosBC < - EPS_SMALL && dPosCA < - EPS_SMALL))
+313 -75
View File
@@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// EgalTech 2013-2014
// EgalTech 2014-2015
//----------------------------------------------------------------------------
// File : SurfTriMesh.cpp Data : 15.05.14 Versione : 1.5e5
// Contenuto : Implementazione della classe Superfici TriMesh.
@@ -33,7 +33,7 @@ GEOOBJ_REGISTER( SRF_TRIMESH, NGE_S_TRM, SurfTriMesh) ;
//----------------------------------------------------------------------------
SurfTriMesh::SurfTriMesh( void)
: m_nStatus( TO_VERIFY), m_dLinTol( STM_STD_LIN_TOL), m_dBoundaryAng( STM_STD_BOUNDARY_ANG),
m_dSmoothAng( STM_STD_SMOOTH_ANG), m_bClosed( false), m_nTempProp()
m_dSmoothAng( STM_STD_SMOOTH_ANG), m_bOriented( false), m_bClosed( false), m_bFaceted( false), m_nTimeStamp(), m_nTempProp()
{
m_dCosBndAng = cos( m_dBoundaryAng * DEGTORAD) ;
m_dCosSmAng = cos( m_dSmoothAng * DEGTORAD) ;
@@ -46,7 +46,7 @@ SurfTriMesh::~SurfTriMesh( void)
//----------------------------------------------------------------------------
bool
SurfTriMesh::Init( int nNumVert, int nNumTria)
SurfTriMesh::Init( int nNumVert, int nNumTria, int nNumFacet)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
@@ -57,6 +57,8 @@ SurfTriMesh::Init( int nNumVert, int nNumTria)
try {
m_vVert.reserve( nNumVert) ;
m_vTria.reserve( nNumTria) ;
if ( nNumFacet > 0)
m_vFacet.reserve( nNumFacet) ;
}
catch (...) {
return false ;
@@ -169,11 +171,115 @@ SurfTriMesh::SetTriangle( int nInd, const StmTria& tT)
m_vTria[i] = tEmpty ;
}
}
// inserisco il vertice
// inserisco il triangolo
m_vTria[nInd] = tT ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetArea( double& dArea) const
{
// controllo parametro di ritorno
if ( &dArea == nullptr)
return false ;
// inizio con area nulla
dArea = 0 ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// sommo l'area di tutti i triangoli
Triangle3d Tria ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
dArea += Tria.GetArea() ;
nId = GetNextTriangle( nId, Tria) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetVolume( double& dVolume) const
{
// controllo parametro di ritorno
if ( &dVolume == nullptr)
return false ;
// inizio con volume nullo
dVolume = 0 ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// la superficie deve essere chiusa
if ( ! IsClosed())
return true ;
// sommo il volume con segno di tutte le piramidi dall'origine ad ogni faccia
Triangle3d Tria ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
Vector3d vtA = ( Tria.GetP( 1) - Tria.GetP( 0)) ^ ( Tria.GetP( 2) - Tria.GetP( 0)) ;
dVolume += ( Tria.GetP( 0) - ORIG) * vtA ;
nId = GetNextTriangle( nId, Tria) ;
}
dVolume /= 6 ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetCentroid( Point3d& ptCen) const
{
// controllo parametro di ritorno
if ( &ptCen == nullptr)
return false ;
// inizio con centro nell'origine
ptCen = ORIG ;
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// se la superficie è chiusa, calcolo il centroide del solido
if ( IsClosed()) {
// applico le formule di R. Nurnberg Imperial College London ad ogni faccia
Triangle3d Tria ;
double dVolume = 0 ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
Vector3d vtA = ( Tria.GetP( 1) - Tria.GetP( 0)) ^ ( Tria.GetP( 2) - Tria.GetP( 0)) ;
dVolume += ( Tria.GetP( 0) - ORIG) * vtA ;
ptCen.x += vtA.x * (( Tria.GetP( 0).x + Tria.GetP( 1).x) * ( Tria.GetP( 0).x + Tria.GetP( 1).x) +
( Tria.GetP( 1).x + Tria.GetP( 2).x) * ( Tria.GetP( 1).x + Tria.GetP( 2).x) +
( Tria.GetP( 2).x + Tria.GetP( 0).x) * ( Tria.GetP( 2).x + Tria.GetP( 0).x)) ;
ptCen.y += vtA.y * (( Tria.GetP( 0).y + Tria.GetP( 1).y) * ( Tria.GetP( 0).y + Tria.GetP( 1).y) +
( Tria.GetP( 1).y + Tria.GetP( 2).y) * ( Tria.GetP( 1).y + Tria.GetP( 2).y) +
( Tria.GetP( 2).y + Tria.GetP( 0).y) * ( Tria.GetP( 2).y + Tria.GetP( 0).y)) ;
ptCen.z += vtA.z * (( Tria.GetP( 0).z + Tria.GetP( 1).z) * ( Tria.GetP( 0).z + Tria.GetP( 1).z) +
( Tria.GetP( 1).z + Tria.GetP( 2).z) * ( Tria.GetP( 1).z + Tria.GetP( 2).z) +
( Tria.GetP( 2).z + Tria.GetP( 0).z) * ( Tria.GetP( 2).z + Tria.GetP( 0).z)) ;
nId = GetNextTriangle( nId, Tria) ;
}
dVolume /= 6 ;
if ( fabs( dVolume) < EPS_SMALL * EPS_SMALL * EPS_SMALL)
return false ;
ptCen /= ( 24 * 2 * dVolume) ;
}
// altrimenti calcolo il centroide della superficie
else {
Triangle3d Tria ;
double dArea = 0 ;
int nId = GetFirstTriangle( Tria) ;
while ( nId != SVT_NULL) {
double dTriaArea = Tria.GetArea() ;
dArea += dTriaArea ;
ptCen += Tria.GetCentroid() * dTriaArea ;
nId = GetNextTriangle( nId, Tria) ;
}
if ( fabs( dArea) < EPS_SMALL * EPS_SMALL)
return false ;
ptCen /= dArea ;
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetVertexNum( void) const
@@ -414,8 +520,14 @@ SurfTriMesh::GetTriangleBoundaryEdges( int nId, TriFlags3d& TFlags) const
for ( int i = 0 ; i < 3 ; ++ i) {
// indice triangolo adiacente al lato
int nT = m_vTria[nId].nIdAdjac[i] ;
// se non c'è triangolo adiacente o se forma un angolo oltre il limite, il lato è un contorno
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].vtN * m_vTria[nT].vtN < m_dCosBndAng) ;
// se già definite le facce, verifico indice faccia
if ( m_bFaceted) {
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].nIdFacet != m_vTria[nT].nIdFacet) ;
}
// altrimenti verifico con le normali
else
// se non c'è triangolo adiacente o se forma un angolo oltre il limite, il lato è un contorno
TFlags.bFlag[i] = ( nT == SVT_NULL || m_vTria[nId].vtN * m_vTria[nT].vtN < m_dCosBndAng) ;
}
return true ;
@@ -523,12 +635,16 @@ SurfTriMesh::CopyFrom( const SurfTriMesh& stmSrc)
return false ;
m_vVert = stmSrc.m_vVert ;
m_vTria = stmSrc.m_vTria ;
m_bOriented = stmSrc.m_bOriented ;
m_bClosed = stmSrc.m_bClosed ;
m_dLinTol = stmSrc.m_dLinTol ;
m_dSmoothAng = stmSrc.m_dSmoothAng ;
m_dCosSmAng = stmSrc.m_dCosSmAng ;
m_nStatus = stmSrc.m_nStatus ;
m_nTimeStamp = stmSrc.m_nTimeStamp ;
m_nTempProp = stmSrc.m_nTempProp ;
m_bFaceted = stmSrc.m_bFaceted ;
m_vFacet = stmSrc.m_vFacet ;
return true ;
}
@@ -551,14 +667,29 @@ SurfTriMesh::GetTitle( void) const
bool
SurfTriMesh::Dump( string& sOut, const char* szNewLine) const
{
// se superficie aperta o chiusa
sOut += ( m_bClosed ? "Closed" : "Open") + string( szNewLine) ;
// area
double dArea ;
GetArea( dArea) ;
sOut += "Area=" + ToString( dArea,1) + szNewLine ;
// altri dati per superficie chiusa
if ( m_bClosed) {
double dVolume ;
GetVolume( dVolume) ;
sOut += "Closed Volume=" + ToString( dVolume,1) + szNewLine ;
}
// se segnalo eventuale incongruenza di orientamento
if ( ! m_bOriented)
sOut += string( "Inconsistent Orientation") + szNewLine ;
// numero di vertici
sOut += "Vert : Nbr=" + ToString( GetVertexNum()) +
" Size=" + ToString( GetVertexSize()) + szNewLine ;
// numero di triangoli
sOut += "Tria : Nbr=" + ToString( GetTriangleNum()) +
" Size=" + ToString( GetTriangleSize()) + szNewLine ;
// numero facce, se calcolate
if ( m_bFaceted)
sOut += "Facet : Nbr=" + ToString( GetFacetNum()) +
" Size=" + ToString( GetFacetSize()) + szNewLine ;
return true ;
}
@@ -580,6 +711,9 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
// angolo limite per mediare le normali
if ( ! ngeOut.WriteDouble( m_dSmoothAng, ";", true))
return false ;
// flag orientata
if ( ! ngeOut.WriteBool( m_bOriented, ";"))
return false ;
// flag aperta/chiusa
if ( ! ngeOut.WriteBool( m_bClosed, ";"))
return false ;
@@ -587,7 +721,10 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
if ( ! ngeOut.WriteInt( GetVertexSize(), ";"))
return false ;
// numero di triangoli
if ( ! ngeOut.WriteInt( GetTriangleSize(), ";", true))
if ( ! ngeOut.WriteInt( GetTriangleSize(), ";"))
return false ;
// numero di facce
if ( ! ngeOut.WriteInt( GetFacetSize(), ";", true))
return false ;
// ciclo sui vertici
for ( int i = 0 ; i < int( m_vVert.size()) ; ++ i) {
@@ -607,10 +744,19 @@ SurfTriMesh::Save( NgeWriter& ngeOut) const
! ngeOut.WriteInt( m_vTria[i].nIdAdjac[1], ",") ||
! ngeOut.WriteInt( m_vTria[i].nIdAdjac[2], ";") ||
! ngeOut.WriteVector( m_vTria[i].vtN, ";") ||
! ngeOut.WriteInt( m_vTria[i].nIdFacet, ";") ||
! ngeOut.WriteInt( m_vTria[i].nTFlag, ";") ||
! ngeOut.WriteInt( m_vTria[i].nEFlag, ";", true))
return false ;
}
// ciclo sulle facce
int nNumFacet = int( m_vFacet.size()) ;
for ( int i = 0 ; i < nNumFacet ; ++ i) {
bool bEndL = ( ( i + 1) % 10 == 0) || i == ( nNumFacet - 1) ;
if ( ! ngeOut.WriteInt( i, ",") ||
! ngeOut.WriteInt( m_vFacet[i], ";", bEndL))
return false ;
}
return true ;
}
@@ -630,26 +776,46 @@ SurfTriMesh::Load( NgeReader& ngeIn)
double dSmoothAng ;
if ( ! ngeIn.ReadDouble( dSmoothAng, ";", true))
return false ;
// leggo la prossima linea ( 3 parametri : flag chiuso num vertici e num tria)
// recupero il flag
bool bClosed ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
// recupero il numero di vertici
int nNumVert ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
// recupero il numero di triangoli
int nNumTria ;
if ( ! ngeIn.ReadInt( nNumTria, ";", true))
return false ;
// preparo la superficie
if ( ! Init( nNumVert, nNumTria))
return false ;
m_bClosed = bClosed ;
m_dLinTol = dLinTol ;
m_dSmoothAng = dSmoothAng ;
m_dCosSmAng = cos( dSmoothAng * DEGTORAD) ;
// leggo la prossima linea
// prima di versione 1010 3 parametri : flag di chiusa, num vertici, num tria
// da versione 1010 leggo flag di orientata
bool bOriented ;
bool bClosed ;
int nNumVert ;
int nNumTria ;
int nNumFacet ;
if ( ngeIn.GetFileVersion() < NGE_VER_1010) {
bOriented = false ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumTria, ";", true))
return false ;
nNumFacet = 0 ;
}
// da versione 1010 5 parametri : flag di orientata, flag di chiusa, num vertici, num tria, num facet
else {
if ( ! ngeIn.ReadBool( bOriented, ";"))
return false ;
if ( ! ngeIn.ReadBool( bClosed, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumVert, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumTria, ";"))
return false ;
if ( ! ngeIn.ReadInt( nNumFacet, ";", true))
return false ;
}
// preparo la superficie
if ( ! Init( nNumVert, nNumTria, nNumFacet))
return false ;
m_bOriented = bOriented ;
m_bClosed = bClosed ;
m_bFaceted = ( nNumFacet > 0) ;
// lettura dei vertici
int nInd ;
StmVert vV ;
@@ -666,7 +832,7 @@ SurfTriMesh::Load( NgeReader& ngeIn)
// lettura dei triangoli
StmTria tT ;
for ( int i = 0 ; i < nNumTria ; ++ i) {
// leggo la prossima linea ( 6 parametri : Indice, IdVertici, IdAdiacenze, Normale, TFlag, EFlag)
// leggo la prossima linea ( 6 o 7 parametri : Indice, IdVertici, IdAdiacenze, Normale, [Facet,] TFlag, EFlag)
// la interpreto e imposto il vertice
if ( ! ngeIn.ReadInt( nInd, ";") ||
! ngeIn.ReadInt( tT.nIdVert[0], ",") ||
@@ -676,11 +842,21 @@ SurfTriMesh::Load( NgeReader& ngeIn)
! ngeIn.ReadInt( tT.nIdAdjac[1], ",") ||
! ngeIn.ReadInt( tT.nIdAdjac[2], ";") ||
! ngeIn.ReadVector( tT.vtN, ";") ||
( ngeIn.GetFileVersion() >= NGE_VER_1010 && ! ngeIn.ReadInt( tT.nIdFacet, ";")) ||
! ngeIn.ReadInt( tT.nTFlag, ";") ||
! ngeIn.ReadInt( tT.nEFlag, ";", true) ||
! SetTriangle( nInd, tT))
return false ;
}
// lettura delle facce
int nT ;
for ( int i = 0 ; i < nNumFacet ; ++ i) {
bool bEndL = ( ( i + 1) % 10 == 0) || i == ( nNumFacet - 1) ;
if ( ! ngeIn.ReadInt( nInd, ",") ||
! ngeIn.ReadInt( nT, ";", bEndL) ||
! SetFacet( nInd, nT))
return false ;
}
// eseguo validazione
return Validate() ;
}
@@ -720,6 +896,15 @@ SurfTriMesh::Validate( void)
}
}
// Verifico che i triangoli riferiti dalle facce esistano
for ( int i = 0 ; i < GetFacetSize() && m_nStatus == OK && m_bFaceted ; ++ i) {
// verifico validità triangolo riferito
if ( m_vFacet[i] <= SVT_NULL ||
m_vFacet[i] >= GetTriangleSize() ||
m_vTria[ m_vFacet[i]].nIdVert[0] == SVT_DEL)
m_bFaceted = false ;
}
return ( m_nStatus == OK) ;
}
@@ -839,57 +1024,113 @@ SurfTriMesh::AdjustAdjacencies( void)
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustOrientations( int nLev, bool& bSomeWrong)
SurfTriMesh::AdjustOrientations( void)
{
// inizializzo parametro di ritorno
bSomeWrong = false ;
// ciclo sui triangoli
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
// flags
int nNull = 0 ;
int nWrong = 0 ;
// ciclo sui lati del triangolo
for ( int j = 0 ; j < 3 ; ++ j) {
// se non c'è adiacenza
if ( m_vTria[i].nIdAdjac[j] == SVT_NULL)
++ nNull ;
// la verifico
else {
// indice altro triangolo
int nT = m_vTria[i].nIdAdjac[j] ;
// indice altro half-hedge
int nE = 0 ;
if ( m_vTria[nT].nIdAdjac[1] == i)
nE = 1 ;
else if ( m_vTria[nT].nIdAdjac[2] == i)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[i].nIdVert[j] == m_vTria[nT].nIdVert[nE])
++ nWrong ;
}
}
// aggiorno stato
if ( nWrong > 0)
bSomeWrong = true ;
// se almeno uno errato e gli altri nulli, inverto il triangolo
if ( nWrong >= nLev && ( nWrong + nNull) == 3)
InvertTriangle( i) ;
// se non ci sono almeno 2 triangoli è inutile fare test
if ( m_vTria.size() < 2) {
m_bOriented = true ;
return true ;
}
// incremento time stamp di due step (serve un marcatore intermedio)
m_nTimeStamp += 2 ;
// ciclo sui triangoli
TRINTDEQUE S3iQ ;
bool bOk = true ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
// se triangolo non cancellato e senza time stamp
if ( m_vTria[i].nIdVert[0] != SVT_DEL &&
abs( m_vTria[i].nTemp) != m_nTimeStamp) {
S3iQ.emplace_back( i, SVT_NULL, 0) ;
while ( ! S3iQ.empty()) {
if ( ! AdjustTriaOrientation( S3iQ))
bOk = false ;
}
}
}
// salvo il risultato
m_bOriented = bOk ;
// in caso di errore ripristino l'orientamento originale
if ( ! m_bOriented){
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( - m_vTria[i].nTemp == m_nTimeStamp)
InvertTriangle( i) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::TestClosure( void)
SurfTriMesh::AdjustTriaOrientation( TRINTDEQUE& S3iQ)
{
// recupero e tolgo i dati dalla testa della coda
int nT = S3iQ.front().nI1 ;
int nRefT = S3iQ.front().nI2 ;
int nRefE = S3iQ.front().nI3 ;
S3iQ.pop_front() ;
// assegno time stamp al triangolo
m_vTria[nT].nTemp = m_nTimeStamp ;
// se c'è triangolo di riferimento, devo verificare se da invertire
if ( nRefT != SVT_NULL) {
// cerco indice half-edge in comune
int nE = 0 ;
if ( m_vTria[nT].nIdAdjac[1] == nRefT)
nE = 1 ;
else if ( m_vTria[nT].nIdAdjac[2] == nRefT)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[nT].nIdVert[nE] == m_vTria[nRefT].nIdVert[nRefE]) {
m_vTria[nT].nTemp = - m_vTria[nT].nTemp ;
InvertTriangle( nT) ;
}
}
// verifico i triangoli adiacenti
bool bOk = true ;
for ( int j = 0 ; j < 3 ; ++ j) {
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
// se non c'è adiacenza o va sul triangolo di provenienza
if ( nAdjT == SVT_NULL || nAdjT == nRefT)
;
// la verifico
else {
// se triangolo adiacente senza timestamp finale e intermedio
if ( abs( m_vTria[nAdjT].nTemp) != m_nTimeStamp &&
m_vTria[nAdjT].nTemp != ( m_nTimeStamp - 1)) {
m_vTria[nAdjT].nTemp = m_nTimeStamp - 1 ;
S3iQ.emplace_back( nAdjT, nT, j) ;
}
// altrimenti verifico che l'orientamento sia congruente
else {
// indice altro half-hedge
int nE = 0 ;
if ( m_vTria[nAdjT].nIdAdjac[1] == nT)
nE = 1 ;
else if ( m_vTria[nAdjT].nIdAdjac[2] == nT)
nE = 2 ;
// verifico corrispondenza vertici ( i due inizi devono essere diversi)
if ( m_vTria[nT].nIdVert[j] == m_vTria[nAdjT].nIdVert[nE])
bOk = false ;
}
}
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::TestSealing( void)
{
// ciclo sui triangoli
bool bClosed = true ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( m_vTria[i].nIdAdjac[0] == SVT_NULL ||
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL)
bClosed = false ;
// se triangolo non cancellato
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// verifico le adiacenze
if ( m_vTria[i].nIdAdjac[0] == SVT_NULL ||
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL)
bClosed = false ;
}
}
// aggiorno la chiusura della superficie
m_bClosed = bClosed ;
@@ -900,6 +1141,8 @@ SurfTriMesh::TestClosure( void)
bool
SurfTriMesh::AdjustTopology( void)
{
// dichiaro sfaccettatura da ricalcolare
ResetFaceting() ;
// verifica indici
if ( ! Validate())
return false ;
@@ -907,15 +1150,10 @@ SurfTriMesh::AdjustTopology( void)
if ( ! AdjustAdjacencies())
return false ;
// verifica continuità orientazione
int nLev = 3 ;
bool bSomeWrong ;
do {
if ( ! AdjustOrientations( nLev, bSomeWrong))
return false ;
-- nLev ;
} while ( bSomeWrong && nLev > 0) ;
if ( ! AdjustOrientations())
return false ;
// verifica chiusura
if ( ! TestClosure())
if ( ! TestSealing())
return false ;
return true ;
+53 -13
View File
@@ -18,8 +18,10 @@
#include "GeoObjRW.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include <algorithm>
#include <deque>
//----------------------------------------------------------------------------
// Classe Vertice
class StmVert
{
public :
@@ -33,27 +35,38 @@ class StmVert
} ;
//----------------------------------------------------------------------------
// Classe Triangolo
class StmTria
{
public :
StmTria( void) : vtN(), nTFlag( 0), nEFlag( 0)
StmTria( void) : vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nTemp( 0)
{ nIdVert[0] = SVT_NULL ; nIdVert[1] = SVT_NULL ; nIdVert[2] = SVT_NULL ;
nIdAdjac[0] = SVT_NULL ; nIdAdjac[1] = SVT_NULL ; nIdAdjac[2] = SVT_NULL ; }
StmTria( const int nIdV[3]) : vtN(), nTFlag( 0), nEFlag( 0)
StmTria( const int nIdV[3]) : vtN(), nIdFacet( SVT_NULL), nTFlag( 0), nEFlag( 0), nTemp( 0)
{ nIdVert[0] = nIdV[0] ; nIdVert[1] = nIdV[1] ; nIdVert[2] = nIdV[2] ;
nIdAdjac[0] = SVT_NULL ; nIdAdjac[1] = SVT_NULL ; nIdAdjac[2] = SVT_NULL ; }
StmTria( const int nIdV[3], const int nIdA[3], const Vector3d& vtV, int nTF, int nEF)
: vtN( vtV), nTFlag( nTF), nEFlag( nEF)
: vtN( vtV), nIdFacet( SVT_NULL), nTFlag( nTF), nEFlag( nEF), nTemp( 0)
{ nIdVert[0] = nIdV[0] ; nIdVert[1] = nIdV[1] ; nIdVert[2] = nIdV[2] ;
nIdAdjac[0] = nIdA[0] ; nIdAdjac[1] = nIdA[1] ; nIdAdjac[2] = nIdA[2] ; }
public :
int nIdVert[3] ;
int nIdAdjac[3] ;
Vector3d vtN ;
int nIdFacet ;
int nTFlag ;
int nEFlag ;
mutable int nTemp ;
} ;
//----------------------------------------------------------------------------
// Classe di tre interi per code di elaborazione sui triangoli (senza iterazioni)
struct Stm3Int {
Stm3Int( int nI, int nJ, int nK) : nI1( nI), nI2( nJ), nI3( nK) {}
int nI1 ; int nI2 ; int nI3 ;
} ;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
{
@@ -94,11 +107,14 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
{ return true ; }
virtual bool IsClosed( void) const
{ return m_bClosed ; }
virtual bool GetArea( double& dArea) const ;
virtual bool GetVolume( double& dVolume) const ;
virtual bool GetCentroid( Point3d& ptCen) const ;
virtual bool Invert( void) ;
public : // ISurfTriMesh
virtual bool CopyFrom( const IGeoObj* pGObjSrc) ;
virtual bool Init( int nNumVert, int nNumTria) ;
virtual bool Init( int nNumVert, int nNumTria, int nNumFacet = 0) ;
virtual void SetLinearTolerance( double dLinTol)
{ m_dLinTol = (std::max)( dLinTol, EPS_SMALL) ; }
virtual void SetBoundaryAngle( double dBoundaryAngDeg)
@@ -145,6 +161,16 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
virtual bool GetVertexSmoothNormal( int nV, int nT, Vector3d& vtN) const ;
virtual bool GetTriangleBoundaryEdges( int nId, TriFlags3d& TFlags) const ;
virtual bool GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const ;
virtual int GetFacetNum( void) const ;
virtual int GetFacetSize( void) const
{ return int( m_vFacet.size()) ; }
virtual int GetFacetFromTria( int nT) const ;
virtual bool GetAllTriaInFacet( int nF, INTVECTOR& vT) const ;
virtual bool GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const ;
virtual bool GetFacetNearestEndPoint( int nF, const Point3d& ptNear, Point3d& ptEnd, Vector3d& vtN) const ;
virtual bool GetFacetNearestMidPoint( int nF, const Point3d& ptNear, Point3d& ptMid, Vector3d& vtN) const ;
virtual bool GetFacetCenter( int nF, Point3d& ptCen, Vector3d& vtN) const ;
virtual bool GetFacetNormal( int nF, Vector3d& vtN) const ;
public : // IGeoObjRW
virtual int GetNgeId( void) const ;
@@ -161,12 +187,21 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
LOG_ERROR( GetEGkLogger(), "SurfTriMesh : copy error")
return *this ; }
private :
typedef std::vector<StmVert> VERTVECTOR ;
typedef std::vector<StmTria> TRIAVECTOR ;
typedef std::deque<Stm3Int> TRINTDEQUE ;
private :
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;
private :
bool CopyFrom( const SurfTriMesh& clSrc) ;
bool Validate( void) ;
bool AdjustAdjacencies( void) ;
bool AdjustOrientations( int nLev, bool& bSomeWrong) ;
bool TestClosure( void) ;
bool AdjustOrientations( void) ;
bool AdjustTriaOrientation( TRINTDEQUE& S3iQ) ;
bool TestSealing( void) ;
bool SetVertex( int nInd, const StmVert& vV) ;
bool SetTriangle( int nInd, const StmTria& tT) ;
bool CalcTriangleNormal( int nT) ;
@@ -182,13 +217,14 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const ;
bool VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vector3d& vtAx) const ;
bool AddBiTriangle( const int nIdVert[4]) ;
private :
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;
private :
typedef std::vector<StmVert> VERTVECTOR ;
typedef std::vector<StmTria> TRIAVECTOR ;
bool ResetFaceting( void) ;
bool VerifyFaceting( void) const ;
bool UpdateFaceting( void) ;
bool UpdateTriaFaceting( int nRefT, int nFacet, const Plane3d& plPlane, int nT) ;
bool SetFacet( int nInd, int nT) ;
bool VerifyAdjacTriaFacet( int nT, INTVECTOR& vT) const ;
bool MarchAlongLoop( int nF, int nT, int nV, int nTimeStamp, PolyLine& PL) const ;
bool MarchOneTria( int nF, int& nT, int& nV, int nTimeStamp, PolyLine& PL, bool& bEnd) const ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
@@ -198,8 +234,12 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
double m_dCosBndAng ; // coseno dell'angolo limite per considerare un lato un contorno
double m_dSmoothAng ; // angolo limite per mediare le normali (in gradi)
double m_dCosSmAng ; // coseno dell'angolo limite per mediare le normali
bool m_bOriented ; // la superficie è orientata consistentemente in tutte le sue parti
bool m_bClosed ; // la superficie racchiude un volume
bool m_bFaceted ; // flag di validità della sfaccettatura
VERTVECTOR m_vVert ; // vettore dei vertici
TRIAVECTOR m_vTria ; // vettore dei triangoli
INTVECTOR m_vFacet ; // vettore delle sfaccettature
mutable int m_nTimeStamp ; // orologio locale
int m_nTempProp ; // proprietà temporanea
} ;
+533
View File
@@ -0,0 +1,533 @@
//----------------------------------------------------------------------------
// 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
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 ;
// calcolo la normale
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 ;
}