From 6421c124088d42f541fe7ddc14359fb1ca19d7c4 Mon Sep 17 00:00:00 2001 From: SaraP Date: Tue, 17 Jun 2025 08:24:47 +0200 Subject: [PATCH 01/13] EgtGeomKernel : - piccola modifica. --- SurfTriMesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 0461250..acc41a5 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -234,12 +234,12 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag) m_vPart.clear() ; m_OGrMgr.Reset() ; ResetHashGrids3d() ; + if ( ! vtN.Normalize( EPS_ZERO)) + return SVT_DEL ; // 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) ; From 057b8273e215db5bed34b221159e049396e8a59a Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 19 Jun 2025 12:47:35 +0200 Subject: [PATCH 02/13] EgtGeomKernel : - in VolZmap::CreateFromTriMesh() corretta espansione per caso Box in attesa di correzione in marching Cubes. --- VolZmap.h | 2 +- VolZmapCreation.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/VolZmap.h b/VolZmap.h index e81bd23..559dc14 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -81,7 +81,7 @@ 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, double dExtraBox = 100 * EPS_SMALL) override ; + bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0.) override ; bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index fef6eae..f1a7a80 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -802,7 +802,8 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex // 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( dExtraBox) ; + if ( dExtraBox > EPS_ZERO) + SurfBBox.Expand( dExtraBox) ; // Determino i punti estremi del bounding box Point3d ptMapOrig, ptMapEnd ; @@ -920,7 +921,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex m_dMaxZ[2] = ( bTriDex ? vtLen.y : 0) ; // Tipologia - m_nShape = ( IsBox() ? BOX : GENERIC) ; + m_nShape = ( dExtraBox > EPS_ZERO && IsBox() ? BOX : GENERIC) ; // Aggiornamento dello stato m_nStatus = OK ; From f05c5f126136c88b68b2618fa73cabee70932f81 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 25 Jun 2025 15:51:19 +0200 Subject: [PATCH 03/13] EgtGeomKernel : - aggiunte funzioni per Offset e FatOffset per un insieme di curve - in VolZmapOffset migliorata la gestione delle normali per l'addizione di intervalli. --- CurveAux.cpp | 45 +++++ VolZmapOffset.cpp | 406 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 445 insertions(+), 6 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index a47fb8e..78f5258 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -2087,6 +2087,51 @@ CalcCurveSingleCurvesOffset( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double d return pVoronoiObj->CalcSingleCurvesOffset( vCrvs, dOffs) ; } +//---------------------------------------------------------------------------- +bool CalcOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs, int nType) +{ + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vpCrvs[i])) + return false ; + } + + return pVoronoiObj->CalcOffset( vCrvs, dOffs, nType) ; +} + +//---------------------------------------------------------------------------- +bool CalcFatOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs, + bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps) +{ + // controllo validità delle curve + for ( auto& pCrv : vpCrvs) { + if ( pCrv == nullptr) + return false ; + } + // se offset nullo restituisco direttamente le curve + if ( abs( dOffs) < EPS_SMALL) { + for ( auto& pCrv : vpCrvs) { + if ( ! vCrvs.emplace_back( pCrv->Clone())) + return false ; + } + return true ; + } + + // creo oggetto Voronoi con le curve passate + PtrOwner pVoronoiObj( new( std::nothrow) Voronoi()) ; + if ( pVoronoiObj == nullptr) + return false ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) { + if ( ! pVoronoiObj->AddCurve( vpCrvs[i])) + return false ; + } + + return pVoronoiObj->CalcFatCurve( vCrvs, dOffs, bSquareEnds, bSquareMids, bMergeOnlySameProps) ; +} + //---------------------------------------------------------------------------- void ResetCurveVoronoi( const ICurve& crvC) diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp index 1812b0a..fcee7a8 100644 --- a/VolZmapOffset.cpp +++ b/VolZmapOffset.cpp @@ -43,9 +43,393 @@ 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) ; + // Controllo che il numero di griglia sia entro i limiti + if ( nGrid < 0 || nGrid > 2) + return false ; + + // Controllo che indici nI, nJ siano entro i limiti + if ( nI < 0 && nI >= m_nNx[nGrid] && + nJ < 0 && nJ >= m_nNy[nGrid]) + return false ; + + // Controllo che dMin < dMax + Vector3d vtNmi = vtNMin ; + Vector3d vtNma = vtNMax ; + if ( dMin > dMax) { + swap( dMin, dMax) ; + swap( vtNmi, vtNma) ; + } + + // Restringo minimo e massimo entro i limiti della mappa + if ( dMin < m_dMinZ[nGrid]) { + dMin = m_dMinZ[nGrid] ; + if ( ! bSkipSwap) + vtNmi = - Z_AX ; + } + else if ( dMin > m_dMaxZ[nGrid]) { + dMin = m_dMaxZ[nGrid] ; + if ( ! bSkipSwap) + vtNmi = - Z_AX ; + } + if ( dMax < m_dMinZ[nGrid]) { + dMax = m_dMinZ[nGrid] ; + if ( ! bSkipSwap) + vtNma = Z_AX ; + } + else if ( dMax > m_dMaxZ[nGrid]) { + dMax = m_dMaxZ[nGrid] ; + if ( ! bSkipSwap) + vtNma = Z_AX ; + } + + // Controllo che dMin e dMax non siano quasi coincidenti + if ( abs( dMax - dMin) < EPS_SMALL) + return true ; + + // Riporto le coordinate cicliche nell'ordine di partenza + if ( !bSkipSwap && nGrid == 1) { + swap( vtNmi.x, vtNmi.z) ; + swap( vtNmi.y, vtNmi.z) ; + swap( vtNma.x, vtNma.z) ; + swap( vtNma.y, vtNma.z) ; + } + else if ( !bSkipSwap && nGrid == 2) { + swap( vtNmi.y, vtNmi.z) ; + swap( vtNmi.x, vtNmi.z) ; + swap( vtNma.y, vtNma.z) ; + swap( vtNma.x, vtNma.z) ; + } + + // Calcolo nPos + int nPos = nJ * m_nNx[nGrid] + nI ; + vector& vDexel = m_Values[nGrid][nPos] ; + + bool bModified = false ; + + // Non esistono segmenti + if ( vDexel.empty()) { + vDexel.emplace_back() ; + vDexel.back().dMin = dMin ; + vDexel.back().vtMinN = vtNmi ; + vDexel.back().nToolMin = nToolNum ; + vDexel.back().dMax = dMax ; + vDexel.back().vtMaxN = vtNma ; + vDexel.back().nToolMax = nToolNum ; + m_OGrMgr.Reset() ; + bModified = true ; + } + // Esiste almeno un segmento + else { + // Cerco l'ultimo intervallo a sinistra e l'ultimo intervallo a destra + // di quello da aggiungere, che non interferiscono strettamente con quest'ultimo. + auto itLastLeft = vDexel.end() ; + auto itFirstRight = vDexel.end() ; + for ( auto it = vDexel.begin() ; it != vDexel.end() ; ++ it) { + if ( dMin > it->dMax + EPS_SMALL) + itLastLeft = it ; + if ( dMax < it->dMin - EPS_SMALL && itFirstRight == vDexel.end()) + itFirstRight = it ; + } + // Esistono intervalli a sinistra. + if ( itLastLeft != vDexel.end()) { + // Intervallo successivo all'ultimo a sinistra + auto itNextToLastLeft = itLastLeft ; + ++ itNextToLastLeft ; + // Il successivo non esiste. + if ( itNextToLastLeft == vDexel.end()) { + // Aggiungo il nuovo semgento + vDexel.emplace_back() ; + vDexel.back().dMin = dMin ; + vDexel.back().dMax = dMax ; + vDexel.back().vtMinN = vtNmi ; + vDexel.back().vtMaxN = vtNma ; + vDexel.back().nToolMin = nToolNum ; + vDexel.back().nToolMax = nToolNum ; + bModified = true ; + } + // Il successivo esiste. + else { + // Il successivo è il primo a destra. + if ( itNextToLastLeft == itFirstRight) { + // Inserisco nuovo segmento + Data NewSegment ; + NewSegment.dMin = dMin ; + NewSegment.dMax = dMax ; + NewSegment.vtMinN = vtNmi ; + NewSegment.vtMaxN = vtNma ; + NewSegment.nToolMin = nToolNum ; + NewSegment.nToolMax = nToolNum ; + vDexel.insert( itFirstRight, NewSegment) ; + bModified = true ; + } + else { + // Il successivo non esce a sinistra da quello da aggiungere. + if ( itNextToLastLeft->dMin > dMin + EPS_SMALL) { + itNextToLastLeft->dMin = dMin ; + itNextToLastLeft->vtMinN = vtNmi ; + itNextToLastLeft->nToolMin = nToolNum ; + } + // il minimo del successivo coincide con quello da aggiungere + else if ( abs( itNextToLastLeft->dMin - dMin) < EPS_SMALL) { + // Media tra le normali + itNextToLastLeft->vtMinN += vtNmi ; + itNextToLastLeft->vtMinN.Normalize() ; + } + // Cerco l'ultimo segmento che interferisce con quello da aggiungere. + auto itPrevToFirstRight = vDexel.end() ; + for ( auto it = itNextToLastLeft ; it != itFirstRight ; ++ it) { + itPrevToFirstRight = it ; + } + // L'ultimo che interferisce non esce a destra da quello da aggiungere. + if ( itPrevToFirstRight->dMax < dMax - EPS_SMALL) { + itNextToLastLeft->dMax = dMax ; + itNextToLastLeft->vtMaxN = vtNma ; + itNextToLastLeft->nToolMax = nToolNum ; + } + // Il massimo dell'ultimo che interferisce coincide con quello da aggiungere. + else if ( abs( itPrevToFirstRight->dMax - dMax) < EPS_SMALL) { + // Media tra le normali + itNextToLastLeft->vtMaxN = ( vtNma + itPrevToFirstRight->vtMaxN) ; + itNextToLastLeft->vtMaxN.Normalize() ; + } + else { + itNextToLastLeft->dMax = itPrevToFirstRight->dMax ; + itNextToLastLeft->vtMaxN = itPrevToFirstRight->vtMaxN ; + itNextToLastLeft->nToolMax = nToolNum ; + } + bModified = true ; + auto itFirstToCancel = itNextToLastLeft ; + ++ itFirstToCancel ; + vDexel.erase( itFirstToCancel, itFirstRight) ; + } + } + } + // Non esistono neanche a destra. + else if ( itFirstRight == m_Values[nGrid][nPos].end()) { + // Il primo intervallo non sporge STRETTAMENTE a sinistra + if ( vDexel.begin()->dMin > dMin + EPS_SMALL) { + vDexel.begin()->dMin = dMin ; + vDexel.begin()->vtMinN = vtNmi ; + vDexel.begin()->nToolMin = nToolNum ; + } + // Il minimo del primo intervallo coincide con il minimo di quello corrente + else if ( abs( vDexel.begin()->dMin - dMin) < EPS_SMALL) { + // Media tra le normali + vDexel.begin()->vtMinN += vtNmi ; + vDexel.begin()->vtMinN.Normalize() ; + } + // L'ultimo intervallo sporge a destra. + if ( vDexel.back().dMax > dMax + EPS_SMALL) { + // Ci sono più segmenti, inglobo tutti nel primo. + if ( vDexel.back().dMax > vDexel.begin()->dMax + EPS_SMALL) { + vDexel.begin()->dMax = vDexel.back().dMax ; + vDexel.begin()->vtMaxN = vDexel.back().vtMaxN ; + vDexel.begin()->nToolMax = nToolNum ; + } + } + // Il massimo dell'ultimo intervallo coincide con il massimo del corrente + else if ( abs( vDexel.back().dMax - dMax) < EPS_SMALL) { + // Ci sono più segmenti, inglobo tutti nel primo e medio le normali del massimo + if ( vDexel.back().dMax > vDexel.begin()->dMax + EPS_SMALL) { + vDexel.begin()->dMax = vDexel.back().dMax ; + vDexel.begin()->vtMaxN = vDexel.back().vtMaxN + vtNma ; + vDexel.begin()->vtMaxN.Normalize() ; + vDexel.begin()->nToolMax = nToolNum ; + } + // Se singolo segmento + else { + // Media delle normali + vDexel.begin()->vtMaxN += vtNma ; + vDexel.begin()->vtMaxN.Normalize() ; + } + } + // L'ultimo intervallo non sporge a destra. + else { + vDexel.begin()->dMax = dMax ; + vDexel.begin()->vtMaxN = vtNma ; + vDexel.begin()->nToolMax = nToolNum ; + } + bModified = true ; + vDexel.erase( vDexel.begin() + 1, vDexel.end()) ; + } + // A destra esistono. + else { + // Tutti i segmenti sono a destra di qullo da aggiungere. + if ( itFirstRight == vDexel.begin()) { + // Inserisco nuovo segmento + Data NewSegment ; + NewSegment.dMin = dMin ; + NewSegment.dMax = dMax ; + NewSegment.vtMinN = vtNmi ; + NewSegment.vtMaxN = vtNma ; + NewSegment.nToolMin = nToolNum ; + NewSegment.nToolMax = nToolNum ; + vDexel.insert( vDexel.begin(), NewSegment) ; + bModified = true ; + } + else { + // Se il primo segmento non esce strettamente a sinistra da quello da aggiungere, cambio l'inizio. + if ( vDexel.begin()->dMin > dMin + EPS_SMALL) { + vDexel.begin()->dMin = dMin ; + vDexel.begin()->vtMinN = vtNmi ; + vDexel.begin()->nToolMin = nToolNum ; + bModified = true ; + } + // Se il minimo del segmento a sinistra coicide con il minimo del corrente + else if ( abs( vDexel.begin()->dMin - dMin) < EPS_SMALL) { + // Media delle normali + vDexel.begin()->vtMinN += vtNmi ; + vDexel.begin()->vtMinN.Normalize() ; + } + // Cerco l'ultimo segmento che interferisce con quello da aggiungere. + auto itPrevToFirstRight = vDexel.begin() ; + for ( auto it = m_Values[nGrid][nPos].begin() ; it != itFirstRight ; ++ it) { + itPrevToFirstRight = it ; + } + // L'ultimo che interferisce non esce strettamente a destra da quello da aggiungere. + if ( itPrevToFirstRight->dMax < dMax - EPS_SMALL) { + vDexel.begin()->dMax = dMax ; + vDexel.begin()->vtMaxN = vtNma ; + vDexel.begin()->nToolMax = nToolNum ; + bModified = true ; + } + // Il massimo dell'ultimo segmento coincide con il massimo corrente + else if ( abs( itPrevToFirstRight->dMax - dMax) < EPS_SMALL) { + vDexel.begin()->vtMaxN = itPrevToFirstRight->vtMaxN + vtNma ; + vDexel.begin()->vtMaxN.Normalize() ; + } + else { + vDexel.begin()->dMax = itPrevToFirstRight->dMax ; + vDexel.begin()->vtMaxN = itPrevToFirstRight->vtMaxN ; + vDexel.begin()->nToolMax = nToolNum ; + bModified = true ; + } + auto itFirstToCancel = vDexel.begin() ; + ++ itFirstToCancel ; + vDexel.erase( itFirstToCancel, itFirstRight) ; + } + } + } + + // Se nessuna modifica, esco + if ( ! bModified) + return true ; + + // Imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + // Imposto forma generica + m_nShape = GENERIC ; + // Imposto ricalcolo numero di componenti connesse + m_nConnectedCompoCount = - 1 ; + + // Passo da indici di dexel a indici di voxel + nI /= m_nDexVoxRatio ; + nJ /= m_nDexVoxRatio ; + + // Determino quali blocchi sono stati modificati + if ( nGrid == 0) { + // Voxel lungo X + int nXStop = 1 ; + int nXBlock[2] ; + nXBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; + if ( nI % N_VOXBLOCK == 0 && nXBlock[0] > 0) { + nXBlock[1] = nXBlock[0] - 1 ; + ++ nXStop ; + } + // Voxel lungo Y + int nYStop = 1 ; + int nYBlock[2] ; + nYBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; + if ( nJ % N_VOXBLOCK == 0 && nYBlock[0] > 0) { + nYBlock[1] = nYBlock[0] - 1 ; + ++ nYStop ; + } + // Voxel lungo Z + int nVoxNumZ = int( m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2)) ; + int nMinK = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumZ - 2) ; + int nMaxK = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumZ - 2) ; + int nMinZBlock = ( m_nMapNum == 1 ? 0 : Clamp( nMinK / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[2] - 1))) ; + int nMaxZBlock = min( int( m_nFracLin[2] - 1), nMaxK / int( m_nVoxNumPerBlock)) ; + // Assegno flag ai voxel + for ( int tI = 0 ; tI < nXStop ; ++ tI) { + for ( int tJ = 0 ; tJ < nYStop ; ++ tJ) { + for ( int k = nMinZBlock ; k <= nMaxZBlock ; ++ k) { + int nBlockNum = k * m_nFracLin[0] * m_nFracLin[1] + nYBlock[tJ] * m_nFracLin[0] + nXBlock[tI] ; + m_BlockToUpdate[nBlockNum] = true ; + } + } + } + } + + else if ( nGrid == 1) { + // Voxel lungo Y + int nYStop = 1 ; + int nYBlock[2] ; + nYBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; + if ( nI % N_VOXBLOCK == 0 && nYBlock[0] > 0) { + nYBlock[1] = nYBlock[0] - 1 ; + ++ nYStop ; + } + // Voxel lungo Z + int nZStop = 1 ; + int nZBlock[2] ; + nZBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; + if ( nJ % N_VOXBLOCK == 0 && nZBlock[0] > 0) { + nZBlock[1] = nZBlock[0] - 1 ; + ++ nZStop ; + } + // Voxel lungo X + int nVoxNumX = int( m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; + int nMinI = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumX - 2) ; + int nMaxI = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumX - 2) ; + int nMinXBlock = Clamp( nMinI / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[0] - 1)) ; + int nMaxXBlock = min( int( m_nFracLin[0] - 1), nMaxI / int( m_nVoxNumPerBlock)) ; + // Assegno flag ai voxel + for ( int tI = 0 ; tI < nYStop ; ++ tI) { + for ( int tJ = 0 ; tJ < nZStop ; ++ tJ) { + for ( int k = nMinXBlock ; k <= nMaxXBlock ; ++ k) { + int nBlockNum = nZBlock[tJ] * m_nFracLin[0] * m_nFracLin[1] + nYBlock[tI] * m_nFracLin[0] + k ; + m_BlockToUpdate[nBlockNum] = true ; + } + } + } + } + + else if ( nGrid == 2) { + // Voxel lungo X + int nXStop = 1 ; + int nXBlock[2] ; + nXBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; + if ( nJ % N_VOXBLOCK == 0 && nXBlock[0] > 0) { + nXBlock[1] = nXBlock[0] - 1 ; + ++ nXStop ; + } + // Voxel lungo Z + int nZStop = 1 ; + int nZBlock[2] ; + nZBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; + if ( nI % N_VOXBLOCK == 0 && nZBlock[0] > 0) { + nZBlock[1] = nZBlock[0] - 1 ; + ++ nZStop ; + } + // Voxel lungo Y + int nVoxNumY = int( m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; + int nMinJ = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumY - 2) ; + int nMaxJ = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumY - 2) ; + int nMinYBlock = Clamp( nMinJ / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[1] - 1)) ; + int nMaxYBlock = min( int( m_nFracLin[1] - 1), nMaxJ / int( m_nVoxNumPerBlock)) ; + // Assegno flag ai voxel + for ( int tI = 0 ; tI < nZStop ; ++ tI) { + for ( int tJ = 0 ; tJ < nXStop ; ++ tJ) { + for ( int k = nMinYBlock ; k <= nMaxYBlock ; ++ k) { + int nBlockNum = nZBlock[tI] * m_nFracLin[0] * m_nFracLin[1] + k * m_nFracLin[0] + nXBlock[tJ] ; + m_BlockToUpdate[nBlockNum] = true ; + } + } + } + } + + return true ; } //---------------------------------------------------------------------------- @@ -220,7 +604,6 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do 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 @@ -282,16 +665,27 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do } // recupero la TriMesh di estrusione PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrvs, 2 * abs( dOffs) * vtN)) ; - if ( IsNull( pStmExtr) || ! pStmExtr->IsValid() || pStmExtr->GetTriangleCount() == 0) + 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 ; + } } } - m_nShape = OFFSET ; // OFFSET (?) ... per ora va bene così + m_nShape = OFFSET ; return true ; } From 53e66032a0968473af4be3477751600ea224c7e0 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 2 Jul 2025 11:44:10 +0200 Subject: [PATCH 04/13] EgtGeomKernel 2.7g1 : - migliorata e corretta la classe di calcolo delle Silhouette (l'Offset viene eseguito su tutte le curve e non singolarmente e l'estensione XY del Box locale tiene conto del raggio utensile per utensili non standard) - in SurfTriMesh aggiunte le funzioni per il calcolo dei Box delle Parts - in Offset delle superfici, ripristinata la funzione di somma di intervalli senza media delle normali e rimozione di memoryLeaks. --- CAvSilhouetteSurfTm.cpp | 261 +++++++++++++++----------- EgtGeomKernel.rc | Bin 11710 -> 11710 bytes SurfTriMesh.cpp | 50 +++++ SurfTriMesh.h | 2 + VolZmapOffset.cpp | 398 +--------------------------------------- 5 files changed, 213 insertions(+), 498 deletions(-) diff --git a/CAvSilhouetteSurfTm.cpp b/CAvSilhouetteSurfTm.cpp index 7869a39..fa7f19c 100644 --- a/CAvSilhouetteSurfTm.cpp +++ b/CAvSilhouetteSurfTm.cpp @@ -311,7 +311,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int const Frame3d& frGrid, double dDimZ, double dLevel, double dStep, double dAngTol, bool bAdvCorners) { - // se non ho polylinee, allora esco if ( vPL.empty()) return true ; @@ -341,10 +340,45 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int if ( ! CalcRegionPolyLines( vPL, vtN, mIndMat, vbInv)) return false ; + #if ENABLE_SHARPED_EDGES_DEBUG + vector> vvpGObj ; vvpGObj.resize( 7) ; + vector> vvCol ; vvCol.resize( 7) ; + // ombra del tool + PtrOwner pCrvToolShape( CreateCurveArc()) ; + pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ; + // 1° gruppo, griglia di punti + for ( int j = 0 ; j <= nStepY ; ++ j) { + for ( int i = 0 ; i <= nStepX ; ++ i) { + Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ; + PtrOwner myPtGrid( CreateGeoPoint3d()) ; + myPtGrid->Set( ptP) ; + vvpGObj[0].emplace_back( static_cast( Release( myPtGrid))) ; + vvCol[0].emplace_back( BLUE) ; + } + } + // 2° gruppo, superfici + CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ; + for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) { + PtrOwner pMyStm( CloneSurfTriMesh( myStmVector[i])) ; + if ( ! IsNull( pMyStm)) { + pMyStm->ToLoc( frGrid) ; + vvpGObj[1].emplace_back( static_cast( Release( pMyStm))) ; + vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ; + } + } + #endif + + // vettore delle polyline visitate ( viste però come curve composite) + ICRVCOMPOPOVECTOR vPL_AsCompo ; vPL_AsCompo.reserve( vPL.size()) ; + // scorro i Chunk della matrice di interi, quindi le righe for ( int nChunk = 0 ; nChunk < int( mIndMat.size()) ; ++ nChunk) { // scorro le PolyLinee presenti nel Chunk - for ( int nPol = 0 ; nPol < int( vPL.size()) ; ++ nPol) { + for ( int nLoop = 0 ; nLoop < int( mIndMat[nChunk].size()) ; ++ nLoop) { + // recupero l'indice della PolyLine di riferimento + int nPol = mIndMat[nChunk][nLoop] ; + if ( nPol < 0 || nPol >= int( vPL.size())) + return false ; // essendo chiusa, se presenti meno di 4 punti, non faccio nulla int nPts = vPL[nPol].GetPointNbr() ; if ( nPts < 4) @@ -380,33 +414,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int vAdvPt.emplace_back( make_pair( myPt, PointType::VALID)) ; #if ENABLE_SHARPED_EDGES_DEBUG - vector> vvpGObj ; vvpGObj.resize( 7) ; - vector> vvCol ; vvCol.resize( 7) ; - // ombra del tool - PtrOwner pCrvToolShape( CreateCurveArc()) ; - pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ; - // 1° gruppo, griglia di punti - for ( int j = 0 ; j <= nStepY ; ++ j) { - for ( int i = 0 ; i <= nStepX ; ++ i) { - Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ; - PtrOwner myPtGrid( CreateGeoPoint3d()) ; - myPtGrid->Set( ptP) ; - vvpGObj[0].emplace_back( static_cast( Release( myPtGrid))) ; - vvCol[0].emplace_back( BLUE) ; - break ; - } - break ; - } - // 2° gruppo, superfici - CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ; - for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) { - PtrOwner pMyStm( CloneSurfTriMesh( myStmVector[i])) ; - if ( ! IsNull( pMyStm)) { - pMyStm->ToLoc( frGrid) ; - vvpGObj[1].emplace_back( static_cast( Release( pMyStm))) ; - vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ; - } - } // 3° gruppo, punti della PolyLine for ( int i = 0 ; i < int( vAdvPt.size()) ; ++ i) { PtrOwner myPt( CreateGeoPoint3d()) ; @@ -416,23 +423,23 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int } #endif - // modifico la posizione dei punti - if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen)) - return false ; + // modifico la posizione dei punti + if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen)) + return false ; - // ricostrusico la polyLine - vPL[nPol].Clear() ; + // ricostrusico la polyLine a partire da una vuota + PolyLine PL_New ; double dPar = -1 ; for ( int j = 0 ; j < int( vAdvPt.size()) ; ++ j) { // se punto valido o sharped di angolo interno, lo aggiungo if ( j == 0 || j == int( vAdvPt.size() - 1) || vAdvPt[j].second == PointType::VALID || vAdvPt[j].second == PointType::SHARPED_INT) - vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ; + PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ; // se è un punto sharped di un angolo esterno else if ( vAdvPt[j].second == PointType::SHARPED_EXT) { // se non richiesto il calcolo avanzato del punto a minima distanza dallo spigolo, aggiungo il punto if ( ! bAdvCorners) - vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ; + PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ; else { // ricavo il punto a minima distanza dal materiale mediante metodo di bisezione Vector3d vtPrev = ( vAdvPt[j-1].first - vAdvPt[j].first) ; @@ -463,51 +470,29 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int DistPointLine distPtLSucc( ptTest, vAdvPt[j].first, vAdvPt[j+1].first) ; distPtLPrev.GetMinDistPoint( ptMinDistA) ; distPtLSucc.GetMinDistPoint( ptMinDistB) ; - vPL[nPol].AddUPoint( ++ dPar, ptMinDistA) ; - vPL[nPol].AddUPoint( ++ dPar, ptTest) ; - vPL[nPol].AddUPoint( ++ dPar, ptMinDistB) ; - } + PL_New.AddUPoint( ++ dPar, ptMinDistA) ; + PL_New.AddUPoint( ++ dPar, ptTest) ; + PL_New.AddUPoint( ++ dPar, ptMinDistB) ; - #if ENABLE_SHARPED_EDGES_DEBUG - // 5° gruppo, punti minDist A e B e ptMid - /*PtrOwner myPtA( CreateGeoPoint3d()) ; - myPtA->Set( ptMinDistA) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtA))) ; - vvCol[4].emplace_back( BROWN) ; - PtrOwner myPtB( CreateGeoPoint3d()) ; - myPtB->Set( ptMinDistB) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtB))) ; - vvCol[4].emplace_back( BROWN) ; - PtrOwner myPtMid( CreateGeoPoint3d()) ; - myPtMid->Set( ptTest) ; - vvpGObj[4].emplace_back( static_cast( Release( myPtMid))) ; - vvCol[4].emplace_back( BROWN) ;*/ - #endif + #if ENABLE_SHARPED_EDGES_DEBUG + // 5° gruppo, punti minDist A e B e ptMid + PtrOwner myPtA( CreateGeoPoint3d()) ; + myPtA->Set( ptMinDistA) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtA))) ; + vvCol[4].emplace_back( BROWN) ; + PtrOwner myPtB( CreateGeoPoint3d()) ; + myPtB->Set( ptMinDistB) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtB))) ; + vvCol[4].emplace_back( BROWN) ; + PtrOwner myPtMid( CreateGeoPoint3d()) ; + myPtMid->Set( ptTest) ; + vvpGObj[4].emplace_back( static_cast( Release( myPtMid))) ; + vvCol[4].emplace_back( BROWN) ; + #endif + } } } - // riposiziono la polyLine - #if ENABLE_SHARPED_EDGES_DEBUG - // 6° gruppo, curve composita derivante dalla polyline - PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; - pCrvCompoPoly->FromPolyLine( vPL[nPol]) ; - //pCrvCompoPoly->SetExtrusion( frGrid.VersZ()) ; - vvpGObj[5].emplace_back( static_cast( CloneCurveComposite( pCrvCompoPoly))) ; - vvCol[5].emplace_back( RED) ; - // 7° gruppo, controOffset - OffsetCurve offsCrv ; - offsCrv.Make( pCrvCompoPoly, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ; - pCrvCompoPoly.Set( ConvertCurveToComposite( offsCrv.GetLongerCurve())) ; - vvpGObj[6].emplace_back( static_cast( Release( pCrvCompoPoly))) ; - vvCol[6].emplace_back( WHITE) ; - string myName = Sharped_Edges_Debug_File_Name + - to_string( nChunk) + "_" + - to_string( nPol) + "_" + - to_string( dLevel) + "_" + - to_string( dAngTol) + ".nge" ; - SaveGeoObj( vvpGObj, vvCol, myName) ; - #endif - // se la polyLinea si autointerseca, allora non la modifico ( essendo a distanza R dalla // trimesh rischio di evere Chunk distinti uniti in un unico Chunk PtrOwner pCompo( CreateCurveComposite()) ; @@ -515,11 +500,53 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int return false ; pCompo->FromPolyLine( vPL[nPol]) ; SelfIntersCurve SIC( *pCompo) ; - if ( SIC.GetCrossOrOverlapIntersCount() > 0) - continue ; + bool bDiscard = ( SIC.GetCrossOrOverlapIntersCount() > 0) ; + if ( ! bDiscard) { + // se la polyLine interseca una delle PolyLine precedenti, non la modifico + for ( auto& pCompoPL_Prev : vPL_AsCompo) { + IntersCurveCurve ICC( *pCompo, *pCompoPL_Prev) ; + if ( ICC.GetCrossOrOverlapIntersCount() > 0) { + bDiscard = true ; + break ; + } + } + } + + // se nuova approssimazione da conservare, memorizzo i risultati + if ( ! bDiscard) { + vPL[nPol] = PL_New ; + vPL_AsCompo.emplace_back( Release( pCompo)) ; + } } } + #if ENABLE_SHARPED_EDGES_DEBUG + ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ; + for ( const auto& PL : vPL) { + // 6° gruppo, curve composita derivante dalla polyline + PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; + pCrvCompoPoly->FromPolyLine( PL) ; + vvpGObj[5].emplace_back( static_cast( CloneCurveComposite( pCrvCompoPoly))) ; + vvCol[5].emplace_back( RED) ; + vpCrv.emplace_back( Release( pCrvCompoPoly)) ; + } + // 7° gruppo, controOffset + ICURVEPOVECTOR vCrvCompoOffs ; + if ( ! CalcOffsetCurves( vpCrv, vCrvCompoOffs, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND)) { + for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;} + return false ; + } + for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;} + for ( const auto& pCvrOffs : vCrvCompoOffs) { + vvpGObj[6].emplace_back( static_cast( CloneCurveComposite( pCvrOffs))) ; + vvCol[6].emplace_back( WHITE) ; + } + string myName = Sharped_Edges_Debug_File_Name + + to_string( dLevel) + "_" + + to_string( dAngTol) + ".nge" ; + SaveGeoObj( vvpGObj, vvCol, myName) ; + #endif + return true ; } @@ -785,21 +812,31 @@ MarchingSquares( const DBLVECTOR& vdGrid, int nStepX, int nStepY, double dStep, if ( TestEdgesClosedPolyLines( vPL_Sharped, cavTstm, nStepX, nStepY, frGrid, dDimZ, dLevel, dStep, ANG_TOL_STD_DEG, false)) swap( vPL_Sharped, vPL) ; + // se vettore di PolyLine vuoto, non faccio nulla + if ( vPL.empty()) + return true ; + // se non ho impostato un utensile, devo effettuare un contro-offset if ( ! bTool) { - POLYLINEVECTOR vPL_Offs ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - CurveComposite crvCompo ; - if ( ! crvCompo.FromPolyLine( vPL[i])) - return false ; - OffsetCurve offsCompo ; - offsCompo.Make( &crvCompo, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ; - PtrOwner pCrvOffset( offsCompo.GetLongerCurve()) ; - while ( ! IsNull( pCrvOffset)) { + ICURVEPOVECTOR vpOwCrv ; vpOwCrv.reserve( vPL.size()) ; + ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ; + for ( const auto& PL : vPL) { + PtrOwner pCrvCompoPoly( CreateCurveComposite()) ; + pCrvCompoPoly->FromPolyLine( PL) ; + vpOwCrv.emplace_back( Release( pCrvCompoPoly)) ; + vpCrv.emplace_back( vpOwCrv.back()) ; + } + // calcolo l'Offset + ICURVEPOVECTOR vpCrvOffs ; + if ( ! CalcOffsetCurves( vpCrv, vpCrvOffs, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND)) + return false ; + // resituisco le PolyLine + POLYLINEVECTOR vPL_Offs ; vPL_Offs.reserve( vpCrvOffs.size()) ; + for ( auto& pCrv : vpCrvOffs) { + if ( pCrv != nullptr && pCrv->IsValid()) { PolyLine myPolyLine ; - pCrvOffset->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ; + pCrv->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ; vPL_Offs.emplace_back( myPolyLine) ; - pCrvOffset.Set( offsCompo.GetLongerCurve()) ; } } swap( vPL_Offs, vPL) ; @@ -976,28 +1013,13 @@ CAvParSilhouettesSurfTm::Prepare( void) return false ; b3All.Add( b3Surf) ; } - - // calcolo dati della griglia - const double EXTRA_XY = ( m_bTool ? m_dRad + 2 : 1.5 * m_dTol) ; + // espansione in Z del Box const double EXTRA_Z = 10 * m_dTol + ( m_dMaxDepth > EPS_SMALL ? max( 0., m_dMaxDepth - b3All.GetDimZ()) : 0) ; - b3All.Expand( EXTRA_XY, EXTRA_XY, EXTRA_Z) ; - m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ; - m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ; - m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ; + b3All.Expand( 0., 0., EXTRA_Z) ; m_dDimZ = b3All.GetDimZ() ; - m_dLevelOffs = - b3All.GetMin().z ; - // calcolo dei punti della griglia (sul top del cilindro) - PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ; - for ( int j = 0 ; j <= m_nStepY ; ++ j) { - for ( int i = 0 ; i <= m_nStepX ; ++ i) { - int nInd = i + j * ( m_nStepX + 1) ; - Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ; - vPntM[nInd] = { ptP, 0.} ; - } - } - - // esecuzione della verifica + // set utensile corrente per calcolo delle collisioni + double dExtraXY = m_dRad ; if ( m_dSideAng < EPS_ANG_SMALL) m_cavTstm.SetStdTool( m_dDimZ + m_dOffsR, m_dRad + m_dOffsR, m_dCornRad + m_dOffsR) ; else { @@ -1015,8 +1037,29 @@ CAvParSilhouettesSurfTm::Prepare( void) double dStemRad = m_dRad + dDeltaRad ; double dTipRad = m_dRad ; + dExtraXY = dStemRad ; m_cavTstm.SetAdvTool( m_dDimZ + m_dOffsR, dStemRad + m_dOffsR, m_dMaxMat, dTipRad + m_dOffsR, m_dCornRad + m_dOffsR) ; } + + // calcolo dati della griglia + const double EXTRA_XY = ( m_bTool ? dExtraXY + 2. : 1.5 * m_dTol) ; + b3All.Expand( EXTRA_XY, EXTRA_XY, 0.) ; + m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ; + m_dLevelOffs = - b3All.GetMin().z ; + m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ; + m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ; + + // calcolo dei punti della griglia (sul top del cilindro) + PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ; + for ( int j = 0 ; j <= m_nStepY ; ++ j) { + for ( int i = 0 ; i <= m_nStepX ; ++ i) { + int nInd = i + j * ( m_nStepX + 1) ; + Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ; + vPntM[nInd] = { ptP, 0.} ; + } + } + + // esecuzione verifica della collisione if ( m_vpStm.empty() || ! m_cavTstm.SetSurfTm( *( m_vpStm[0]))) return false ; for ( int k = 1 ; k < int( m_vpStm.size()) ; ++ k) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index bfc65202e856703942494e91624054296ebcd77c..8574b8e8481ce48184ee5fe4f8a2b362bde66c96 100644 GIT binary patch delta 105 zcmdlNy)SyhCpK1d1|0^&&FAIhnVHjpjE{$f}3`h8vwhkA8r5u delta 105 zcmdlNy)SyhCpK0y1|0^Y&FAIhnVHjojE{$f}3`h8vwhMA8r5u diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index acc41a5..725eb83 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -4029,6 +4029,56 @@ SurfTriMesh::CloneShell( int nShell) const return Release( pSurfTM) ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartLocalBBox( int nP, BBox3d& b3Loc) const +{ + // verifico esistenza della parte + if ( nP < 0 || nP >= GetPartCount()) + return false ; + + // assegno il box in locale + b3Loc.Reset() ; + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + // recupero il vettore delle Shell della parte corrente + const auto& vShell = m_vPart[nP].vShell ; + // scorro i triangoli validi contenuti nella Shell + if ( m_vTria[i].nIdVert[0] != SVT_DEL && + find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { + // ciclo sui tre vertici + for ( int j = 0 ; j < 3 ; ++ j) + b3Loc.Add( m_vVert[m_vTria[i].nIdVert[j]].ptP) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const +{ + // verifico esistenza della parte + if ( nP < 0 || nP >= GetPartCount()) + return false ; + + // assegno il box in locale + b3Ref.Reset() ; + for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) { + // recupero il vettore delle Shell della parte corrente + const auto& vShell = m_vPart[nP].vShell ; + // scorro i triangoli validi contenuti nella Shell + if ( m_vTria[i].nIdVert[0] != SVT_DEL && + find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) { + // ciclo sui tre vertici + for ( int j = 0 ; j < 3 ; ++ j) + b3Ref.Add( GetToGlob( m_vVert[m_vTria[i].nIdVert[j]].ptP, frRef)) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- int SurfTriMesh::GetPartCount( void) const diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 36cc13a..8c5a650 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -337,6 +337,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool GetShellArea( int nShell, double& dArea) const override ; bool RemoveShell( int nShell) override ; SurfTriMesh* CloneShell( int nShell) const override ; + bool GetPartLocalBBox( int nP, BBox3d& b3Loc) const override ; + bool GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const override ; int GetPartCount( void) const override ; bool RemovePart( int nPart) override ; bool GetPartArea( int nPart, double& dArea) const override ; diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp index fcee7a8..f595812 100644 --- a/VolZmapOffset.cpp +++ b/VolZmapOffset.cpp @@ -31,7 +31,6 @@ 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) ; } @@ -43,393 +42,8 @@ VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ, double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum, bool bSkipSwap) { - // Controllo che il numero di griglia sia entro i limiti - if ( nGrid < 0 || nGrid > 2) - return false ; - - // Controllo che indici nI, nJ siano entro i limiti - if ( nI < 0 && nI >= m_nNx[nGrid] && - nJ < 0 && nJ >= m_nNy[nGrid]) - return false ; - - // Controllo che dMin < dMax - Vector3d vtNmi = vtNMin ; - Vector3d vtNma = vtNMax ; - if ( dMin > dMax) { - swap( dMin, dMax) ; - swap( vtNmi, vtNma) ; - } - - // Restringo minimo e massimo entro i limiti della mappa - if ( dMin < m_dMinZ[nGrid]) { - dMin = m_dMinZ[nGrid] ; - if ( ! bSkipSwap) - vtNmi = - Z_AX ; - } - else if ( dMin > m_dMaxZ[nGrid]) { - dMin = m_dMaxZ[nGrid] ; - if ( ! bSkipSwap) - vtNmi = - Z_AX ; - } - if ( dMax < m_dMinZ[nGrid]) { - dMax = m_dMinZ[nGrid] ; - if ( ! bSkipSwap) - vtNma = Z_AX ; - } - else if ( dMax > m_dMaxZ[nGrid]) { - dMax = m_dMaxZ[nGrid] ; - if ( ! bSkipSwap) - vtNma = Z_AX ; - } - - // Controllo che dMin e dMax non siano quasi coincidenti - if ( abs( dMax - dMin) < EPS_SMALL) - return true ; - - // Riporto le coordinate cicliche nell'ordine di partenza - if ( !bSkipSwap && nGrid == 1) { - swap( vtNmi.x, vtNmi.z) ; - swap( vtNmi.y, vtNmi.z) ; - swap( vtNma.x, vtNma.z) ; - swap( vtNma.y, vtNma.z) ; - } - else if ( !bSkipSwap && nGrid == 2) { - swap( vtNmi.y, vtNmi.z) ; - swap( vtNmi.x, vtNmi.z) ; - swap( vtNma.y, vtNma.z) ; - swap( vtNma.x, vtNma.z) ; - } - - // Calcolo nPos - int nPos = nJ * m_nNx[nGrid] + nI ; - vector& vDexel = m_Values[nGrid][nPos] ; - - bool bModified = false ; - - // Non esistono segmenti - if ( vDexel.empty()) { - vDexel.emplace_back() ; - vDexel.back().dMin = dMin ; - vDexel.back().vtMinN = vtNmi ; - vDexel.back().nToolMin = nToolNum ; - vDexel.back().dMax = dMax ; - vDexel.back().vtMaxN = vtNma ; - vDexel.back().nToolMax = nToolNum ; - m_OGrMgr.Reset() ; - bModified = true ; - } - // Esiste almeno un segmento - else { - // Cerco l'ultimo intervallo a sinistra e l'ultimo intervallo a destra - // di quello da aggiungere, che non interferiscono strettamente con quest'ultimo. - auto itLastLeft = vDexel.end() ; - auto itFirstRight = vDexel.end() ; - for ( auto it = vDexel.begin() ; it != vDexel.end() ; ++ it) { - if ( dMin > it->dMax + EPS_SMALL) - itLastLeft = it ; - if ( dMax < it->dMin - EPS_SMALL && itFirstRight == vDexel.end()) - itFirstRight = it ; - } - // Esistono intervalli a sinistra. - if ( itLastLeft != vDexel.end()) { - // Intervallo successivo all'ultimo a sinistra - auto itNextToLastLeft = itLastLeft ; - ++ itNextToLastLeft ; - // Il successivo non esiste. - if ( itNextToLastLeft == vDexel.end()) { - // Aggiungo il nuovo semgento - vDexel.emplace_back() ; - vDexel.back().dMin = dMin ; - vDexel.back().dMax = dMax ; - vDexel.back().vtMinN = vtNmi ; - vDexel.back().vtMaxN = vtNma ; - vDexel.back().nToolMin = nToolNum ; - vDexel.back().nToolMax = nToolNum ; - bModified = true ; - } - // Il successivo esiste. - else { - // Il successivo è il primo a destra. - if ( itNextToLastLeft == itFirstRight) { - // Inserisco nuovo segmento - Data NewSegment ; - NewSegment.dMin = dMin ; - NewSegment.dMax = dMax ; - NewSegment.vtMinN = vtNmi ; - NewSegment.vtMaxN = vtNma ; - NewSegment.nToolMin = nToolNum ; - NewSegment.nToolMax = nToolNum ; - vDexel.insert( itFirstRight, NewSegment) ; - bModified = true ; - } - else { - // Il successivo non esce a sinistra da quello da aggiungere. - if ( itNextToLastLeft->dMin > dMin + EPS_SMALL) { - itNextToLastLeft->dMin = dMin ; - itNextToLastLeft->vtMinN = vtNmi ; - itNextToLastLeft->nToolMin = nToolNum ; - } - // il minimo del successivo coincide con quello da aggiungere - else if ( abs( itNextToLastLeft->dMin - dMin) < EPS_SMALL) { - // Media tra le normali - itNextToLastLeft->vtMinN += vtNmi ; - itNextToLastLeft->vtMinN.Normalize() ; - } - // Cerco l'ultimo segmento che interferisce con quello da aggiungere. - auto itPrevToFirstRight = vDexel.end() ; - for ( auto it = itNextToLastLeft ; it != itFirstRight ; ++ it) { - itPrevToFirstRight = it ; - } - // L'ultimo che interferisce non esce a destra da quello da aggiungere. - if ( itPrevToFirstRight->dMax < dMax - EPS_SMALL) { - itNextToLastLeft->dMax = dMax ; - itNextToLastLeft->vtMaxN = vtNma ; - itNextToLastLeft->nToolMax = nToolNum ; - } - // Il massimo dell'ultimo che interferisce coincide con quello da aggiungere. - else if ( abs( itPrevToFirstRight->dMax - dMax) < EPS_SMALL) { - // Media tra le normali - itNextToLastLeft->vtMaxN = ( vtNma + itPrevToFirstRight->vtMaxN) ; - itNextToLastLeft->vtMaxN.Normalize() ; - } - else { - itNextToLastLeft->dMax = itPrevToFirstRight->dMax ; - itNextToLastLeft->vtMaxN = itPrevToFirstRight->vtMaxN ; - itNextToLastLeft->nToolMax = nToolNum ; - } - bModified = true ; - auto itFirstToCancel = itNextToLastLeft ; - ++ itFirstToCancel ; - vDexel.erase( itFirstToCancel, itFirstRight) ; - } - } - } - // Non esistono neanche a destra. - else if ( itFirstRight == m_Values[nGrid][nPos].end()) { - // Il primo intervallo non sporge STRETTAMENTE a sinistra - if ( vDexel.begin()->dMin > dMin + EPS_SMALL) { - vDexel.begin()->dMin = dMin ; - vDexel.begin()->vtMinN = vtNmi ; - vDexel.begin()->nToolMin = nToolNum ; - } - // Il minimo del primo intervallo coincide con il minimo di quello corrente - else if ( abs( vDexel.begin()->dMin - dMin) < EPS_SMALL) { - // Media tra le normali - vDexel.begin()->vtMinN += vtNmi ; - vDexel.begin()->vtMinN.Normalize() ; - } - // L'ultimo intervallo sporge a destra. - if ( vDexel.back().dMax > dMax + EPS_SMALL) { - // Ci sono più segmenti, inglobo tutti nel primo. - if ( vDexel.back().dMax > vDexel.begin()->dMax + EPS_SMALL) { - vDexel.begin()->dMax = vDexel.back().dMax ; - vDexel.begin()->vtMaxN = vDexel.back().vtMaxN ; - vDexel.begin()->nToolMax = nToolNum ; - } - } - // Il massimo dell'ultimo intervallo coincide con il massimo del corrente - else if ( abs( vDexel.back().dMax - dMax) < EPS_SMALL) { - // Ci sono più segmenti, inglobo tutti nel primo e medio le normali del massimo - if ( vDexel.back().dMax > vDexel.begin()->dMax + EPS_SMALL) { - vDexel.begin()->dMax = vDexel.back().dMax ; - vDexel.begin()->vtMaxN = vDexel.back().vtMaxN + vtNma ; - vDexel.begin()->vtMaxN.Normalize() ; - vDexel.begin()->nToolMax = nToolNum ; - } - // Se singolo segmento - else { - // Media delle normali - vDexel.begin()->vtMaxN += vtNma ; - vDexel.begin()->vtMaxN.Normalize() ; - } - } - // L'ultimo intervallo non sporge a destra. - else { - vDexel.begin()->dMax = dMax ; - vDexel.begin()->vtMaxN = vtNma ; - vDexel.begin()->nToolMax = nToolNum ; - } - bModified = true ; - vDexel.erase( vDexel.begin() + 1, vDexel.end()) ; - } - // A destra esistono. - else { - // Tutti i segmenti sono a destra di qullo da aggiungere. - if ( itFirstRight == vDexel.begin()) { - // Inserisco nuovo segmento - Data NewSegment ; - NewSegment.dMin = dMin ; - NewSegment.dMax = dMax ; - NewSegment.vtMinN = vtNmi ; - NewSegment.vtMaxN = vtNma ; - NewSegment.nToolMin = nToolNum ; - NewSegment.nToolMax = nToolNum ; - vDexel.insert( vDexel.begin(), NewSegment) ; - bModified = true ; - } - else { - // Se il primo segmento non esce strettamente a sinistra da quello da aggiungere, cambio l'inizio. - if ( vDexel.begin()->dMin > dMin + EPS_SMALL) { - vDexel.begin()->dMin = dMin ; - vDexel.begin()->vtMinN = vtNmi ; - vDexel.begin()->nToolMin = nToolNum ; - bModified = true ; - } - // Se il minimo del segmento a sinistra coicide con il minimo del corrente - else if ( abs( vDexel.begin()->dMin - dMin) < EPS_SMALL) { - // Media delle normali - vDexel.begin()->vtMinN += vtNmi ; - vDexel.begin()->vtMinN.Normalize() ; - } - // Cerco l'ultimo segmento che interferisce con quello da aggiungere. - auto itPrevToFirstRight = vDexel.begin() ; - for ( auto it = m_Values[nGrid][nPos].begin() ; it != itFirstRight ; ++ it) { - itPrevToFirstRight = it ; - } - // L'ultimo che interferisce non esce strettamente a destra da quello da aggiungere. - if ( itPrevToFirstRight->dMax < dMax - EPS_SMALL) { - vDexel.begin()->dMax = dMax ; - vDexel.begin()->vtMaxN = vtNma ; - vDexel.begin()->nToolMax = nToolNum ; - bModified = true ; - } - // Il massimo dell'ultimo segmento coincide con il massimo corrente - else if ( abs( itPrevToFirstRight->dMax - dMax) < EPS_SMALL) { - vDexel.begin()->vtMaxN = itPrevToFirstRight->vtMaxN + vtNma ; - vDexel.begin()->vtMaxN.Normalize() ; - } - else { - vDexel.begin()->dMax = itPrevToFirstRight->dMax ; - vDexel.begin()->vtMaxN = itPrevToFirstRight->vtMaxN ; - vDexel.begin()->nToolMax = nToolNum ; - bModified = true ; - } - auto itFirstToCancel = vDexel.begin() ; - ++ itFirstToCancel ; - vDexel.erase( itFirstToCancel, itFirstRight) ; - } - } - } - - // Se nessuna modifica, esco - if ( ! bModified) - return true ; - - // Imposto ricalcolo della grafica - m_OGrMgr.Reset() ; - // Imposto forma generica - m_nShape = GENERIC ; - // Imposto ricalcolo numero di componenti connesse - m_nConnectedCompoCount = - 1 ; - - // Passo da indici di dexel a indici di voxel - nI /= m_nDexVoxRatio ; - nJ /= m_nDexVoxRatio ; - - // Determino quali blocchi sono stati modificati - if ( nGrid == 0) { - // Voxel lungo X - int nXStop = 1 ; - int nXBlock[2] ; - nXBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; - if ( nI % N_VOXBLOCK == 0 && nXBlock[0] > 0) { - nXBlock[1] = nXBlock[0] - 1 ; - ++ nXStop ; - } - // Voxel lungo Y - int nYStop = 1 ; - int nYBlock[2] ; - nYBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; - if ( nJ % N_VOXBLOCK == 0 && nYBlock[0] > 0) { - nYBlock[1] = nYBlock[0] - 1 ; - ++ nYStop ; - } - // Voxel lungo Z - int nVoxNumZ = int( m_nNy[1] / m_nDexVoxRatio + ( m_nNy[1] % m_nDexVoxRatio == 0 ? 1 : 2)) ; - int nMinK = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumZ - 2) ; - int nMaxK = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumZ - 2) ; - int nMinZBlock = ( m_nMapNum == 1 ? 0 : Clamp( nMinK / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[2] - 1))) ; - int nMaxZBlock = min( int( m_nFracLin[2] - 1), nMaxK / int( m_nVoxNumPerBlock)) ; - // Assegno flag ai voxel - for ( int tI = 0 ; tI < nXStop ; ++ tI) { - for ( int tJ = 0 ; tJ < nYStop ; ++ tJ) { - for ( int k = nMinZBlock ; k <= nMaxZBlock ; ++ k) { - int nBlockNum = k * m_nFracLin[0] * m_nFracLin[1] + nYBlock[tJ] * m_nFracLin[0] + nXBlock[tI] ; - m_BlockToUpdate[nBlockNum] = true ; - } - } - } - } - - else if ( nGrid == 1) { - // Voxel lungo Y - int nYStop = 1 ; - int nYBlock[2] ; - nYBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[1] - 1) ; - if ( nI % N_VOXBLOCK == 0 && nYBlock[0] > 0) { - nYBlock[1] = nYBlock[0] - 1 ; - ++ nYStop ; - } - // Voxel lungo Z - int nZStop = 1 ; - int nZBlock[2] ; - nZBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; - if ( nJ % N_VOXBLOCK == 0 && nZBlock[0] > 0) { - nZBlock[1] = nZBlock[0] - 1 ; - ++ nZStop ; - } - // Voxel lungo X - int nVoxNumX = int( m_nNx[0] / m_nDexVoxRatio + ( m_nNx[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; - int nMinI = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumX - 2) ; - int nMaxI = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumX - 2) ; - int nMinXBlock = Clamp( nMinI / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[0] - 1)) ; - int nMaxXBlock = min( int( m_nFracLin[0] - 1), nMaxI / int( m_nVoxNumPerBlock)) ; - // Assegno flag ai voxel - for ( int tI = 0 ; tI < nYStop ; ++ tI) { - for ( int tJ = 0 ; tJ < nZStop ; ++ tJ) { - for ( int k = nMinXBlock ; k <= nMaxXBlock ; ++ k) { - int nBlockNum = nZBlock[tJ] * m_nFracLin[0] * m_nFracLin[1] + nYBlock[tI] * m_nFracLin[0] + k ; - m_BlockToUpdate[nBlockNum] = true ; - } - } - } - } - - else if ( nGrid == 2) { - // Voxel lungo X - int nXStop = 1 ; - int nXBlock[2] ; - nXBlock[0] = min( nJ / m_nVoxNumPerBlock, m_nFracLin[0] - 1) ; - if ( nJ % N_VOXBLOCK == 0 && nXBlock[0] > 0) { - nXBlock[1] = nXBlock[0] - 1 ; - ++ nXStop ; - } - // Voxel lungo Z - int nZStop = 1 ; - int nZBlock[2] ; - nZBlock[0] = min( nI / m_nVoxNumPerBlock, m_nFracLin[2] - 1) ; - if ( nI % N_VOXBLOCK == 0 && nZBlock[0] > 0) { - nZBlock[1] = nZBlock[0] - 1 ; - ++ nZStop ; - } - // Voxel lungo Y - int nVoxNumY = int( m_nNy[0] / m_nDexVoxRatio + ( m_nNy[0] % m_nDexVoxRatio == 0 ? 1 : 2)) ; - int nMinJ = Clamp( int( floor( ( ( dMin - 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) - EPS_SMALL))), 0, nVoxNumY - 2) ; - int nMaxJ = Clamp( int( floor( ( ( dMax + 0.5 * m_dStep) / ( m_nDexVoxRatio * m_dStep) + EPS_SMALL))), 0, nVoxNumY - 2) ; - int nMinYBlock = Clamp( nMinJ / int( m_nVoxNumPerBlock), 0, int( m_nFracLin[1] - 1)) ; - int nMaxYBlock = min( int( m_nFracLin[1] - 1), nMaxJ / int( m_nVoxNumPerBlock)) ; - // Assegno flag ai voxel - for ( int tI = 0 ; tI < nZStop ; ++ tI) { - for ( int tJ = 0 ; tJ < nXStop ; ++ tJ) { - for ( int k = nMinYBlock ; k <= nMaxYBlock ; ++ k) { - int nBlockNum = nZBlock[tI] * m_nFracLin[0] * m_nFracLin[1] + k * m_nFracLin[0] + nXBlock[tJ] ; - m_BlockToUpdate[nBlockNum] = true ; - } - } - } - } - - return true ; + // TODO -- Aggiustare eventuali tolleranze + return AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, bSkipSwap) ; } //---------------------------------------------------------------------------- @@ -659,8 +273,14 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do 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])) + 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 From b957cc75be963d1cfbeb4d2fbfe46c15b13817ab Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 4 Jul 2025 12:59:43 +0200 Subject: [PATCH 05/13] EgtGeomKernel : - aggiunte funzioni per calcolo di Zmap e TriMesh di Offset Fillet Thickening. --- SurfTriMeshOffset.cpp | 53 ++++- VolZmap.h | 12 +- VolZmapOffset.cpp | 446 ++++++++++++++++++++++++++++++++---------- 3 files changed, 400 insertions(+), 111 deletions(-) diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp index 666e863..56213cf 100644 --- a/SurfTriMeshOffset.cpp +++ b/SurfTriMeshOffset.cpp @@ -1,12 +1,14 @@ //---------------------------------------------------------------------------- -// EgalTech 2014-2022 +// EgalTech 2025 //---------------------------------------------------------------------------- // 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. +// Modifiche : 10.06.25 RE - Creazione modulo. +// 10.06.25 RE - Offset di superfici chiuse. ( ver. 2.7e4) +// 04.07.25 RE - Thickening Offset di superfici generiche. ( ver. 2.7g1) // //---------------------------------------------------------------------------- @@ -44,17 +46,25 @@ SumStm( const CISURFTMPVECTOR& vStm) } //---------------------------------------------------------------------------- -/* Funzione che crea l'Offset di una superficie TriMesh chiusa */ +/* Funzione che crea l'Offset di una superficie TriMesh */ ISurfTriMesh* -CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol) +CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol, int nType) { - return CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol) ; + return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol, nType)) ; +} + +//---------------------------------------------------------------------------- +/* Funzione che crea il Fat Offset di una superficie TriMesh */ +ISurfTriMesh* +CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol, int nType) +{ + return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dLinTol, nType)) ; } //---------------------------------------------------------------------------- /* Funzione che crea l'Offset di un insieme di superfici */ ISurfTriMesh* -CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol) +CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol, int nType) { // se vettore delle superfici vuoto, non faccio nulla if ( vStm.empty()) @@ -66,10 +76,37 @@ CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLi // ( 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 + + // creo lo Zmap associato alle superfici TriMesh PtrOwner pVolZmap( CreateVolZmap()) ; - if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol)) + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol, nType)) return nullptr ; + + // restituisco la superficie TriMesh + return ( pVolZmap->GetSurfTriMesh()) ; +} + +//---------------------------------------------------------------------------- +/* Funzione che crea il Fat Offset di un insieme di superfici */ +ISurfTriMesh* +CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol, int nType) +{ + // 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) ; + + // creo lo Zmap associato alle superfici TriMesh + PtrOwner pVolZmap( CreateVolZmap()) ; + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyLinTol, nType)) + return nullptr ; + // restituisco la superficie TriMesh return ( pVolZmap->GetSurfTriMesh()) ; } \ No newline at end of file diff --git a/VolZmap.h b/VolZmap.h index 559dc14..d8ecd70 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -82,7 +82,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW 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, double dExtraBox = 0.) override ; - bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) override ; + bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = ISurfTriMesh::OFF_FILLET) override ; + bool CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = ISurfTriMesh::OFF_FILLET) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ; @@ -439,8 +440,13 @@ class VolZmap : public IVolZmap, public IGeoObjRW 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 InitVolZMapOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; + bool InitVolZMapThickeningOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ; + bool UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ; + bool CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, int nVertexType = 0) ; + bool CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid, int nVertexType = 0) ; bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ, double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum, bool bSkipSwap = false) ; diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp index f595812..61223bb 100644 --- a/VolZmapOffset.cpp +++ b/VolZmapOffset.cpp @@ -23,9 +23,8 @@ using namespace std ; - //---------------------------------------------------------------------------- -/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +/* 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, @@ -50,7 +49,7 @@ VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ, /* 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) +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.), @@ -76,9 +75,9 @@ VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) Vector3d vtNmax = Point3d( dX, dY, dMax) - ptV ; vtNmax.Normalize() ; if ( dOffs > 0.) - AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, 0) ; + AddIntervalsForOffset( nGrid, i, j, dMin, dMax, vtNmin, vtNmax, nTool) ; else - SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, 0) ; + SubtractIntervalsForOffset( nGrid, i, j, dMin, dMax, -vtNmin, -vtNmax, nTool) ; } } } @@ -90,7 +89,8 @@ VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid) /* 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) +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) ; @@ -129,9 +129,9 @@ VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, dou 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) ; + AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, nTool) ; else - SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, 0) ; + SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nTool) ; } } } @@ -140,44 +140,53 @@ VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, dou } //---------------------------------------------------------------------------- -/* Funzione per la creazine di uno Zmap di Offset (positivo o negativo) a partire da una - superficie TriMesh */ +/* 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::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) +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 ; } - // 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 + // 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 ; - // definisco lo Zamp a partire dall'espansione del Box della superficie - if ( ! CreateFromTriMesh( *vSurf[0], dTol, true, dBoxExpansion)) + // --- 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 + // --- se più superfici else { - // calcolo il Box complessivo delle superfici TriMesh + // calcolo il Box complessivo BBox3d BBoxGlob ; - for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) { + for ( const ISurfTriMesh* Surf : vSurf) { // controllo la validità della superficie - if ( ! vSurf[i]->IsValid() || vSurf[i]->GetTriangleCount() == 0) + if ( ! Surf->IsValid() || Surf->GetTriangleCount() == 0) continue ; // calcolo il Box della superficie - BBox3d BBoxSurf ; vSurf[i]->GetLocalBBox( BBoxSurf) ; + BBox3d BBoxSurf ; Surf->GetLocalBBox( BBoxSurf) ; // aggiungo il Box a quello complessivo BBoxGlob.Add( BBoxSurf) ; } @@ -185,20 +194,80 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do 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 chiusa */ +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 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) + - 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) @@ -218,74 +287,57 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do 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) + // 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 ; - // 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)) + // 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 ; - // aggiungo/sottraggo gli intervalli definiti dalla sfera - if ( ! vbVert[nV1]) { - vbVert[nV1] = ( nGrid == 2) ; - if ( ! CreateOffsSphereOnVertex( ptP1, dOffs, nGrid)) - return false ; - } - if ( ! vbVert[nV2]) { - vbVert[nV2] = ( nGrid == 2) ; - if ( ! CreateOffsSphereOnVertex( ptP2, dOffs, nGrid)) - return false ; - } } } - // ----------------------- Facce ----------------------- - // scorro tutte le facce definendo una superficie di estrusione - for ( int nF = 0 ; nF < Surf->GetFacetCount() ; ++ nF) { - // recupero lo faccia - POLYLINEVECTOR vPL ; Surf->GetFacetLoops( nF, vPL) ; - // recupero la normale della faccia - Vector3d vtN ; Surf->GetFacetNormal( nF, vtN) ; - // definisco la superficie di estrusione - CICURVEPVECTOR vpCrvs ; vpCrvs.reserve( vPL.size()) ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - vPL[i].Translate( - abs( dOffs) * vtN) ; - PtrOwner pCrvCompo( CreateCurveComposite()) ; - if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( vPL[i])) { - // 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) { + 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]) ; @@ -293,22 +345,216 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do } return false ; } - // aggiorno gli spilloni - if ( dOffs > 0.) - AddSurfTm( pStmExtr) ; - else - SubtractSurfTm( pStmExtr) ; + 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 ; } } - m_nShape = OFFSET ; 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 == ISurfTriMesh::OFF_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 == ISurfTriMesh::OFF_FILLET) { + if ( ! UpdateVolZMapBySurfThickeningFilletOffset( Surf, dOffs, dTol)) + return false ; + } + } + + m_nShape = OFFSET ; + return true ; +} + From ff6307fcca650e93cbc890746f21dc2a8f38b2dd Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 7 Jul 2025 14:59:06 +0200 Subject: [PATCH 06/13] EgtGeomKernel : - prime sistemazioni per offset superfici trimesh tramite Zmap. --- EgtGeomKernel.vcxproj | 1 + EgtGeomKernel.vcxproj.filters | 5 +- SurfTriMeshOffset.cpp | 44 +++++++------- VolZmap.h | 4 +- VolZmapOffset.cpp | 110 ++++++++++++++++++---------------- 5 files changed, 90 insertions(+), 74 deletions(-) diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index b8b6bc4..b9099fc 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -345,6 +345,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 6120010..68e0c44 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -550,7 +550,7 @@ File di origine\Geo - File di origine\Geo + File di origine\GeoOffset @@ -1232,6 +1232,9 @@ File di intestazione + + File di intestazione\Include + diff --git a/SurfTriMeshOffset.cpp b/SurfTriMeshOffset.cpp index 56213cf..dba93f3 100644 --- a/SurfTriMeshOffset.cpp +++ b/SurfTriMeshOffset.cpp @@ -1,21 +1,21 @@ //---------------------------------------------------------------------------- // EgalTech 2025 //---------------------------------------------------------------------------- -// File : SurfTriMeshOffset.cpp Data : 10.06.25 Versione : 2.7e4 +// File : SurfTriMeshOffset.cpp Data : 07.07.25 Versione : 2.7g1 // Contenuto : Implementazione funzione per Offset di Superfici TriMesh. // // // -// Modifiche : 10.06.25 RE - Creazione modulo. -// 10.06.25 RE - Offset di superfici chiuse. ( ver. 2.7e4) -// 04.07.25 RE - Thickening Offset di superfici generiche. ( ver. 2.7g1) +// Modifiche : 10.06.25 RE Creazione modulo. +// 10.06.25 RE Offset di superfici chiuse. +// 04.07.25 RE Thickening Offset di superfici generiche. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "SurfTriMesh.h" #include "VolZmap.h" +#include "\EgtDev\Include\EGkSurfTriMeshAux.h" using namespace std ; @@ -46,31 +46,34 @@ SumStm( const CISURFTMPVECTOR& vStm) } //---------------------------------------------------------------------------- -/* Funzione che crea l'Offset di una superficie TriMesh */ +// Funzione che crea l'Offset di una superficie TriMesh +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol, int nType) +CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) { - return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dLinTol, nType)) ; + return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dPrec, nType)) ; } //---------------------------------------------------------------------------- -/* Funzione che crea il Fat Offset di una superficie TriMesh */ +// Funzione che crea il Fat Offset di una superficie TriMesh +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dLinTol, int nType) +CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType) { - return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dLinTol, nType)) ; + return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dPrec, nType)) ; } //---------------------------------------------------------------------------- -/* Funzione che crea l'Offset di un insieme di superfici */ +// Funzione che crea l'Offset di un insieme di superfici +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol, int nType) +CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) { // 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) ; + double dMyPrec = max( dPrec, 100 * 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) @@ -79,7 +82,7 @@ CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLi // creo lo Zmap associato alle superfici TriMesh PtrOwner pVolZmap( CreateVolZmap()) ; - if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyLinTol, nType)) + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType)) return nullptr ; // restituisco la superficie TriMesh @@ -87,15 +90,16 @@ CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLi } //---------------------------------------------------------------------------- -/* Funzione che crea il Fat Offset di un insieme di superfici */ +//* Funzione che crea il Fat Offset di un insieme di superfici +//---------------------------------------------------------------------------- ISurfTriMesh* -CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dLinTol, int nType) +CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType) { // 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) ; + double dMyPrec = max( dPrec, 100 * 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) @@ -104,9 +108,9 @@ CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, // creo lo Zmap associato alle superfici TriMesh PtrOwner pVolZmap( CreateVolZmap()) ; - if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyLinTol, nType)) + if ( IsNull( pVolZmap) || ! pVolZmap->CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyPrec, nType)) return nullptr ; // restituisco la superficie TriMesh return ( pVolZmap->GetSurfTriMesh()) ; -} \ No newline at end of file +} diff --git a/VolZmap.h b/VolZmap.h index d8ecd70..64d4dfb 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -82,8 +82,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW 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, double dExtraBox = 0.) override ; - bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = ISurfTriMesh::OFF_FILLET) override ; - bool CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = ISurfTriMesh::OFF_FILLET) override ; + bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) override ; + bool CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) override ; int GetBlockCount( void) const override ; int GetBlockUpdatingCounter( int nBlock) const override ; bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ; diff --git a/VolZmapOffset.cpp b/VolZmapOffset.cpp index 61223bb..3907beb 100644 --- a/VolZmapOffset.cpp +++ b/VolZmapOffset.cpp @@ -24,7 +24,8 @@ using namespace std ; //---------------------------------------------------------------------------- -/* Funzione per sottrarre intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +// 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, @@ -35,7 +36,8 @@ VolZmap::SubtractIntervalsForOffset( int nGrid, int nI, int nJ, } //---------------------------------------------------------------------------- -/* Funzione per aggiungere intervalli lungo un Dexel per l'offset di una superficie TriMesh */ +// 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, @@ -46,8 +48,9 @@ VolZmap::AddIntervalsForOffset( int nGrid, int nI, int nJ, } //---------------------------------------------------------------------------- -/* 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 */ +// 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) { @@ -86,8 +89,9 @@ VolZmap::CreateOffsSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, } //---------------------------------------------------------------------------- -/* Funzione per la creazione di un cilindro di Offset sul vertice di una TriMesh con cui - aggiungere o sottrarre intervalli lungo i Dexel coinvolti */ +// 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) @@ -140,10 +144,11 @@ VolZmap::CreateOffsCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, dou } //---------------------------------------------------------------------------- -/* 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 */ +// 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) { @@ -207,8 +212,9 @@ VolZmap::InitVolZMapOffs( const CISURFTMPVECTOR& vSurf, double dOffs, double dTo } //---------------------------------------------------------------------------- -/* 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 */ +// 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) { @@ -240,8 +246,10 @@ VolZmap::InitVolZMapThickeningOffs( const CISURFTMPVECTOR& vSurf, double dOffs, 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 chiusa */ +//---------------------------------------------------------------------------- +// [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) { @@ -249,8 +257,10 @@ VolZmap::UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double d return false ; } -/* [Fillet] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente - mediante una superficie chiusa */ +//---------------------------------------------------------------------------- +// [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) { @@ -260,25 +270,25 @@ VolZmap::UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double 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. - */ + // 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) ; @@ -372,8 +382,9 @@ VolZmap::UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double return true ; } -/* [Fillet Thickening] Funzione per aggiornare mediante Sfere, Cilindri e Facce di estrusione lo ZMap corrente - mediante una superficie generica (aperta o chiusa) */ +//---------------------------------------------------------------------------- +// [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) @@ -470,13 +481,12 @@ VolZmap::UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, do } //---------------------------------------------------------------------------- -/* 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...) -*/ +// 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) { @@ -503,7 +513,7 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do continue ; // aggiorno lo ZMap if ( Surf->IsClosed()) { - if ( nType == ISurfTriMesh::OFF_FILLET) { + if ( nType == STMOFF_FILLET) { if ( ! UpdateVolZMapByClosedSurfFilletOffset( Surf, dOffs, dTol)) return false ; } @@ -518,8 +528,9 @@ VolZmap::CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, do } //---------------------------------------------------------------------------- -/* Funzione per la creazine di uno Zmap di Fat Offset a partire da un - vettore di superfici TriMesh (aperte o chiuse) */ +// 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) { @@ -546,7 +557,7 @@ VolZmap::CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double continue ; // aggiorno lo Zmap - if ( nType == ISurfTriMesh::OFF_FILLET) { + if ( nType == STMOFF_FILLET) { if ( ! UpdateVolZMapBySurfThickeningFilletOffset( Surf, dOffs, dTol)) return false ; } @@ -555,6 +566,3 @@ VolZmap::CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double m_nShape = OFFSET ; return true ; } - - - From 2fe22a62c29c680a0d7efeb564b9377686019c81 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Wed, 9 Jul 2025 15:36:36 +0200 Subject: [PATCH 07/13] EgtGeomKernel : - in svuotature SpiralOut non si eliminano le passate iniziali adiacenti. --- CalcPocketing.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index d98d22d..318eca3 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -5728,6 +5728,10 @@ CheckIfOffsetIsNecessary( const ISurfFlatRegion* pSfrAct, const ICurveComposite* if ( ! PockParams.bOptOffsets) return true ; + // se spiral out non vanno eliminati parti di percorso + if ( PockParams.nType == POCKET_SPIRALOUT) + return true ; + if ( nIter != 0) { // controllo se sono almeno al secondo offset... // per ogni curva controllo se il suo Offset massimo non genera alcuna regione double dMaxOffs ; From 3b5c34cb05902ea9c70ada9725cd3ee5d10c74ba Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 11 Jul 2025 15:38:55 +0200 Subject: [PATCH 08/13] EgtGeomKernel : - in CalcPocketing migliorati i collegamenti per lavorazioni Conformal e migliorato l'orientamento delle curve per lavorazioni Spiral. --- CalcPocketing.cpp | 293 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 203 insertions(+), 90 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 318eca3..5c3c3b7 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -398,6 +398,16 @@ AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURV return true ; } +//---------------------------------------------------------------------------- +static bool +SwapSideBySecondTempParam( ICurveComposite* pCompo) +{ + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + pCompo->SetTempParam( int( pCompo->GetTempParam( 1)) == MDS_LEFT ? MDS_RIGHT : MDS_LEFT, 1) ; + return true ; +} + //---------------------------------------------------------------------------- static bool CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll) @@ -462,7 +472,7 @@ AssignFeedForOpenEdge( ICurveComposite* pCrv, const ISurfFlatRegion* pSfrOpenEdg pNewCrv->SetTempProp( pCrv->GetTempProp( 0), 0) ; pNewCrv->SetTempProp( pCrv->GetTempProp( 1), 1) ; pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; - pNewCrv->SetTempParam( pCrv->GetTempParam( 0), 0) ; + pNewCrv->SetTempParam( pCrv->GetTempParam( 1), 1) ; double dThick ; pCrv->GetThickness( dThick) ; pNewCrv->SetThickness( dThick) ; Vector3d vtExtr ; pCrv->GetExtrusion( vtExtr) ; @@ -4784,7 +4794,7 @@ CalcSpecialBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, pZigZagLink->AddLine( ptNew) ; } - // questa composita contiene al massimo 5 curve e, in generale, quella una curva molto più lunga + // questa composita contiene al massimo 5 curve e, in generale, una curva molto più lunga // delle altre ( quella che collega le due estensioni calcolate). Spezzo la composita ottenuta in curve // la cui lunghezza massima è circa il raggio utensile PolyLine PL ; @@ -4965,12 +4975,14 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM double dLenS ; pCrvS->GetLength( dLenS) ; double dLenE ; pCrvE->GetLength( dLenE) ; - // se ho una curva di primo Offset allora non devo accorciarla ( sia per bordi esterni che per isole) + // azzero i parametri per curve di primo Offset for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) { if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE)) dLenPercS = 0. ; - if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) - dLenPercE = 0. ; + #if 0 + if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) + dLenPercE = 0. ; + #endif } #if 0 // nel caso volessi estendere anche prima del punto finale double dLStepS = ( dLenPercS < EPS_SMALL ? 0. : PockParams.dRad) ; @@ -5081,6 +5093,9 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& // recupero le proprietà temporanee int nProp0 = vOffs[i]->GetTempProp( 0) ; int nProp1 = vOffs[i]->GetTempProp( 1) ; + // il primo TempParam viene settato in proporzione alla Feed + // il secondo TempParam contiene l'nSide della curva + double dTempPar1 = vOffs[i]->GetTempParam( 1) ; // Feed bool bFirstOffs = false ; @@ -5104,6 +5119,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } vOffs[i]->SetTempProp( nProp0, 0) ; vOffs[i]->SetTempProp( nProp1, 1) ; + vOffs[i]->SetTempParam( dTempPar1, 1) ; // ================= LINK ================================ int nLink_Ind = ( bFollowOrder ? i + 1 : i) ; @@ -5150,12 +5166,13 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR const Point3d& ptToGo, const PocketParams& PockParams, int& nInd, Point3d& ptCloser, bool& bFirstOffs) { - /* - E' richiesto che le curve di Offset presentino le seguenti TempProps : - - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] - - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] - [per SPIRAL le proprietà sono ricavate automaticamente] - */ + // E' richiesto che le curve di Offset presentino le seguenti proprietà : + // - CONFORMAL + // * TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) + // * TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) + // - SPIRAL + // * vOffsFirstCurve -> per capire se l'Offset corrente è di primo Offset o meno + // * TempParam1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) // controllo dei parametri nInd = -1 ; @@ -5177,10 +5194,8 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR vOffsPtMinDist[i].nInd = i ; // nel caso di Conformal, escludo le curve di primo Offset dalla ricerca if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG || PockParams.nType == POCKET_CONFORMAL_ONEWAY) { - bool bSkip = false ; - for ( int j = 0 ; j < int( vOffsFirstCurve.size()) && ! bSkip ; ++ j) - bSkip = ( vOffs[i]->GetTempProp( 0) == 0) ; // prima iterazione - if ( bSkip) { + // prima iterazione + if ( vOffs[i]->GetTempProp( 0) == 0) { vOffsPtMinDist[i].bFirstOffs = true ; continue ; } @@ -5190,26 +5205,16 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR // in questo modo riesco a creare le curve a ricciolo int nSide ; DistPointCurve DistPtCrv( ptToGo, *vOffs[i]) ; - bool bFirstBorderIsland = false ; if ( DistPtCrv.GetSideAtMinDistPoint( EPS_SMALL, Z_AX, nSide)) { // nel caso Spiral if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_SPIRALOUT) { // InVsOut - vOffsPtMinDist[i].bInVsOut = ( ( ! PockParams.bInvert && nSide == MDS_LEFT) || - ( PockParams.bInvert && nSide == MDS_RIGHT)) ; + vOffsPtMinDist[i].bInVsOut = ( int( vOffs[i]->GetTempParam( 1) != nSide)) ; // controllo se la curva in questione è di primo Offset Point3d ptCheck ; vOffs[i]->GetStartPoint( ptCheck) ; for ( int j = 0 ; j < int( vOffsFirstCurve.size()) ; ++ j) { if ( vOffsFirstCurve[j]->IsPointOn( ptCheck, 100 * EPS_SMALL)) { vOffsPtMinDist[i].bFirstOffs = true ; - // controllo se Isola o di bordo - double dArea = 0. ; - vOffs[i]->GetAreaXY( dArea) ; - bFirstBorderIsland = ( ( ! PockParams.bInvert && dArea < 0.) || - ( PockParams.bInvert && dArea > 0.)) ; - // se isola di primo Offset, InVsOut va invertito - if ( bFirstBorderIsland) - vOffsPtMinDist[i].bInVsOut = ( ! vOffsPtMinDist[i].bInVsOut) ; break ; } } @@ -5228,7 +5233,7 @@ ChooseCurveForRemovingUnclearedRegion( const ICRVCOMPOPOVECTOR& vOffs, const ICR PockParams.dSideStep + PockParams.dSideStep ; } // se curva di bordo esterno, aggiungo un'altra penalità ( euristica) - if ( vOffsPtMinDist[i].bFirstOffs && ! bFirstBorderIsland) + if ( vOffsPtMinDist[i].bFirstOffs) vOffsPtMinDist[i].dSqDist *= 2. ; } } @@ -5252,7 +5257,7 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& /* E' richiesto che le curve di Offset presentino le seguenti TempProps : - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] - - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_LEFT) [per CONFORMAL] + - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) [per CONFORMAL] [per SPIRAL le proprietà sono ricavate automaticamente] */ @@ -5267,12 +5272,10 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& for ( int nC = 0 ; nC < pSfrUncleared->GetChunkCount() ; ++ nC) { // recupero il centroide del Chunk da rimuovere Point3d ptCentroid ; pSfrUncleared->GetChunkCentroid( nC, ptCentroid) ; - /* - Tra tutte le curve di Offset escludo le curve che : - - Sono di primo Offset - - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) - ... cerco la più vicina tra le rimanenti - */ + // Tra tutte le curve di Offset escludo le curve che : + // - Sono di primo Offset + // - Non contengono il centroide ( condizione già verificata per quelle di primo Offset) + // ... cerco la più vicina tra le rimanenti // recupero la curva migliore int nInd = -1 ; Point3d ptCloser ; @@ -5570,6 +5573,9 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con vLinks.clear() ; vLinks.resize( int( vOffs.size())) ; + // NB. Dato che le curve di Offset sono invertite a seconda di dove si trova il materiale, + // Utilizzo il secondo TempParam per evere l'nSide + // scorro tutte le curva di Offset for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { @@ -5577,6 +5583,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; + // tra le curve successive cerco la curva interna e più vicina ad essa int nNextInd = -1 ; // indice della curva successiva double dMinDist = INFINITO ; // distanza tra questa curva e la successiva @@ -5588,8 +5595,8 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // se interna if ( IntCC.GetCurveClassification( 1, EPS_SMALL, ccClass) && int( ccClass.size()) == 1 && - ( ( ! PockParams.bInvert && ccClass[0].nClass == CRVC_IN) || - ( PockParams.bInvert && ccClass[0].nClass == CRVC_OUT))) { + ( ( ccClass[0].nClass == CRVC_IN && int( vOffs[i]->GetTempParam( 1)) == MDS_RIGHT) || + ( ccClass[0].nClass == CRVC_OUT && int( vOffs[i]->GetTempParam( 1)) == MDS_LEFT))) { // calcolo la distanza minima tra essa int nFlag ; double dPar = 0. ; @@ -5649,13 +5656,14 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con // scambio la curva i+1 esima con la j-esima ( se non sono già in ordine) if ( nNextInd != i + 1) swap( vOffs[nNextInd], vOffs[i+1]) ; + // cambio il suo punto iniziale nel punto più vicino tovato double dUS ; if ( ! vOffs[i+1]->GetParamAtPoint( ptStartNext, dUS, EPS_SMALL)) return false ; vOffs[i+1]->ChangeStartPoint( dUS) ; - // accorcio la curva per raccordarmi in tangenza con la successiva + // se ho più di una curva di Offset if ( int( vOffs.size()) > 1) { // clono le curve i ed i+1 esime ( nel caso non riuscissi ad accorciarle o raccordarle ) PtrOwner pCrv_i( vOffs[i]->Clone()) ; @@ -5666,15 +5674,14 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con PtrOwner pCrvLink( CreateCurveComposite()) ; if ( IsNull( pCrvLink)) return false ; - // NB. Le curve di Offset da tagliare non devono essere quelle di primo Offset double dLenPercS = ( i == 0 ? 0. : 10 * EPS_SMALL) ; double dLenPercE = ( bMinDistAtSmooth ? 0. : 10 * EPS_SMALL) ; if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsFirstCurve, PockParams, dLenPercS, dLenPercE, pCrvLink) || ! pCrvLink->IsValid()) { // se non sono riuscito, cerco una strada più semplice ripristinando le curve pCrvLink->Clear() ; - vOffs[i].Set( pCrv_i) ; // chiuso - vOffs[i+1].Set( pCrv_ii) ; // chiuso + vOffs[i].Set( pCrv_i) ; + vOffs[i+1].Set( pCrv_ii) ; // recupero i vettori tangenti iniziali ( le curve sono chiuse ) Vector3d vtS, vtE ; if ( ! vOffs[i]->GetStartDir( vtS) || ! vOffs[i+1]->GetStartDir( vtE)) @@ -5823,6 +5830,55 @@ IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const Po return true ; } +//---------------------------------------------------------------------------- +static int +CalcInversionForSpiralOffset( const ISurfFlatRegion* pSfrChunk) +{ + // controllo validità della regione + if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid()) + return -1 ; + + // Caso 0 : Non esistono isole + // Caso 1 : Loop Esterno Chiuso e, se esiste, Isola Chiusa + // Caso 2 : Loop Esterno Chiuso e, se esiste, Isola Aperta + // Caso 3 : Loop Esterno Aperto e, se esiste, Isola Chiusa + // Caso 4 : Loop Esterno Aperto e, se esiste, Isola Aperta + + // se non esistono isole, allora Caso 0 + if ( pSfrChunk->GetLoopCount( 0) == 1) + return 0 ; + + // Il Loop esterno è considerato chiuso <=> esiste almeno una curva chiusa + bool bExtClosed = false ; + for ( int nU = 0 ; nU < pSfrChunk->GetLoopCurveCount( 0, 0) && ! bExtClosed ; ++ nU) { + int nTempProp = TEMP_PROP_INVALID ; + bExtClosed = ( pSfrChunk->GetCurveTempProp( 0, 0, nU, nTempProp) && + nTempProp == TEMP_PROP_CLOSE_EDGE) ; + } + + // Le isole vengono classificate come tutte chiuse <=> esiste almeno un isola chiusa + bool bIntClosed = false ; + for ( int nLoop = 1 ; nLoop < pSfrChunk->GetLoopCount( 0) && ! bIntClosed ; ++ nLoop) { + for ( int nU = 0 ; nU < pSfrChunk->GetLoopCurveCount( 0, nLoop) && ! bIntClosed ; ++ nU) { + int nTempProp = TEMP_PROP_INVALID ; + bIntClosed = ( pSfrChunk->GetCurveTempProp( 0, nLoop, nU, nTempProp) && + nTempProp == TEMP_PROP_CLOSE_EDGE) ; + } + } + + // restituisco il caso corrente + if ( bExtClosed && bIntClosed) + return 1 ; + if ( bExtClosed && ! bIntClosed) + return 2 ; + if ( ! bExtClosed && bIntClosed) + return 3 ; + if ( ! bExtClosed && ! bIntClosed) + return 4 ; + + return -1 ; +} + //---------------------------------------------------------------------------- static bool CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, int& nReg, Point3d& ptStart, @@ -5837,14 +5893,19 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; - ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset - ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset + ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset + ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset // tengo una copia della regione corrente da svuotare PtrOwner pSrfAct( CloneSurfFlatRegion( pSfrPock)) ; if ( IsNull( pSrfAct) || pSrfAct->GetChunkCount() == 0) return false ; + // ricavo il tipo di relazione descritta tra Open/Close di bordo esterno e/o isole + int nCase = CalcInversionForSpiralOffset( pSrfAct) ; + if ( nCase == -1) + return false ; + // ricavo le regioni progressive double dOffsPrec = 0. ; int nCrvFirstOffs = 0 ; @@ -5862,12 +5923,15 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se primo Offset if ( nIter == 0) { + // aggiorno il nuovo valore delle regioni totali di primo Offset int my_nReg = nReg ; - nReg = pSfrOffsVR->GetChunkCount() ; // aggiorno il nuovo valore delle regioni totali di primo Offset + nReg = pSfrOffsVR->GetChunkCount() ; // gli Offset progressivi appartengono al Chunk nReg-esimo pSrfAct.Set( pSfrOffsVR->CloneChunk( my_nReg)) ; - if ( IsNull( pSrfAct)) // se supero i chunk ottenuti + // se supero i chunk ottenuti + if ( IsNull( pSrfAct)) return true ; + // imposto la regione id svuotatura corrente pSfrOffsVR.Set( pSrfAct->Clone()) ; } @@ -5877,24 +5941,41 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co for ( int i = 0 ; i < nChunks ; ++ i) { // per ogni chunk... int nLoops = pSfrOffsVR->GetLoopCount( i) ; - for ( int j = 0 ; j < nLoops ; ++ j) { + for ( int j = 0 ; j < nLoops ; ++ j) { // per ogni loop... PtrOwner pCrvCompoBorder( ConvertCurveToComposite( pSfrOffsVR->GetLoop( i, j))) ; if ( IsNull( pCrvCompoBorder) || ! pCrvCompoBorder->IsValid()) return false ; - /* - Il materiale deve sempre trovarsi alla destra ( se bInvert -> alla sinistra) del tool - soltanto sul primo bordo; Nel caso di isole aperte o nelle passate di Offset intermedio - l'orientamente non ha importanza. - */ - if ( nIter != 0 && j > 0) // inverto l'orientamento delle curve interne ( offset delle isole trovate) - pCrvCompoBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert)) return false ; - if ( bInsert) + if ( bInsert) { + // imposto come secondo TempParam il Side di classificazione + pCrvCompoBorder->SetTempParam( j == 0 ? MDS_RIGHT : MDS_LEFT, 1) ; + // stabilisco l'orientamento della curva + // --- Loop esterno chiuso e isole chiuse + if ( nCase == 1 && nIter != 0 && j > 0) { + pCrvCompoBorder->Invert() ; + SwapSideBySecondTempParam( pCrvCompoBorder) ; + } + // --- Loop esterno chiuso e isole aperte + else if ( nCase == 2 && j > 0) { + pCrvCompoBorder->Invert() ; + SwapSideBySecondTempParam( pCrvCompoBorder) ; + } + // --- Loop esterno aperto e isole chiuse + else if ( nCase == 3 && j == 0) { + pCrvCompoBorder->Invert() ; + SwapSideBySecondTempParam( pCrvCompoBorder) ; + } + // --- Loop esterno aperto e isole aperte + else if ( nCase == 4 && j > 0) { + pCrvCompoBorder->Invert() ; + SwapSideBySecondTempParam( pCrvCompoBorder) ; + } vOffs.emplace_back( Release( pCrvCompoBorder)) ; + } if ( nIter == 0) { // salvo il bordo per i link ( non invertiti, devo sapere IN/OUT) PtrOwner pCrvCompoExtBorder( ConvertCurveToComposite( pSfrOffsVR->GetLoop( i, j))) ; vOffsFirstCurve.emplace_back( Release( pCrvCompoExtBorder)) ; @@ -5940,11 +6021,12 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co Point3d ptNewStart ; // Se ho come lavorazione uno SpiralIn posso poter entrare dalle isole aperte... - int nIndexSwap = 0 ; // indice del vettore di curve per identificare la curva su cui entrare + int nIndexSwap = 0 ; if ( PockParams.nType == POCKET_SPIRALIN) { if ( SetAdvancedPtStartForPath( vOffsFirstCurve, PockParams, pSfrPock, ptRef, ptStart, - vtMidOut, bMidOut, nIndexSwap, vCrvOrigChunkLoops)) + vtMidOut, bMidOut, nIndexSwap, vCrvOrigChunkLoops)) { vOffsFirstCurve[nIndexSwap]->GetStartPoint( ptNewStart) ; + } else return false ; } @@ -5958,8 +6040,10 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se richiesta inversione if ( PockParams.bInvert) { - for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { vOffs[i]->Invert() ; + SwapSideBySecondTempParam( vOffs[i]) ; + } } // smusso le curve di offset ( ad eccezione di quelle di primo Offset) @@ -5979,10 +6063,6 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co vOffs[0]->SetTempParam( 0., 0) ; // prima iterazione // riordino le curve e creo i collegamenti - /* - Se richiesto parametro di smusso, tutti gli Offset ( ad eccezione di quelli generati alla - prima iterazione vengono tagliati, quindi diventano aperti - */ ICURVEPOVECTOR vLinks( vOffs.size()) ; if ( ! CreateSpiralPocketingPath( vOffs, vLinks, PockParams, vOffsFirstCurve)) return false ; @@ -7067,8 +7147,8 @@ AddOneWay( ISurfFlatRegion* pSrfPock, const ISurfFlatRegion* pSfrOrig, PocketPar //---------------------------------------------------------------------------- static bool -SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurveComposite* pCrvLink, - const PocketParams& PockParams, bool bFirstOffs0, bool bFirstOffs1, double dSmoothPar, double dTol) +SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurveComposite* pCrvLink, + const PocketParams& PockParams, bool bFirstOffs0, bool bFirstOffs1, double dSmoothPar, double dTol) { // controllo dei parametri @@ -7077,53 +7157,79 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve pCrvLink == nullptr || ! pCrvLink->IsValid()) return false ; - // curva precedente + // definisco la lunghezza del segmento iniziale e finale sulle due curve di Offset + double dRefLenSeg = 2. * dSmoothPar ; + + // --- Curva precedente --- + // recupero la lunghezza e il dominio del primo Offset + double dLen ; + pCrvOffs0->GetLength( dLen) ; + double dUStart, dUEnd ; + pCrvOffs0->GetDomain( dUStart, dUEnd) ; + // inizializzo la curva PtrOwner pCrvBef( CreateCurveComposite()) ; if ( IsNull( pCrvBef)) return false ; + // se primo Offset di bordo o chiuso... if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { - const ICurve* pCrvFirst = pCrvOffs0->GetFirstCurve() ; - if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvFirst->Clone()) ; + double dU = dUEnd ; + if ( dLen > dRefLenSeg - EPS_SMALL) + pCrvOffs0->GetParamAtLength( dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs0->CopyParamRange( dUStart, dU)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvBef->AddCurve( Release( pMyCrv)) ; } + // altrimenti... else { - const ICurve* pCrvLast = pCrvOffs0->GetLastCurve() ; - if ( pCrvLast == nullptr || ! pCrvLast->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvLast->Clone()) ; + double dU = dUStart ; + if ( dLen > dRefLenSeg) + pCrvOffs0->GetParamAtLength( dLen - dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs0->CopyParamRange( dU, dUEnd)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvBef->AddCurve( Release( pMyCrv)) ; } + // se non valida, errore + if ( ! pCrvBef->IsValid()) + return false ; - // curva successiva + // --- Curva successiva --- + // recupero la lunghezza e il dominio del primo Offset + pCrvOffs1->GetLength( dLen) ; + pCrvOffs1->GetDomain( dUStart, dUEnd) ; + // inizializzo la curva PtrOwner pCrvAft( CreateCurveComposite()) ; if ( IsNull( pCrvAft)) return false ; - const ICurve* pCrvFirst = pCrvOffs1->GetFirstCurve() ; - if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) - return false ; - PtrOwner pMyCrv( pCrvFirst->Clone()) ; + // calcolo il parametro di taglio + double dU = dUEnd ; + if ( dLen > dRefLenSeg - EPS_SMALL) + pCrvOffs1->GetParamAtLength( dRefLenSeg, dU) ; + PtrOwner pMyCrv( pCrvOffs1->CopyParamRange( dUStart, dU)) ; if ( IsNull( pMyCrv) || ! pMyCrv->IsValid()) return false ; pCrvAft->AddCurve( Release( pMyCrv)) ; + // se non valida, errore + if ( ! pCrvAft->IsValid()) + return false ; - // controllo la validità delle curve precedenti e successive ricavate - if ( IsNull( pCrvBef) || IsNull( pCrvAft) || ! pCrvBef->IsValid() || ! pCrvAft->IsValid()) - return false ; - // estendo il Link + // estendo il Link ( linea di ingresso, segmento Link, linea d'uscita) pCrvLink->AddCurve( Release( pCrvBef), false, dTol) ; pCrvLink->AddCurve( Release( pCrvAft), true, dTol) ; - // smusso + + // miglioro la curva + pCrvLink->MergeCurves( 100 * EPS_SMALL, ANG_TOL_STD_DEG) ; + + // smusso la curva ModifyCurveToSmoothed( pCrvLink, PockParams, dSmoothPar, dSmoothPar, false) ; - // toglo gli estremi + + // toglo gli estremi, il Link è in tangenza e le linee di ingresso e d'uscita sono più + // estese dell'arco di smusso creato delete( pCrvLink->RemoveFirstOrLastCurve( false)) ; delete( pCrvLink->RemoveFirstOrLastCurve( true)) ; - // modifico Offset0 per raccordarlo al nuovo Link + + // modifico il primo Offset per raccordarlo al nuovo Link if ( bFirstOffs0 && pCrvOffs0->IsClosed()) { const ICurve* pCrvFirst = pCrvLink->GetFirstCurve() ; if ( pCrvFirst == nullptr || ! pCrvFirst->IsValid()) @@ -7139,7 +7245,8 @@ SmoothLinkByOffs( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, ICurve double dUE ; pCrvOffs0->GetParamAtPoint( ptS, dUE, dTol) ; pCrvOffs0->TrimEndAtParam( dUE) ; } - // modifico Offset1 per raccordarlo al nuovo Link + + // modifico il secondo Offset per raccordarlo al nuovo Link Point3d ptE ; pCrvLink->GetEndPoint( ptE) ; double dUS ; pCrvOffs1->GetParamAtPoint( ptE, dUS, dTol) ; if ( bFirstOffs1 && pCrvOffs1->IsClosed()) @@ -7199,8 +7306,8 @@ GetConformalLinkForOpenCrv( const ICurveComposite* pCrvOffs0, const ICurveCompos //---------------------------------------------------------------------------- static bool -GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, PocketParams& PockParams, - const ICRVCOMPOPOVECTOR& vCrvClassBorder, ICurveComposite* pCrvLink) +CalcConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, PocketParams& PockParams, + const ICRVCOMPOPOVECTOR& vCrvClassBorder, ICurveComposite* pCrvLink) { // controllo validità delle due curve di Offset if ( pCrvOffs0 == nullptr || ! pCrvOffs0->IsValid() || @@ -7252,10 +7359,16 @@ GetConformalLink( ICurveComposite* pCrvOffs0, ICurveComposite* pCrvOffs1, Pocket ICRVCOMPOPOVECTOR vCrvChunk ; for ( int i = 0 ; i < int( vIndOffs0.size()) ; ++ i) vCrvChunk.emplace_back( vCrvClassBorder[vIndOffs0[i]]->Clone()) ; + // se la curva successiva è chiusa, aggiorno il suo punto iniziale a quello a minima distanza + if ( ! bOpen1) { + Point3d ptS ; pCrvOffs0->GetStartPoint( ptS) ; + double dPar ; + int nFlag ; + if ( DistPointCurve( ptS, *pCrvOffs1).GetParamAtMinDistPoint( 0., dPar, nFlag)) + pCrvOffs1->ChangeStartPoint( dPar) ; + } if ( ! CutCurveToConnect( pCrvOffs0, pCrvOffs1, vCrvChunk, PockParams, - ( ( bOpen0 || bFirstIterOffs0) ? 0. : 10 * EPS_SMALL), - ( ( bOpen1 || bFirstIterOffs1) ? 0. : 10 * EPS_SMALL), - pCrvLink) || + bOpen0 ? 0. : 10 * EPS_SMALL, bOpen1 ? 0. : 10 * EPS_SMALL, pCrvLink) || ! pCrvLink->IsValid()) { // se curva di Link non valida, cerco una strada più semplice pCrvLink->Clear() ; @@ -7782,7 +7895,7 @@ CalcConformalOffsAndLinks( VICRVCOMPOPOVECTOR& vvCrvOffs, const ISurfFlatRegion* if ( IsNull( pCrvLink)) return false ; // se non calcolabile, allora retroazione, altrimenti lo memorizzo - if ( ! GetConformalLink( vCrvOffs[i], vCrvOffs[i+1], PockParams, vCrvSfrClass, pCrvLink) || + if ( ! CalcConformalLink( vCrvOffs[i], vCrvOffs[i+1], PockParams, vCrvSfrClass, pCrvLink) || IsNull( pCrvLink) || ! pCrvLink->IsValid() || pCrvLink->GetCurveCount() == 0) vCrvLink.resize( int( vCrvLink.size()) + 1) ; else From eb2b90c6f23acddad768992ad4438c156d924d58 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 14 Jul 2025 10:14:04 +0200 Subject: [PATCH 09/13] EgtGeomKernel : - In CalcPocketing aggiunto flag per calcolo delle regioni non svuotate. --- CalcPocketing.cpp | 70 ++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 5c3c3b7..dde5768 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -56,6 +56,7 @@ struct PocketParams { double dMaxOptSize = 0. ; // dimensione per ottimizzazione double dAngle = 0. ; // angolo per orientare le passate OneWay e ZigZag double dLiTang = INFINITO ; // valore di LeadIn in ingresso + bool bCalcUnclearedRegs = true ; // flag per calcolare o meno le regioni non svuotate bool bOptOffsets = true ; // flag per evitare Offset non necessari bool bAboveHead = true ; // flag per testa da sopra ( Z+) bool bSmooth = false ; // curve smussate @@ -5037,14 +5038,13 @@ CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, const ICRVCOM //---------------------------------------------------------- static bool -GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, - const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSrfToCut) +GetUnclearedRegionAndSetFeed( const ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, + const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSfrUncleared) { - // controllo dei parametri if ( vFirstOffs.empty() || int( vOffs.size()) < int( vFirstOffs.size())) return false ; - pSrfToCut->Clear() ; + pSfrUncleared->Clear() ; // creo la regione esterna ( definita dalle curve di primo Offset) // NB. Questa regione è diversa dalla pSfrOrig : @@ -5065,7 +5065,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } } - // 2) creo la regione che all'esterno contiene i lati aperti + // creo la regione che all'esterno contiene i lati aperti // NB. Prendendo la superficie originale ( con lati Open/Close impostati), se effettuo un // Offset interno dell'estensione degli aperti, tutto ciò che è all'esterno di tale regione è classificato // come lato aperto @@ -5115,7 +5115,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) pSfrTool.Set( pSrfToolOffs) ; else - pSfrTool->Add( *pSrfToolOffs) ; + pSfrTool->Add( *pSrfToolOffs) ; } vOffs[i]->SetTempProp( nProp0, 0) ; vOffs[i]->SetTempProp( nProp1, 1) ; @@ -5141,7 +5141,7 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& if ( ! IsNull( pSfrToolLink)) { if ( ! pSfrTool->IsValid() || pSfrTool->GetChunkCount() == 0) pSfrTool.Set( pSfrToolLink) ; - else + else pSfrTool->Add( *pSfrToolLink) ; } // risetto il Link come curva composita ... @@ -5152,10 +5152,12 @@ GetUnclearedRegionAndSetFeed( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& } - // 4) Creo la regione contenente tutte le parti non svuotate - pSrfToCut->CopyFrom( pSrfExtern) ; - if ( ! pSrfToCut->Subtract( *pSfrTool)) - return false ; + // se rischiesto, creo la regione contenente tutte le parti non svuotate + if ( PockParams.bCalcUnclearedRegs) { + pSfrUncleared->CopyFrom( pSrfExtern) ; + if ( ! pSfrUncleared->Subtract( *pSfrTool)) + return false ; + } return true ; } @@ -5254,12 +5256,17 @@ static bool RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsFirstCurve, const PocketParams& PockParams) { - /* - E' richiesto che le curve di Offset presentino le seguenti TempProps : - - TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) [per CONFORMAL] - - TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) [per CONFORMAL] - [per SPIRAL le proprietà sono ricavate automaticamente] - */ + // se non devo calcolare le regioni non svuotate, esco subito + if ( ! PockParams.bCalcUnclearedRegs) + return true ; + + // E' richiesto che le curve di Offset presentino le seguenti proprietà : + // - CONFORMAL + // * TempProp0 -> Offset progressivo ricavato ( 0, 1, 2, ... nMaxIter) + // * TempProp1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) + // - SPIRAL + // * vOffsFirstCurve -> per capire se l'Offset corrente è di primo Offset o meno + // * TempParam1 -> parte esterna della curva ( MDS_LEFT o MDS_RIGHT) // se non ho nessuna superficie valida da svuotare, allora esco if ( pSfrUncleared == nullptr) @@ -5280,7 +5287,7 @@ RemoveUnclearedRegions( const ISurfFlatRegion* pSfrUncleared, ICRVCOMPOPOVECTOR& int nInd = -1 ; Point3d ptCloser ; bool bFirstOffs = false ; - if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, + if ( ! ChooseCurveForRemovingUnclearedRegion( vOffs, vOffsFirstCurve, ptCentroid, PockParams, nInd, ptCloser, bFirstOffs)) return false ; // se nessun indice trovato, salto il chunk @@ -5954,23 +5961,10 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // imposto come secondo TempParam il Side di classificazione pCrvCompoBorder->SetTempParam( j == 0 ? MDS_RIGHT : MDS_LEFT, 1) ; // stabilisco l'orientamento della curva - // --- Loop esterno chiuso e isole chiuse - if ( nCase == 1 && nIter != 0 && j > 0) { - pCrvCompoBorder->Invert() ; - SwapSideBySecondTempParam( pCrvCompoBorder) ; - } - // --- Loop esterno chiuso e isole aperte - else if ( nCase == 2 && j > 0) { - pCrvCompoBorder->Invert() ; - SwapSideBySecondTempParam( pCrvCompoBorder) ; - } - // --- Loop esterno aperto e isole chiuse - else if ( nCase == 3 && j == 0) { - pCrvCompoBorder->Invert() ; - SwapSideBySecondTempParam( pCrvCompoBorder) ; - } - // --- Loop esterno aperto e isole aperte - else if ( nCase == 4 && j > 0) { + if ( ( nCase == 1 && nIter != 0 && j > 0) || + ( nCase == 2 && j > 0) || + ( nCase == 3 && j == 0) || + ( nCase == 4 && j > 0)) { pCrvCompoBorder->Invert() ; SwapSideBySecondTempParam( pCrvCompoBorder) ; } @@ -6080,9 +6074,8 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { // accodo nel percorso di lavorazione - if ( ! pMCrv->AddCurve( Release( vLinks[i]))) { + if ( ! pMCrv->AddCurve( Release( vLinks[i]))) return false ; - } } pMCrv->AddCurve( Release( vOffs[i])) ; } @@ -8925,7 +8918,7 @@ SmoothExtensionLinesByIntersection( ICRVCOMPOPOVECTOR& vCrvPaths, const PocketPa //---------------------------------------------------------------------------- bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, - double dOpenMinSafe, int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, + double dOpenMinSafe, int nType, bool bSmooth, bool bCalcUnclReg, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, bool bCalcFeed, const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, double dMaxOptSize, double dLiTang, int nLiType, ICRVCOMPOPOVECTOR& vCrvCompoRes) { @@ -8948,6 +8941,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.dAngle = dAngle ; myParams.dSideStep = dStep ; myParams.dOpenMinSafe = dOpenMinSafe ; + myParams.bCalcUnclearedRegs = bCalcUnclReg ; myParams.bInvert = bInvert ; myParams.bAvoidOpt = bAvoidOpt ; myParams.bCalcFeed = bCalcFeed ; From 8b0d5bddbf0aab925810301e1fdfe1722521b9b7 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 14 Jul 2025 17:46:36 +0200 Subject: [PATCH 10/13] EgtGeomKernel : - In CalcPocketing piccola miglioria per il calcolo delle regioni non svuotate. --- CalcPocketing.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index dde5768..8e0baa2 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -5041,6 +5041,10 @@ static bool GetUnclearedRegionAndSetFeed( const ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, const ISurfFlatRegion* pSfrOrig, const PocketParams& PockParams, ISurfFlatRegion* pSfrUncleared) { + // se non devo nè calcolare la Feed nè calcolare le regioni svuotate, allora non faccio nulla + if ( ! PockParams.bCalcFeed && ! PockParams.bCalcUnclearedRegs) + return true ; + // controllo dei parametri if ( vFirstOffs.empty() || int( vOffs.size()) < int( vFirstOffs.size())) return false ; @@ -5996,9 +6000,12 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co dOffs = PockParams.dSideStep ; } } - // se devo usare un Offset più piccolo... - else if ( ! bSmallRad) + // se non ho Chunks e devo usare un Offset più piccolo... + else if ( ! bSmallRad) { + if ( PockParams.dRad < EPS_SMALL) + break ; dOffs = dOffsPrec + ( nIter == 0 ? PockParams.dRad + PockParams.dRadialOffset : PockParams.dRad) ; + } // altrimenti ho finito la regione da svuotare... else break ; From ee4bb7d7c4aed936492b0ebfdf76fa57a65b70e0 Mon Sep 17 00:00:00 2001 From: SaraP Date: Tue, 15 Jul 2025 11:52:23 +0200 Subject: [PATCH 11/13] EgtGeomKernel : - correzione nell'offset con Voronoi per archi piccoli. --- Voronoi.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Voronoi.cpp b/Voronoi.cpp index 4feb971..7388cb1 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -610,25 +610,25 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) return false ; // sistemo le curve di offset calcolate con vroni - for ( auto pCrv : OffsList) { + for ( auto pCrv : OffsList) { // seleziono le porzioni dell'offset che si trovano dal lato richiesto ICRVCOMPOPOVECTOR vResult = AdjustOffsetCurves( pCrv, dOffs) ; - + for ( int i = 0 ; i < int( vResult.size()) ; ++ i) { // eventuale inversione if ( dOffs > EPS_SMALL) vResult[i]->Invert() ; - + // sistemo il punto di inizio if ( vResult[i]->IsClosed()) AdjustOffsetStart( vResult[i]) ; - + // identifico i raccordi if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) IdentifyFillets( vResult[i], dOffs) ; - + // unisco le parti allineate vResult[i]->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ; // aggiungo al vettore finale @@ -986,9 +986,19 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) double dAng = pArc->GetAngCenter() ; if ( ( nType == CCW && dAng < - EPS_ANG_SMALL) || ( nType == CW && dAng > EPS_ANG_SMALL)) pArc->ToExplementary() ; - // aggiungo alla composita - if ( ! pCrvOffs->AddCurve( Release( pArc))) - return false ; + // verifico se l'arco degenera in segmento + Vector3d vtS, vtE ; + pArc->GetStartDir( vtS) ; + pArc->GetEndDir( vtE) ; + if ( AreSameVectorApprox( vtS, vtE)) { + if ( ! pCrvOffs->AddLine( ptE)) + return false ; + } + else { + // aggiungo alla composita + if ( ! pCrvOffs->AddCurve( Release( pArc))) + return false ; + } } } From 81a8eb698ef8544ee86f80388e6a229387b5f8d6 Mon Sep 17 00:00:00 2001 From: SaraP Date: Tue, 15 Jul 2025 15:07:50 +0200 Subject: [PATCH 12/13] EgtGeomKernel : - correzione del test per archi degeneri nell'offset con Voronoi. --- Voronoi.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Voronoi.cpp b/Voronoi.cpp index 7388cb1..63ae5ee 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -987,10 +987,9 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( ( nType == CCW && dAng < - EPS_ANG_SMALL) || ( nType == CW && dAng > EPS_ANG_SMALL)) pArc->ToExplementary() ; // verifico se l'arco degenera in segmento - Vector3d vtS, vtE ; - pArc->GetStartDir( vtS) ; - pArc->GetEndDir( vtE) ; - if ( AreSameVectorApprox( vtS, vtE)) { + Point3d ptMLine = Media( ptS, ptE) ; + Point3d ptMArc ; pArc->GetMidPoint( ptMArc) ; + if ( Dist( ptMLine, ptMArc) < EPS_SMALL) { if ( ! pCrvOffs->AddLine( ptE)) return false ; } From 38a5c0cbb3dd6cceefedb44c0717d0cf2eb664f5 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Tue, 15 Jul 2025 19:25:36 +0200 Subject: [PATCH 13/13] EgtGeomKernel : - correzione nell'aggiunta di curve a CurveComposite (gestito caso di altra curva che va trasformata in segmento di retta). --- CurveComposite.cpp | 14 +- Voronoi.cpp | 323 ++++++++++++++++++++++----------------------- 2 files changed, 167 insertions(+), 170 deletions(-) diff --git a/CurveComposite.cpp b/CurveComposite.cpp index fa9f197..a364a5f 100644 --- a/CurveComposite.cpp +++ b/CurveComposite.cpp @@ -224,8 +224,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT // lunghezza della curva originale double dOldLen ; pCrv->GetLength( dOldLen) ; // eseguo modifica - if ( ! pCrv->ModifyStart( ptEnd)) - return false ; + if ( ! pCrv->ModifyStart( ptEnd)) { + CurveLine crvLine ; + if ( ! crvLine.Set( ptEnd, ptCrvEnd) || ! pCrv.Set( crvLine.Clone())) + return false ; + } // verifico che la lunghezza non sia variata troppo double dNewLen ; pCrv->GetLength( dNewLen) ; if ( abs( dNewLen - dOldLen) > 10 * dLinTol) @@ -246,8 +249,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT // lunghezza della curva originale double dOldLen ; pCrv->GetLength( dOldLen) ; // eseguo modifica - if ( ! pCrv->ModifyEnd( ptStart)) - return false ; + if ( ! pCrv->ModifyEnd( ptStart)) { + CurveLine crvLine ; + if ( ! crvLine.Set( ptCrvStart, ptStart) || ! pCrv.Set( crvLine.Clone())) + return false ; + } // verifico che la lunghezza non sia variata troppo double dNewLen ; pCrv->GetLength( dNewLen) ; if ( abs( dNewLen - dOldLen) > 10 * dLinTol) diff --git a/Voronoi.cpp b/Voronoi.cpp index 63ae5ee..0146793 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -25,7 +25,7 @@ using namespace std ; //---------------------------------------------------------------------------- -Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) +Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) : m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true) { // tento di aggiungere la curva @@ -35,7 +35,7 @@ Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd) } //---------------------------------------------------------------------------- -Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) +Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) : m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true) { // tento di aggiungere la superficie @@ -45,16 +45,16 @@ Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd) } //---------------------------------------------------------------------------- -Voronoi::~Voronoi( void) +Voronoi::~Voronoi( void) { Clear() ; } //---------------------------------------------------------------------------- bool -Voronoi::Clear( void) +Voronoi::Clear( void) { - // pulizia oggetto vroni + // pulizia oggetto vroni if ( m_vroni != nullptr) delete m_vroni ; m_vroni = nullptr ; @@ -72,7 +72,7 @@ Voronoi::Clear( void) //---------------------------------------------------------------------------- bool -Voronoi::AddCurve( const ICurve* pCrv) +Voronoi::AddCurve( const ICurve* pCrv) { if ( ! m_bAllowAdd) return false ; @@ -99,21 +99,21 @@ Voronoi::AddCurve( const ICurve* pCrv) if ( ! vtExtr.IsSmall()) plPlane.Set( ptS, vtExtr) ; else - plPlane.Set( ptS, Z_AX) ; + plPlane.Set( ptS, Z_AX) ; } else { if ( ! pCrv->IsFlat( plPlane, false, 10 * EPS_SMALL)) - return false ; - } - + return false ; + } + if ( m_vpCrvs.empty()) { // se prima curva considerata assegno il frame al Voronoi - m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ; + m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ; } else { // altrimenti verifico sia complanare ad eventuali curve già presenti if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), plPlane.GetVersN()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane)) - return false ; + return false ; } // creo una copia della curva e la porto in locale @@ -128,8 +128,8 @@ Voronoi::AddCurve( const ICurve* pCrv) m_vroni = new( nothrow) vroniObject() ; if ( m_vroni == nullptr) return false ; - m_vroni->apiInitializeProgram() ; - } + m_vroni->apiInitializeProgram() ; + } // aggiungo la curva in locale all'oggetto vroni if ( ! AddCurveToVroni( pCrvLoc)) @@ -144,61 +144,61 @@ Voronoi::AddCurve( const ICurve* pCrv) BBox3d bBox ; pCrvLoc->GetLocalBBox( bBox) ; m_bBox.Add( bBox) ; - + return true ; } //---------------------------------------------------------------------------- bool -Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) +Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) { if ( ! m_bAllowAdd) return false ; if ( pSfr == nullptr) return false ; - + // recupero il piano Point3d ptCen ; pSfr->GetCentroid( ptCen) ; - Vector3d vtN = pSfr->GetNormVersor() ; + Vector3d vtN = pSfr->GetNormVersor() ; if ( m_vpCrvs.empty()) { // assegno il frame al Voronoi - m_Frame.Set( ptCen, vtN) ; + m_Frame.Set( ptCen, vtN) ; } else { // verifico sia complanare ad eventuali curve già presenti Plane3d plPlane ; plPlane.Set( ptCen, pSfr->GetNormVersor()) ; if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), pSfr->GetNormVersor()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane)) - return false ; + return false ; } - + try { // verifico se oggetto vroni è stato inizializzato if ( m_vroni == nullptr) { m_vroni = new( nothrow) vroniObject() ; if ( m_vroni == nullptr) return false ; - m_vroni->apiInitializeProgram() ; + m_vroni->apiInitializeProgram() ; } - + // aggiungo le curve di loop for ( int i = 0 ; i < pSfr->GetChunkCount() ; i ++) { for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; j ++) { PtrOwner pCrvLoc( pSfr->GetLoop( i, j)) ; if ( IsNull( pCrvLoc)) return false ; - pCrvLoc->ToLoc( m_Frame) ; + pCrvLoc->ToLoc( m_Frame) ; if ( ! AddCurveToVroni( pCrvLoc)) return false ; - } + } } } catch (...) { LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage()) return false ; } - + // aggiorno il box complessivo BBox3d bBox ; Frame3d frSrf = m_Frame ; @@ -211,16 +211,16 @@ Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr) //---------------------------------------------------------------------------- bool -Voronoi::AddCurveToVroni( const ICurve* pCrv) +Voronoi::AddCurveToVroni( const ICurve* pCrv) { int nLoopId = m_vpCrvs.size() ; // aggiungo il punto iniziale - Point3d ptStart ; + Point3d ptStart ; if ( ! pCrv->GetStartPoint( ptStart)) return false ; int nCrv = m_vroni->HandlePnt( ptStart.x, ptStart.y, {nLoopId, 0}) ; - + // aggiungo la parte rimanente della curva switch ( pCrv->GetType()) { case CRV_LINE : @@ -229,7 +229,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv) case CRV_ARC : m_vpCrvs.emplace_back( pCrv->Clone()) ; return AddArcToVroni( GetCurveArc( pCrv), nCrv, nLoopId) ; - case CRV_COMPO : + case CRV_COMPO : return AddCompoToVroni( GetCurveComposite( pCrv), nCrv, nLoopId) ; case CRV_BEZIER : return AddBezierToVroni( GetCurveBezier( pCrv), nCrv, nLoopId) ; @@ -242,7 +242,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv) //---------------------------------------------------------------------------- bool -Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) +Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) { if ( pLine == nullptr) return false ; @@ -250,7 +250,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i // verifico se il punto finale viene forzato oppure deve essere ricavato dalla pLine if ( ! ptEnd.IsValid()) { if ( ! pLine->GetEndPoint( ptEnd)) - return false ; + return false ; } m_vroni->AddSeg( &nVroniCrv, ptEnd.x, ptEnd.y, {nLoopId, nCrvId}) ; @@ -259,7 +259,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i //---------------------------------------------------------------------------- bool -Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) +Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd) { if ( pArc == nullptr) return false ; @@ -285,7 +285,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int // verifico se il punto finale viene forzato oppure deve essere ricavato dal pArc if ( ! ptEnd.IsValid()) { if ( ! pArc->GetEndPoint( ptEnd)) - return false ; + return false ; } m_vroni->AddArc( &nVroniCrv, ptEnd.x, ptEnd.y, ptCen.x, ptCen.y, nArcSiteType, {nLoopId, nCrvId}) ; } @@ -295,7 +295,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int //---------------------------------------------------------------------------- bool -Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId) +Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId) { if ( pCompo == nullptr) return false ; @@ -315,18 +315,18 @@ Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLo bool bClosed = pCopy->IsClosed() ; for ( int i = 0 ; i < pCopy->GetCurveCount() ; i++) { Point3d ptForcedEnd = P_INVALID ; - + // se curva è chiusa, forzo l'end point a coincidere con lo start ( per le tolleranze di vroni) if ( i == pCopy->GetCurveCount() - 1 && bClosed) pCompo->GetStartPoint( ptForcedEnd) ; - + // aggiungo const ICurve* pCrv = pCopy->GetCurve( i) ; int nType = pCrv->GetType() ; if ( nType == CRV_LINE) AddLineToVroni( GetCurveLine( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; else if ( nType == CRV_ARC) - AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; + AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ; } // aggiungo al vettore di curve @@ -341,7 +341,7 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo { if ( pBezier == nullptr) return false ; - + // riconduco al caso di curva composita PtrOwner pCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCompo)) @@ -352,28 +352,28 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo Vector3d vtExtr ; pBezier->GetExtrusion( vtExtr) ; pCompo->SetExtrusion( vtExtr) ; - + return AddCompoToVroni( pCompo, nVroniCrv, nLoopId) ; } //---------------------------------------------------------------------------- -ICurve* +ICurve* Voronoi::GetCurve( int nId) const { // verifico validità indice if ( nId < 0 || nId > ( int)m_vpCrvs.size() - 1) - return nullptr ; + return nullptr ; // ne faccio una copia ICurve* pCrv = m_vpCrvs[nId]->Clone() ; if ( pCrv == nullptr) - return nullptr ; + return nullptr ; // la porto nel riferimento globale pCrv->ToGlob( m_Frame) ; return pCrv ; } //---------------------------------------------------------------------------- -bool +bool Voronoi::GetVroniPlane( Plane3d& plPlane) const { if ( ! IsValid()) @@ -383,13 +383,13 @@ Voronoi::GetVroniPlane( Plane3d& plPlane) const } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcVoronoi( int nBound) -{ +{ // se già stato calcolato con lo stesso bound non devo fare nulla if ( m_bVDComputed && nBound == m_nBound) return true ; - + // se già stato calcolato reset dei dati if ( m_bVDComputed) m_vroni->ResetVoronoiDiagram() ; @@ -398,9 +398,9 @@ Voronoi::CalcVoronoi( int nBound) m_nBound = max( nBound, VORONOI_STD_BOUND) ; // calcolo - m_bVDComputed = true ; + m_bVDComputed = true ; string sTmp = "" ; - m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ; + m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ; return true ; } @@ -416,7 +416,7 @@ Voronoi::GetBisectorCurve( int i) int nType = m_vroni->GetBisectorType( i) ; // linea - if ( nType == BisectorType::LINE) { + if ( nType == BisectorType::LINE) { // recupero i dati del bisettore da vroni Point3d ptS, ptE ; double dParS, dParE ; @@ -434,7 +434,7 @@ Voronoi::GetBisectorCurve( int i) pLine->SetTempParam( dParS, 0) ; pLine->SetTempParam( dParE, 1) ; pLine->ToGlob( m_Frame) ; - return pLine ; + return pLine ; } // degenerate hyperellipse ( arco) @@ -454,20 +454,20 @@ Voronoi::GetBisectorCurve( int i) pArc->SetTempParam( dParS, 0) ; pArc->SetTempParam( dParS, 1) ; // dParE = dParS pArc->ToGlob( m_Frame) ; - return pArc ; + return pArc ; } - + // bisettore generico else if ( nType != BisectorType::NONE) { // approssimo linearmente il bisettore int nPoints = m_vroni->GetApproxedBisectorPointsNbr( i) ; if ( nPoints < 2) return nullptr ; - + CurveComposite* pCompo = CreateBasicCurveComposite() ; if ( pCompo == nullptr) return nullptr ; - + // verifico se devo leggere i punti del bisettore al contrario per averlo orientato dal parametro minore al maggiore bool bInvert = false ; double dPar1, dPar2 ; @@ -481,13 +481,13 @@ Voronoi::GetBisectorCurve( int i) m_vroni->GetApproxedBisectorPoint( i, bInvert ? nPoints - 1 : 0, pt.v, dParS) ; pCompo->AddPoint( pt) ; int nCrvCount = 0 ; - + double dParPrev = dParS ; int j = bInvert ? nPoints - 2 : 1 ; while ( ( bInvert && j >= 0) || ( ! bInvert && j < nPoints)) { double dPar ; m_vroni->GetApproxedBisectorPoint( i, j, pt.v, dPar) ; - if ( pCompo->AddLine( pt)) { + if ( pCompo->AddLine( pt)) { // setto i parametri sulla sottocurva pCompo->SetCurveTempParam( nCrvCount, dParPrev, 0) ; pCompo->SetCurveTempParam( nCrvCount, dPar, 1) ; @@ -501,7 +501,7 @@ Voronoi::GetBisectorCurve( int i) else j ++ ; } - + // setto parametri sulla curva pCompo->SetTempParam( dParS, 0) ; pCompo->SetTempParam( dParPrev, 1) ; @@ -521,12 +521,12 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound) if ( ! IsValid()) return false ; - + try { // verifico se necessario calcolo Voronoi if ( ! m_bVDComputed || nBound != m_nBound) CalcVoronoi( nBound) ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // recupero la curva del bisettore PtrOwner pCrv( GetBisectorCurve( i)) ; @@ -546,7 +546,7 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) { vCrvs.clear() ; @@ -561,21 +561,21 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) bRight = false ; else if ( nSide == WMAT_RIGHT) bLeft = false ; - - try { + + try { if ( ! m_bVDComputed) CalcVoronoi() ; // calcolo medial axis m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // verifico se il lato appartiene al medial axis if ( m_vroni->IsWMATEdge( i)) { PtrOwner pCrv( GetBisectorCurve( i)) ; - if ( ! IsNull( pCrv) && pCrv->IsValid()) - vCrvs.emplace_back( Release( pCrv)) ; - } + if ( ! IsNull( pCrv) && pCrv->IsValid()) + vCrvs.emplace_back( Release( pCrv)) ; + } } // libero la memoria di vroni utilizzata per calcolare bisettore @@ -590,7 +590,7 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) { vOffs.clear() ; @@ -603,32 +603,32 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) for ( auto pCrv : m_vpCrvs) vOffs.emplace_back( pCrv->Clone()) ; } - + // calcolo offset ICRVCOMPOPLIST OffsList ; if ( ! CalcVroniOffset( OffsList, abs( dOffs))) - return false ; - + return false ; + // sistemo le curve di offset calcolate con vroni - for ( auto pCrv : OffsList) { + for ( auto pCrv : OffsList) { // seleziono le porzioni dell'offset che si trovano dal lato richiesto ICRVCOMPOPOVECTOR vResult = AdjustOffsetCurves( pCrv, dOffs) ; - - for ( int i = 0 ; i < int( vResult.size()) ; ++ i) { - + + for ( int i = 0 ; i < int( vResult.size()) ; ++ i) { + // eventuale inversione if ( dOffs > EPS_SMALL) vResult[i]->Invert() ; - + // sistemo il punto di inizio - if ( vResult[i]->IsClosed()) + if ( vResult[i]->IsClosed()) AdjustOffsetStart( vResult[i]) ; - - // identifico i raccordi + + // identifico i raccordi if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) IdentifyFillets( vResult[i], dOffs) ; - + // unisco le parti allineate vResult[i]->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ; // aggiungo al vettore finale @@ -643,17 +643,17 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) if ( ! AdjustCurveFillets( vOffs, dOffs, nType)) { vOffs.clear() ; return false ; - } + } // porto nel frame globale for ( int i = 0 ; i < int( vOffs.size()) ; i++) - vOffs[i]->ToGlob( m_Frame) ; + vOffs[i]->ToGlob( m_Frame) ; return true ; } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) { // calcola, se possibile, le curve di offset del valore richiesto come curve singole, andando a recuperare i tratti del @@ -667,22 +667,22 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) if ( ! IsValid()) return false ; - try { + try { if ( ! m_bVDComputed) CalcVoronoi() ; - // individuo il lato richiesto + // individuo il lato richiesto bool bLeft = ( dOffs < 0) ; - bool bRight = ! bLeft ; + bool bRight = ! bLeft ; for ( int i = 0 ; i < int( m_vpCrvs.size()) ; i++) { if ( ! m_vpCrvs[i]->IsClosed()) { // se è presente una curva aperta il medial axis deve essere fatto sia a destra sia a sinistra bLeft = true ; bRight = true ; - break ; + break ; } } - int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ; + int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ; // seleziono le curve del medial axis aventi parametro costante pari all'offset richiesto m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ; @@ -695,7 +695,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) m_vroni->GetBisectorParams( i, dParS, dParE) ; if ( abs( dParS - abs( dOffs)) < EPS_SMALL && abs( dParE - abs( dOffs)) < EPS_SMALL) { PtrOwner pCrv( GetBisectorCurve( i)) ; - if ( ! IsNull( pCrv) && pCrv->IsValid()) { + if ( ! IsNull( pCrv) && pCrv->IsValid()) { // se necessario verifico se dal lato corretto rispetto ai siti di riferimento if ( bLeft && bRight) { // recupero i siti di riferimento @@ -707,7 +707,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) pCrv->SetTempProp( nOrigCrv1, 1) ; int nSide = GetOffsetCurveSide( pCrv) ; if ( nSide != nSideRef) - continue ; + continue ; } if ( nOrigCrv2 != -1) { // verifico il lato rispetto al secondo sito @@ -716,18 +716,18 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) int nSide = GetOffsetCurveSide( pCrv) ; if ( nSide != nSideRef) continue ; - } + } } - vCrvs.emplace_back( Release( pCrv)) ; - } - } - } + vCrvs.emplace_back( Release( pCrv)) ; + } + } + } } // concateno le curve ottenute if ( vCrvs.size() == 1) vOffs.emplace_back( Release( vCrvs[0])) ; - else if ( ! vCrvs.empty()) { + else if ( ! vCrvs.empty()) { ChainCurves chainC ; chainC.Init( true, 10 * EPS_SMALL, int( vCrvs.size())) ; for ( int i = 0 ; i < int( vCrvs.size()) ; ++ i) { @@ -754,14 +754,14 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) vCrvs[nInd]->Invert() ; // aggiungo alla composita if ( ! pCrvCompo->AddCurve( Release( vCrvs[nInd]))) - return false ; + return false ; } if ( pCrvCompo->IsValid()) { pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; vOffs.emplace_back( Release( pCrvCompo)) ; - } + } } - } + } // libero la memoria di vroni utilizzata per calcolare bisettore m_vroni->apiFreeBisectorBuffer() ; @@ -775,11 +775,11 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) { // calcola i punti e le tangenti sui bisettori del medial axis in corrispondenza del valore di offset richiesto - + vResult.clear() ; if ( abs( dOffs) < EPS_SMALL) @@ -792,12 +792,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) // verifico se necessario ricalcolo Voronoi UpdateVoronoi( dOffs) ; - // indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare + // indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare // la chiusura solo sulla prima curva. Eventualmente da estendere) bool bLeft = true, bRight = true ; if ( m_vpCrvs[0]->IsClosed()) { bLeft = dOffs < 0 ; - bRight = ! bLeft ; + bRight = ! bLeft ; } // calcolo medial axis @@ -826,12 +826,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) double dPar ; Point3d ptTemp ; Vector3d vtDir ; - if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) + if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) return false ; vtDir.Normalize() ; vResult.emplace_back( pt, vtDir) ; - } + } } // libero la memoria di vroni utilizzata per calcolare bisettori @@ -846,23 +846,23 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) } //---------------------------------------------------------------------------- -bool +bool 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 ; if ( ! CalcVroniOffset( OffsList, abs( dOffs))) return false ; - + // sistemo le curve di offset calcolate con vroni bool bClosed = m_vpCrvs[0]->IsClosed() ; for ( auto pCrvOffs : OffsList) { @@ -910,7 +910,7 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo } //---------------------------------------------------------------------------- -bool +bool Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) { OffsList.clear() ; @@ -931,21 +931,21 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) m_vroni->apiComputeOff( false, &sTmp[0], false, false, dOffs, 0.0, false, true, true) ; // recupero le curve di offset da vroni - int nOffsCnt = m_vroni->GetOffsetCount() ; + int nOffsCnt = m_vroni->GetOffsetCount() ; for ( int i = 0 ; i < nOffsCnt ; i++) { Point3d ptSChain = P_INVALID ; PtrOwner pCrvOffs ( CreateBasicCurveComposite()) ; int nCrvCnt = m_vroni->GetOffsetCurveCount( i) ; // numero di sottocurve for ( int j = 0 ; j < nCrvCnt ; j ++) { - // recupero la sottocurva da vroni + // recupero la sottocurva da vroni Point3d ptS, ptE, ptC ; int nType ; int nOrigCrv, nOrigLoop, nOrigPnt ; // sito m_vroni->GetOffsetCurve( i, j, nType, ptS.v, ptE.v, ptC.v, nOrigLoop, nOrigCrv, nOrigPnt) ; if ( j == 0) - pCrvOffs->AddPoint( ptS) ; + pCrvOffs->AddPoint( ptS) ; // se estremi coincidenti la curva va ignorata ( da vroni non possono arrivare circonferenze) // ma controllo se appartiene ad una catena di tratti infinitesimi @@ -954,7 +954,7 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( ! AreSamePointApprox( ptSChain, ptE)) { if ( ! pCrvOffs->AddLine( ptE)) return false ; - ptSChain = P_INVALID ; + ptSChain = P_INVALID ; } } else { @@ -970,52 +970,43 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) if ( ! pCrvOffs->AddLine( ptE)) return false ; } - else { + else { PtrOwner pArc( CreateBasicCurveArc()) ; if ( ! pArc->SetC2P( ptC, ptS, ptE)) { // se raggio minore di EPS_SMALL approssimo con linea if ( AreSamePointApprox( ptC, ptS)) { if ( ! pCrvOffs->AddLine( ptE)) - return false ; + return false ; } else - return false ; + return false ; } else { // verifico orientamento double dAng = pArc->GetAngCenter() ; if ( ( nType == CCW && dAng < - EPS_ANG_SMALL) || ( nType == CW && dAng > EPS_ANG_SMALL)) pArc->ToExplementary() ; - // verifico se l'arco degenera in segmento - Point3d ptMLine = Media( ptS, ptE) ; - Point3d ptMArc ; pArc->GetMidPoint( ptMArc) ; - if ( Dist( ptMLine, ptMArc) < EPS_SMALL) { - if ( ! pCrvOffs->AddLine( ptE)) - return false ; - } - else { - // aggiungo alla composita - if ( ! pCrvOffs->AddCurve( Release( pArc))) - return false ; - } - } + // aggiungo alla composita + if ( ! pCrvOffs->AddCurve( Release( pArc))) + return false ; + } } // setto come info la sottocurva da cui si è generata int nCurrCrvId = pCrvOffs->GetCurveCount() - 1 ; pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigCrv + 1, 0) ; pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigLoop, 1) ; - // verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva + // verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva // aperta e chiusa) if ( nOrigCrv == -1) { int nOrigCrvCnt = 1 ; if ( m_vpCrvs[nOrigLoop]->GetType() == CRV_COMPO) nOrigCrvCnt = GetBasicCurveComposite( m_vpCrvs[nOrigLoop])->GetCurveCount() ; if ( nOrigPnt == 0 || nOrigPnt == nOrigCrvCnt) { - double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ; + double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ; pCrvOffs->SetCurveTempParam( nCurrCrvId, dParam, 0) ; } - } + } } // rimuovo tratti di lunghezza inferiore a 5 * EPS_SMALL @@ -1023,8 +1014,8 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) // aggiungo la curva alla lista degli offset if ( ! IsNull( pCrvOffs) && pCrvOffs->IsValid() && pCrvOffs->GetCurveCount() > 0) - OffsList.push_back( Release( pCrvOffs)) ; - } + OffsList.push_back( Release( pCrvOffs)) ; + } // libero la memoria di vroni dedicata agli offset m_vroni->apiFreeOffsetData() ; @@ -1038,11 +1029,11 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) } //---------------------------------------------------------------------------- -bool +bool Voronoi::UpdateVoronoi( double dOffs) { // calcolo il bound necessario per l'offset desiderato - double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ; + double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ; if ( ! m_bVDComputed || dNeededBound > m_nBound) { // aggiorno il valore del bound int nBound = ( int)( ceil( dNeededBound) + 0.5) ; @@ -1054,9 +1045,9 @@ Voronoi::UpdateVoronoi( double dOffs) } //---------------------------------------------------------------------------- -ICRVCOMPOPOVECTOR -Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const -{ +ICRVCOMPOPOVECTOR +Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const +{ ICRVCOMPOPOVECTOR vResult ; int nSideRef = dOffs < EPS_SMALL ? MDS_LEFT : MDS_RIGHT ; @@ -1074,13 +1065,13 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const // controllo la curva complessiva int nSide = GetOffsetCurveSide( pCompo->GetCurve( 0)) ; if ( nSide == nSideRef) - vResult.emplace_back( pCompo->Clone()) ; + vResult.emplace_back( pCompo->Clone()) ; } - else { + else { // scorro la curva eliminando le giunzioni relative a curve aperte e le sottocurve che si trovano dal lato sbagliato PtrOwner pCompoCurr( CreateBasicCurveComposite()) ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; i ++) { - bool bKeep = true ; + bool bKeep = true ; double dParTmp ; pCompo->GetCurveTempParam( i, dParTmp) ; if ( abs( dParTmp - VRONI_JUNCTION_OPEN) < EPS_SMALL) bKeep = false ; @@ -1096,8 +1087,8 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const if ( pCompoCurr->IsValid()) { vResult.emplace_back( Release( pCompoCurr)) ; pCompoCurr.Set( CreateBasicCurveComposite()) ; - } - } + } + } } // salvo eventuale ultima curva if ( pCompoCurr->IsValid()) @@ -1111,17 +1102,17 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const vResult.pop_back() ; } } - + return vResult ; } //--------------------------------------------------------------------------- -int -Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const -{ +int +Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const +{ if ( pCrv == nullptr) return -1 ; - + Point3d ptM ; pCrv->GetMidPoint( ptM) ; // recupero curva e sottocurva di riferimento dalle temp prop @@ -1130,8 +1121,8 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const const ICurve* pCrvRef = m_vpCrvs[nOrigCrv] ; if ( nOrigSubCrv != 0 && m_vpCrvs[nOrigCrv]->GetType() == CRV_COMPO) { const CurveComposite* pCompoOrig = GetBasicCurveComposite( m_vpCrvs[nOrigCrv]) ; - if ( pCompoOrig != nullptr) - pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ; + if ( pCompoOrig != nullptr) + pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ; } DistPointCurve distPC( ptM, *pCrvRef) ; @@ -1141,9 +1132,9 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const } //--------------------------------------------------------------------------- -bool -Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const -{ +bool +Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const +{ for ( int i = 0 ; i < pCrv->GetCurveCount() ; i++) { // cerco il tratto associato alla prima sottocurva originale int nOrigCrv ; pCrv->GetCurveTempProp( i, nOrigCrv) ; @@ -1163,15 +1154,15 @@ Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const //--------------------------------------------------------------------------- bool -Voronoi::Translate( const Vector3d & vtMove) -{ +Voronoi::Translate( const Vector3d & vtMove) +{ if ( ! IsValid()) return false ; return m_Frame.Translate( vtMove) ; } //--------------------------------------------------------------------------- -bool +bool Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg) { if ( ! IsValid()) @@ -1180,7 +1171,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg) } //--------------------------------------------------------------------------- -bool +bool Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { if ( ! IsValid()) @@ -1189,7 +1180,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, doub } //--------------------------------------------------------------------------- -bool +bool Voronoi::ToGlob( const Frame3d& frRef) { if ( ! IsValid()) @@ -1198,7 +1189,7 @@ Voronoi::ToGlob( const Frame3d& frRef) } //--------------------------------------------------------------------------- -bool +bool Voronoi::ToLoc( const Frame3d& frRef) { if ( ! IsValid()) @@ -1207,7 +1198,7 @@ Voronoi::ToLoc( const Frame3d& frRef) } //--------------------------------------------------------------------------- -bool +bool Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { if ( ! IsValid()) @@ -1216,7 +1207,7 @@ Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) } //--------------------------------------------------------------------------- -bool +bool Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) { if ( nCrv < 0 || nCrv > int( m_vpCrvs.size()) - 1) @@ -1230,14 +1221,14 @@ Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) // verifico se necessario calcolo Voronoi if ( ! m_bVDComputed) CalcVoronoi() ; - + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { // verifico se è un bisettore relativo alla curva richiesta e dal lato opportuno if ( m_vroni->IsRelatedEdge( i, nCrv, bLeft)) { // calcolo i parametri del bisettore double dParS, dParE ; m_vroni->GetBisectorParams( i, dParS, dParE) ; - dOffs = max( { dParS, dParE, dOffs}) ; + dOffs = max( { dParS, dParE, dOffs}) ; } }