From 3e6aa0d81b07f18b21d1fca951e330d803cf4df3 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Wed, 15 May 2024 10:57:37 +0200 Subject: [PATCH 1/2] EgtGeomKernel : - creazione Zmap aggiungendo TriMesh. --- VolZmap.cpp | 184 +++++++++++++++++++++++++++++++++- VolZmap.h | 15 ++- VolZmapCreation.cpp | 93 ++++++++++++++++++ VolZmapGraphics.cpp | 34 ++++--- VolZmapVolume.cpp | 233 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 534 insertions(+), 25 deletions(-) diff --git a/VolZmap.cpp b/VolZmap.cpp index cb1b028..352d434 100644 --- a/VolZmap.cpp +++ b/VolZmap.cpp @@ -25,6 +25,8 @@ #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtNumUtils.h" +#include "/EgtDev/Include/EGkIntersLineSurfTm.h" +#include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include #include @@ -1500,7 +1502,187 @@ VolZmap::GetPartMinDistFromPoint( const Point3d& ptP) const //---------------------------------------------------------------------------- bool -VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt) +VolZmap::AddSurfTm( const ISurfTriMesh* pStm) +{ + // controllo sulla superficie + double dVol ; + if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() || + ! pStm->GetVolume( dVol) || dVol < 0) + return false ; + + // controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente + BBox3d BBox_stm, BBox_curr ; + if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr)) + return false ; + BBox3d BBox_inters ; + if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty()) + return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap + Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone + + // ciclo sulle griglie + bool bCompleted = true ; + for ( int g = 0 ; g < m_nMapNum ; ++ g) { + // definisco dei sistemi di riferimento ausiliari + Frame3d frMapFrame ; + if ( g == 0) + frMapFrame = m_MapFrame ; + else if ( g == 1) + frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ; + else if ( g == 2) + frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ; + + // oggetto per calcolo massivo intersezioni + IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ; + + // numero massimo di thread + int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ; + vector> vRes ; + vRes.resize( nThreadMax) ; + // se dimensione griglia in X maggiore di dimensione Y + if ( m_nNx[g] > m_nNy[g]) { + int nDexNum = m_nNx[g] / nThreadMax ; + int nRemainder = m_nNx[g] % nThreadMax ; + int nInfI = 0 ; + int nSupI = 0 ; + // aggiungo le parti interessate alla mappa + for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { + nInfI = nSupI ; + nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; + vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g, + nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; + } + } + // se dimensione griglia in Y maggiore di dimensione X + else { + int nDexNum = m_nNy[g] / nThreadMax ; + int nRemainder = m_nNy[g] % nThreadMax ; + int nInfJ = 0 ; + int nSupJ = 0 ; + // aggiungo le parti interessate alla mappa + for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) { + nInfJ = nSupJ ; + nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ; + vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g, + 0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()), + ref( *pStm), ref( intPLSTM)) ; + } + } + + // ciclo per attendere che tutti gli async abbiano terminato. + int nTerminated = 0 ; + while ( nTerminated < nThreadMax) { + for ( int nL = 0 ; nL < nThreadMax ; ++ nL) { + // async terminato + if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) { + ++ nTerminated ; + bCompleted = bCompleted && vRes[nL].get() ; + } + } + } + + if ( ! bCompleted) + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +VolZmap::MakeUniform( double dToler) +{ + // controllo validità dello Zmap + if ( ! IsValid()) + return false ; + // la tolleranza deve essere minore dello step + dToler = min( dToler, 0.95 * m_dStep) ; + + // creo lo Zmpa che andrà a sostituire il corrente + PtrOwner pOldVolZmap( CloneBasicVolZmap( this)) ; + if ( IsNull( pOldVolZmap)) + return false ; + + // ciclo sulle griglie + for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) { + // salvo lo Zmap prima di modificare gli spilloni + PtrOwner pVolZMapCurrGrid( CloneBasicVolZmap( this)) ; + if ( IsNull( pVolZMapCurrGrid)) + return false ; + // ciclo sul numero di dexel presenti + for ( int nDex = 0 ; nDex < int( m_Values[nGrid].size()) ; ++ nDex) { + // se il dexel corrente non ha sotto-intervalli passo al successivo + if ( int( m_Values[nGrid][nDex].size()) == 0) + continue ; + // indici del dexel + int nI = nDex % m_nNx[nGrid] ; + int nJ = nDex / m_nNx[nGrid] ; + // salvo le informazioni dei sotto-intervalli del dexel corrente + vector vInfo ; + for ( int nExtr = 0 ; nExtr < int( m_Values[nGrid][nDex].size()) ; ++ nExtr) + vInfo.push_back( m_Values[nGrid][nDex][nExtr]) ; + // per ogni sotto-intervallo, estendo a destra e a sinistra della tolleranza + int nSub_intervals = int( vInfo.size()) ; + // scorro gli intervalli + for ( int nInfo = 0 ; nInfo < int( pVolZMapCurrGrid->m_Values[nGrid][nDex].size()) ; ++ nInfo) { + // estremo inferiore + if ( vInfo[nInfo].dMin - dToler > m_dMinZ[nGrid]) { + AddIntervals( nGrid, nI, nJ, + vInfo[nInfo].dMin - dToler, + vInfo[nInfo].dMin + dToler, + vInfo[nInfo].vtMinN, vInfo[nInfo].vtMinN, vInfo[nInfo].nToolMin, + true) ; + // se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due + // direzioni nel voxel corrispondente + if ( IsTriDexel() && dToler > 0.5 * m_dStep - EPS_SMALL && + nSub_intervals != int( m_Values[nGrid][nDex].size())) { + nSub_intervals = int( m_Values[nGrid][nDex].size()) ; // aggiorno gli intervalli correnti + // l'intervallo corrente si è unito con il precedente... + AddMissingIntervalsInVoxel( pOldVolZmap, nGrid, nI, nJ, vInfo[nInfo].dMin, dToler, + vInfo[nInfo].vtMinN, vInfo[nInfo].vtMinN, + vInfo[nInfo].nToolMin) ; + } + } + // estremo superiore + if ( vInfo[nInfo].dMax + dToler < m_dMaxZ[nGrid]) { + AddIntervals( nGrid, nI, nJ, + vInfo[nInfo].dMax - dToler, + vInfo[nInfo].dMax + dToler, + vInfo[nInfo].vtMaxN, vInfo[nInfo].vtMaxN, vInfo[nInfo].nToolMax, + true) ; + if ( IsTriDexel() && dToler > 0.5 * m_dStep - EPS_SMALL && + nSub_intervals != int( m_Values[nGrid][nDex].size())) { + nSub_intervals = int( m_Values[nGrid][nDex].size()) ; // aggiorno gli intervalli correnti + AddMissingIntervalsInVoxel( pOldVolZmap, nGrid, nI, nJ, vInfo[nInfo].dMax, dToler, + vInfo[nInfo].vtMaxN, vInfo[nInfo].vtMaxN, + vInfo[nInfo].nToolMax) ; + } + } + } + // per ogni sotto-intervallo ricavato fino ad ora, restringo della tolleranza + // ( NB. avendo aggiunto intervalli, il dexel può modificare la sua struttura interna ) + for ( int nInfo = 0 ; nInfo < int( m_Values[nGrid][nDex].size()) ; ++ nInfo) { + // ( NB. la rimozione di un intervallo ora va definita per intervalli a destra e a sinistra, + // altrimenti rimuovo parti in eccesso ) + if ( ! pVolZMapCurrGrid->m_Values[nGrid][nDex].empty()) { + if ( nInfo != 0 || + pVolZMapCurrGrid->m_Values[nGrid][nDex][0].dMin - dToler > m_dMinZ[nGrid]) + m_Values[nGrid][nDex][nInfo].dMin += dToler ; + if ( nInfo != int( m_Values[nGrid][nDex].size()) - 1 || + pVolZMapCurrGrid->m_Values[nGrid][nDex].back().dMax + dToler < m_dMaxZ[nGrid]) + m_Values[nGrid][nDex][nInfo].dMax -= dToler ; + } + } + } + } + + return true ; +} + + +//---------------------------------------------------------------------------- +bool +VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt) { // Controllo sulla validità della griglia if ( nGrid < 0 || nGrid > 2) diff --git a/VolZmap.h b/VolZmap.h index 85034ef..c7fcb86 100644 --- a/VolZmap.h +++ b/VolZmap.h @@ -143,6 +143,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW VolZmap* ClonePart( int nPart) const override ; bool RemovePart( int nPart) override ; int GetPartMinDistFromPoint( const Point3d& ptP) const override ; + bool AddSurfTm( const ISurfTriMesh* pStm) override ; + bool MakeUniform( double dToler) override ; public : // IGeoObjRW int GetNgeId( void) const override ; @@ -243,9 +245,15 @@ class VolZmap : public IVolZmap, public IGeoObjRW INTVECTOR& vAdjBlockVoxComp, INTVECTOR& vAdjBordBlockVoxComp) const ; // OPERAZIONI SU INTERVALLI bool SubtractIntervals( int nGrid, int nI, int nJ, - double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum) ; + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap = false) ; bool AddIntervals( int nGrid, int nI, int nJ, - double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum) ; + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap = false) ; + bool AddMissingIntervalsInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, double dZ, double dToler, + Vector3d vtToolMin, Vector3d vtToolMax, int nToolNum) ; + bool AddSubIntervalInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, int nK, double& dMin, double& dMax, + Vector3d& vtMin, Vector3d& vtMax) ; // Spostamenti utensile bool MillingTranslationStep( const Point3d& ptPs, const Point3d& ptPe, const Vector3d& vtD, const Vector3d& vtA) ; bool MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, const Vector3d& vtAs, @@ -422,6 +430,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW // Funzione per crezione solido in parallelo bool CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; + bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ; @@ -455,6 +465,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW } ; std::vector> m_Values[N_MAPS] ; // dexel delle 3 griglie + int m_nShape ; // Forma : 0 generica, 1 box, 2 estrusione int m_nVoxNumPerBlock ; // Numero di voxel per blocco diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index a6a9d6a..b5abb62 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -597,6 +597,99 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co return true ; } +bool +VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig, + const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) +{ + // controllo sui parametri + if ( nMap < 0 || nMap > 2 || + nInfI < 0 || nInfI > m_nNx[nMap] || + nSupI < 0 || nSupI > m_nNx[nMap] || + nInfJ < 0 || nInfJ > m_nNy[nMap] || + nSupJ < 0 || nSupJ > m_nNy[nMap]) + return false ; + + // determinazione e ridimensionamento dei dexel interni alla trimesh + for ( int i = nInfI ; i < nSupI ; ++ i) { + for ( int j = nInfJ ; j < nSupJ ; ++ j) { + + // definisco la retta da intersecare con la trimesh + double dX = ( i + 0.5) * m_dStep ; + double dY = ( j + 0.5) * m_dStep ; + Point3d ptP0( dX, dY, 0) ; + + // intersezioni della retta con la TriMesh + ILSIVECTOR IntersectionResults ; + intPLSTM.GetInters( ptP0, vtLen.v[(nMap+2)%3], IntersectionResults) ; + + // rimuovo le intersezioni in eccesso + for ( int nI = 0 ; nI < int( IntersectionResults.size()) - 3 ; ++ nI) { + int nJ = nI + 1 ; // prima successiva + int nK = nJ + 1 ; // seconda successiva + int nT = nK + 1 ; // terza successiva + // determino i segni delle 4 intersezioni tra la linea e il trangolo della TriMesh + int nSgnI = IntersectionResults[nI].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nI].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnJ = IntersectionResults[nJ].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nJ].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnK = IntersectionResults[nK].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nK].dCosDN > -EPS_SMALL ? 0 : - 1 ; + int nSgnT = IntersectionResults[nT].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nT].dCosDN > -EPS_SMALL ? 0 : - 1 ; + // parametri dell'intersezione sulla linea + double dUJ = IntersectionResults[nJ].dU ; + double dUK = IntersectionResults[nK].dU ; + // controllo coerenza con segni... + if ( nSgnI != 0 && nSgnI == nSgnJ && + nSgnK != 0 && nSgnK == nSgnT && + nSgnI == - nSgnT && + abs( dUJ - dUK) < EPS_SMALL) { + // ... ed elimino le intersezioni in eccesso... + IntersectionResults.erase( IntersectionResults.begin() + nK) ; + IntersectionResults.erase( IntersectionResults.begin() + nJ) ; + } + } + + int nInt = int( IntersectionResults.size()) ; // numero di intersezioni valide + int nPos = j * m_nNx[nMap] + i ; // posizione del dexel corrente + bool bInside = false ; // Flag entrata/uscita per tratto di retta + Point3d ptIn ; Vector3d vtInN ; + + // per ogni intersezione valida trovata... + for ( int k = 0 ; k < nInt ; ++ k) { + // ricavo il tipo di intersezione + int nIntType = IntersectionResults[k].nILTT ; + // se c'è intersezione + if ( nIntType != ILTT_NO) { + // ricavo il cos tra i vettori ( normale del triangolo e tangente alla retta) + double dCos = IntersectionResults[k].dCosDN ; + + // se entro nella superficie trimesh... + if ( dCos < - EPS_SMALL) { + ptIn = IntersectionResults[k].ptI ; // punto di intersezione + int nT = IntersectionResults[k].nT ; // triangolo di interesse + int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse + Surf.GetFacetNormal( nF, vtInN) ; + bInside = true ; // entrata + } + // ...se esco dalla superficie trimesh ( prima sono per forza entrato) + else if ( dCos > EPS_SMALL && bInside) { + Point3d ptOut = IntersectionResults[k].ptI ; // punto di intersezione + int nT = IntersectionResults[k].nT ; // triangolo di interesse + int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse + Vector3d vtOutN ; Surf.GetFacetNormal( nF, vtOutN) ; // vettore d'uscita + + // Aggiungo un tratto al dexel + AddIntervals( nMap, i, j, + ptIn.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3], + ptOut.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3], + vtInN, vtOutN, 0, true) ; + bInside = false ; // uscita + } + } + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex) diff --git a/VolZmapGraphics.cpp b/VolZmapGraphics.cpp index d79817f..001a6aa 100644 --- a/VolZmapGraphics.cpp +++ b/VolZmapGraphics.cpp @@ -3327,12 +3327,12 @@ VolZmap::IsThereMat( int nI, int nJ, int nK) const nK *= m_nDexVoxRatio ; // Se l'indice è alla frontiera del reticolo non vi è materiale - if ( nI <= - 1 || nI >= int( m_nNx[0]) || + if ( nI <= - 1 || nI >= int( m_nNx[0]) || nJ <= - 1 || nJ >= int( m_nNy[0]) || - nK <= - 1 || nK >= int( m_nNy[1])) + nK <= - 1 || nK >= int( m_nNy[1])) return false ; - // ciclo sulle griglie + // ciclo sulle griglie int nCount = 0 ; int nMinPos[3] = { -1, -1, -1} ; int nMinIndex[3] ; @@ -3361,18 +3361,22 @@ VolZmap::IsThereMat( int nI, int nJ, int nK) const } // verifica spillone su vertice double dMinDist = INFINITO ; - int nIndex = 0 ; + int nIndex = 0 ; int nPos = nGrJ * m_nNx[nGrid] + nGrI ; nDexSize[nGrid] = int( m_Values[nGrid][nPos].size()) ; + // scorro i sotto-interalli dello spillone while ( nIndex < nDexSize[nGrid]) { + // distanza tra la "Z" attuale e il parametro minimo e massimo dell'intervallo nIndex-esimo double dDistInf = dZ[nGrid] - m_Values[nGrid][nPos][nIndex].dMin + 2 * EPS_SMALL ; double dDistSup = dZ[nGrid] - m_Values[nGrid][nPos][nIndex].dMax - 2 * EPS_SMALL ; + // se "Z" attuale a cavallo tra queste due distanze... if ( dDistInf > 0. && dDistSup < 0.) { - nMinIndex[nGrid] = nIndex ; + nMinIndex[nGrid] = nIndex ; // aggiorno l'indice ++ nCount ; - bInterOnNode[nGrid] = true ; + bInterOnNode[nGrid] = true ; // flag T per griglia zero break ; } + // se "Z" attuale tutta sopra o tutta sotto else { double dDist = min( abs( dDistInf), abs( dDistSup)) ; if ( dDist < dMinDist) { @@ -3380,16 +3384,22 @@ VolZmap::IsThereMat( int nI, int nJ, int nK) const nMinIndex[nGrid] = nIndex ; dMinDist = dDist ; } - } + } + // sotto-intervallo successivo nIndex += 1 ; } - } - if ( nCount == 3) + } // fine ciclo sulle griglie + + if ( nCount == 3) // ... se interno a tutte e 3 le griglie, allora c'è materiale ... return true ; - else if ( nCount == 2) { + else if ( nCount == 2) { // ... se interno solo a 2 griglie ... + // recupero la griglia sulla quale è esterno int nGrid = ( bInterOnNode[0] ? ( bInterOnNode[1] ? 2 : 1) : 0) ; + // se tale griglia non ha sotto-intervalli allora non c'è materiale if ( nDexSize[nGrid] == 0) return false ; + // se il valore in "Z" dello spillone è vicino al punto ( 1/10 dello step), aggiorno il + // parametro minimo e massimo e considero la presenza di materiale if ( dZ[nGrid] > m_Values[nGrid][nMinPos[nGrid]][nMinIndex[nGrid]].dMin - 0.1 * m_dStep && dZ[nGrid] < m_Values[nGrid][nMinPos[nGrid]][nMinIndex[nGrid]].dMax + 0.1 * m_dStep) { double dDistInf = abs( dZ[nGrid] - m_Values[nGrid][nMinPos[nGrid]][nMinIndex[nGrid]].dMin) ; @@ -3401,9 +3411,9 @@ VolZmap::IsThereMat( int nI, int nJ, int nK) const return true ; } else - return false ; + return false ; } - else + else // ... se invece interno a 1 o a nessuna delle griglie, allora non c'è materiale return false ; } diff --git a/VolZmapVolume.cpp b/VolZmapVolume.cpp index 03f5561..9466788 100644 --- a/VolZmapVolume.cpp +++ b/VolZmapVolume.cpp @@ -30,7 +30,8 @@ using namespace std ; //---------------------------------------------------------------------------- bool VolZmap::SubtractIntervals( int nGrid, int nI, int nJ, - double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum) + double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, + int nToolNum, bool bSkipSwap) { // Controllo che dMin e dMax non siano quasi coincidenti if ( abs( dMax - dMin) < EPS_ZERO) @@ -54,13 +55,13 @@ VolZmap::SubtractIntervals( int nGrid, int nI, int nJ, } // Riporto le coordinate cicliche delle normali nell'ordine di partenza (da griglia a sistema intrinseco) - if ( nGrid == 1) { + 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 ( nGrid == 2) { + else if ( !bSkipSwap && nGrid == 2) { swap( vtNmi.y, vtNmi.z) ; swap( vtNmi.x, vtNmi.z) ; swap( vtNma.y, vtNma.z) ; @@ -250,7 +251,8 @@ VolZmap::SubtractIntervals( int nGrid, int nI, int nJ, //---------------------------------------------------------------------------- bool VolZmap::AddIntervals( int nGrid, int nI, int nJ, - double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax, int nToolNum) + 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) @@ -272,19 +274,23 @@ VolZmap::AddIntervals( int nGrid, int nI, int nJ, // Restringo minimo e massimo entro i limiti della mappa if ( dMin < m_dMinZ[nGrid]) { dMin = m_dMinZ[nGrid] ; - vtNmi = - Z_AX ; + if ( ! bSkipSwap) + vtNmi = - Z_AX ; } else if ( dMin > m_dMaxZ[nGrid]) { dMin = m_dMaxZ[nGrid] ; - vtNmi = - Z_AX ; + if ( ! bSkipSwap) + vtNmi = - Z_AX ; } if ( dMax < m_dMinZ[nGrid]) { dMax = m_dMinZ[nGrid] ; - vtNma = Z_AX ; + if ( ! bSkipSwap) + vtNma = Z_AX ; } else if ( dMax > m_dMaxZ[nGrid]) { dMax = m_dMaxZ[nGrid] ; - vtNma = Z_AX ; + if ( ! bSkipSwap) + vtNma = Z_AX ; } // Controllo che dMin e dMax non siano quasi coincidenti @@ -292,13 +298,13 @@ VolZmap::AddIntervals( int nGrid, int nI, int nJ, return true ; // Riporto le coordinate cicliche nell'ordine di partenza - if ( nGrid == 1) { + 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 ( nGrid == 2) { + else if ( !bSkipSwap && nGrid == 2) { swap( vtNmi.y, vtNmi.z) ; swap( vtNmi.x, vtNmi.z) ; swap( vtNma.y, vtNma.z) ; @@ -600,6 +606,213 @@ VolZmap::AddIntervals( int nGrid, int nI, int nJ, return true ; } +//---------------------------------------------------------------------------- +bool +VolZmap::AddSubIntervalInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, int nK, + double& dMin, double& dMax, Vector3d& vtMin, Vector3d& vtMax) +{ + // se non Tridex, esco + if ( ! IsTriDexel()) + return true ; + + // 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 ; + + // valori di default + vector vTdMin = { -1., -1., -1., -1.} ; + vector vTdMax = { -1., -1., -1., -1.} ; + VCT3DVECTOR vtNMin = { V_INVALID, V_INVALID, V_INVALID, V_INVALID} ; + VCT3DVECTOR vtNMax = { V_INVALID, V_INVALID, V_INVALID, V_INVALID} ; + + // se esiste un precedente lungo x-locale + if ( nI != 0) { + int nPos = nJ * m_nNx[nGrid] + ( nI - 1) ; // recupero posizione dexel + // cerco l'intervallo corretto sullo Zmap di riferimento + for ( int it = 0 ; it < int( VolZmapRef->m_Values[nGrid][nPos].size()) ; ++ it) { + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMax + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMax - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMax[0] = VolZmapRef->m_Values[nGrid][nPos][it].vtMaxN ; + vTdMax[0] = VolZmapRef->m_Values[nGrid][nPos][it].dMax ; + } + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMin + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMin - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMin[0] = VolZmapRef->m_Values[nGrid][nPos][it].vtMinN ; + vTdMin[0] = VolZmapRef->m_Values[nGrid][nPos][it].dMin ; + } + } + } + // se esiste il successivo lungo x-locale + if ( nI != m_dMaxZ[( nGrid + 2) % 3]) { + int nPos = nJ * m_nNx[nGrid] + ( nI + 1) ; // recupero posizione dexel + for ( int it = 0 ; it < int( VolZmapRef->m_Values[nGrid][nPos].size()) ; ++ it) { + // cerco l'intervallo corretto sullo Zmap di riferimento + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMax + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMax - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMax[1] = VolZmapRef->m_Values[nGrid][nPos][it].vtMaxN ; + vTdMax[1] = VolZmapRef->m_Values[nGrid][nPos][it].dMax ; + } + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMin + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMin - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMin[1] = VolZmapRef->m_Values[nGrid][nPos][it].vtMinN ; + vTdMin[1] = VolZmapRef->m_Values[nGrid][nPos][it].dMin ; + } + } + } + // se esiste il precedente lungo y-locale + if ( nJ != 0) { + int nPos = ( nJ - 1) * m_nNx[nGrid] + nI ; // recupero posizione dexel + for ( int it = 0 ; it < int( VolZmapRef->m_Values[nGrid][nPos].size()) ; ++ it) { + // cerco l'intervallo corretto sullo Zmap di riferimento + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMax + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMax - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMax[2] = VolZmapRef->m_Values[nGrid][nPos][it].vtMaxN ; + vTdMax[2] = VolZmapRef->m_Values[nGrid][nPos][it].dMax ; + } + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMin + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMin - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMin[2] = VolZmapRef->m_Values[nGrid][nPos][it].vtMinN ; + vTdMin[2] = VolZmapRef->m_Values[nGrid][nPos][it].dMin ; + } + } + } + // se esiste il successivo lungo y-locale + if ( nJ != m_dMaxZ[( nGrid + 1) % 3]) { + int nPos = ( nJ + 1) * m_nNx[nGrid] + nI ; // recupero posizione dexel + // cerco l'intervallo corretto sullo Zmap di riferimento + for ( int it = 0 ; it < int( VolZmapRef->m_Values[nGrid][nPos].size()) ; ++ it) { + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMax + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMax - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMax[3] = VolZmapRef->m_Values[nGrid][nPos][it].vtMaxN ; + vTdMax[3] = VolZmapRef->m_Values[nGrid][nPos][it].dMax ; + } + if ( VolZmapRef->m_Values[nGrid][nPos][it].dMin + EPS_SMALL > nK * m_dStep && + VolZmapRef->m_Values[nGrid][nPos][it].dMin - EPS_SMALL < ( nK + 1) * m_dStep) { + vtNMin[3] = VolZmapRef->m_Values[nGrid][nPos][it].vtMinN ; + vTdMin[3] = VolZmapRef->m_Values[nGrid][nPos][it].dMin ; + } + } + } + + // scelgo le normali che si discostano il meno possibile dalla normale della faccia del voxel + + // analisi dei massimi e delle normali --------------------------- + // 1) angolo minimo tra la normale trovata la faccia del voxel + double dMinAngle = ANG_FULL ; + // 2) vettore di riferimento per la direzione della normale + vtMax = ( nGrid == 0 ? m_MapFrame.VersZ() : + ( nGrid == 1 ? m_MapFrame.VersX() : m_MapFrame.VersY())) ; + Vector3d vtRef = vtMax ; + // 3) determino il massimo per questo intervallo + dMax = ( nK + 1) * m_dStep ; + for ( int i = 0 ; i < 4 ; ++ i) { // scorro le normali + if ( vtNMax[i].IsValid()) { // se normale trovata, quindi valida... + double dCurrAngle ; // angolo corrente tra la normale della TriMesh e quella della faccia del voxel + vtNMax[i].GetAngle( vtRef, dCurrAngle) ; + if ( abs( dCurrAngle) < dMinAngle) { // se angolo minore del minimo trovato... + // aggiorno i parametri + dMinAngle = dCurrAngle ; + vtMax = vtNMax[i] ; + dMax = vTdMax[i] ; + } + } + } + + // analisi dei minimi e delle normali --------------------------- + dMinAngle = ANG_FULL ; + vtRef.Invert() ; + dMin = nK * m_dStep ; + vtMin = vtRef ; + for ( int i = 0 ; i < 4 ; ++ i) { + if ( vtNMin[i].IsValid()) { + double dCurrAngle ; + vtNMin[i].GetAngle( vtRef, dCurrAngle) ; + if ( abs( dCurrAngle) < dMinAngle) { + dMinAngle = dCurrAngle ; + vtMin = vtNMin[i] ; + dMin = vTdMin[i] ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +VolZmap::AddMissingIntervalsInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, double dZ, double dToler, + Vector3d vtToolMin, Vector3d vtToolMax, int nToolNum) +{ + + // se non Tridex, esco + if ( ! IsTriDexel()) + return true ; + + // 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 ; + + // passo da indici di dexel a indici di voxel + nI /= m_nDexVoxRatio ; + nJ /= m_nDexVoxRatio ; + + // numero di voxel nel dexel corrente + int nVoxNum = int( m_nNy[(( nGrid+1) % 3)] / m_nDexVoxRatio + + ( m_nNy[(( nGrid+1) % 3)] % m_nDexVoxRatio == 0 ? 1 : 2)) ; + + int nK = 0 ; + for ( int i = 0 ; i < nVoxNum ; ++ i) { + // controllo se sono nel voxel corrente + if ( i * m_dStep < dZ && ( i + 1) * m_dStep > dZ) { + nK = i ; + break ; + } + } + + // ----------- griglia successiva ----------- + { + int nMyGrid = ( nGrid + 1) % 3 ; + int nMyI = nJ ; + int nMyJ = nK ; + int nMyK = nI ; + double dMyMin ; + double dMyMax ; + Vector3d vtMyMin ; + Vector3d vtMyMax ; + AddSubIntervalInVoxel( VolZmapRef, nMyGrid, nMyI, nMyJ, nMyK, dMyMin, dMyMax, vtMyMin, vtMyMax) ; + AddIntervals( nMyGrid, nMyI, nMyJ, dMyMin - EPS_SMALL, dMyMax + EPS_SMALL, vtMyMin, vtMyMax, + nToolNum, true) ; + } + + // ----------- griglia precedente ----------- + { + int nMyGrid = ( nGrid + 2) % 3 ; + int nMyI = nK ; + int nMyJ = nI ; + int nMyK = nJ ; + double dMyMin ; + double dMyMax ; + Vector3d vtMyMin ; + Vector3d vtMyMax ; + AddSubIntervalInVoxel( VolZmapRef, nMyGrid, nMyI, nMyJ, nMyK, dMyMin, dMyMax, vtMyMin, vtMyMax) ; + AddIntervals( nMyGrid, nMyI, nMyJ, dMyMin - EPS_SMALL, dMyMax + EPS_SMALL, vtMyMin, vtMyMax, + nToolNum, true) ; + } + + return true ; + +} + // ------------------------- LAVORAZIONI -------------------------------------------------------------------------------------- //---------------------------------------------------------------------------- From c0b5f38301f8a2749e09bdeaeb55401744096f0f Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 16 May 2024 13:06:55 +0200 Subject: [PATCH 2/2] EgtGeomKernel : - migliorie alle funzioni SharpRectSwept e BeveledRectSwept - migliorie varie. --- PolyLine.cpp | 58 ++--- StmFromCurves.cpp | 516 ++++++++++++++++++++++++++++++-------------- VolZmap.cpp | 1 - VolZmapCreation.cpp | 1 - 4 files changed, 388 insertions(+), 188 deletions(-) diff --git a/PolyLine.cpp b/PolyLine.cpp index 3e0ff5a..2e1f3d1 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -1,4 +1,4 @@ -//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : PolyLine.cpp Data : 22.12.13 Versione : 1.4l3 @@ -53,7 +53,7 @@ PolyLine::AddUPoint( double dPar, const Point3d& ptP, bool bEndOrStart) { // se da aggiungere in coda if ( bEndOrStart) { - // se il punto è uguale all'ultimo (ignoro parametro), non lo inserisco ma ok + // se il punto è uguale all'ultimo (ignoro parametro), non lo inserisco ma ok if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.back().first)) { ++ m_nRejected ; return true ; @@ -68,7 +68,7 @@ PolyLine::AddUPoint( double dPar, const Point3d& ptP, bool bEndOrStart) } // altrimenti si aggiunge in testa else { - // se il punto è uguale al primo (ignoro parametro), non lo inserisco ma ok + // se il punto è uguale al primo (ignoro parametro), non lo inserisco ma ok if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.front().first)) { ++ m_nRejected ; return true ; @@ -92,7 +92,7 @@ PolyLine::Close( void) // ci devono essere almeno 2 punti if ( m_lUPoints.size() < 2) return false ; - // verifico non sia già chiuso + // verifico non sia già chiuso if ( AreSamePointApprox( m_lUPoints.front().first, m_lUPoints.back().first)) return false ; // aggiungo un punto uguale al primo in coda @@ -219,7 +219,7 @@ PolyLine::ToLoc( const Frame3d& frRef) bool PolyLine::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { - // se i due riferimenti coincidono, non devo fare alcunché + // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; // ciclo sui punti @@ -233,7 +233,7 @@ PolyLine::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) bool PolyLine::Join( PolyLine& PL, double dOffsetPar) { - // se l'altra polilinea non contiene alcunchè, esco con ok + // se l'altra polilinea non contiene alcunchè, esco con ok if ( PL.m_lUPoints.size() == 0) return true ; // verifico che l'ultimo punto di questa polilinea coincida con il primo dell'altra @@ -385,7 +385,7 @@ PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP, bool bNotFirst) const bool PolyLine::GetCurrUPoint( double* pdPar, Point3d* pptP) const { - // verifico validità punto corrente + // verifico validità punto corrente if ( m_iter == m_lUPoints.end()) return false ; @@ -426,7 +426,7 @@ PolyLine::GetFirstULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* bool PolyLine::GetNextULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const { - // parametro e punto iniziali (è il precedente finale) + // parametro e punto iniziali (è il precedente finale) if ( m_iter == m_lUPoints.end()) return false ; if ( pdIni != nullptr) @@ -510,19 +510,19 @@ PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) co ptsPCA.AddPoint( Media( ptP1, ptP2, 0.25), dLen / 2) ; ptsPCA.AddPoint( Media( ptP1, ptP2, 0.75), dLen / 2) ; } - // recupero il rango, ovvero la dimensionalità dell'insieme di punti + // recupero il rango, ovvero la dimensionalità dell'insieme di punti nRank = ptsPCA.GetRank() ; // se dimensione nulla, o non ci sono punti o sono tutti praticamente coincidenti if ( nRank == 0) return ptsPCA.GetCenter( ptCen) ; // se dimensione 1, allora i punti sono distribuiti su una linea if ( nRank == 1) { - // assegno il centro e la direzione della linea (il verso è indifferente) + // assegno il centro e la direzione della linea (il verso è indifferente) ptsPCA.GetCenter( ptCen) ; ptsPCA.GetPrincipalComponent( 0, vtDir) ; return true ; } - // altrimenti dimensione 2 o 3, allora è determinato un piano principale, verifico se tutti i punti vi giacciono + // altrimenti dimensione 2 o 3, allora è determinato un piano principale, verifico se tutti i punti vi giacciono // Center and normal vector ptsPCA.GetCenter( ptCen) ; Vector3d vtX, vtY ; @@ -530,9 +530,9 @@ PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) co ptsPCA.GetPrincipalComponent( 1, vtY) ; vtDir = vtX ^ vtY ; if ( ! vtDir.Normalize()) { - // riduco la dimensionalità a lineare + // riduco la dimensionalità a lineare nRank = 1 ; - // assegno il centro e la direzione della linea (il verso è indifferente) + // assegno il centro e la direzione della linea (il verso è indifferente) ptsPCA.GetCenter( ptCen) ; vtDir = vtX ; return true ; @@ -561,12 +561,12 @@ PolyLine::IsFlat( Plane3d& plPlane, double dToler) const plPlane.Reset() ; return false ; } - // recupero dati sulla planarità della polilinea + // recupero dati sulla planarità della polilinea int nRank ; Point3d ptCen ; Vector3d vtDir ; bool bFlat = IsFlat( nRank, ptCen, vtDir, dToler) ; - // imposto il piano a seconda della dimensionalità + // imposto il piano a seconda della dimensionalità switch ( nRank) { case 0 : // punto plPlane.Set( ptCen, Z_AX) ; @@ -639,13 +639,13 @@ PolyLine::GetAreaXY( double& dArea) const // verifico sia chiusa if ( ! IsClosed()) return false ; - // calcolo l'area considerando solo XY (è la Z di Newell) + // calcolo l'area considerando solo XY (è la Z di Newell) dArea = 0 ; Point3d ptIni, ptFin ; for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { dArea += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy } - // considero anche la linea tra l'ultimo e il primo punto perchè in alcuni casi potrebbero definire area + // considero anche la linea tra l'ultimo e il primo punto perchè in alcuni casi potrebbero definire area // significativa anche se sono coincidenti per le nostre tolleranze ptIni = ptFin ; GetFirstPoint( ptFin) ; @@ -746,7 +746,7 @@ DouglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const } } - // se la distanza massima trovata è sopra la tolleranza, allora controllo la parte di PolyLine tra + // se la distanza massima trovata è sopra la tolleranza, allora controllo la parte di PolyLine tra // (nIndStart, nMaxInd) e quella tra (nMaxInd, nIndEnd) if ( dMaxSqDist > dSqTol) { // inserisco il punto @@ -789,7 +789,7 @@ PolyLine::RemoveAlignedPoints( double dToler) } // altrimenti chiusa else { - // cerco il punto più distante dal primo + // cerco il punto più distante dal primo double dMaxDist = 0. ; int nMaxInd = 0 ; for ( int i = 1 ; i < int( vPtU.size()) ; ++ i) { @@ -966,7 +966,7 @@ PolyLine::MyApproxOnSide( const Vector3d& vtN, bool bLeftSide, double dToler) } } } - // non è stato eliminato alcunché + // non è stato eliminato alcunché // ripristino la tolleranza corrente dCurrToler = dToler ; // avanzo il terzetto di uno step @@ -1007,7 +1007,7 @@ PolyLine::MakeConvex( const Vector3d& vtN, bool bLeftSide) bool PolyLine::MyMakeConvex( const Vector3d& vtN, bool bLeftSide) { - // ciclo i controlli finchè non ci sono rimozioni + // ciclo i controlli finchè non ci sono rimozioni bool bRemoved = true ; while ( bRemoved) { bRemoved = false ; @@ -1035,7 +1035,7 @@ PolyLine::MyMakeConvex( const Vector3d& vtN, bool bLeftSide) bRemoved = true ; continue ; } - // non è stato eliminato alcunché : avanzo il terzetto di uno step + // non è stato eliminato alcunché : avanzo il terzetto di uno step precP = currP ; currP = nextP ; ++ nextP ; @@ -1062,7 +1062,7 @@ PolyLine::Invert( bool bInvertU) m_lUPoints.reverse() ; // se richiesto, inverto anche il parametro U if ( bInvertU) { - // recupero il primo valore di U che è il vecchio finale ed è il riferimento di inversione + // recupero il primo valore di U che è il vecchio finale ed è il riferimento di inversione double dUfin = m_lUPoints.front().second ; // ciclo su tutti gli elementi for ( auto& UPoint : m_lUPoints) { @@ -1277,7 +1277,7 @@ PolyLine::GetMinAreaRectangleXY( Point3d& ptCen, Vector3d& vtAx, double& dLen, d bool PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut) { - // se vuota non faccio alcunché + // se vuota non faccio alcunché if ( m_lUPoints.size() == 0) return false ; @@ -1379,7 +1379,7 @@ IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler return false ; // Riferimento alla lista dei punti PNTULIST& List = const_cast( plPoly).GetUPointList() ; - // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto double dMinSqDist = SQ_INFINITO ; Point3d ptMinDist ; auto itMinDistEnd = List.end() ; @@ -1468,7 +1468,7 @@ GetPointParamOnPolyLine( const Point3d& ptP, const PolyLine& plPoly, double dTol // assegno nuovo inizio ptStart = ptEnd ; } - // Il punto è sulla linea se la sua distanza rispetta la tolleranza + // Il punto è sulla linea se la sua distanza rispetta la tolleranza return ( dMinSqDist < dToler * dToler) ; } @@ -1481,7 +1481,7 @@ ChangePolyLineStart( PolyLine& plPoly, const Point3d& ptNewStart, double dToler) return false ; // Riferimento alla lista dei punti PNTULIST& LoopList = const_cast( plPoly).GetUPointList() ; - // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto double dMinSqDist = SQ_INFINITO ; auto itMinDistEnd = LoopList.end() ; auto itStart = LoopList.begin() ; @@ -1525,7 +1525,7 @@ SplitPolyLineAtPoint( const PolyLine& plPoly, const Point3d& ptP, double dToler, return false ; // Riferimento alla lista dei punti const PNTULIST& LoopList = const_cast( plPoly).GetUPointList() ; - // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto double dMinSqDist = SQ_INFINITO ; auto itMinDistEnd = LoopList.end() ; auto itStart = LoopList.begin() ; @@ -1608,7 +1608,7 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV if ( nMinJ < nLastJ) nMinJ = nLastJ ; - // verifica se è un punto interno in comune con l'altra polyline + // verifica se è un punto interno in comune con l'altra polyline if ( i < nTotP1 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL) bCommonInternalPoints = true ; diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index 2d6d14e..c548740 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -330,9 +330,11 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, { // verifico che la linea guida sia piana Plane3d plGuide ; - if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) + if ( ! pGuide->IsFlat( plGuide, true, 10 * EPS_SMALL)) return nullptr ; - Vector3d vtNorm = plGuide.GetVersN() ; + Vector3d vtNorm ; pGuide->GetExtrusion( vtNorm) ; + if ( vtNorm.IsSmall()) + vtNorm = Z_AX ; // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; // curve di offset @@ -355,7 +357,7 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, PtrOwner pSrfBot( pSrfTop->Clone()) ; if ( IsNull( pSrfBot)) return nullptr ; - pSrfBot->Translate( -dDimV * vtNorm) ; + pSrfBot->Translate( - dDimV * vtNorm) ; pSrfBot->Invert() ; PtrOwner pSrfRgt( GetSurfTriMeshByExtrusion( pCrvR, -dDimV * vtNorm, false, dLinTol)) ; if ( IsNull( pSrfRgt)) @@ -407,81 +409,131 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { // step di rotazione per rispettare la tolleranza double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; - // aggiungo il cap sull'inizio - Point3d ptStart ; - pGuide->GetStartPoint( ptStart) ; - Vector3d vtStart ; - pGuide->GetStartDir( vtStart) ; - vtStart.Rotate( vtNorm, 0, 1) ; - PolyLine PLStart ; - PLStart.AddUPoint( 0, ptStart) ; - PLStart.AddUPoint( 1, ptStart + dDimH / 2 * vtStart) ; - PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dDimV * vtNorm) ; - PLStart.AddUPoint( 3, ptStart - dDimV * vtNorm) ; - PtrOwner pSci( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) - return nullptr ; - pSci->Invert() ; - // per le facce con normale parallela a vtNorm, evito di creare giunzioni a T sull'asse di rotazione - for ( int i = 0 ; i < pSci->GetFacetCount() ; ++ i) { - Vector3d vtN ; - // se la faccia ha normale parallela a vtNorm... - if ( pSci->GetFacetNormal( i, vtN) && - AreSameOrOppositeVectorEpsilon( vtN, vtNorm, 5 * EPS_SMALL)) { - // ... ricavo il loop - POLYLINEVECTOR vLoops ; - if ( ! pSci->GetFacetLoops( i, vLoops) || vLoops.empty()) - return nullptr ; - // lo semplifico - vLoops[0].RemoveAlignedPoints( 5 * EPS_SMALL) ; - // eseguo triangolazione e aggiungo la faccia alla Soup - PtrOwner pStmNewFace( CreateSurfTriMesh()) ; - if ( IsNull( pStmNewFace) || - ! pStmNewFace->CreateByFlatContour( vLoops[0])) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmNewFace) ; + // se l'offset interno alla guida è chiuso + if ( pCrvL->IsClosed()) { + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + Point3d ptRight ; pCrvR->GetEndPoint( ptRight) ; + Point3d ptLeft ; pCrvR->GetStartPoint( ptLeft) ; + Point3d ptJunction ; pCrvL->GetStartPoint( ptJunction) ; + Point3d ptCenter = Media( ptRight, ptLeft) ; + Vector3d vtRight = ptRight - ptCenter ; + Vector3d vtLeft = ptLeft - ptCenter ; + double dAng = ANG_STRAIGHT ; + vtRight.GetAngle( vtLeft, dAng) ; + vtRight.Normalize() ; + PolyLine plLoop ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptRight) ; // primo punto + double dAngStep = ceil( dAng / dStepRotDeg) ; // aggiusto lo step + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptRight ; + ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; // punto intermedio sulla circonferenza } - // altrimenti faccia con normale non parallela a vtNorm, aggiungo tutti i triangoli - else - stmSoup.AddSurfTriMesh( *pSci->CloneFacet( i)) ; + plLoop.AddUPoint( dAngStep ++, ptLeft) ; // ultimo punto + plLoop.AddUPoint( dAngStep ++, ptJunction) ; // punto centrale sull'offset chiuso + plLoop.AddUPoint( dAngStep, ptRight) ; // polyLine chiusa + // superificie Top + PtrOwner pStmTop( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop) || ! pStmTop->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop) ; + // superificie Bottom + PtrOwner pStmBottom( CloneSurfTriMesh( pStmTop)) ; + pStmBottom->Translate( - dDimV * vtNorm) ; + pStmBottom->Invert() ; + stmSoup.AddSurfTriMesh( *pStmBottom) ; + // superificie perpendicolare + // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra + plLoop.EraseLastUPoint() ; // apro il loop + plLoop.EraseLastUPoint() ; // tolgo il punto di contatto sull'offset + PtrOwner pStmPerp( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp) || ! pStmPerp->CreateByExtrusion( plLoop, - vtNorm * dDimV) || + ! pStmPerp->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp) ; } - // aggiungo il cap sulla fine - Point3d ptEnd ; - pGuide->GetEndPoint( ptEnd) ; - Vector3d vtEnd ; - pGuide->GetEndDir( vtEnd) ; - vtEnd.Rotate( vtNorm, 0, -1) ; - PolyLine PLEnd ; - PLEnd.AddUPoint( 0, ptEnd) ; - PLEnd.AddUPoint( 1, ptEnd + dDimH / 2 * vtEnd) ; - PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dDimV * vtNorm) ; - PLEnd.AddUPoint( 3, ptEnd - dDimV * vtNorm) ; - PtrOwner pSce( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) - return nullptr ; - pSce->Invert() ; - // per le facce con normale parallela a vtNorm, evito di creare giunzioni a T sull'asse di rotazione - for ( int i = 0 ; i < pSce->GetFacetCount() ; ++ i) { - Vector3d vtN ; - // se la faccia ha normale parallela a vtNorm... - if ( pSce->GetFacetNormal( i, vtN) && - AreSameOrOppositeVectorEpsilon( vtN, vtNorm, 5 * EPS_SMALL)) { - // ... ricavo il loop - POLYLINEVECTOR vLoops ; - if ( ! pSce->GetFacetLoops( i, vLoops) || vLoops.empty()) - return nullptr ; - // lo semplifico - vLoops[0].RemoveAlignedPoints( 5 * EPS_SMALL) ; - // eseguo triangolazione e aggiungo la faccia alla Soup - PtrOwner pStmNewFace( CreateSurfTriMesh()) ; - if ( IsNull( pStmNewFace) || - ! pStmNewFace->CreateByFlatContour( vLoops[0])) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmNewFace) ; + // se l'offset interno della guida è aperto... + else { + // aggiungo il cap sull'inizio + Point3d ptStart ; + pGuide->GetStartPoint( ptStart) ; + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + Point3d ptSLeft ; pCrvL->GetStartPoint( ptSLeft) ; + Point3d ptSRight ; pCrvR->GetStartPoint( ptSRight) ; + Vector3d vtLeft = ptSLeft - ptStart ; + Vector3d vtRight = ptSRight - ptStart ; + double dAng = ANG_STRAIGHT ; + vtLeft.GetAngle( vtRight, dAng) ; + vtLeft.Normalize() ; + PolyLine plLoop ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptSLeft) ; // primo punto + double dAngStep = ceil( dAng / dStepRotDeg) ; + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSLeft ; + ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; } - // altrimenti faccia con normale non parallela a vtNorm, aggiungo tutti i triangoli - else - stmSoup.AddSurfTriMesh( *pSce->CloneFacet( i)) ; + plLoop.AddUPoint( dAngStep, ptSRight) ; // ultimo punto + plLoop.AddUPoint( dAngStep + 1, ptSLeft) ; // polyline chiusa + // creo la superficie Top + PtrOwner pStmTop_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop_start) || ! pStmTop_start->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop_start) ; + // superificie Bottom + PtrOwner pStmBottom_start( CloneSurfTriMesh( pStmTop_start)) ; + pStmBottom_start->Translate( - dDimV * vtNorm) ; + pStmBottom_start->Invert() ; + stmSoup.AddSurfTriMesh( *pStmBottom_start) ; + // superificie perpendicolare + // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra + plLoop.EraseLastUPoint() ; // apro il loop + PtrOwner pStmPerp_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp_start) || ! pStmPerp_start->CreateByExtrusion( plLoop, - vtNorm * dDimV) || + ! pStmPerp_start->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp_start) ; + // aggiungo il cap sulla fine + Point3d ptEnd ; + pGuide->GetEndPoint( ptEnd) ; + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + pCrvL->GetEndPoint( ptSLeft) ; + pCrvR->GetEndPoint( ptSRight) ; + vtLeft = ptSLeft - ptEnd ; + vtRight = ptSRight - ptEnd ; + dAng = ANG_STRAIGHT ; + vtRight.GetAngle( vtLeft, dAng) ; + vtRight.Normalize() ; + plLoop.Clear() ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptSRight) ; + dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSRight ; + ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; + } + plLoop.AddUPoint( dAngStep, ptSLeft) ; // ultimo punto + plLoop.AddUPoint( dAngStep + 1, ptSRight) ; // polyline chiusa + // creo la superficie Top + PtrOwner pStmTop_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop_end) || ! pStmTop_end->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop_end) ; + // creo la superificie Bottom + PtrOwner pStmBottom_end( CloneSurfTriMesh( pStmTop_end)) ; + pStmBottom_end->Translate( - dDimV * vtNorm) ; + pStmBottom_end->Invert() ; + stmSoup.AddSurfTriMesh( *pStmBottom_end) ; + // creo la superificie perpendicolare alla guida + plLoop.EraseLastUPoint() ; // apro il loop + PtrOwner pStmPerp_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp_end) || ! pStmPerp_end->CreateByExtrusion( plLoop, - vtNorm * dDimV) || + ! pStmPerp_end->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp_end) ; } // completo unione e recupero la superficie risultante if ( ! stmSoup.End()) @@ -509,13 +561,13 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub // verifico che la linea guida sia piana Plane3d plGuide ; - if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) + if ( ! pGuide->IsFlat( plGuide, true, 10 * EPS_SMALL)) return nullptr ; - // assegno la normale del piano - Vector3d vtNorm = plGuide.GetVersN() ; + Vector3d vtNorm ; pGuide->GetExtrusion( vtNorm) ; + if ( vtNorm.IsSmall()) + vtNorm = Z_AX ; // determino il punto centrale della sezione - Point3d ptCen ; - pGuide->GetStartPoint( ptCen) ; + Point3d ptCen ; pGuide->GetStartPoint( ptCen) ; ptCen -= dDimV / 2 * vtNorm ; // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; @@ -544,7 +596,6 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub for ( int i = 0 ; i < NUM_OFFS && bOk ; ++ i) bOk = vOffsCrv[i].Make( pGuide, vDist[i], ICurve::OFF_FILLET) ; } - if ( ! bOk || vOffsCrv[0].GetCurveCount() == 0 || vOffsCrv[1].GetCurveCount() == 0 || vOffsCrv[2].GetCurveCount() == 0 || vOffsCrv[3].GetCurveCount() == 0) @@ -640,85 +691,235 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub else if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { // step di rotazione per rispettare il tipo o la tolleranza double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; - // aggiungo il cap sull'inizio - Point3d ptStart ; - pGuide->GetStartPoint( ptStart) ; - Vector3d vtStart ; - pGuide->GetStartDir( vtStart) ; - vtStart.Rotate( vtNorm, 0, 1) ; - PolyLine PLStart ; - PLStart.AddUPoint( 0, ptStart) ; - PLStart.AddUPoint( 1, ptStart + ( dDimH / 2 - dBevelH) * vtStart) ; - PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dBevelV * vtNorm) ; - PLStart.AddUPoint( 3, ptStart + dDimH / 2 * vtStart - ( dDimV - dBevelV) * vtNorm) ; - PLStart.AddUPoint( 4, ptStart + ( dDimH / 2 - dBevelH) * vtStart - dDimV * vtNorm) ; - PLStart.AddUPoint( 5, ptStart - dDimV * vtNorm) ; - PtrOwner pSci( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) - return nullptr ; - pSci->Invert() ; - // per le facce con normale parallela a vtNorm, evito di creare giunzioni a T sull'asse di rotazione - for ( int i = 0 ; i < pSci->GetFacetCount() ; ++ i) { - Vector3d vtN ; - // se la faccia ha normale parallela a vtNorm... - if ( pSci->GetFacetNormal( i, vtN) && - AreSameOrOppositeVectorEpsilon( vtN, vtNorm, 5 * EPS_SMALL)) { - // ... ricavo il loop - POLYLINEVECTOR vLoops ; - if ( ! pSci->GetFacetLoops( i, vLoops) || vLoops.empty()) - return nullptr ; - // lo semplifico - vLoops[0].RemoveAlignedPoints( 5 * EPS_SMALL) ; - // eseguo triangolazione e aggiungo la faccia alla Soup - PtrOwner pStmNewFace( CreateSurfTriMesh()) ; - if ( IsNull( pStmNewFace) || - ! pStmNewFace->CreateByFlatContour( vLoops[0])) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmNewFace) ; + // se l'offset interno della guida è chiuso... + if ( pCrvL->IsClosed()) { + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + Point3d ptRight ; pCrvR->GetEndPoint( ptRight) ; + Point3d ptLeft ; pCrvR->GetStartPoint( ptLeft) ; + Point3d ptJunction ; pCrvL->GetStartPoint( ptJunction) ; + Point3d ptCenter = Media( ptRight, ptLeft) ; + Vector3d vtRight = ptRight - ptCenter ; + Vector3d vtLeft = ptLeft - ptCenter ; + double dAng = ANG_STRAIGHT ; + vtRight.GetAngle( vtLeft, dAng) ; + vtRight.Normalize() ; + PolyLine plLoop ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptRight) ; // primo punto + double dAngStep = ceil( dAng / dStepRotDeg) ; // aggiusto lo step + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptRight ; + ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; // punto intermedio sulla circonferenza } - // altrimenti faccia con normale non parallela a vtNorm, aggiungo tutti i triangoli - else - stmSoup.AddSurfTriMesh( *pSci->CloneFacet( i)) ; + plLoop.AddUPoint( dAngStep ++, ptLeft) ; // ultimo punto + plLoop.AddUPoint( dAngStep ++, ptJunction) ; // punto centrale sull'offset chiuso + plLoop.AddUPoint( dAngStep, ptRight) ; // polyLine chiusa + // superificie Top + PtrOwner pStmTop( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop) || ! pStmTop->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop) ; + // superificie Bottom + PtrOwner pStmBottom( CloneSurfTriMesh( pStmTop)) ; + if ( IsNull( pStmBottom) || ! pStmBottom->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmBottom) ; + // calcolo l'angolo di rotazione per la faccia Top del bevel + // NB. Questo angolo va ricalcolato, il bevel è inclinato rispetto alla normale della guida + ptCenter.Translate( - dBevelV * vtNorm) ; + Point3d ptbRight ; pCrvRb->GetEndPoint( ptbRight) ; + Point3d ptbLeft ; pCrvRb->GetStartPoint( ptbLeft) ; + Vector3d vtbLeft = ptbLeft - ptCenter ; + Vector3d vtbRight = ptbRight - ptCenter ; + dAng = ANG_STRAIGHT ; + vtbRight.GetAngle( vtbLeft, dAng) ; + vtbRight.Normalize() ; + // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra + plLoop.EraseLastUPoint() ; // apro il loop + plLoop.EraseLastUPoint() ; // tolgo il punto di contatto sull'offset + // creo il loop defininendo i punti + PolyLine plLoopB ; + plLoopB.AddUPoint( 0, ptbRight) ; + dAngStep = ceil( dAng / dStepRotDeg) ; + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptbRight ; + ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; + plLoopB.AddUPoint( i, ptRot) ; + } + plLoopB.AddUPoint( dAngStep, ptbLeft) ; + // creo la superficie Top Bevel + PtrOwner pStmbTop_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmbTop_start) || + ! pStmbTop_start->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || + ! pStmbTop_start->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbTop_start) ; + // creo la superificie Bottom Bevel + PtrOwner pStmbBottom_start( CloneSurfTriMesh( pStmbTop_start)) ; + if ( IsNull( pStmbBottom_start) || ! pStmbBottom_start->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbBottom_start) ; + // creo la superficie perpendicolare alla guida + PolyLine plLoopB1 = plLoopB ; + plLoopB1.Mirror( ptCen, vtNorm) ; + PtrOwner pStmPerp( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp) || + ! pStmPerp->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || + ! pStmPerp->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp) ; } - // aggiungo il cap sulla fine - Point3d ptEnd ; - pGuide->GetEndPoint( ptEnd) ; - Vector3d vtEnd ; - pGuide->GetEndDir( vtEnd) ; - vtEnd.Rotate( vtNorm, 0, -1) ; - PolyLine PLEnd ; - PLEnd.AddUPoint( 0, ptEnd) ; - PLEnd.AddUPoint( 1, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd) ; - PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dBevelV * vtNorm) ; - PLEnd.AddUPoint( 3, ptEnd + dDimH / 2 * vtEnd - ( dDimV - dBevelV) * vtNorm) ; - PLEnd.AddUPoint( 4, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd - dDimV * vtNorm) ; - PLEnd.AddUPoint( 5, ptEnd - dDimV * vtNorm) ; - PtrOwner pSce( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) - return nullptr ; - pSce->Invert() ; - // per le facce con normale parallela a vtNorm, evito di creare giunzioni a T sull'asse di rotazione - for ( int i = 0 ; i < pSce->GetFacetCount() ; ++ i) { - Vector3d vtN ; - // se la faccia ha normale parallela a vtNorm... - if ( pSce->GetFacetNormal( i, vtN) && - AreSameOrOppositeVectorEpsilon( vtN, vtNorm, 5 * EPS_SMALL)) { - // ... ricavo il loop - POLYLINEVECTOR vLoops ; - if ( ! pSce->GetFacetLoops( i, vLoops) || vLoops.empty()) - return nullptr ; - // lo semplifico - vLoops[0].RemoveAlignedPoints( 5 * EPS_SMALL) ; - // eseguo triangolazione e aggiungo la faccia alla Soup - PtrOwner pStmNewFace( CreateSurfTriMesh()) ; - if ( IsNull( pStmNewFace) || - ! pStmNewFace->CreateByFlatContour( vLoops[0])) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmNewFace) ; + // se l'offset interno della guida è aperto... + else { + // aggiungo il cap sull'inizio + Point3d ptStart ; + pGuide->GetStartPoint( ptStart) ; + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + Point3d ptSLeft ; pCrvL->GetStartPoint( ptSLeft) ; + Point3d ptSRight ; pCrvR->GetStartPoint( ptSRight) ; + Vector3d vtLeft = ptSLeft - ptStart ; + Vector3d vtRight = ptSRight - ptStart ; + double dAng = ANG_STRAIGHT ; + vtLeft.GetAngle( vtRight, dAng) ; + vtLeft.Normalize() ; + PolyLine plLoop ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptSLeft) ; // primo punto + double dAngStep = ceil( dAng / dStepRotDeg) ; + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSLeft ; + ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; } - // altrimenti faccia con normale non parallela a vtNorm, aggiungo tutti i triangoli - else - stmSoup.AddSurfTriMesh( *pSce->CloneFacet( i)) ; + plLoop.AddUPoint( dAngStep, ptSRight) ; // ultimo punto + plLoop.AddUPoint( dAngStep + 1, ptSLeft) ; // polyline chiusa + // creo la superficie Top + PtrOwner pStmTop_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop_start) || ! pStmTop_start->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop_start) ; + // creo la superificie Bottom + PtrOwner pStmBottom_start( CloneSurfTriMesh( pStmTop_start)) ; + if ( IsNull( pStmBottom_start) || ! pStmBottom_start->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmBottom_start) ; + // calcolo l'angolo di rotazione per la faccia Top del bevel + ptStart.Translate( - dBevelV * vtNorm) ; + Point3d ptSbLeft ; pCrvLb->GetStartPoint( ptSbLeft) ; + Point3d ptSbRight ; pCrvRb->GetStartPoint( ptSbRight) ; + Vector3d vtbLeft = ptSbLeft - ptStart ; + Vector3d vtbRight = ptSbRight - ptStart ; + dAng = ANG_STRAIGHT ; + vtbLeft.GetAngle( vtbRight, dAng) ; + vtbLeft.Normalize() ; + plLoop.EraseLastUPoint() ; // apro il loop + // creo il loop defininendo i punti + PolyLine plLoopB ; + plLoopB.AddUPoint( 0, ptSbLeft) ; + dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSbLeft ; + ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; + plLoopB.AddUPoint( i, ptRot) ; + } + plLoopB.AddUPoint( dAngStep, ptSbRight) ; // ultimo punto + // creo la superficie Top Bevel + PtrOwner pStmbTop_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmbTop_start) || + ! pStmbTop_start->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || + ! pStmbTop_start->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbTop_start) ; + // creo la superificie Bottom Bevel + PtrOwner pStmbBottom_start( CloneSurfTriMesh( pStmbTop_start)) ; + if ( IsNull( pStmbBottom_start) || ! pStmbBottom_start->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbBottom_start) ; + // creo la superficie perpendicolare alla guida + PolyLine plLoopB1 = plLoopB ; + plLoopB1.Mirror( ptCen, vtNorm) ; + PtrOwner pStmPerp_start( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp_start) || + ! pStmPerp_start->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || + ! pStmPerp_start->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp_start) ; + // aggiungo il cap sulla fine + Point3d ptEnd ; + pGuide->GetEndPoint( ptEnd) ; + // calcolo l'angolo di rotazione per screwing faccia Top e Bottom + pCrvL->GetEndPoint( ptSLeft) ; + pCrvR->GetEndPoint( ptSRight) ; + vtLeft = ptSLeft - ptEnd ; + vtRight = ptSRight - ptEnd ; + dAng = ANG_STRAIGHT ; + vtRight.GetAngle( vtLeft, dAng) ; + vtRight.Normalize() ; + plLoop.Clear() ; + // creo il loop defininendo i punti + plLoop.AddUPoint( 0, ptSRight) ; + dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSRight ; + ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; + plLoop.AddUPoint( i, ptRot) ; + } + plLoop.AddUPoint( dAngStep, ptSLeft) ; // ultimo punto + plLoop.AddUPoint( dAngStep + 1, ptSRight) ; // polyline chiusa + // creo la superficie Top + PtrOwner pStmTop_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmTop_end) || ! pStmTop_end->CreateByFlatContour( plLoop)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmTop_end) ; + // creo la superificie Bottom + PtrOwner pStmBottom_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmBottom_end) || + ! pStmBottom_end->CopyFrom( pStmTop_end) || + ! pStmBottom_end->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmBottom_end) ; + // calcolo l'angolo di rotazione per la faccia Top del bevel + ptEnd.Translate( - dBevelV * vtNorm) ; + pCrvLb->GetEndPoint( ptSbLeft) ; + pCrvRb->GetEndPoint( ptSbRight) ; + vtbLeft = ptSbLeft - ptEnd ; + vtbRight = ptSbRight - ptEnd ; + dAng = ANG_STRAIGHT ; + vtbRight.GetAngle( vtbLeft, dAng) ; + vtbRight.Normalize() ; + plLoop.EraseLastUPoint() ; // apro il loop + // creo il loop defininendo i punti + plLoopB.Clear() ; + plLoopB.AddUPoint( 0, ptSbRight) ; + dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto + for ( int i = 1 ; i < dAngStep ; ++ i) { + Point3d ptRot = ptSbRight ; + ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; + plLoopB.AddUPoint( i, ptRot) ; + } + plLoopB.AddUPoint( dAngStep, ptSbLeft) ; // ultimo punto + // creo la superficie Top Bevel + PtrOwner pStmbTop_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmbTop_end) || + ! pStmbTop_end->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || + ! pStmbTop_end->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbTop_end) ; + // creo la superificie Bottom Bevel + PtrOwner pStmbBottom_end( CloneSurfTriMesh( pStmbTop_end)) ; + if ( IsNull( pStmbBottom_end) || ! pStmbBottom_end->Mirror( ptCen, vtNorm)) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmbBottom_end) ; + // creo la superficie perpendicolare alla guida + plLoopB1 = plLoopB ; + plLoopB1.Mirror( ptCen, vtNorm) ; + PtrOwner pStmPerp_end( CreateSurfTriMesh()) ; + if ( IsNull( pStmPerp_end) || + ! pStmPerp_end->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || + ! pStmPerp_end->Invert()) + return nullptr ; + stmSoup.AddSurfTriMesh( *pStmPerp_end) ; } // completo unione e recupero la superficie risultante if ( ! stmSoup.End()) @@ -738,6 +939,7 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub return Release( pSTM) ; } + //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol) diff --git a/VolZmap.cpp b/VolZmap.cpp index 352d434..2eb7355 100644 --- a/VolZmap.cpp +++ b/VolZmap.cpp @@ -26,7 +26,6 @@ #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" -#include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include #include diff --git a/VolZmapCreation.cpp b/VolZmapCreation.cpp index b5abb62..4fefdee 100644 --- a/VolZmapCreation.cpp +++ b/VolZmapCreation.cpp @@ -647,7 +647,6 @@ VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const } int nInt = int( IntersectionResults.size()) ; // numero di intersezioni valide - int nPos = j * m_nNx[nMap] + i ; // posizione del dexel corrente bool bInside = false ; // Flag entrata/uscita per tratto di retta Point3d ptIn ; Vector3d vtInN ;