diff --git a/CAvToolSurfTm.cpp b/CAvToolSurfTm.cpp index c45176c..bb25fe1 100644 --- a/CAvToolSurfTm.cpp +++ b/CAvToolSurfTm.cpp @@ -80,7 +80,7 @@ CAvToolSurfTm::SetSurfTm( const ISurfTriMesh& Stm) bool CAvToolSurfTm::AddSurfTm( const ISurfTriMesh& Stm) { - // verifico validità superficie + // verifico validità superficie const SurfTriMesh* pStm = GetBasicSurfTriMesh( &Stm) ; if ( pStm == nullptr || ! pStm->IsValid()) return false ; @@ -130,7 +130,7 @@ CAvToolSurfTm::TestPosition( const Point3d& ptT, const Vector3d& vtDir, const Ve // Se direzioni non definite, errore if ( vtDir.IsSmall() || vtMove.IsSmall()) return false ; - // Se riferimento di movimento già presente + // Se riferimento di movimento già presente if ( m_frMove.IsValid()) { // Calcolo nuovo riferimento di movimento Frame3d frMove ; @@ -158,6 +158,108 @@ CAvToolSurfTm::TestPosition( const Point3d& ptT, const Vector3d& vtDir, const Ve return ( dTotDist > - EPS_SMALL) ; } +//---------------------------------------------------------------------------- +bool +CAvToolSurfTm::TestPointAdv( const Point3d& ptT, const Vector3d& vtDir, const Vector3d& vtMove, + double& dTotDist, VCT3DVECTOR& vVtN) const +{ + // Funzione per calcolo collisione tra utensile e superfici; + // dToTDist è la distanza di traslazione del punto ptT lungo vtDir per evitare la collisione, + // vVtN è la normale del triangolo che genera collsione ( NB. Nel caso di più triangoli concorrenti, + // vengono restituite tutte le normali trovate) + + // Inizializzazione parametri + dTotDist = 0 ; + vVtN.clear() ; + // Se utensile non definito, errore + if ( m_Tool.GetType() == Tool::UNDEF) + return false ; + // Se direzioni non definite, errore + if ( vtDir.IsSmall() || vtMove.IsSmall()) + return false ; + // Se riferimento di movimento già presente + if ( m_frMove.IsValid()) { + // Calcolo nuovo riferimento di movimento + Frame3d frMove ; + if ( ! AreSameOrOppositeVectorApprox( vtDir, vtMove)) + frMove.Set( ORIG, vtMove, vtDir) ; + else + frMove.Set( ORIG, vtMove) ; + // Se riferimenti di movimento uguali, sfrutto HashGrid 2d + if ( AreSameFrame( frMove, m_frMove)) { + // calcolo box utensile nel riferimento di movimento + BBox3d b3Tool ; + Point3d ptTL = ptT ; ptTL.ToLoc( m_frMove) ; + Vector3d vtDirL = vtDir ; vtDirL.ToLoc( m_frMove) ; + b3Tool.Add( ptTL) ; + b3Tool.Add( ptTL - vtDirL * m_Tool.GetHeigth()) ; + if ( vtDirL.IsX()) + b3Tool.Expand( 0, m_Tool.GetRadius(), m_Tool.GetRadius()) ; + else if ( vtDirL.IsY()) + b3Tool.Expand( m_Tool.GetRadius(), 0, m_Tool.GetRadius()) ; + else if ( vtDirL.IsZ()) + b3Tool.Expand( m_Tool.GetRadius(), m_Tool.GetRadius(), 0) ; + else { + double dExpandX = m_Tool.GetRadius() * sqrt( 1 - vtDirL.x * vtDirL.x) ; + double dExpandY = m_Tool.GetRadius() * sqrt( 1 - vtDirL.y * vtDirL.y) ; + double dExpandZ = m_Tool.GetRadius() * sqrt( 1 - vtDirL.z * vtDirL.z) ; + b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ; + } + // ciclo sui triangoli che intersecano box in 2d + INTVECTOR vnIds ; + if ( m_HGrids.Find( b3Tool, vnIds)) { + for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) { + // recupero la superficie + int nInd = vnIds[i] ; + int nSurf = GetSurfInd( nInd) ; + if ( nSurf == -1) + return false ; + // recupero il triangolo + int nT = nInd - m_vBaseInd[nSurf] ; + Triangle3d Tria ; + if ( ! m_vSTM[nSurf]->GetTriangle( nT, Tria)) + return false ; + // calcolo della collisione + double dDist = CAvToolTriangle( m_Tool, ptT, vtDir, Tria, m_frMove.VersZ()) ; + if ( dDist < - EPS_SMALL) + return false ; + // se nuova distanza circa uguale a quella massima + if ( dDist > EPS_ZERO && abs( dDist - dTotDist) < 10 * EPS_SMALL) + vVtN.push_back( Tria.GetN()) ; + else if ( dDist > dTotDist + 10 * EPS_SMALL) { + dTotDist = dDist ; + vVtN.clear() ; + vVtN.push_back( Tria.GetN()) ; + } + } + } + return true ; + } + } + // Altrimenti eseguo controllo avanzato diretto + // scorro tutte le superfici + for ( auto pStm : m_vSTM) { + Triangle3d Tria ; + // scorro tutti i trinagoli + for ( int nTria = pStm->GetFirstTriangle( Tria) ; nTria != SVT_NULL ; nTria = pStm->GetNextTriangle( nTria, Tria)) { + double dDist = CAvToolTriangle( m_Tool, ptT, vtDir, Tria, vtMove) ; + if ( dDist < - EPS_SMALL) + return false ; + // se nuova distanza maggiore della massima ... + if ( dDist > dTotDist) { + dTotDist = dDist ; + vVtN.clear() ; + vVtN.push_back( Tria.GetN()) ; + } + // se distanza circa uguale alla massima corrente... + else if ( dDist > EPS_SMALL && dDist > dTotDist - EPS_SMALL) + vVtN.push_back( Tria.GetN()) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool CAvToolSurfTm::TestSeries( PNTUVECTOR& vPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff) @@ -168,7 +270,7 @@ CAvToolSurfTm::TestSeries( PNTUVECTOR& vPntM, const Vector3d& vtDir, const Vecto // Se direzioni non definite, errore if ( vtDir.IsSmall() || vtMove.IsSmall()) return false ; - // Se vettore vuoto, non devo fare alcunché + // Se vettore vuoto, non devo fare alcunché if ( vPntM.empty()) return true ; // Calcolo nuovo riferimento di movimento @@ -239,7 +341,7 @@ CAvToolSurfTm::TestSeries( PNTUVECTOR& vPntM, const Vector3d& vtDir, const Vecto bool CAvToolSurfTm::TestSubSeries( int nId, PNTUVECTOR& vPntM, const Vector3d& vtDir, int nFirst, int nLast, double dProgCoeff) { - // Se vettore vuoto, non devo fare alcunché + // Se vettore vuoto, non devo fare alcunché if ( vPntM.empty()) return true ; // Ciclo sui punti da verificare @@ -279,7 +381,7 @@ CAvToolSurfTm::TestPath( PNTULIST& lPntM, const Vector3d& vtDir, const Vector3d& // Se direzioni non definite, errore if ( vtDir.IsSmall() || vtMove.IsSmall()) return false ; - // Se lista vuota, non devo fare alcunché + // Se lista vuota, non devo fare alcunché if ( lPntM.empty()) return true ; // Controllo la tolleranza lineare (se negativa non vanno fatti controlli sui punti medi) @@ -359,11 +461,97 @@ CAvToolSurfTm::TestPath( PNTULIST& lPntM, const Vector3d& vtDir, const Vector3d& return bOk ; } +//---------------------------------------------------------------------------- +bool +CAvToolSurfTm::TestPointsAdv( PNTUVVECTLIST& lPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff) +{ + // Se utensile non definito, errore + if ( m_Tool.GetType() == Tool::UNDEF) + return false ; + // Se direzioni non definite, errore + if ( vtDir.IsSmall() || vtMove.IsSmall()) + return false ; + // Se lista vuota, non devo fare alcunché + if ( lPntM.empty()) + return true ; + // Calcolo nuovo riferimento di movimento + Frame3d frMove ; + if ( ! AreSameOrOppositeVectorApprox( vtDir, vtMove)) + frMove.Set( ORIG, vtMove, vtDir) ; + else + frMove.Set( ORIG, vtMove) ; + // Se riferimento di movimento non presente o diverso dal calcolato + if ( ! m_frMove.IsValid() || ! AreSameFrame( frMove, m_frMove)) { + // Salvo nuovo riferimento + m_frMove = frMove ; + // Ricalcolo HashGrid + if ( ! PrepareHashGrid()) + return false ; + } + // Determino il numero di punti del path + m_nTotPnt = int( lPntM.size()) ; + // Recupero il numero massimo di thread concorrenti + int nThreadMax = thread::hardware_concurrency() ; + bool bOk = true ; + // Se un solo thread o pochi punti + if ( nThreadMax <= 1 || m_nTotPnt < 500) { + m_nCurrPnt = 0 ; + bOk = TestSubPointsAdv( -1, lPntM, vtDir, vtMove, dProgCoeff) ; + ProcessEvents( int( 100 * dProgCoeff), 0) ; + } + // altrimenti + else { + const int MAX_PARTS = 32 ; + PNTUVVECTLIST vlPntM[MAX_PARTS] ; + // divido la lista in parti + int nPartCnt = min( nThreadMax, MAX_PARTS) ; + int nPartDim = m_nTotPnt / nPartCnt ; + for ( int i = nPartCnt - 1 ; i > 0 ; -- i) { + auto itSplit = prev( lPntM.end(), nPartDim) ; + vlPntM[i].splice( vlPntM[i].end(), lPntM, itSplit, lPntM.end()) ; + vlPntM[i].push_front( lPntM.back()) ; + } + vlPntM[0].splice( vlPntM[0].end(), lPntM) ; + // processo le parti + m_nCurrPnt = 0 ; + m_bBreak = false ; + future vRes[MAX_PARTS] ; + for ( int i = 0 ; i < nPartCnt ; ++ i) + vRes[i] = async( launch::async, &CAvToolSurfTm::TestSubPointsAdv, this, i, ref( vlPntM[i]), cref( vtDir), cref( vtMove), dProgCoeff) ; + // attendo i risultati + int nFin = 0 ; + int nNextPE = 0 ; + while ( nFin < nPartCnt) { + for ( int i = 0 ; i < nPartCnt ; ++ i) { + if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) { + bOk = vRes[i].get() && bOk ; + ++ nFin ; + } + } + if ( m_nCurrPnt > nNextPE) { + int nRes = ProcessEvents( int( m_nCurrPnt * 100. / m_nTotPnt * dProgCoeff), 10) ; + nNextPE += STEP_PE ; + if ( nRes == 1) + m_bBreak = true ; + } + } + // unisco le liste risultati + for ( int i = 0 ; i < nPartCnt ; ++ i) { + if ( i > 0) + lPntM.pop_back() ; + lPntM.splice( lPntM.end(), vlPntM[i]) ; + } + ProcessEvents( int( 100 * dProgCoeff), 0) ; + } + + return bOk ; +} + //---------------------------------------------------------------------------- bool CAvToolSurfTm::TestSubPath( int nId, PNTULIST& lPntM, const Vector3d& vtDir, double dLinTol, double dProgCoeff) { - // Se lista vuota, non devo fare alcunché + // Se lista vuota, non devo fare alcunché if ( lPntM.empty()) return true ; // Ciclo sui punti @@ -405,6 +593,43 @@ CAvToolSurfTm::TestSubPath( int nId, PNTULIST& lPntM, const Vector3d& vtDir, dou return true ; } +//---------------------------------------------------------------------------- +bool +CAvToolSurfTm::TestSubPointsAdv( int nId, PNTUVVECTLIST& lPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff) +{ + // Se lista vuota, non devo fare alcunché + if ( lPntM.empty()) + return true ; + // Ciclo sui punti + auto itPntMPrev = lPntM.end() ; + auto itPntMCurr = lPntM.begin() ; + while ( itPntMCurr != lPntM.end()) { + // verifico il punto + if ( ! TestPointAdv( get<0>( *itPntMCurr), vtDir, vtMove, get<1>( *itPntMCurr), get<2>( *itPntMCurr))) + return false ; + // passo al successivo + itPntMPrev = itPntMCurr ; + ++ itPntMCurr ; + ++ m_nCurrPnt ; + // se singolo thread + if ( nId == -1) { + // gestione eventi (ogni STEP_PE punti) + if (( m_nCurrPnt % STEP_PE) == 0) { + int nRes = ProcessEvents( int( m_nCurrPnt * 100. / m_nTotPnt * dProgCoeff), 0) ; + if ( nRes == 1) + return false ; + } + } + // altrimenti multithread + else { + if ( m_bBreak) + return false ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool CAvToolSurfTm::MyTestMidPointHG( PNTULIST& lPntM, const PNTULIST::iterator& itPntMPrev, const PNTULIST::iterator& itPntMCurr, @@ -485,7 +710,8 @@ CAvToolSurfTm::MyTestPositionHG( Point3d& ptT, const Vector3d& vtDir, Vector3d& double dExpandZ = m_Tool.GetRadius() * sqrt( 1 - vtDirL.z * vtDirL.z) ; b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ; } - // ciclo sui triangoli che intersecano box in 2d + + // ciclo sui triangoli che intersecano box in 2d double dTotDist = 0 ; vtTriaN = V_NULL ; INTVECTOR vnIds ; @@ -509,6 +735,7 @@ CAvToolSurfTm::MyTestPositionHG( Point3d& ptT, const Vector3d& vtDir, Vector3d& return -1 ; } } + return dTotDist ; } diff --git a/CAvToolSurfTm.h b/CAvToolSurfTm.h index 694c87b..7b7f445 100644 --- a/CAvToolSurfTm.h +++ b/CAvToolSurfTm.h @@ -50,8 +50,11 @@ class CAvToolSurfTm : public ICAvToolSurfTm { return ( bApprox ? m_Tool.GetApproxOutline() : m_Tool.GetOutline()) ;} bool TestPosition( const Point3d& ptT, const Vector3d& vtDir, const Vector3d& vtMove, double& dTotDist, Vector3d* pvtTriaN = nullptr) const override ; + bool TestPointAdv( const Point3d& ptT, const Vector3d& vtDir, const Vector3d& vtMove, + double& dTotDist, VCT3DVECTOR& vVtN) const override ; bool TestSeries( PNTUVECTOR& vPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff = 1) override ; bool TestPath( PNTULIST& lPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dLinTol, double dProgCoeff = 1) override ; + bool TestPointsAdv( PNTUVVECTLIST& lPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff = 1) override ; public : CAvToolSurfTm( void) ; @@ -60,6 +63,7 @@ class CAvToolSurfTm : public ICAvToolSurfTm private : bool TestSubSeries( int nId, PNTUVECTOR& vPntM, const Vector3d& vtDir, int nFirst, int nLast, double dProgCoeff) ; bool TestSubPath( int nId, PNTULIST& lPntM, const Vector3d& vtDir, double dLinTol, double dProgCoeff) ; + bool TestSubPointsAdv( int nId, PNTUVVECTLIST& lPntM, const Vector3d& vtDir, const Vector3d& vtMove, double dProgCoeff) ; double MyTestPosition( Point3d& ptT, const Vector3d& vtDir, const Vector3d& vtMove, Vector3d& vtTriaN) const ; double MyTestPositionHG( Point3d& ptT, const Vector3d& vtDir, Vector3d& vtTriaN) const ; bool MyTestMidPointHG( PNTULIST& lPntM, const PNTULIST::iterator& itPntMPrev, const PNTULIST::iterator& itPntMCurr, diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 7f21973..c10778f 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -8572,7 +8572,7 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, bool CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle, int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders, - const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, ICRVCOMPOPOVECTOR& vCrvCompoRes) + const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, ICRVCOMPOPOVECTOR& vCrvCompoRes) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || @@ -8595,6 +8595,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double myParams.bInvert = bInvert ; myParams.bAvoidOpt = bAvoidOpt ; myParams.bAllowZigZagOneWayBorders = bAllowZigZagOneWayBorders ; + myParams.bOptOffsets = ( ! bAllOffs) ; if ( ptEndPrec.IsValid()) myParams.ptStart = ptEndPrec ; if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 71f5e4e..7518f17 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 547753b..3b22004 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -4063,6 +4063,133 @@ SurfTriMesh::GetPartVolume( int nPart, double& dVolume) const return true ; } +//---------------------------------------------------------------------------- +bool +SurfTriMesh::GetPartLoops( int nPart, POLYLINEVECTOR& vPL) const +{ + // verifico lo stato + if ( m_nStatus != OK) + return false ; + vPL.clear() ; + // aggiorno timestamp dei triangoli + ++ m_nTimeStamp ; + for ( auto& Tria : m_vTria) + Tria.nTemp = m_nTimeStamp ; + // incremento time stamp + ++ m_nTimeStamp ; + // recupero il vettore delle Shell che compongono la part + const auto& vShell = m_vPart[nPart].vShell ; + // ciclo sui triangoli + for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) { + // se triangolo valido e non ancora visitato + if ( m_vTria[nT].nIdVert[0] != SVT_DEL && m_vTria[nT].nTemp != m_nTimeStamp && + find( vShell.begin(), vShell.end(), m_vTria[nT].nShell) != vShell.end()) { + // determino i triangoli adiacenti + int nAdjT[3] ; + for ( int j = 0 ; j < 3 ; ++ j) + nAdjT[j] = m_vTria[nT].nIdAdjac[j] ; + // se tutti e tre i lati sono di contorno + if ( nAdjT[0] == SVT_NULL && + nAdjT[1] == SVT_NULL && + nAdjT[2] == SVT_NULL) { + // ho trovato un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + } + // se i due lati 0 e 1 sono di contorno + else if ( nAdjT[0] == SVT_NULL && + nAdjT[1] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 2, m_nTimeStamp, vPL.back())) + return false ; + } + // se i due lati 1 e 2 sono di contorno + else if ( nAdjT[1] == SVT_NULL && + nAdjT[2] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 0, m_nTimeStamp, vPL.back())) + return false ; + } + // se i due lati 2 e 0 sono di contorno + else if ( nAdjT[2] == SVT_NULL && + nAdjT[0] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 1, m_nTimeStamp, vPL.back())) + return false ; + } + // se il lato 0 è di contorno + else if ( nAdjT[0] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 1, m_nTimeStamp, vPL.back())) + return false ; + } + // se il lato 1 è di contorno + else if ( nAdjT[1] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 2, m_nTimeStamp, vPL.back())) + return false ; + } + // se il lato 2 è di contorno + else if ( nAdjT[2] == SVT_NULL) { + // ho trovato l'inizio di un loop + vPL.emplace_back() ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ; + vPL.back().AddUPoint( nT, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ; + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + // cammino lungo il loop fino a chiuderlo + if ( ! MarchAlongLoop( nT, 0, m_nTimeStamp, vPL.back())) + return false ; + } + // altrimenti non c'è contorno + else { + // marco il triangolo come verificato + m_vTria[nT].nTemp = m_nTimeStamp ; + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::RemovePart( int nPart) diff --git a/SurfTriMesh.h b/SurfTriMesh.h index d8ca79f..135ea7e 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -339,6 +339,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool RemovePart( int nPart) override ; bool GetPartArea( int nPart, double& dArea) const override ; bool GetPartVolume( int nPart, double& dVolume) const override ; + bool GetPartLoops( int nPart, POLYLINEVECTOR& vPL) const override ; SurfTriMesh* ClonePart( int nPart) const override ; bool SetTFlag( int nId, int nTFlag) override ; bool GetTFlag( int nId, int& nFlag) const override ;