//---------------------------------------------------------------------------- // 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 sottrarre 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) { // 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) { // 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, int nTool) { // 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, nTool) ; else SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, nTool) ; } } } 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, int nTool) { // 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, nTool) ; else SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nTool) ; } } } return true ; } //---------------------------------------------------------------------------- // Funzione per inizializzare lo ZMap a partire da un vettore di superfici TriMesh // L'idea è quella di creare uno ZMap a partire dal Box complessivo delle superfici TriMesh : // - le superfici chiuse possono già inserire i rispettivi spilloni // - le superfici aperte non danno contributo //---------------------------------------------------------------------------- bool VolZmap::InitVolZMapOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) { // se non ho superfici, non faccio nulla if ( vSurf.empty()) return true ; // controllo delle superfici for ( const ISurfTriMesh* Surf : vSurf) { if ( Surf == nullptr) return false ; } // definisco la tolleranza di espansione del Box per la creazione dellop ZMap double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; // --- se una sola superficie if ( int( vSurf.size()) == 1) { // controllo la validità della superficie if ( ! vSurf[0]->IsValid() || vSurf[0]->GetTriangleCount() == 0) return true ; // --- se superficie chiusa posso direttamente creare lo Zmap iniziale if ( vSurf[0]->IsClosed()) { // definisco lo Zamp a partire dall'espansione del Box della superficie if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion)) return false ; } // --- se superficie aperta, lo creo inizialmente vuoto a partire dal suo Box BBox3d BBoxSurf ; vSurf[0]->GetLocalBBox( BBoxSurf) ; BBoxSurf.Expand( dBoxExpansion) ; if ( ! CreateEmpty( BBoxSurf.GetMin(), BBoxSurf.GetDimX(), BBoxSurf.GetDimY(), BBoxSurf.GetDimZ(), dTol, true)) return false ; } // --- se più superfici else { // calcolo il Box complessivo BBox3d BBoxGlob ; for ( const ISurfTriMesh* Surf : vSurf) { // controllo la validità della superficie if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; // calcolo il Box della superficie BBox3d BBoxSurf ; Surf->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 ; // aggiungo tutte le superfici chiuse for ( const ISurfTriMesh* Surf : vSurf) { if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0 || ! Surf->IsClosed()) continue ; if ( ! AddSurfTm( Surf)) return false ; } } return true ; } //---------------------------------------------------------------------------- // Funzione per inizializzare lo ZMap a partire da un vettore di superfici TriMesh // L'idea è quella di creare uno ZMap vuoto a partire dal Box complessivo delle superfici TriMesh //---------------------------------------------------------------------------- bool VolZmap::InitVolZMapThickeningOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) { // se non ho superfici, non faccio nulla if ( vSurf.empty()) return true ; // controllo delle superfici for ( const ISurfTriMesh* Surf : vSurf) { if ( Surf == nullptr) return false ; } // definisco la tolleranza di espansione del Box per la creazione dellop ZMap double dBoxExpansion = ( abs( dOffs) + 1.5 * dTol) + 10 * EPS_SMALL ; // calcolo il Box complessivo BBox3d BBoxGlob ; for ( const ISurfTriMesh* Surf : vSurf) { // controllo la validità della superficie if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; // calcolo il Box della superficie BBox3d BBoxSurf ; Surf->GetLocalBBox( BBoxSurf) ; // aggiungo il Box a quello complessivo BBoxGlob.Add( BBoxSurf) ; } // definisco uno Zmap vuoto a partire dal Box BBoxGlob.Expand( dBoxExpansion) ; return ( CreateEmpty( BBoxGlob.GetMin(), BBoxGlob.GetDimX(), BBoxGlob.GetDimY(), BBoxGlob.GetDimZ(), dTol, true)) ; } //---------------------------------------------------------------------------- // [Fillet] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente // mediante una superficie aperta //---------------------------------------------------------------------------- bool VolZmap::UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) { // da studiare... return false ; } //---------------------------------------------------------------------------- // [Fillet] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente // mediante una superficie chiusa //---------------------------------------------------------------------------- bool VolZmap::UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) { // controlli sulla superficie if ( Surf == nullptr || ! Surf->IsClosed()) return false ; if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) return true ; // 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 base 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()) ; // 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]) { if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid)) return false ; } if ( ! vbVert[nV2]) { if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid)) return false ; } } vbVert[nV1] = true ; vbVert[nV2] = true ; } // ----------------------- 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])) { // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } 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) { // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } return false ; } // aggiorno gli spilloni if ( dOffs > 0.) AddSurfTm( pStmExtr) ; else SubtractSurfTm( pStmExtr) ; // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } } return true ; } //---------------------------------------------------------------------------- // [Fillet Thickening] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente // mediante una superficie generica (aperta o chiusa) //---------------------------------------------------------------------------- bool VolZmap::UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) { // controlli sulla superficie if ( Surf == nullptr) return false ; if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) return true ; // non inizializzo lo Zmap, semplicemente lavoro con facce, spigoli e vertici // 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()) ; // 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) ; // 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, abs( dOffs), nGrid)) return false ; // aggiungo/sottraggo gli intervalli definiti dalla sfera if ( ! vbVert[nV1]) { if ( ! CreateOffsSphereOnVertex( ptP1, abs( dOffs), nGrid)) return false ; } if ( ! vbVert[nV2]) { if ( ! CreateOffsSphereOnVertex( ptP2, abs( dOffs), nGrid)) return false ; } } vbVert[nV1] = true ; vbVert[nV2] = true ; } // ----------------------- 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])) { // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } 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) { // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } return false ; } // aggiorno gli spilloni AddSurfTm( pStmExtr) ; // dealloco le curve for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { delete ( vpCrvs[i]) ; vpCrvs[i] = nullptr ; } } return true ; } //---------------------------------------------------------------------------- // Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da un // vettore di superfici TriMesh (aperte o chiuse). // Definizione : // - Lo Zmap di Offset ( positivo o negativo) di una superficie chiusa è automaticamente l'Offset stesso // - Lo Zmap di Offset ( positivo o negativo) di una superficie aperta è ????? ( da capire...) //---------------------------------------------------------------------------- bool VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType) { // 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 ; // inizializzo lo Zmap di Offset a partire dalle superfici if ( ! InitVolZMapOffs( vSurf, dOffs, dTol)) return false ; // scorro le superfici for ( const ISurfTriMesh* Surf : vSurf) { // se superficie non valida, passo alla successiva if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; // aggiorno lo ZMap if ( Surf->IsClosed()) { if ( nType == STMOFF_FILLET) { if ( ! UpdateVolZMapByClosedSurfFilletOffset( Surf, dOffs, dTol)) return false ; } } else { // --- LE SUPERFICI APERTE SONO PER ORA DISABILITATE --- } } m_nShape = OFFSET ; return true ; } //---------------------------------------------------------------------------- // Funzione per la creazine di uno Zmap di Fat Offset a partire da un // vettore di superfici TriMesh (aperte o chiuse). //---------------------------------------------------------------------------- bool VolZmap::CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType) { // 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 ; // inizializzo lo Zmap di Offset a partire dalle superfici if ( ! InitVolZMapThickeningOffs( vSurf, dOffs, dTol)) return false ; // scorro le superfici for ( const ISurfTriMesh* Surf : vSurf) { // se superficie non valida, passo alla successiva if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; // aggiorno lo Zmap if ( nType == STMOFF_FILLET) { if ( ! UpdateVolZMapBySurfThickeningFilletOffset( Surf, dOffs, dTol)) return false ; } } m_nShape = OFFSET ; return true ; }