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:
Binary file not shown.
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
} ;
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
Reference in New Issue
Block a user