Merge branch 'master' into FasterVMill5Axis

This commit is contained in:
Daniele Bariletti
2025-06-16 15:12:20 +02:00
25 changed files with 1928 additions and 800 deletions
+713 -513
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -2043,13 +2043,14 @@ CalcCurvesMedialAxis( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nS
//----------------------------------------------------------------------------
bool
CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids)
CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids,
bool bMergeOnlySameProps)
{
Voronoi* pVoronoiObj = GetCurveVoronoi( crvC) ;
if ( pVoronoiObj == nullptr)
return false ;
return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids) ;
return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps) ;
}
//----------------------------------------------------------------------------
+40 -25
View File
@@ -192,7 +192,7 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT
return false ;
// verifico lo stato
if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && m_nStatus == TO_VERIFY))
if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && ( m_nStatus == TO_VERIFY || m_nStatus == IS_A_POINT)))
return false ;
// controllo la tolleranza
@@ -1778,10 +1778,11 @@ bool
CurveComposite::AddPoint( const Point3d& ptStart)
{
// verifico lo stato
if ( m_nStatus != TO_VERIFY)
if ( m_nStatus != TO_VERIFY && m_nStatus != IS_A_POINT)
return false ;
// assegno il punto
// assegno il punto e setto lo stato
m_ptStart = ptStart ;
m_nStatus = IS_A_POINT ;
return true ;
}
@@ -1825,7 +1826,7 @@ bool
CurveComposite::AddLine( const Point3d& ptNew, bool bEndOrStart)
{
// verifico lo stato
if ( m_nStatus != OK && m_nStatus != TO_VERIFY)
if ( m_nStatus != OK && m_nStatus != IS_A_POINT)
return false ;
// costruisco la linea
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
@@ -3168,11 +3169,26 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
// se precedente molto corta
double dLenP ;
if ( pCrvP->GetLength( dLenP) && dLenP < dCurrLinTol) {
// se abbastanza allineata alla successiva
// se abbastanza allineata alla successiva
Vector3d vtDirP, vtDirC ;
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
Point3d ptStart ;
return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ;
bool bModifStart = ( pCrvC->GetType() != CRV_ARC) ;
if ( ! bModifStart) {
/* nel caso in cui la curva corrente sia un arco, bisogna controllare che la somma tra
l'angolo al centro e l'angolo sotteso dalla curva precedente non superi l'angolo giro; in
caso positivo, la modifica del punto inziale dell'arco ( curva corrente) rimoverebbe
tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */
Point3d ptS ; pCrvP->GetStartPoint( ptS) ;
Point3d ptE ; pCrvC->GetStartPoint( ptE) ;
const ICurveArc* pArcC = GetBasicCurveArc( pCrvC) ;
double dAngRef = ( Dist( ptS, ptE) / pArcC->GetRadius()) * RADTODEG ;
bModifStart = ( abs( pArcC->GetAngCenter()) + dAngRef < ANG_FULL - 10 * EPS_ANG_SMALL) ;
}
if ( bModifStart) {
Point3d ptStart ;
return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ;
}
}
}
// se corrente molto corta
@@ -3181,10 +3197,24 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
// se abbastanza allineata alla precedente
Vector3d vtDirP, vtDirC ;
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
Point3d ptEnd ;
return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ;
bool bModifEnd = ( pCrvP->GetType() != CRV_ARC) ;
if ( ! bModifEnd) {
/* nel caso in cui la curva predecente sia un arco, bisogna controllare che la somma tra
l'angolo al centro e l'angolo sotteso dalla curva corrente non superi l'angolo giro; in
caso positivo, la modifica del punto finale dell'arco ( curva precedente) rimoverebbe
tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */
Point3d ptS ; pCrvP->GetEndPoint( ptS) ;
Point3d ptE ; pCrvC->GetEndPoint( ptE) ;
const CurveArc* pArcP = GetBasicCurveArc( pCrvP) ;
double dAngRef = ( Dist( ptS, ptE) / pArcP->GetRadius()) * RADTODEG ;
bModifEnd = ( abs( pArcP->GetAngCenter()) + dAngRef < ANG_FULL - 10. * EPS_ANG_SMALL) ;
}
if ( bModifEnd) {
Point3d ptEnd ;
return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ;
}
}
}
}
// coefficiente deduzione tolleranza
const double COEFF_TOL = 0.7 ;
// se entrambe rette
@@ -3279,8 +3309,6 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
CurveArc NewArc ;
if ( NewArc.Set3P( ptP1, ptP2, ptP3, bCirc)) {
// se vicino a circonferenza arco per 3 punti potrebbe non dare il risultato desiderato quindi faccio controllo su raggio e centro
double dDist = Dist( NewArc.GetCenter(), ptC1Fin) ;
double dDelta = abs( NewArc.GetRadius() - pArcP->GetRadius()) ;
if ( Dist( NewArc.GetCenter(), ptC1Fin) > 2 * dCurrLinTol || abs( NewArc.GetRadius() - pArcP->GetRadius()) > 2 * dCurrLinTol)
return 0 ;
@@ -3801,19 +3829,6 @@ CurveComposite::ResetVoronoiObject() const
m_pVoronoiObj = nullptr ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::FromPoint(Point3d& ptStart)
{
// verifico lo stato
if ( m_nStatus != TO_VERIFY)
return false ;
// assegno il punto e setto lo stato
m_ptStart = ptStart ;
m_nStatus = IS_A_POINT ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetOnlyPoint(Point3d& ptStart) const
+1 -2
View File
@@ -177,8 +177,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool GetCurveTempProp( int nCrv, int& nProp, int nPropInd = 0) const override ;
bool SetCurveTempParam( int nCrv, double dParam, int nParamInd = 0) override ;
bool GetCurveTempParam( int nCrv, double& dParam, int nParamInd = 0) const override ;
bool FromPoint( Point3d& ptStart) override ; // funzione per settare la curva ad un unico punto
bool GetOnlyPoint( Point3d& ptStart) const override ; // funzione per recuperare l'unico punto da cui è composta la curva ( degenere)
bool GetOnlyPoint( Point3d& ptStart) const override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
BIN
View File
Binary file not shown.
+2
View File
@@ -320,6 +320,8 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="IntersLineVolZmap.cpp" />
<ClCompile Include="IntersPlaneVolZmap.cpp" />
<ClCompile Include="IntersLineSurfBez.cpp" />
<ClCompile Include="SurfTriMeshOffset.cpp" />
<ClCompile Include="VolZmapOffset.cpp" />
<ClCompile Include="PolygonElevation.cpp" />
<ClCompile Include="Quaternion.cpp" />
<ClCompile Include="RotationMinimizingFrame.cpp" />
+6
View File
@@ -546,6 +546,12 @@
<ClCompile Include="DistPointSurfFr.cpp">
<Filter>File di origine\GeoDist</Filter>
</ClCompile>
<ClCompile Include="VolZmapOffset.cpp">
<Filter>File di origine\Geo</Filter>
</ClCompile>
<ClCompile Include="SurfTriMeshOffset.cpp">
<Filter>File di origine\Geo</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
+5 -5
View File
@@ -19,10 +19,10 @@
void
PolygonPlane::AddPoint( const Point3d& ptP)
{
// se è il primo punto (parto da -1 perchè verrà contato alla chiusura)
// se è il primo punto (parto da -1 perchè verrà contato alla chiusura)
if ( m_nPntNbr == -1) {
// inizializzazioni
m_dLenN = 0 ;
m_dLenN = -1 ;
m_vtN = V_NULL ;
m_ptMid = ORIG ;
m_dSXy = 0 ; m_dSXz = 0 ;
@@ -60,16 +60,16 @@ PolygonPlane::AddPoint( const Point3d& ptP)
bool
PolygonPlane::Finalize( void)
{
// almeno 3 punti (il triangolo è il poligono con minimo numero di lati)
// almeno 3 punti (il triangolo è il poligono con minimo numero di lati)
if ( m_nPntNbr + 1 < 3)
return false ;
// se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato
// se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato
if ( ! AreSamePointExact( m_ptFirst, m_ptLast)) {
// aggiungo il primo punto per far eseguire i conti sul lato di chiusura
AddPoint( m_ptFirst) ;
}
// se non effettuato, eseguo il calcolo finale
if ( m_dLenN < EPS_SMALL) {
if ( m_dLenN < 0) {
// lunghezza della normale (doppio dell'area del poligono)
m_dLenN = m_vtN.Len() ;
if ( m_dLenN < SQ_EPS_SMALL)
+3 -2
View File
@@ -115,7 +115,8 @@ GetSurfFlatRegionDisk( double dRadius)
//-------------------------------------------------------------------------------
ISurfFlatRegion*
GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol)
GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol,
bool bMergeOnlySameProps)
{
// metodo di calcolo impostato da USE_VORONOI
@@ -330,7 +331,7 @@ GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, b
else {
// calcolo la fat curve con Voronoi
ICURVEPOVECTOR vFatCurves ;
if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids))
if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps))
return nullptr ;
// costruisco la superficie a partire dalle curve
+164 -36
View File
@@ -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
@@ -1220,16 +1224,17 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR&
// se rimasto qualcosa
if ( pgTria.GetSideCount() > 0) {
// lo proietto sul piano e creo la regione
pgTria.Scale( frOCS, 1, 1, 0) ;
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ;
if ( ! IsNull( pSfrTria)) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
if ( pgTria.Scale( frOCS, 1, 1, 0)) {
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ;
if ( ! IsNull( pSfrTria)) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
}
}
}
}
@@ -1687,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) {
@@ -1874,7 +1881,7 @@ SurfTriMesh::TestSealing( void)
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL) {
bClosed = false ;
break ;
break ;
}
}
}
@@ -1936,7 +1943,7 @@ SurfTriMesh::PackVertices( void)
++ nFirstFree ;
}
else
vVId.push_back( nId) ;
vVId.push_back( nId) ;
}
else {
if ( nFirstFree == SVT_NULL)
@@ -3043,7 +3050,7 @@ SurfTriMesh::AddBiTriangle( const int nIdVert[4])
//----------------------------------------------------------------------------
bool
SurfTriMesh::DoCompacting( double dTol)
{
{
// imposto ricalcolo
m_nStatus = ERR ;
m_OGrMgr.Reset() ;
@@ -3084,6 +3091,7 @@ SurfTriMesh::DoCompacting( double dTol)
int nVIdSize = int( vVId.size()) ;
// sistemo gli indici dei vertici nei triangoli
INTVECTOR vInvalidIds ;
for ( int nId = 0 ; nId < GetTriangleSize() ; ++ nId) {
// salto i triangoli cancellati
if ( m_vTria[nId].nIdVert[0] == SVT_DEL)
@@ -3100,15 +3108,51 @@ SurfTriMesh::DoCompacting( double dTol)
// aggiorno il triangolo
m_vTria[nId].nIdVert[0] = vVId[vOId[0]] ;
m_vTria[nId].nIdVert[1] = vVId[vOId[1]] ;
m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ;
// se due vertici coincidono o la normale non è calcolabile, cancello il triangolo
if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1] ||
m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2] ||
m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2] ||
! CalcTriangleNormal( nId))
RemoveTriangle( nId) ;
m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ;
// verifico se triangolo da rimuovere per vertici coincidenti
bool bRemove = false ;
int nTAdj1 = SVT_NULL, nTAdj2 = SVT_NULL ;
if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1]) {
nTAdj1 = m_vTria[nId].nIdAdjac[1] ;
nTAdj2 = m_vTria[nId].nIdAdjac[2] ;
bRemove = true ;
}
else if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2]) {
nTAdj1 = m_vTria[nId].nIdAdjac[0] ;
nTAdj2 = m_vTria[nId].nIdAdjac[1] ;
bRemove = true ;
}
else if ( m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2]) {
nTAdj1 = m_vTria[nId].nIdAdjac[0] ;
nTAdj2 = m_vTria[nId].nIdAdjac[2] ;
bRemove = true ;
}
if ( bRemove) {
// sistemo le contro adiacenze
if ( nTAdj1 != SVT_NULL) {
for ( int j = 0 ; j < 3 ; ++ j)
if ( m_vTria[nTAdj1].nIdAdjac[j] == nId)
m_vTria[nTAdj1].nIdAdjac[j] = nTAdj2 ;
}
if ( nTAdj2 != SVT_NULL) {
for ( int j = 0 ; j < 3 ; ++ j)
if ( m_vTria[nTAdj2].nIdAdjac[j] == nId)
m_vTria[nTAdj2].nIdAdjac[j] = nTAdj1 ;
}
// rimuovo il triangolo
RemoveTriangle( nId) ;
}
// verifico se il triangolo va rimosso per normale non calcolabile
else if ( ! CalcTriangleNormal( nId))
vInvalidIds.emplace_back( nId) ;
}
// elimino triangoli invalidi ( con gestione speciale per evitare T-junctions)
if ( ! vInvalidIds.empty())
RemoveInvalidTriangles( vInvalidIds) ;
// compatto il vettore dei vertici
if ( ! PackVertices())
return false ;
@@ -3345,22 +3389,23 @@ SurfTriMesh::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double
bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ;
bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ;
// aggiorno le facce
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// se c'è mirror, devo invertire la faccia
if ( bMirror)
InvertTriangle( i) ;
// aggiorno la normale
if ( ! CalcTriangleNormal( i)) {
// elimino il triangolo
RemoveTriangle( i) ;
}
}
// se c'è mirror, devo invertire le facce
if ( bMirror) {
for ( int i = 0 ; i < GetTriangleSize() ; ++ i)
if ( m_vTria[i].nIdVert[0] != SVT_DEL)
InvertTriangle( i) ;
}
// rimuovo i triangoli resi invalidi dalla scalatura
bool bOk = DoCompacting() ;
return DoCompacting() ;
// rimuovo i triangoli doppi
bool bModified = false ;
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
return bOk ;
}
//----------------------------------------------------------------------------
@@ -4322,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 ;
}
+10 -5
View File
@@ -18,6 +18,7 @@
#include "GeoObjRW.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkHashGrids3d.h"
#include "/EgtDev/Include/EGkPointGrid3d.h"
#include <deque>
#include <set>
@@ -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<StmVert> 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,14 +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, 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
+42 -83
View File
@@ -502,9 +502,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
}
}
// -------------------------------------------------------------------------------------------
// Creo il loop chiuso padre di tutti, il perimetro del triangolo. Questo viene diviso in sotto-loop
// chiusi mediante quelli aperti. I loop chiusi trovati precedentemente sono interni a uno dei
// sotto-loop chiusi di cui è formato il perimetro.
@@ -704,16 +702,18 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
}
}
// Elimino loop interni non validi
bool bDouble = true ;
// Verifico se i loop interni sono validi
bool bAllInvalid = true ;
for ( int nInnLoop = 0 ; nInnLoop < int( vInnerLoop.size()) ; ++ nInnLoop) {
if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 2) {
bDouble = false ;
// se chain formata da tre segmenti significa che si tratta di due linee sovrapposte ( il terzo tratto è quello aggiunto
// per forzare la chiusura)
if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 3) {
bAllInvalid = false ;
break ;
}
}
if ( vInnerLoop.empty() || bDouble) {
if ( vInnerLoop.empty() || bAllInvalid) {
// Eseguo triangolazione
PNTVECTOR vPt ;
INTVECTOR vTr ;
@@ -753,63 +753,20 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
vPolygons.emplace_back( CurLoop) ;
}
// poligono
Polygon3d pgPol ;
pgPol.FromPolyLine( vPolygons[1]) ;
// controllo direzioni delle normali
bool bCodirectedNormals = trTria.GetN() * pgPol.GetVersN() > 0. ;
// Aggiungo al loop esterno i punti dei loop interni che si trovano su di esso
PNTULIST& ExternLoopList = vPolygons[0].GetUPointList() ;
// Ciclo sui segmenti del loop esterno
auto itSt = ExternLoopList.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != ExternLoopList.end() && itEn != ExternLoopList.end() ; ++ itSt, ++ itEn) {
// Estremi del segmento corrente del loop esterno e scorrispondente vettore
Point3d ptSt = itSt->first ;
Point3d ptEn = itEn->first ;
Vector3d vtSeg = ptEn - ptSt ;
double dSegLen = vtSeg.Len() ;
vtSeg /= dSegLen ;
// Vettore dei punti dei loop interni che stanno sul segmento del loop esterno
PNTUVECTOR vPointWithOrder ;
// Ciclo sui loop interni
for ( int nInnPoly = 1 ; nInnPoly < int( vPolygons.size()) ; ++ nInnPoly) {
// Ciclo sui punti dei loop interni
Point3d ptInnPoint ;
bool bIsFirst = true ;
bool bContinue = vPolygons[nInnPoly].GetFirstPoint( ptInnPoint) ;
while ( bContinue) {
DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ;
double dDist ;
DistCalculator.GetDist( dDist) ;
double dLongPos = ( ptInnPoint - ptSt) * vtSeg ;
if ( dDist < EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) {
POINTU NewPointU ;
NewPointU.first = ptInnPoint ;
NewPointU.second = dLongPos ;
if ( ! bIsFirst)
vPointWithOrder.emplace_back( NewPointU) ;
}
bIsFirst = false ;
bContinue = vPolygons[nInnPoly].GetNextPoint( ptInnPoint) ;
}
}
// Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) {
for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) {
if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) {
swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ;
}
}
}
// Aggiungo i punti al loop esterno
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) {
itSt = ExternLoopList.emplace( itEn, vPointWithOrder[nPi]) ;
}
// controllo la direzione della normale del triangolo con quella del poligono di area maggiore
// ( per gestire eventuali inscatolamenti)
Vector3d vtPoly = V_NULL ;
double dMaxArea = -1 ;
for ( int i = 1 ; i < int( vPolygons.size()) ; i ++) {
Plane3d plPoly ;
double dAreaPoly ;
vPolygons[i].IsClosedAndFlat( plPoly, dAreaPoly) ;
if ( dAreaPoly > dMaxArea) {
vtPoly = plPoly.GetVersN() ;
dMaxArea = dAreaPoly ;
}
}
bool bCodirectedNormals = trTria.GetN() * vtPoly > 0. ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
@@ -836,6 +793,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
// Divido i loop che si autointercettano
// TO DO : da verificare. Questa porzione di codice non dovrebbe andare prima della triangolazione?
int nInitialLoopNum = int( vPolygons.size()) ;
for ( int nL = 1 ; nL < nInitialLoopNum ; ++ nL) {
// Lista dei punti della PolyLine Loop corrente
@@ -883,11 +841,11 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
itSt2 = LoopPointList.emplace( itEn2, vAddingPointWithOrder[nPi]) ;
}
}
// Spezzo i loop autointersecantesi
POLYLINEVECTOR vAuxPolygons ;
vAuxPolygons.emplace_back( vPolygons[nL]) ;
bool bSplitted = true ;
while ( bSplitted) {
bSplitted = false ;
@@ -956,16 +914,13 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
vPolygons.erase( vPolygons.begin() + i) ;
else
++ i ;
}
bool bCordirectedNormals_intLoop = bCodirectedNormals ;
// eventuale inversione della prima curva ( che determina il verso della triangolazione) per averla orientata
// come il triangolo
if ( ! vPolygons.empty()) {
Polygon3d pgPol ;
pgPol.FromPolyLine( vPolygons[0]) ;
// controllo direzioni delle normali
bCordirectedNormals_intLoop = trTria.GetN() * pgPol.GetVersN() > 0. ;
if ( ! bCordirectedNormals_intLoop)
if ( trTria.GetN() * pgPol.GetVersN() < 0.)
vPolygons[0].Invert() ;
}
@@ -981,7 +936,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
if ( bCordirectedNormals_intLoop)
if ( bCodirectedNormals)
Surf.m_vTria[nNewTriaNum].nTempShell = 1 ;
else
Surf.m_vTria[nNewTriaNum].nTempShell = -1 ;
@@ -1123,7 +1078,7 @@ SurfTriMesh::AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Su
//----------------------------------------------------------------------------
bool
SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
{
{
bool bModif = false ;
SurfTriMesh& SurfB = Other ;
@@ -1176,7 +1131,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
INTVECTOR vNearTria ;
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
// I scorro tutti i triangoli di B che intersecano il box di A
// Scorro tutti i triangoli di B che intersecano il box di A
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
// Se il triangolo B non è valido, continuo
@@ -1365,7 +1320,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
// Triangoli sovrapposti
if ( bContinue) {
int nTriaNum2A = GetTriangleSize() ;
// Resetto e ricalcolo la HashGrid della superficie B
// Resetto e ricalcolo la HashGrid della superficie B
SurfB.ResetHashGrids3d() ;
for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) {
// Se il triangolo A non è valido, continuo
@@ -1375,15 +1330,19 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
// Box del triangolo A
BBox3d b3dTriaA ;
trTriaA.GetLocalBBox( b3dTriaA) ;
// Recupero i triangoli di B che interferiscono col box del triangolo di A
// Recupero i triangoli di B che interferiscono col box del triangolo di A
INTVECTOR vNearTria ;
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
// Se il triangolo B non è valido, continuo
// Se il triangolo B non è valido, continuo
Triangle3d trTriaB ;
if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true))
continue ;
// Se i triangoli sono sovrapposti
// Se sono già stati classificati entrambi come sovrapposti continuo
if ( abs( m_vTria[nTA].nTempShell) == 2 && abs( SurfB.m_vTria[vNearTria[nTB]].nTempShell) == 2)
continue ;
// Se i triangoli sono sovrapposti
TRIA3DVECTOR vTriaAB ;
Point3d ptTempA, ptTempB ;
int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ;
@@ -1475,7 +1434,7 @@ SurfTriMesh::Add( const ISurfTriMesh& Other)
// tengo una copia di B ( la superficie B viene modificata durante la ritriangolazione )
SurfTriMesh SurfA_cl ;
SurfA_cl.CopyFrom( this) ;
// ritriangolo le due superfici mediante ogni intersezione Triangolo-Triangolo
IntersectTriMeshTriangle( SurfB) ;
@@ -1625,12 +1584,12 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other)
AddTriangle( nNewVert, m_nMaxTFlag) ;
}
}
// sistemazioni varie
bool bOk = ( AdjustVertices() && DoCompacting()) ;
bool bModified = false ;
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
bOk = bOk && RemoveTJunctions( bModified) ;
if ( bModified)
+75
View File
@@ -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<ISurfTriMesh> 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<IVolZmap> pVolZmap( CreateVolZmap()) ;
if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol))
return nullptr ;
// restituisco la superficie TriMesh
return ( pVolZmap->GetSurfTriMesh()) ;
}
+204 -31
View File
@@ -17,7 +17,6 @@
#include "Triangulate.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkDistLineLine.h"
#include <unordered_map>
using namespace std ;
@@ -35,6 +34,7 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified)
// recupero i vertici dei triangoli
int nIdV[3] ;
GetTriangle( nT, nIdV) ;
bool bToRemove = false ;
// ciclo sui triangoli adiacenti
for ( int nE = 0 ; nE < 3 ; ++ nE) {
// recupero triangolo adiacente, se non esiste passo al successivo
@@ -53,10 +53,14 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified)
}
}
if ( nCoinc == 3) {
RemoveTriangle( nAdjT) ;
// se i vertici coincidono rimuovo entrambi i triangoli
bToRemove = true ;
bModified = true ;
RemoveTriangle( nAdjT) ;
}
}
if ( bToRemove)
RemoveTriangle( nT) ;
}
return true ;
@@ -86,8 +90,8 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB)
// Recupero i vertici del triangolo A
Point3d ptSegSt, ptSegEn, ptVertA ;
if ( ! GetVertex( m_vTria[nTA].nIdVert[nEdgeA], ptSegSt) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA))
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA))
return false ;
// Recupero il vertice opposto del triangolo B
Point3d ptVertB ;
@@ -98,23 +102,43 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB)
if ( ! DiagDist.IsSmall())
return false ;
double dPos1, dPos2 ;
if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2) ||
dPos1 < EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() - EPS_SMALL ||
dPos2 < EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() - EPS_SMALL)
return false ;
if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2))
return false ;
if ( dPos1 < - EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() + EPS_SMALL ||
dPos2 < - EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() + EPS_SMALL)
return false ;
// Eseguo il flipping
m_vTria[nTA].nIdVert[nEdgeA] = m_vTria[nTB].nIdVert[( nEdgeB + 2) % 3] ;
m_vTria[nTB].nIdVert[nEdgeB] = m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3] ;
m_vTria[nTA].nIdAdjac[nEdgeA] = m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] ;
m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ;
m_vTria[nTB].nIdAdjac[nEdgeB] = m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] ;
m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ;
m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] = nTA ;
// sistemo anche le contro-adiacenze
int nTC = m_vTria[nTA].nIdAdjac[nEdgeA] ;
if ( nTC != SVT_NULL) {
for ( int i = 0 ; i < 3 ; i++)
if ( m_vTria[nTC].nIdAdjac[i] == nTB) {
m_vTria[nTC].nIdAdjac[i] = nTA ;
break ;
}
}
int nTD = m_vTria[nTB].nIdAdjac[nEdgeB] ;
if ( nTD != SVT_NULL) {
for ( int i = 0 ; i < 3 ; i++)
if ( m_vTria[nTD].nIdAdjac[i] == nTA) {
m_vTria[nTD].nIdAdjac[i] = nTB ;
break ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::RemoveTJunctions( bool& bModified)
SurfTriMesh::RemoveTJunctions( bool& bModified, double dMinSqDist)
{
bModified = false ;
@@ -123,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))
@@ -150,6 +179,8 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
if ( dSegLen < EPS_SMALL)
continue ;
vtSeg /= dSegLen ;
int nV1 = m_vTria[nT].nIdVert[nSeg] ;
int nV2 = m_vTria[nT].nIdVert[Next( nSeg)] ;
// Ciclo sui triangoli vicini
for ( int nI = 0 ; nI < int( vNearTria.size()) ; ++ nI) {
// Salto il triangolo se è quello di riferimento
@@ -157,13 +188,16 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
continue ;
// Cerco i vertici che stanno sul lato del triangolo
for ( int nVert = 0 ; nVert < 3 ; ++ nVert) {
int nCurrVert = m_vTria[vNearTria[nI]].nIdVert[nVert] ;
if ( nCurrVert == nV1 || nCurrVert == nV2)
continue ;
Point3d ptVert ;
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
@@ -307,16 +341,42 @@ ChooseGoodStartPoint( PNTULIST& PointList)
return false ;
}
//----------------------------------------------------------------------------
static bool
AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
// -------------------------------------------------------------
bool
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) {
// Se dal punto corrente inizia un segmento adiacente a un'altra faccia
if ( itLast->second != it->second) {
// 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) {
if ( LoopVec.empty())
GetFacetLoops( int( itLast->second), LoopVec) ;
for ( int i = 0 ; i < int( LoopVec.size()) && ! bAnalyze ; i ++) {
const PNTULIST& PointListAdj = LoopVec[i].GetUPointList() ;
int nSamePoints = 0 ;
for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) ; ++ itAdj) {
// cerco il punto corrente sul loop della faccia adiacente
if ( AreSamePointApprox( it->first, itAdj->first))
++ nSamePoints ;
if ( ( nSamePoints == 1 && int( PointListAdj.size()) <= 4) || nSamePoints > 1) {
bAnalyze = true ;
break ;
}
}
}
}
if ( bAnalyze) {
// Raccolgo i punti in una polyline
PolyLine PL ;
int nPar = -1 ;
@@ -326,7 +386,7 @@ AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
}
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 ;
@@ -418,7 +478,7 @@ AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
//----------------------------------------------------------------------------
bool
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced, double dTolAlign)
{
// La trimesh deve essere valida
if ( ! IsValid())
@@ -433,8 +493,8 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Ciclo sulle facce della mesh per trovare quelle da ritriangolare
unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ;
for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) {
// Recupero i loop della faccia (il parametro indica la faccia adiacente)
// Recupero i loop della faccia ( il parametro indica la faccia adiacente)
POLYLINEVECTOR LoopVec ;
GetFacetLoops( nF, LoopVec) ;
@@ -445,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, bModif))
if ( ! AdjustLoop( PointList, dMaxEdgeLen, dTolAlign, bModif))
return false ;
if ( bModif)
bToRetriangulate = true ;
@@ -479,9 +543,8 @@ 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 ;
@@ -502,17 +565,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Cancello i triangoli
for ( int nT : vDelTria)
RemoveTriangle( nT) ;
// Applico le nuove triangolazioni delle facce
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
const PNTVECTOR& vPt = itF->second.first ;
const INTVECTOR& vTr = itF->second.second ;
// Inserisco i nuovi triangoli
// Inserisco i nuovi triangoli
bool bFirstTria = true ;
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
int nNewId[3] = { AddVertex( vPt[vTr[n]]),
AddVertex( vPt[vTr[n + 1]]),
AddVertex( vPt[vTr[n + 2]])} ;
AddVertex( vPt[vTr[n + 1]]),
AddVertex( vPt[vTr[n + 2]])} ;
auto itCol = ColorMap.find( itF->first) ;
int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ;
int nNewTriaId = AddTriangle( nNewId, nTFlag) ;
@@ -525,7 +588,7 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
}
}
}
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
m_OGrMgr.Reset() ;
ResetHashGrids3d() ;
@@ -722,3 +785,113 @@ SurfTriMesh::SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECT
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const
{
// recupero il lato più lungo del triangolo
double dLen0 = SqDist( m_vVert[m_vTria[nT].nIdVert[0]].ptP, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
double dLen1 = SqDist( m_vVert[m_vTria[nT].nIdVert[1]].ptP, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
double dLen2 = SqDist( m_vVert[m_vTria[nT].nIdVert[2]].ptP, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
nEdge = -1 ;
if ( dLen0 > dLen1 && dLen0 > dLen2)
nEdge = 0 ;
else if ( dLen1 > dLen2)
nEdge = 1 ;
else
nEdge = 2 ;
// recupero il triangolo adiacente sul lato più lungo
nAdjTrg = m_vTria[nT].nIdAdjac[nEdge] ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::RemoveInvalidTriangles( const INTVECTOR& vIds)
{
// al momento gestito solo per trimesh con adiacenze definite, eventualmente da estendere.
// Analoga a RemoveFistInvalidTrg in Triangulate.cpp
// TO DO da capire e gestire casi in cui flip lascia triangoli invalidi
unordered_map<int, bool> InvalidMap ;
for ( auto nId : vIds)
InvalidMap[nId] = true ;
for ( int i = 0 ; i < int( vIds.size()) ; i++) {
int nTA = vIds[i] ;
if ( ! InvalidMap[nTA])
continue ;
// recupero il triangolo adiacente sul suo lato più lungo
int nTB, nEdgeA ;
FindAdjacentOnLongerEdge( nTA, nEdgeA, nTB) ;
// se adiacente è nullo posso rimuovere tranquillamente il triangolo senza creare TJunctions
if ( nTB == SVT_NULL) {
RemoveTriangle( nTA) ;
continue ;
}
// se adiacente è valido posso fare il flip per rendere valido nTA
else if ( ! InvalidMap[nTB]) {
FlipTriangles( nTA, nTB) ;
InvalidMap[nTA] = false ;
}
// se adiacente è invalido creo una catena da risolvere non appena si trova un triangolo valido
else {
INTVECTOR vChain = {nTA} ;
INTVECTOR vChainEdges = {nEdgeA} ;
int nTCurr = nTB ;
while ( nTCurr != SVT_NULL && InvalidMap[nTCurr]) {
// calcolo il successivo
int nTOther, nEdgeCurr ;
FindAdjacentOnLongerEdge( nTCurr, nEdgeCurr, nTOther) ;
if ( nTOther == vChain.back()) {
// se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua
FlipTriangles( nTCurr, nTOther) ;
if ( vChain.size() > 1) {
vChain.pop_back() ;
vChainEdges.pop_back() ;
// individuo il nuovo adiacente all'ultimo triangolo della catena dopo aver fatto flip
nTOther = m_vTria[vChain.back()].nIdAdjac[vChainEdges.back()] ;
}
}
else {
vChain.emplace_back( nTCurr) ;
vChainEdges.emplace_back( nEdgeCurr) ;
}
// aggiorno per iterazione successiva
nTCurr = nTOther ;
}
// se la catena termina su triangolo nullo, posso rimuovere tutti i triangoli della catena
if ( nTCurr == SVT_NULL) {
for ( int k = 0 ; k < int( vChain.size()) ; k++) {
RemoveTriangle( vChain[k]) ;
InvalidMap[vChain[k]] = false ;
}
}
// se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido trovato
else {
FlipTriangles( vChain.back(), nTCurr) ;
InvalidMap[vChain.back()] = false ;
for ( int i = int( vChain.size()) - 2 ; i >= 0 ; i--) {
int nTA = vChain[i] ;
if ( ! InvalidMap[nTA])
continue ;
// eseguo il flip con il triangolo adiacente sul suo lato più lungo
int nTOther = m_vTria[nTA].nIdAdjac[vChainEdges[i]] ;
FlipTriangles( nTA, nTOther) ;
InvalidMap[nTA] = false ;
}
}
}
}
return true ;
}
+6 -6
View File
@@ -2101,7 +2101,7 @@ Tree::UpdateSplitLoop( ICurveComposite* pCC, Point3d& pt)
// potrei avere una compo vuota o con solo un punto
// se non riesco ad aggiungere una linea allora era una compo vuota
if ( ! pCC->GetOnlyPoint( ptLast)) {
pCC->FromPoint( pt) ;
pCC->AddPoint( pt) ;
ptLast = pt ;
}
else {
@@ -4139,7 +4139,7 @@ Tree::GetEdges3D( vector<ICRVCOMPOPOVECTOR>& mCCEdges, POLYLINEVECTOR& vPolygons
pt3d = ORIG ; GetPoint( cNeigh.GetBottomLeft().x, cNeigh.GetTopRight().y, pt3d) ;
mCCEdges.back().back()->AddLine( pt3d) ;
if ( ! mCCEdges.back().back()->IsValid())
mCCEdges.back().back()->FromPoint( pt3d) ;
mCCEdges.back().back()->AddPoint( pt3d) ;
}
else if ( i == 1 ) {
while ( ! AreSamePointXYApprox(pt, cNeigh.GetTopLeft()) && plCell.GetNextPoint( pt)) {
@@ -4155,7 +4155,7 @@ Tree::GetEdges3D( vector<ICRVCOMPOPOVECTOR>& mCCEdges, POLYLINEVECTOR& vPolygons
pt3d = ORIG ; GetPoint( cNeigh.GetBottomLeft().x, cNeigh.GetBottomLeft().y, pt3d) ;
mCCEdges.back().back()->AddLine( pt3d) ;
if ( ! mCCEdges.back().back()->IsValid())
mCCEdges.back().back()->FromPoint( pt3d) ;
mCCEdges.back().back()->AddPoint( pt3d) ;
}
else if ( i == 2) {
while ( ! AreSamePointXYApprox(pt, cNeigh.GetBottomLeft()) && plCell.GetNextPoint( pt)) {
@@ -4171,7 +4171,7 @@ Tree::GetEdges3D( vector<ICRVCOMPOPOVECTOR>& mCCEdges, POLYLINEVECTOR& vPolygons
pt3d = ORIG ; GetPoint( cNeigh.GetTopRight().x, cNeigh.GetBottomLeft().y, pt3d) ;
mCCEdges.back().back()->AddLine( pt3d) ;
if ( ! mCCEdges.back().back()->IsValid())
mCCEdges.back().back()->FromPoint( pt3d) ;
mCCEdges.back().back()->AddPoint( pt3d) ;
}
else if ( i == 3) {
while ( ! AreSamePointXYApprox(pt, cNeigh.GetBottomRight()) && plCell.GetNextPoint( pt)) {
@@ -4187,7 +4187,7 @@ Tree::GetEdges3D( vector<ICRVCOMPOPOVECTOR>& mCCEdges, POLYLINEVECTOR& vPolygons
pt3d = ORIG ; GetPoint( cNeigh.GetTopRight().x, cNeigh.GetTopRight().y, pt3d) ;
mCCEdges.back().back()->AddLine( pt3d) ;
if ( ! mCCEdges.back().back()->IsValid())
mCCEdges.back().back()->FromPoint( pt3d) ;
mCCEdges.back().back()->AddPoint( pt3d) ;
}
}
}
@@ -4212,7 +4212,7 @@ Tree::GetEdges3D( vector<ICRVCOMPOPOVECTOR>& mCCEdges, POLYLINEVECTOR& vPolygons
pCC3D->AddLine( pt3D) ;
}
if ( ! pCC3D->IsValid())
pCC3D->FromPoint( pt3D) ;
pCC3D->AddPoint( pt3D) ;
// qui devo fare dei controlli prima di aggiungere questa polyline?
mCCEdges[i].emplace_back( Release(pCC3D)) ;
}
+53 -34
View File
@@ -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)
@@ -1385,6 +1407,7 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
// I triangoli cap se eliminati danno origine a T-junctions, quindi devono essere gestiti opportunamente con dei flip.
// I triangoli needle se eliminati non sono problematici, ma i loro vertici coincidenti vanno gestiti opportunamente nel
// calcolo delle adiacenze dei triangoli cap.
// TO DO da capire e gestire casi in cui flip lascia triangoli invalidi
int nTria = int( vTr.size()) / 3 ;
INTVECTOR vCapTria ;
@@ -1482,46 +1505,40 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
INTVECTOR vChain, vChainEdges ;
vChain.emplace_back( nTA) ;
vChainEdges.emplace_back( nEA) ;
while ( nTB != -1 && ! vbIsValidTria[nTB]) {
// aggiungo alla catena
vChain.emplace_back( nTB) ;
int nTCurr = nTB ;
int nEOther ;
while ( nTCurr != -1 && ! vbIsValidTria[nTCurr]) {
// calcolo il successivo
nTA = nTB ;
FindAdjacentOnLongerEdge( vPt, vTr, nTA, nEA, nTB, nEB) ;
vChainEdges.emplace_back( nEA) ;
int nTOther, nECurr ;
FindAdjacentOnLongerEdge( vPt, vTr, nTCurr, nECurr, nTOther, nEOther) ;
// verifico di non aver trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// e quindi di non essere entrato in un loop
if ( nTB == vChain[vChain.size()-2]) {
if ( nTOther == vChain.back()) {
// se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua
FlipTrg( vTr, nTA, nTB, nEA, nEB) ;
// aggiorno per iterazione successiva
if ( vChain.size() == 2) {
FlipTrg( vTr, nTCurr, nTOther, nECurr, nEOther) ;
if ( vChain.size() > 1) {
vChain.pop_back() ;
vChainEdges.pop_back() ;
FindAdjacentOnLongerEdge( vPt, vTr, vChain.back(), nEA, nTB, nEB) ;
vChainEdges[0] = nEA ;
// individuo il nuovo adiacente all'ultimo triangolo della catena tra i due appena flippati
TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTCurr, nTOther, nTB, nEB) ;
nTOther = nTB ;
}
else {
// elimino gli ultimi due triangoli che sono appena stati flippati e ricalcolo adiacenza del triangolo
// precedente
vChain.pop_back() ;
vChain.pop_back() ;
vChainEdges.pop_back() ;
vChainEdges.pop_back() ;
int nTTest1 = nTA ;
int nTTest2 = nTB ;
TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTTest1, nTTest2, nTB, nEB) ;
}
}
else {
vChain.emplace_back( nTCurr) ;
vChainEdges.emplace_back( nECurr) ;
}
// aggiorno per iterazione successiva
nTCurr = nTOther ;
}
// se la catena termina su triangolo nullo, annullo tutti i triangoli della catena
if ( nTB == -1) {
if ( nTCurr == -1) {
bRemovedTrg = true ;
for ( int k = 0 ; k < int( vChain.size()) ; k++) {
if ( vbIsValidTria[vChain[k]])
continue ;
vTr[3*vChain[k]] = -1 ;
vTr[3*vChain[k] + 1] = -1 ;
vTr[3*vChain[k] + 2] = -1 ;
@@ -1530,14 +1547,16 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
}
// se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido
else {
FlipTrg( vTr, vChain.back(), nTB, vChainEdges.back(), nEB) ;
FlipTrg( vTr, vChain.back(), nTCurr, vChainEdges.back(), nEOther) ;
vbIsValidTria[vChain.back()] = true ;
int nTrgTest1 = vChain.back() ;
int nTrgTest2 = nTB ;
for ( int i = int( vChain.size()-2) ; i >= 0 ; i--) {
int nTrgTest2 = nTCurr ;
for ( int j = int( vChain.size()-2) ; j >= 0 ; j--) {
// triangolo corrente
int nTA = vChain[i] ;
int nEA = vChainEdges[i] ;
int nTA = vChain[j] ;
if ( vbIsValidTria[nTA])
continue ;
int nEA = vChainEdges[j] ;
// devo trovare il nuovo adiacente dopo il flip dei successivi nella catena
TestAdjacentOnEdge( vTr, nTA, nEA, nTrgTest1, nTrgTest2, nTB, nEB) ;
// flip per rendere valido il triangolo corrente
@@ -1608,7 +1627,7 @@ MakeByFist( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
vPt.reserve( fist.c_vertex.num_vertices) ;
for ( int i = 0 ; i < fist.c_vertex.num_vertices ; i ++)
vPt.emplace_back( fist.c_vertex.vertices[i].x, fist.c_vertex.vertices[i].y, fist.c_vertex.vertices[i].z) ;
// recupero i triangoli da fist
vTr.reserve( 3 * fist.c_vertex.num_triangles) ;
for ( int i = 0 ; i < fist.c_vertex.num_triangles ; i ++) {
+1
View File
@@ -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) ;
+103 -15
View File
@@ -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<future<bool>> 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<future<bool>> 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)) ;
}
}
+25 -10
View File
@@ -18,6 +18,7 @@
#include "Tool.h"
#include "/EgtDev/Include/EGkVolZmap.h"
#include "/EgtDev/Include/EGkIntersLineVolZmap.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include <unordered_map>
#include <stack>
#include <mutex>
@@ -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
@@ -93,7 +96,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
{ return m_nDexVoxRatio ; }
bool ChangeResolution( int nDexVoxRatio) override ;
void SetShowEdges( bool bShow) override
{ m_bShowEdges = bShow ; // qui è necessario far ricreare la grafica
{ m_bShowEdges = bShow ; // qui necessario far ricreare la grafica
m_OGrMgr.Clear() ; }
bool GetShowEdges( void) const override
{ return m_bShowEdges ; }
@@ -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
@@ -291,9 +295,9 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool Conus_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool Conus_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool Mrt_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ;
bool Mrt_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realtà un Perp
bool Mrt_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realt un Perp
bool Chs_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ;
bool Chs_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realtà un Perp
bool Chs_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realt un Perp
bool GenTool_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool GenTool_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
// lavorazioni a 5 assi
@@ -319,7 +323,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const Vector3d& vtArcNormMaxR, const Vector3d& vtArcNormMinR, int nToolNum) ;
bool CompPar_ZMilling( int nGrid, double dLenX, double dLenY, double dLenZ,
const Point3d& ptS, const Point3d& ptE,
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realtà MillingPerp
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realt MillingPerp
// Asse di simmetria con orientazione generica
bool CompCyl_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir,
double dHei, double dRad, bool bTapB, bool bTapT, int nToolNum) ;
@@ -335,7 +339,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const Vector3d& vtArcNormMaxR, const Vector3d& vtArcNormMinR, int nToolNum) ;
bool CompPar_Milling( int nGrid, double dLenX, double dLenY, double dLenZ,
const Point3d& ptS, const Point3d& ptE,
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realtà MillingPerp
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realt MillingPerp
// lavorazioni a 5 assi
bool Comp_5AxisMilling( int nGrid, const PNTVECTOR& ptS, const PNTVECTOR& ptE, const VCT3DVECTOR& vtLs, const VCT3DVECTOR& vtLe,
double dHeight, double dMaxRad, double dMinRad, int nToolNum) ;
@@ -450,6 +454,17 @@ 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) ;
public :
// ------------------------- ENUM ----------------------------------------------------------------
enum MillingPhase {
@@ -468,14 +483,14 @@ class VolZmap : public IVolZmap, public IGeoObjRW
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 ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
Status m_nStatus ; // stato
int m_nTempProp[2] ; // vettore proprietà temporanee
int m_nTempProp[2] ; // vettore propriet temporanee
double m_dTempParam[2] ; // vettore parametri temporanei
bool m_bShowEdges ; // flag di visualizzazione spigoli vivi
Frame3d m_MapFrame ; // riferimento intrinseco dello Zmap
@@ -509,8 +524,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW
mutable BOOLVECTOR m_BlockToUpdate ;
mutable INTVECTOR m_BlockUpdatingCounter ;
int m_nConnectedCompoCount ; // Se == - 1 il numero di componenti non è noto
// Se >= 0 è il numero di componenti connesse
int m_nConnectedCompoCount ; // Se == - 1 il numero di componenti non noto
// Se >= 0 il numero di componenti connesse
mutable std::vector<VoxelContainer> m_InterBlockVox ;
mutable SharpTriaMatrix m_InterBlockOriginalSharpTria ;
+114 -19
View File
@@ -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 <future>
@@ -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<bool>> 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)) ;
}
}
+31 -1
View File
@@ -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<SurfTriMesh> 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 ;
+300
View File
@@ -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 <future>
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<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i]))
return false ;
vpCrvs.emplace_back( Release( pCrvCompo)) ;
}
// recupero la TriMesh di estrusione
PtrOwner<ISurfTriMesh> 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 ;
}
+16 -1
View File
@@ -1999,13 +1999,28 @@ bool
VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, const Vector3d& vtAs,
const Point3d& ptPe, const Vector3d& vtDe, const Vector3d& vtAe)
{
// Calcolo angoli di rotazione utensile longitudinale e trasversale rispetto al movimento
// Deve essere definito l'utensile corrente
if ( m_nCurrTool < 0 || m_nCurrTool >= int( m_vTool.size()))
return false ;
// Calcolo angoli di rotazione utensile longitudinale e trasversale rispetto al movimento per eventuale suddivisione
double dAlongAngDeg, dAcrossAngDeg ;
GetAlongAcrossRotation( vtDs, vtDe, ptPe - ptPs, dAlongAngDeg, dAcrossAngDeg) ;
// Divido il movimento in tratti con direzione utensile costante
const double ANG_ACROSS_STEP = 1.0 ;
const double ANG_ALONG_STEP = 1.0 ;
int nStepCnt = int( max( { abs( dAlongAngDeg) / ANG_ALONG_STEP, abs( dAcrossAngDeg) / ANG_ACROSS_STEP, 1.})) ;
// Calcolo coefficiente di riduzione movimenti con direzione costante per evitare extra tagli
// !!! In attesa dell'algoritmo esatto !!!
double dToolLen = m_vTool[m_nCurrTool].GetHeigth() ;
double dToolCrad = m_vTool[m_nCurrTool].GetCornRadius() ;
Vector3d vtBase = ptPe - ptPs ;
double dBaseLen = vtBase.Len() ;
Vector3d vtTip = ptPe - dToolLen * vtDe - ( ptPs - dToolLen * vtDs) ;
double dTipLen = vtTip.Len() ;
double dK = ( vtBase * vtTip > EPS_SMALL ? dTipLen / dBaseLen : 0) ;
if ( dTipLen / nStepCnt < 0.1 * dToolCrad)
dK = 0 ;
// Divido il movimento in tratti con direzione utensile costante
bool bOk = true ;
//////// debug - vecchia modalità
+10 -9
View File
@@ -847,18 +847,19 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
//----------------------------------------------------------------------------
bool
Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids)
Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids,
bool bMergeOnlySameProps)
{
vCrvs.clear() ;
if ( ! IsValid())
return false ;
// se offset nullo errore
if ( abs( dOffs) < EPS_SMALL)
return false ;
ICRVCOMPOPLIST OffsList ;
// se offset nullo errore
if ( abs( dOffs) < EPS_SMALL)
return false ;
ICRVCOMPOPLIST OffsList ;
if ( ! CalcVroniOffset( OffsList, abs( dOffs)))
return false ;
@@ -873,7 +874,7 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo
// identifico i raccordi da modificare
if ( bClosed && bSquareMids) {
// se curva è chiusa tutti i raccordi rispondono a bSquareMids
IdentifyFillets( pCrvOffs, dOffs) ;
IdentifyFillets( pCrvOffs, dOffs) ;
}
else if ( ! bClosed && ( bSquareMids || bSquareEnds)) {
// se curva è aperta devo distinguere i raccordi interni da quelli relativi agli estremi e
@@ -889,9 +890,9 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo
}
// unisco le parti allineate
pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, bMergeOnlySameProps) ;
// aggiungo al vettore finale
vCrvs.emplace_back( pCrvOffs) ;
vCrvs.emplace_back( pCrvOffs) ;
}
// sistemo i raccordi
+1 -1
View File
@@ -57,7 +57,7 @@ class Voronoi
bool CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) ;
bool CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) ;
bool CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) ;
bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids) ;
bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps = true) ;
bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) ;
bool CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) ;