diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc
index cdc95ef..bfc6520 100644
Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ
diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj
index fe37790..b8b6bc4 100644
--- a/EgtGeomKernel.vcxproj
+++ b/EgtGeomKernel.vcxproj
@@ -320,6 +320,8 @@ copy $(TargetPath) \EgtProg\Dll64
+
+
diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters
index a313b23..6120010 100644
--- a/EgtGeomKernel.vcxproj.filters
+++ b/EgtGeomKernel.vcxproj.filters
@@ -546,6 +546,12 @@
File di origine\GeoDist
+
+ File di origine\Geo
+
+
+ File di origine\Geo
+
diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp
index d7ff791..0461250 100644
--- a/SurfTriMesh.cpp
+++ b/SurfTriMesh.cpp
@@ -237,6 +237,10 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag)
// inserisco il triangolo
try { m_vTria.emplace_back( nIdVert, nTFlag) ;}
catch(...) { return SVT_NULL ;}
+ // aggiorno la sua normale
+ if ( ! vtN.Normalize( EPS_ZERO))
+ return false ;
+ m_vTria.back().vtN = vtN ;
// aggiorno massimo TFlag
m_nMaxTFlag = max( m_nMaxTFlag, nTFlag) ;
// ne determino l'indice
@@ -1688,11 +1692,13 @@ SurfTriMesh::AdjustVertices( void)
//----------------------------------------------------------------------------
bool
-SurfTriMesh::AdjustAdjacencies( void)
+SurfTriMesh::AdjustAdjacencies( bool AdjustVert)
{
// sistemo le relazioni tra triangoli e vertici
- if ( ! AdjustVertices())
- return false ;
+ if ( AdjustVert) {
+ if ( ! AdjustVertices())
+ return false ;
+ }
// matrice di incidenza vertici-triangoli
INTMATRIX mVertTria( GetVertexSize()) ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
@@ -1875,7 +1881,7 @@ SurfTriMesh::TestSealing( void)
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL) {
bClosed = false ;
- break ;
+ break ;
}
}
}
@@ -1937,7 +1943,7 @@ SurfTriMesh::PackVertices( void)
++ nFirstFree ;
}
else
- vVId.push_back( nId) ;
+ vVId.push_back( nId) ;
}
else {
if ( nFirstFree == SVT_NULL)
@@ -4361,3 +4367,86 @@ SurfTriMesh::SetTempInt( int nId, int nTempInt) const
m_vTria[nId].nTemp = nTempInt ;
return true ;
}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol)
+{
+ // scorro i triangoli
+ for ( const Triangle3dEx& Tria : vTria) {
+ // ciclo sui tre vertici
+ int nIdV[3]{} ;
+ for ( int nV = 0 ; nV < 3 ; ++ nV) {
+ // verifico se vertice già presente
+ int nId ;
+ if ( ! VertGrid.Find( Tria.GetP( nV), dVertexTol, nId)) {
+ // se non presente, lo aggiugo
+ nIdV[nV] = AddVertex( Tria.GetP( nV)) ;
+ if ( nIdV[nV] == SVT_NULL)
+ return false ;
+ VertGrid.InsertPoint( Tria.GetP( nV), nIdV[nV]) ;
+ }
+ else
+ nIdV[nV] = nId ;
+ }
+ // se i vertici sono tutti diversi tra loro, inserisco il triangolo
+ if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) {
+ int nT = AddTriangle( nIdV, Tria.GetGrade()) ;
+ if ( nT != SVT_NULL && nT != SVT_DEL) {
+ // associo relazione vertice-triangolo
+ for ( int i = 0 ; i < 3 ; ++ i)
+ m_vVert[nIdV[i]].nIdTria = nT ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+SurfTriMesh::AdjustTopologyFromZMap( void)
+{
+ // cancello tutti i vertici che puntano a triangoli cancellati
+ bool bPack = false ;
+ for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
+ if ( m_vVert[i].nIdTria == SVT_NULL) {
+ m_vVert[i].nIdTria = SVT_DEL ;
+ bPack = true ;
+ }
+ }
+ if ( bPack)
+ PackVertices() ;
+ m_nStatus = SurfTriMesh::OK ;
+
+ // calcolo le adiacenze
+ if ( ! AdjustAdjacencies())
+ return false ;
+
+ // verifico l'orientamento ( TODO -- Da migliorare...)
+ // Ora per funzionare è necessario che il ciclo sui triangoli parta da un triangolo orientato
+ // correttamente e che i triangoli invertiti siano "circondati" da triangoli tutti orientati correttamente
+ if ( ! AdjustOrientations())
+ return false ;
+
+ // calcolo le facce
+ if ( ! VerifyFaceting())
+ return false ;
+
+ // rimozione delle TJunction
+ bool bModified = false ;
+ if ( ! RemoveTJunctions( bModified, SQ_EPS_SMALL))
+ return false ;
+ if ( bModified) {
+ if ( ! AdjustVertices() || ! DoCompacting())
+ return false ;
+ }
+ else
+ TestSealing() ;
+
+ // semplifico le facce ( anche più piccola)
+ if ( ! SimplifyFacets( MAX_EDGE_LEN_STD, false, 5. * EPS_SMALL))
+ LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::AdjustTopologyFromZMap")
+
+ return true ;
+}
diff --git a/SurfTriMesh.h b/SurfTriMesh.h
index 90bf43d..36cc13a 100644
--- a/SurfTriMesh.h
+++ b/SurfTriMesh.h
@@ -18,6 +18,7 @@
#include "GeoObjRW.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkHashGrids3d.h"
+#include "/EgtDev/Include/EGkPointGrid3d.h"
#include
#include
@@ -327,7 +328,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool Intersect( const ISurfTriMesh& Other) override ;
bool Subtract( const ISurfTriMesh& Other) override ;
bool GetSurfClassification( const ISurfTriMesh& ClassifierSurf,
- INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ;
+ INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ;
bool CutWithOtherSurf( const ISurfTriMesh& CutterSurf, bool bInVsOut, bool bSaveOnEq) override ;
bool Repair( double dMaxEdgeLen = MAX_EDGE_LEN_STD) override ;
bool GetAllTriaOverlapBox( const BBox3d& b3Box, INTVECTOR& vT) const override ;
@@ -373,6 +374,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetTempInt( int nId, int& nTempInt) const ;
bool ResetTempInts( void) const ;
bool SetTempInt( int nId, int nTempInt) const ;
+ bool AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol = 2 * EPS_SMALL) ;
+ bool AdjustTopologyFromZMap( void) ;
private :
typedef std::vector VERTVECTOR ;
@@ -388,7 +391,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool CopyFrom( const SurfTriMesh& clSrc) ;
bool Validate( bool bCorrect = false) ;
bool AdjustVertices( void) ;
- bool AdjustAdjacencies( void) ;
+ bool AdjustAdjacencies( bool AdjustVert = true) ;
bool AdjustOrientations( void) ;
bool AdjustTriaOrientation( TRINTDEQUE& S3iQ) ;
bool TestSealing( void) ;
@@ -433,18 +436,16 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool IntersectTriMeshTriangle( SurfTriMesh& Other) ;
bool IdentifyShells( void) const ;
bool RemoveDoubleTriangles( bool& bModified) ;
- bool RemoveTJunctions( bool& bModified) ;
+ bool RemoveTJunctions( bool& bModified, double dMinSqDist = SQ_EPS_TRIA_H) ;
bool FlipTriangles( int nTA, int nTB) ;
- bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true) ;
+ bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true, double dTolAlign = 50 * EPS_SMALL) ;
bool AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) ;
bool DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) ;
bool ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) ;
bool SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) ;
- bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const ;
+ bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const ;
bool RemoveInvalidTriangles( const INTVECTOR& vIds) ;
bool FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const ;
-
-
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
Status m_nStatus ; // stato
diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp
new file mode 100644
index 0000000..666e863
--- /dev/null
+++ b/SurfTriMeshOffset.cpp
@@ -0,0 +1,75 @@
+//----------------------------------------------------------------------------
+// EgalTech 2014-2022
+//----------------------------------------------------------------------------
+// File : SurfTriMeshOffset.cpp Data : 10.06.25 Versione : 2.7e4
+// Contenuto : Implementazione funzione per Offset di Superfici TriMesh.
+//
+//
+//
+// Modifiche : 10.06.25 RE Creazione modulo.
+//
+//----------------------------------------------------------------------------
+
+//--------------------------- Include ----------------------------------------
+#include "stdafx.h"
+#include "SurfTriMesh.h"
+#include "VolZmap.h"
+
+using namespace std ;
+
+//----------------------------------------------------------------------------
+static ISurfTriMesh*
+SumStm( const CISURFTMPVECTOR& vStm)
+{
+ // se vettore vuoto, non faccio nulla
+ if ( vStm.empty())
+ return nullptr ;
+ // definisco la superficie somma tra tutte ( la prima deve essere valida)
+ PtrOwner pStmAdd( CreateSurfTriMesh()) ;
+ if ( IsNull( pStmAdd))
+ return nullptr ;
+ // scorro le superfici
+ for ( const ISurfTriMesh* pStm : vStm) {
+ if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0)
+ continue ;
+ if ( ! pStmAdd->IsValid() || pStmAdd->GetTriangleCount() == 0) {
+ if ( ! pStmAdd->CopyFrom( pStm))
+ return nullptr ;
+ }
+ else
+ pStmAdd->Add( *pStm) ;
+ }
+ // restituisco la superficie ottenuta
+ return ( Release( pStmAdd)) ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione che crea l'Offset di una superficie TriMesh chiusa */
+ISurfTriMesh*
+CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol)
+{
+ return CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol) ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione che crea l'Offset di un insieme di superfici */
+ISurfTriMesh*
+CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol)
+{
+ // se vettore delle superfici vuoto, non faccio nulla
+ if ( vStm.empty())
+ return nullptr ;
+ // controllo sul valore di tolleranza lineare
+ double dMyLinTol = max( dLinTol, 10 * EPS_SMALL) ;
+ // --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto)
+ // Nel caso sia minore, restituisco semplicemente la somma delle superfici
+ // ( questo valore serve per rimanere coerente con l'Offset delle curve)
+ if ( abs( dOffs) < 10 * EPS_SMALL)
+ return SumStm( vStm) ;
+ // --- NB. Per la creazione dello Zmap è necessario che le superfici siano chiuse
+ PtrOwner pVolZmap( CreateVolZmap()) ;
+ if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol))
+ return nullptr ;
+ // restituisco la superficie TriMesh
+ return ( pVolZmap->GetSurfTriMesh()) ;
+}
\ No newline at end of file
diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp
index b1f10f1..7174040 100644
--- a/SurfTriMeshUtilities.cpp
+++ b/SurfTriMeshUtilities.cpp
@@ -138,7 +138,7 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB)
//----------------------------------------------------------------------------
bool
-SurfTriMesh::RemoveTJunctions( bool& bModified)
+SurfTriMesh::RemoveTJunctions( bool& bModified, double dMinSqDist)
{
bModified = false ;
@@ -147,6 +147,11 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
// Ciclo sui triangoli della superficie per determinare gli altri vertici sul loro perimetro
for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) {
+ // se adiacenze tutte valide, passo al successivo
+ if ( m_vTria[nT].nIdAdjac[0] != SVT_DEL && m_vTria[nT].nIdAdjac[0] != SVT_NULL &&
+ m_vTria[nT].nIdAdjac[1] != SVT_DEL && m_vTria[nT].nIdAdjac[1] != SVT_NULL &&
+ m_vTria[nT].nIdAdjac[2] != SVT_DEL && m_vTria[nT].nIdAdjac[2] != SVT_NULL)
+ continue ;
// Se il triangolo non è valido, passo al successivo
Triangle3d trTria ;
if ( ! GetTriangle( nT, trTria) || ! trTria.Validate( true))
@@ -190,9 +195,9 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
if ( ! GetVertex( m_vTria[vNearTria[nI]].nIdVert[nVert], ptVert))
continue ;
double dProj = ( ptVert - ptSegSt) * vtSeg ;
- double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ;
- if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < SQ_EPS_TRIA_H)
- vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ;
+ double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ;
+ if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < dMinSqDist)
+ vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ;
}
}
// Riordino i vertici sul segmento
@@ -338,8 +343,10 @@ ChooseGoodStartPoint( PNTULIST& PointList)
// -------------------------------------------------------------
bool
-SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool& bModif) const
+SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const
{
+ // vettore dei loop della faccia adiacente
+ POLYLINEVECTOR LoopVec ;
// Ciclo sui punti del loop
auto itLast = PointList.begin() ;
for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) {
@@ -347,30 +354,26 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool&
// bisogna fermarsi per analizzare il tratto corrente alla ricerca di punti allineati se dal punto corrente
// inizia un tratto adiacente ad un'altra faccia oppure se il punto corrente non verrà eliminato dal loop
// della faccia adiacente
+
bool bAnalyze = ( itLast->second != it->second) ;
+ if ( bAnalyze)
+ LoopVec.clear() ;
if ( ! bAnalyze && itLast->second != - 1) {
- // recupero i loop della faccia adiacente
- POLYLINEVECTOR LoopVec ;
- GetFacetLoops( int( itLast->second), LoopVec) ;
- bool bFound = false ;
- for ( int i = 0 ; i < int( LoopVec.size()) && ! bFound ; i ++) {
+ if ( LoopVec.empty())
+ GetFacetLoops( int( itLast->second), LoopVec) ;
+ for ( int i = 0 ; i < int( LoopVec.size()) && ! bAnalyze ; i ++) {
const PNTULIST& PointListAdj = LoopVec[i].GetUPointList() ;
- for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) && ! bFound ; ++ itAdj) {
+ int nSamePoints = 0 ;
+ for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) ; ++ itAdj) {
// cerco il punto corrente sul loop della faccia adiacente
- if ( itAdj->second == nF && AreSamePointApprox( it->first, itAdj->first)) {
- bFound = true ;
- auto itPrev = ( itAdj == PointListAdj.begin() ? prev( prev( PointListAdj.end())) : prev( itAdj)) ;
- auto itNext = next( itAdj) ;
- DistPointLine PointLineDistCalc( itAdj->first, itPrev->first, itNext->first) ;
- double dDist ;
- if ( PointLineDistCalc.GetDist( dDist) && dDist > 50 * EPS_SMALL)
- // se il punto non è allineato al precedente e al successivo non verrà rimosso dal loop della faccia adiacente,
- // quindi non deve essere rimosso dal loop corrente altrimenti si genererebbe una T-Junction. Quindi posso
- // interrompere e analizzare il tratto trovato fino ad ora
- bAnalyze = true ;
+ if ( AreSamePointApprox( it->first, itAdj->first))
+ ++ nSamePoints ;
+ if ( ( nSamePoints == 1 && int( PointListAdj.size()) <= 4) || nSamePoints > 1) {
+ bAnalyze = true ;
+ break ;
}
- }
- }
+ }
+ }
}
if ( bAnalyze) {
@@ -383,7 +386,7 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool&
}
PL.AddUPoint( ++nPar, it->first) ;
// Provo ad eliminare i punti allineati
- PL.RemoveAlignedPoints( 50 * EPS_SMALL) ;
+ PL.RemoveAlignedPoints( dTolAlign) ;
if ( PL.GetPointNbr() < nPar + 1) {
// rimuovo dalla lista dei punti gli eliminati (salto gli estremi)
int nUCurr = 1 ;
@@ -475,7 +478,7 @@ SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, int nF, bool&
//----------------------------------------------------------------------------
bool
-SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
+SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced, double dTolAlign)
{
// La trimesh deve essere valida
if ( ! IsValid())
@@ -502,13 +505,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Lista dei punti del loop
PNTULIST& PointList = LoopVec[nL].GetUPointList() ;
+ // Se il loop è un triangolo, non va modificato
+ if ( int( PointList.size()) <= 4)
+ continue ;
+
// Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento
if ( ! ChooseGoodStartPoint( PointList))
continue ;
// Sistemo il loop
bool bModif = false ;
- if ( ! AdjustLoop( PointList, dMaxEdgeLen, nF, bModif))
+ if ( ! AdjustLoop( PointList, dMaxEdgeLen, dTolAlign, bModif))
return false ;
if ( bModif)
bToRetriangulate = true ;
@@ -536,12 +543,11 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Eseguo la ritriangolazione della faccia
PNTVECTOR vPt ;
INTVECTOR vTr ;
- if ( Triangulate().Make( LoopVec, vPt, vTr)) {
+ if ( Triangulate().Make( LoopVec, vPt, vTr) && ! vTr.empty())
FacetMap.emplace( nF, make_pair( vPt, vTr)) ;
- }
// Se non riesco a triangolare anche solo questa faccia, interrompo tutto
- else
- return false ;
+ else
+ return false ;
}
}
diff --git a/Triangulate.cpp b/Triangulate.cpp
index e942a08..4be97fb 100644
--- a/Triangulate.cpp
+++ b/Triangulate.cpp
@@ -818,7 +818,7 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
}
}
// If vertex k is inside the ear triangle, then this is not an ear
- else if ( TestPointInTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
+ else if ( TestPointInOrOnTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
@@ -978,6 +978,28 @@ Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const
return true ;
}
+//----------------------------------------------------------------------------
+// test if point p is inside or on the border of triangle (a, b, c)
+bool
+Triangulate::TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
+{
+ // If P is on a vertex is considered inside
+ if ( AreSamePoint( ptP, ptA))
+ return true ;
+ if ( AreSamePoint( ptP, ptB))
+ return true ;
+ if ( AreSamePoint( ptP, ptC))
+ return true ;
+ // If P is on the right of at least one edge is outside
+ if ( TriangleIsCCW( ptA, ptP, ptB, EPS_SMALL))
+ return false ;
+ if ( TriangleIsCCW( ptB, ptP, ptC, EPS_SMALL))
+ return false ;
+ if ( TriangleIsCCW( ptC, ptP, ptA, EPS_SMALL))
+ return false ;
+ return true ;
+}
+
//----------------------------------------------------------------------------
bool
Triangulate::SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd)
diff --git a/Triangulate.h b/Triangulate.h
index 7145157..b0d9d91 100644
--- a/Triangulate.h
+++ b/Triangulate.h
@@ -45,6 +45,7 @@ class Triangulate
bool TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler = 0.1 * EPS_SMALL) ;
bool TestIntersection( const Point3d& ptA1, const Point3d& ptA2, const Point3d& ptB1, const Point3d& ptB2) ;
bool TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
+ bool TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd) ;
bool GetPntVectorFromPolyline( const PolyLine& PL, bool bXmaxStart, PNTVECTOR& vPi) ;
bool GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& nI) ;
diff --git a/VolZmap.cpp b/VolZmap.cpp
index bdb0987..35a6ecd 100644
--- a/VolZmap.cpp
+++ b/VolZmap.cpp
@@ -1520,14 +1520,14 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
// ciclo sulle griglie
bool bCompleted = true ;
- for ( int g = 0 ; g < m_nMapNum ; ++ g) {
+ for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
- if ( g == 0)
+ if ( nG == 0)
frMapFrame = m_MapFrame ;
- else if ( g == 1)
+ else if ( nG == 1)
frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
- else if ( g == 2)
+ else if ( nG == 2)
frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
// oggetto per calcolo massivo intersezioni
@@ -1538,33 +1538,121 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
vector> vRes ;
vRes.resize( nThreadMax) ;
// se dimensione griglia in X maggiore di dimensione Y
- if ( m_nNx[g] > m_nNy[g]) {
- int nDexNum = m_nNx[g] / nThreadMax ;
- int nRemainder = m_nNx[g] % nThreadMax ;
+ if ( m_nNx[nG] > m_nNy[nG]) {
+ int nDexNum = m_nNx[nG] / nThreadMax ;
+ int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
- vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g,
- nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( m_MapFrame.Orig()),
- ref( *pStm), ref( intPLSTM)) ;
+ vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
+ nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
+ ref( *pStm), ref( intPLSTM)) ;
}
}
// se dimensione griglia in Y maggiore di dimensione X
else {
- int nDexNum = m_nNy[g] / nThreadMax ;
- int nRemainder = m_nNy[g] % nThreadMax ;
+ int nDexNum = m_nNy[nG] / nThreadMax ;
+ int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
- vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g,
- 0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
- ref( *pStm), ref( intPLSTM)) ;
+ vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
+ 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
+ ref( *pStm), ref( intPLSTM)) ;
+ }
+ }
+
+ // ciclo per attendere che tutti gli async abbiano terminato.
+ int nTerminated = 0 ;
+ while ( nTerminated < nThreadMax) {
+ for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
+ // async terminato
+ if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
+ ++ nTerminated ;
+ bCompleted = bCompleted && vRes[nL].get() ;
+ }
+ }
+ }
+
+ if ( ! bCompleted)
+ return false ;
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+VolZmap::SubtractSurfTm( const ISurfTriMesh* pStm)
+{
+ // controllo sulla superficie
+ double dVol ;
+ if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() ||
+ ! pStm->GetVolume( dVol) || dVol < 0)
+ return false ;
+
+ // controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente
+ BBox3d BBox_stm, BBox_curr ;
+ if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr))
+ return false ;
+ BBox3d BBox_inters ;
+ if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty())
+ return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap
+ Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone
+
+ // ciclo sulle griglie
+ bool bCompleted = true ;
+ for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
+ // definisco dei sistemi di riferimento ausiliari
+ Frame3d frMapFrame ;
+ if ( nG == 0)
+ frMapFrame = m_MapFrame ;
+ else if ( nG == 1)
+ frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
+ else if ( nG == 2)
+ frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
+
+ // oggetto per calcolo massivo intersezioni
+ IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ;
+
+ // numero massimo di thread
+ int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
+ vector> vRes ;
+ vRes.resize( nThreadMax) ;
+ // se dimensione griglia in X maggiore di dimensione Y
+ if ( m_nNx[nG] > m_nNy[nG]) {
+ int nDexNum = m_nNx[nG] / nThreadMax ;
+ int nRemainder = m_nNx[nG] % nThreadMax ;
+ int nInfI = 0 ;
+ int nSupI = 0 ;
+ // aggiungo le parti interessate alla mappa
+ for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
+ nInfI = nSupI ;
+ nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
+ vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
+ nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
+ ref( *pStm), ref( intPLSTM)) ;
+ }
+ }
+ // se dimensione griglia in Y maggiore di dimensione X
+ else {
+ int nDexNum = m_nNy[nG] / nThreadMax ;
+ int nRemainder = m_nNy[nG] % nThreadMax ;
+ int nInfJ = 0 ;
+ int nSupJ = 0 ;
+ // aggiungo le parti interessate alla mappa
+ for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
+ nInfJ = nSupJ ;
+ nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
+ vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
+ 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
+ ref( *pStm), ref( intPLSTM)) ;
}
}
diff --git a/VolZmap.h b/VolZmap.h
index c7fcb86..e81bd23 100644
--- a/VolZmap.h
+++ b/VolZmap.h
@@ -18,6 +18,7 @@
#include "Tool.h"
#include "/EgtDev/Include/EGkVolZmap.h"
#include "/EgtDev/Include/EGkIntersLineVolZmap.h"
+#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include
#include
#include
@@ -80,10 +81,12 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ;
bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ;
bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex) override ;
- bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex) override ;
+ bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 100 * EPS_SMALL) override ;
+ bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) override ;
int GetBlockCount( void) const override ;
int GetBlockUpdatingCounter( int nBlock) const override ;
bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ;
+ ISurfTriMesh* GetSurfTriMesh( void) const override ;
bool GetEdges( ICURVEPOVECTOR& vpCurve) const override ;
bool GetVolume( double& dVol) const override ;
bool IsTriDexel( void) const override
@@ -144,6 +147,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool RemovePart( int nPart) override ;
int GetPartMinDistFromPoint( const Point3d& ptP) const override ;
bool AddSurfTm( const ISurfTriMesh* pStm) override ;
+ bool SubtractSurfTm( const ISurfTriMesh* pStm) override ;
bool MakeUniform( double dToler) override ;
public : // IGeoObjRW
@@ -432,10 +436,21 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
+ bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
+ const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
+ // Funzioni per Offset di superfici
+ bool CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) ;
+ bool CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid) ;
+ bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ,
+ double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
+ int nToolNum, bool bSkipSwap = false) ;
+ bool AddIntervalsForOffset( int nGrid, int nI, int nJ,
+ double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
+ int nToolNum, bool bSkipSwap = false) ;
private :
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;
- enum Shape { GENERIC = 0, BOX = 1, EXTRUSION = 2} ;
+ enum Shape { GENERIC = 0, BOX = 1, EXTRUSION = 2, OFFSET = 3} ;
static const int N_MAPS = 3 ;
static const int N_VOXBLOCK = 32 ;
diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp
index 4fefdee..fef6eae 100644
--- a/VolZmapCreation.cpp
+++ b/VolZmapCreation.cpp
@@ -17,6 +17,7 @@
#include "CurveLine.h"
#include "VolZmap.h"
#include "GeoConst.h"
+#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include
@@ -597,6 +598,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
return true ;
}
+//----------------------------------------------------------------------------
bool
VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM)
@@ -691,7 +693,100 @@ VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const
//----------------------------------------------------------------------------
bool
-VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex)
+VolZmap::SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
+ const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM)
+{
+ // controllo sui parametri
+ if ( nMap < 0 || nMap > 2 ||
+ nInfI < 0 || nInfI > m_nNx[nMap] ||
+ nSupI < 0 || nSupI > m_nNx[nMap] ||
+ nInfJ < 0 || nInfJ > m_nNy[nMap] ||
+ nSupJ < 0 || nSupJ > m_nNy[nMap])
+ return false ;
+
+ // determinazione e ridimensionamento dei dexel interni alla trimesh
+ for ( int i = nInfI ; i < nSupI ; ++ i) {
+ for ( int j = nInfJ ; j < nSupJ ; ++ j) {
+
+ // definisco la retta da intersecare con la trimesh
+ double dX = ( i + 0.5) * m_dStep ;
+ double dY = ( j + 0.5) * m_dStep ;
+ Point3d ptP0( dX, dY, 0) ;
+
+ // intersezioni della retta con la TriMesh
+ ILSIVECTOR IntersectionResults ;
+ intPLSTM.GetInters( ptP0, vtLen.v[(nMap+2)%3], IntersectionResults) ;
+
+ // rimuovo le intersezioni in eccesso
+ for ( int nI = 0 ; nI < int( IntersectionResults.size()) - 3 ; ++ nI) {
+ int nJ = nI + 1 ; // prima successiva
+ int nK = nJ + 1 ; // seconda successiva
+ int nT = nK + 1 ; // terza successiva
+ // determino i segni delle 4 intersezioni tra la linea e il trangolo della TriMesh
+ int nSgnI = IntersectionResults[nI].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nI].dCosDN > -EPS_SMALL ? 0 : - 1 ;
+ int nSgnJ = IntersectionResults[nJ].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nJ].dCosDN > -EPS_SMALL ? 0 : - 1 ;
+ int nSgnK = IntersectionResults[nK].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nK].dCosDN > -EPS_SMALL ? 0 : - 1 ;
+ int nSgnT = IntersectionResults[nT].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nT].dCosDN > -EPS_SMALL ? 0 : - 1 ;
+ // parametri dell'intersezione sulla linea
+ double dUJ = IntersectionResults[nJ].dU ;
+ double dUK = IntersectionResults[nK].dU ;
+ // controllo coerenza con segni...
+ if ( nSgnI != 0 && nSgnI == nSgnJ &&
+ nSgnK != 0 && nSgnK == nSgnT &&
+ nSgnI == - nSgnT &&
+ abs( dUJ - dUK) < EPS_SMALL) {
+ // ... ed elimino le intersezioni in eccesso...
+ IntersectionResults.erase( IntersectionResults.begin() + nK) ;
+ IntersectionResults.erase( IntersectionResults.begin() + nJ) ;
+ }
+ }
+
+ int nInt = int( IntersectionResults.size()) ; // numero di intersezioni valide
+ bool bInside = false ; // Flag entrata/uscita per tratto di retta
+ Point3d ptIn ; Vector3d vtInN ;
+
+ // per ogni intersezione valida trovata...
+ for ( int k = 0 ; k < nInt ; ++ k) {
+ // ricavo il tipo di intersezione
+ int nIntType = IntersectionResults[k].nILTT ;
+ // se c'è intersezione
+ if ( nIntType != ILTT_NO) {
+ // ricavo il cos tra i vettori ( normale del triangolo e tangente alla retta)
+ double dCos = IntersectionResults[k].dCosDN ;
+
+ // se entro nella superficie trimesh...
+ if ( dCos < - EPS_SMALL) {
+ ptIn = IntersectionResults[k].ptI ; // punto di intersezione
+ int nT = IntersectionResults[k].nT ; // triangolo di interesse
+ int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse
+ Surf.GetFacetNormal( nF, vtInN) ;
+ bInside = true ; // entrata
+ }
+ // ...se esco dalla superficie trimesh ( prima sono per forza entrato)
+ else if ( dCos > EPS_SMALL && bInside) {
+ Point3d ptOut = IntersectionResults[k].ptI ; // punto di intersezione
+ int nT = IntersectionResults[k].nT ; // triangolo di interesse
+ int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse
+ Vector3d vtOutN ; Surf.GetFacetNormal( nF, vtOutN) ; // vettore d'uscita
+
+ // Aggiungo un tratto al dexel
+ SubtractIntervals( nMap, i, j,
+ ptIn.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3],
+ ptOut.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3],
+ - vtInN, - vtOutN, 0, true) ;
+ bInside = false ; // uscita
+ }
+ }
+ }
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+bool
+VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox)
{
// Se la superficie non è chiusa oppure orientata al contrario non ha senso continuare
double dVol ;
@@ -704,14 +799,14 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
// Determino il bounding box della TriMesh
BBox3d SurfBBox ;
Surf.GetLocalBBox( SurfBBox) ;
-
- // Determino i punti estremi del bounding box
- Point3d ptMapOrig, ptMapEnd ;
- SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ;
// Il dexel se parte da un triangolo della trimesh può non trovare l'intersezione,
// quindi espandiamo il bounding box per ovviare al problema.
- SurfBBox.Expand( 100 * EPS_SMALL, 100 * EPS_SMALL, 100 * EPS_SMALL) ;
+ SurfBBox.Expand( dExtraBox) ;
+
+ // Determino i punti estremi del bounding box
+ Point3d ptMapOrig, ptMapEnd ;
+ SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ;
// Sistema di riferimento intrinseco dello Zmap
m_MapFrame.Set( ptMapOrig, Frame3d::TOP) ;
@@ -760,15 +855,15 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
// ciclo sulle griglie
bool bCompleted = true ;
- for ( int g = 0 ; g < m_nMapNum ; ++ g) {
+ for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// Definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
- if ( g == 0)
+ if ( nG == 0)
frMapFrame = m_MapFrame ;
- else if ( g == 1)
+ else if ( nG == 1)
frMapFrame.Set( ptMapOrig, Y_AX, Z_AX, X_AX) ;
- else if ( g == 2)
+ else if ( nG == 2)
frMapFrame.Set( ptMapOrig, Z_AX, X_AX, Y_AX) ;
// Oggetto per calcolo massivo intersezioni
@@ -778,28 +873,28 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector< future> vRes ;
vRes.resize( nThreadMax) ;
- if ( m_nNx[g] > m_nNy[g]) {
- int nDexNum = m_nNx[g] / nThreadMax ;
- int nRemainder = m_nNx[g] % nThreadMax ;
+ if ( m_nNx[nG] > m_nNy[nG]) {
+ int nDexNum = m_nNx[nG] / nThreadMax ;
+ int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
- vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g,
- nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ;
+ vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
+ nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ;
}
}
else {
- int nDexNum = m_nNy[g] / nThreadMax ;
- int nRemainder = m_nNy[g] % nThreadMax ;
+ int nDexNum = m_nNy[nG] / nThreadMax ;
+ int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
- vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g,
- 0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ;
+ vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
+ 0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ;
}
}
diff --git a/VolZmapGraphics.cpp b/VolZmapGraphics.cpp
index 01fe8ae..9fff5ef 100644
--- a/VolZmapGraphics.cpp
+++ b/VolZmapGraphics.cpp
@@ -19,6 +19,7 @@
#include "MC_Tables.h"
#include "PolygonPlane.h"
#include "IntersLineBox.h"
+#include "SurfTriMesh.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkChainCurves.h"
@@ -571,6 +572,35 @@ VolZmap::GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const
}
}
+//----------------------------------------------------------------------------
+ISurfTriMesh*
+VolZmap::GetSurfTriMesh( void) const
+{
+ // controllo che lo Zmap sia valido
+ if ( ! IsValid())
+ return nullptr ;
+
+ // inizializzo la superficie
+ PtrOwner pStm( CreateBasicSurfTriMesh()) ;
+ if ( IsNull( pStm) || ! pStm->Init( 3, 1))
+ return nullptr ;
+ PointGrid3d VertGrid ; VertGrid.Init( 50000) ;
+
+ // ciclo lungo i blocchi dello Zmap
+ for ( int nB = 0 ; nB < GetBlockCount() ; ++ nB) {
+ TRIA3DEXVECTOR vTria ;
+ GetBlockTriangles( nB, vTria) ;
+ if ( ! pStm->AddTriaFromZMap( vTria, VertGrid))
+ return nullptr ;
+ }
+
+ // sistemo la topologia
+ if ( ! pStm->AdjustTopologyFromZMap())
+ return nullptr ;
+
+ return ( Release( pStm)) ;
+}
+
//----------------------------------------------------------------------------
int
VolZmap::GetBlockCount( void) const
@@ -1142,7 +1172,7 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
}
// Controllo se il voxel ha una sola faccia che giace in un piano canonico e quindi ha gestione speciale
- if ( m_nShape != BOX) {
+ if ( m_nShape != BOX && m_nShape != OFFSET) {
// Faccia XY normale Z+
if ( nIndex == 15) {
int nTool ; double dPos ;
diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp
new file mode 100644
index 0000000..1812b0a
--- /dev/null
+++ b/VolZmapOffset.cpp
@@ -0,0 +1,300 @@
+//----------------------------------------------------------------------------
+// EgalTech 2025-2025
+//----------------------------------------------------------------------------
+// File : OffsetSurfTm.cpp Data : 09.06.25 Versione : 2.7e3
+// Contenuto : Dichiarazione della funzione per calcolare l'offset di superfici TriMesh
+// mediante Zmap
+//
+//
+//
+// Modifiche : 09.06.25 RE Creazione modulo.
+//
+//
+//----------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "VolZmap.h"
+#include "CurveLine.h"
+#include "GeoConst.h"
+#include "/EgtDev/Include/EGkStmFromCurves.h"
+#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
+#include "/EgtDev/Include/EgtNumUtils.h"
+#include
+
+using namespace std ;
+
+
+//----------------------------------------------------------------------------
+/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */
+bool
+VolZmap::SubtractIntervalsForOffset( int nGrid, int nI, int nJ,
+ double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
+ int nToolNum, bool bSkipSwap)
+{
+ // per ora la funzione è la stessa della differenza in generale
+ // TODO -- Aggiustare eventuali tolleranze
+ return SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */
+bool
+VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ,
+ double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
+ int nToolNum, bool bSkipSwap)
+{
+ // per ora la funzione è la stessa della somma generale
+ // TODO -- Aggiustare eventuali tolleranze
+ return AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione per la creazione di una sfera di Offset centrata sul vertice di una TriMesh con cui
+ aggiungere o sottrarre intervalli lungo i Dexel coinvolti */
+bool
+VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid)
+{
+ // determino il Box della sfera posizionata su tale vertice
+ BBox3d BBoxSphere( ptV - dOffs * Vector3d( 1., 1., 1.),
+ ptV + dOffs * Vector3d( 1., 1., 1.)) ;
+ // determino gli intervalli di interesse mediante intersezione con Box della sfera
+ int nStartI = max( 0, int( BBoxSphere.GetMin().x / m_dStep)) ;
+ int nEndI = min( m_nNx[nGrid] - 1, int( BBoxSphere.GetMax().x / m_dStep)) ;
+ int nStartJ = max( 0, int( BBoxSphere.GetMin().y / m_dStep)) ;
+ int nEndJ = min( m_nNy[nGrid] - 1, int( BBoxSphere.GetMax().y / m_dStep)) ;
+ // aggiorno gli spilloni interessati
+ double dSqRad = dOffs * dOffs ;
+ for ( int i = nStartI ; i <= nEndI ; ++ i) {
+ for ( int j = nStartJ ; j <= nEndJ ; ++ j) {
+ double dX = ( i + 0.5) * m_dStep ;
+ double dY = ( j + 0.5) * m_dStep ;
+ Point3d ptC( dX, dY, 0.) ;
+ double dStSqDXY = SqDistXY( ptC, ptV) ;
+ if ( dStSqDXY < dSqRad) {
+ double dMin = ptV.z - sqrt( dSqRad - dStSqDXY) ;
+ Vector3d vtNmin = Point3d( dX, dY, dMin) - ptV ;
+ vtNmin.Normalize() ;
+ double dMax = ptV.z + sqrt( dSqRad - dStSqDXY) ;
+ Vector3d vtNmax = Point3d( dX, dY, dMax) - ptV ;
+ vtNmax.Normalize() ;
+ if ( dOffs > 0.)
+ AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, 0) ;
+ else
+ SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, 0) ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione per la creazione di un cilindro di Offset sul vertice di una TriMesh con cui
+ aggiungere o sottrarre intervalli lungo i Dexel coinvolti */
+bool
+VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid)
+{
+ // determino la lunghezza dello spigolo corrente
+ double dH = Dist( ptP1, ptP2) ;
+ // asse del cilindro
+ Vector3d vtV = ptP2 - ptP1 ; vtV.Normalize() ;
+ // calcolo box del cilindro
+ BBox3d BBoxCylinder ;
+ BBoxCylinder.Add( ptP1) ;
+ BBoxCylinder.Add( ptP2) ;
+ if ( AreSameOrOppositeVectorApprox( vtV, X_AX))
+ BBoxCylinder.Expand( 0., abs( dOffs), abs( dOffs)) ;
+ else if ( AreSameOrOppositeVectorApprox( vtV, Y_AX))
+ BBoxCylinder.Expand( abs( dOffs), 0., abs( dOffs)) ;
+ else if ( AreSameOrOppositeVectorApprox( vtV, Z_AX))
+ BBoxCylinder.Expand( abs( dOffs), abs( dOffs), 0.) ;
+ else {
+ double dExpandX = abs( dOffs) * sqrt( 1 - vtV.x * vtV.x) ;
+ double dExpandY = abs( dOffs) * sqrt( 1 - vtV.y * vtV.y) ;
+ double dExpandZ = abs( dOffs) * sqrt( 1 - vtV.z * vtV.z) ;
+ BBoxCylinder.Expand( dExpandX, dExpandY, dExpandZ) ;
+ }
+ // determino gli intervalli di interesse mediante intersezione
+ int nStartI = max( 0, int( BBoxCylinder.GetMin().x / m_dStep)) ;
+ int nEndI = min( m_nNx[nGrid] - 1, int( BBoxCylinder.GetMax().x / m_dStep)) ;
+ int nStartJ = max( 0, int( BBoxCylinder.GetMin().y / m_dStep)) ;
+ int nEndJ = min( m_nNy[nGrid] - 1, int( BBoxCylinder.GetMax().y / m_dStep)) ;
+ // aggiorno gli spilloni interessati
+ Frame3d CylFrame ;
+ if ( ! CylFrame.Set( ptP1, vtV))
+ return false ;
+ for ( int i = nStartI ; i <= nEndI ; ++ i) {
+ for ( int j = nStartJ ; j <= nEndJ ; ++ j) {
+ Point3d ptC( ( i + 0.5) * m_dStep, ( j + 0.5) * m_dStep, 0) ;
+ Point3d ptInt1, ptInt2 ;
+ Vector3d vtN1, vtN2 ;
+ if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, abs( dOffs), true, true,
+ ptInt1, vtN1, ptInt2, vtN2)) {
+ if ( dOffs > 0.)
+ AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, 0) ;
+ else
+ SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, 0) ;
+ }
+ }
+ }
+
+ return true ;
+}
+
+//----------------------------------------------------------------------------
+/* Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da una
+ superficie TriMesh */
+bool
+VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol)
+{
+ // controllo delle superfici
+ for ( const ISurfTriMesh* Surf : vSurf) {
+ if ( Surf == nullptr)
+ return false ;
+ }
+ // verifica sul parametro di Offset ( coerente con Curve e FlatRegion)
+ if ( abs( dOffs) < 10 * EPS_SMALL)
+ return true ;
+ // se non ho superfici, non faccio nulla
+ if ( vSurf.empty())
+ return true ;
+
+ // definisco lo Zmap di partenza a partire dalle superfici
+ // se una sola superficie
+ double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ;
+ if ( int( vSurf.size()) == 1) {
+ // controllo la validità della superficie
+ if ( ! vSurf[0]->IsValid() || vSurf[0]->GetTriangleCount() == 0)
+ return true ;
+ // definisco lo Zamp a partire dall'espansione del Box della superficie
+ if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion))
+ return false ;
+ }
+ // se più superfici
+ else {
+ // calcolo il Box complessivo delle superfici TriMesh
+ BBox3d BBoxGlob ;
+ for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) {
+ // controllo la validità della superficie
+ if ( ! vSurf[i]->IsValid() || vSurf[i]->GetTriangleCount() == 0)
+ continue ;
+ // calcolo il Box della superficie
+ BBox3d BBoxSurf ; vSurf[i]->GetLocalBBox( BBoxSurf) ;
+ // aggiungo il Box a quello complessivo
+ BBoxGlob.Add( BBoxSurf) ;
+ }
+ // definisco uno Zmap vuoto a partire dal Box
+ BBoxGlob.Expand( dBoxExpansion) ;
+ if ( ! CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true))
+ return false ;
+ for ( const ISurfTriMesh* Surf : vSurf) {
+ if ( ! AddSurfTm( Surf))
+ return false ;
+ }
+ }
+
+ /* Assunzioni :
+ - Idea Generale di Offset
+ - Su ogni vertice viene definita una sfera ( con raggio pari al valore di Offset e
+ centro il vertice corrente)
+ - Su ogni lato viene definito un cilindro ( con raggio di pase pari al valore di Offset
+ e asse definito dall'edge stesso)
+ - Su ogni faccia viene definita una superficie di estrusione ( dove le due basi sono
+ definite dalla traslazione sia in positivo che in negativo della faccia lungo la sua normale)
+
+ - Segno dell'Offset :
+ - Positivo ( si sommano gli intervalli corrisipondenti alle entità create)
+ - Negativo ( si sottraggono gli intervalli corrispondenti alle enetità create)
+
+ - Semplificazione entità :
+ La creazione di Sfere e Cilindri potrebbe essere resa più "corretta" definitendo solo
+ "spicchi 3d" di sfera e "spicchi 3d" di cilindri. Dato che le operazioni di somma, sottrazioni e
+ calcolo delle normali per gli spilloni sono elementari su queste figure, si rischia di appesantire
+ troppo i conti introducendo variabili angolari che non sommando tutte le parti.
+ */
+
+ // definisco vettore di frame Locali alle 3 griglie
+ FRAME3DVECTOR vFrGrid( 4) ;
+ vFrGrid[0].Set( ORIG, X_AX, Y_AX, Z_AX) ;
+ vFrGrid[1].Set( m_MapFrame.Orig(), m_MapFrame.VersX(), m_MapFrame.VersY(), m_MapFrame.VersZ()) ;
+ vFrGrid[2].Set( m_MapFrame.Orig(), m_MapFrame.VersY(), m_MapFrame.VersZ(), m_MapFrame.VersX()) ;
+ vFrGrid[3].Set( m_MapFrame.Orig(), m_MapFrame.VersZ(), m_MapFrame.VersX(), m_MapFrame.VersY()) ;
+
+
+ // scorro le superfici
+ for ( const ISurfTriMesh* Surf : vSurf) {
+ // se superficie non valida, passo alla successiva
+ if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0)
+ continue ;
+ // definisco una mappa dei vertici, in modo da sapere su quali sono state già create le sfere
+ BOOLVECTOR vbVert( Surf->GetVertexCount(), false) ;
+ // ----------------------- Cilindri e Sfere -----------------------
+ // scorro gli Edge della superficie
+ for ( int nE = 0 ; nE < Surf->GetEdgeCount() ; ++ nE) {
+ // recupero lo spigolo
+ int nV1, nV2, nF1, nF2 ; double dAng ;
+ Surf->GetEdge( nE, nV1, nV2, nF1, nF2, dAng) ;
+ // controllo se il cilindro serve
+ // NB. la mancata creazione del cilindro comporta la mancata creazione delle sfere sui suoi vertici
+ // durante questa iterazione; non significa che questa sfera non verrà mai creata...
+ // Non esiste la sfera sul vertive V <=> non esiste alcun cilindro su tutti gli edge concorrenti
+ if ( dAng * dOffs < 0)
+ continue ;
+ // recupero le coordinate dei vertici
+ Point3d ptP1 ; Surf->GetVertex( nV1, ptP1) ;
+ Point3d ptP2 ; Surf->GetVertex( nV2, ptP2) ;
+ // ciclo sulle griglie
+ for ( int nGrid = 0 ; nGrid < 3 ; ++ nGrid) {
+ // esprimo gli estremi nel riferimento della griglia
+ ptP1.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ;
+ ptP2.LocToLoc( vFrGrid[nGrid], vFrGrid[nGrid + 1]) ;
+ // aggiungo/sottraggo gli intervalli definiti dal cilindro
+ if ( ! CreateOffsCylinderOnEdge( ptP1, ptP2, dOffs, nGrid))
+ return false ;
+ // aggiungo/sottraggo gli intervalli definiti dalla sfera
+ if ( ! vbVert[nV1]) {
+ vbVert[nV1] = ( nGrid == 2) ;
+ if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid))
+ return false ;
+ }
+ if ( ! vbVert[nV2]) {
+ vbVert[nV2] = ( nGrid == 2) ;
+ if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid))
+ return false ;
+ }
+ }
+ }
+ // ----------------------- Facce -----------------------
+ // scorro tutte le facce definendo una superficie di estrusione
+ for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) {
+ // recupero lo faccia
+ POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ;
+ // recupero la normale della faccia
+ Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ;
+ // definisco la superficie di estrusione
+ CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ;
+ for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
+ vPL[i].Translate( - abs( dOffs) * vtN) ;
+ PtrOwner pCrvCompo( CreateCurveComposite()) ;
+ if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i]))
+ return false ;
+ vpCrvs.emplace_back( Release( pCrvCompo)) ;
+ }
+ // recupero la TriMesh di estrusione
+ PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ;
+ if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0)
+ return false ;
+ // aggiorno gli spilloni
+ if ( dOffs > 0.)
+ AddSurfTm( pStmExtr) ;
+ else
+ SubtractSurfTm( pStmExtr) ;
+ }
+ }
+ m_nShape = OFFSET ; // OFFSET (?) ... per ora va bene così
+
+ return true ;
+}
+
+
+