EgtGeomKernel :

- In CalcPocketing aggiunto parametro per ottimizzazione Offsets
- In CavToolSurfTm aggiunta funzione per Test griglia di punti con parametro di alzata dell'utensile e normali dei triangoli coinvolti
- In SurfTriMesh aggiunta funzione per calcolo dei Loop su una Part specifica.
This commit is contained in:
Riccardo Elitropi
2025-02-21 11:09:45 +01:00
parent 3b9f6773f2
commit 730dd396f4
6 changed files with 368 additions and 8 deletions
+234 -7
View File
@@ -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<bool> 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 ;
}
+4
View File
@@ -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,
+2 -1
View File
@@ -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())
BIN
View File
Binary file not shown.
+127
View File
@@ -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)
+1
View File
@@ -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 ;