EgtMachKernel :

- in SawFinishing aggiunto sottotipo "Along5A"
- in SawFinishing correzioni varie.
This commit is contained in:
Riccardo Elitropi
2026-07-10 17:22:19 +02:00
parent 32c20e6eaa
commit 74bf6c65e8
4 changed files with 688 additions and 33 deletions
+2 -2
View File
@@ -2525,8 +2525,8 @@ Operation::VerifyMcentLineMidPoint( const Point3d& ptPrec, const Vector3d& vtDir
bAxError = false ;
Machine* pMachine = m_pMchMgr->GetCurrMachine() ;
// se disposizione non vanno fatti controlli
if ( GetType() == OPER_DISP)
// se disposizione o finitura di cornici con lama non vanno fatti controlli
if ( GetType() == OPER_DISP || GetType() == OPER_SAWFINISHING)
return true ;
// se superato il limite di ricursioni, non devo fare alcunché
+659 -28
View File
@@ -24,6 +24,7 @@
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include "/EgtDev/Include/EGkCurveAux.h"
#include "/EgtDev/Include/EGkSurfLocal.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkOffsetCurve.h"
@@ -59,6 +60,8 @@ using namespace std ;
// 2715 = "Error in SawFinishing : post apply not calculable"
// 2716 = "Error in SawFinishing : special apply not calculable"
// 2717 = "Error in SawFinishing : CalculateSectionToolPath failed"
// 2718 = "Error in SawFinishing : CalculateStraightAlong5AToolPath failed"
// 2719 = "Error in SawFinishing : Splitting Section failed"
// 2751 = "Warning in SawFinishing : Skipped entity (xx)"
// 2752 = "Warning in SawFinishing : No machinable path"
// 2753 = "Warning in SawFinishing : Tool name changed (xx)"
@@ -565,35 +568,45 @@ SawFinishing::Apply( bool bRecalc, bool bPostApply)
if ( m_Params.m_nSubType == SAWFIN_SUB_ALONG) {
if ( m_bStraight) {
if ( ! CalculateStraightAlongToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
return false ;
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
return false ;
}
}
else {
if ( ! CalculateCurvedAlongToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
return false ;
m_pMchMgr->SetLastError( 2709, "Error in SawFinishing : CalculateAlongToolPath failed") ;
return false ;
}
}
}
else if ( m_Params.m_nSubType == SAWFIN_SUB_ACROSS) {
if ( m_bStraight) {
if ( ! CalculateStraightAcrossToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
return false ;
}
}
else {
if ( ! CalculateCurvedAcrossToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ;
return false ;
}
}
}
else if ( m_Params.m_nSubType == SAWFIN_SUB_SECTION) {
if ( ! CalculateStraightSectionToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2717, "Error in SawFinishing : CalculateSectionToolPath failed") ;
return false ;
if ( m_bStraight) {
if ( ! CalculateStraightSectionToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2717, "Error in SawFinishing : CalculateSectionToolPath failed") ;
return false ;
}
}
}
else if ( m_Params.m_nSubType == SAWFIN_SUB_ALONG_5A) {
if ( m_bStraight) {
if ( ! CalculateStraightAlong5AToolPath( nAuxId, nClId)) {
m_pMchMgr->SetLastError( 2718, "Error in SawFinishing : CalculateStraightAlong5AToolPath failed") ;
return false ;
}
}
}
@@ -1100,7 +1113,7 @@ SawFinishing::CalculateStraightAlongToolPath( int nAuxId, int nClId)
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, pSect, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, false))
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, false))
return false ;
if ( m_Params.m_bInvert) {
swap( ptGdStart, ptGdEnd) ;
@@ -1295,7 +1308,7 @@ SawFinishing::CalculateStraightAcrossToolPath( int nAuxId, int nClId)
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, pSect, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
return false ;
Vector3d vtDeltaSect = vtGdDir * ( vtGdDir * ( ptGdStart - frSect.Orig())) ;
if ( m_Params.m_bInvert) {
@@ -1811,7 +1824,7 @@ SawFinishing::CalculateStraightSectionToolPath( int nAuxId, int nClId)
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, pSect, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, bExtend))
return false ;
if ( m_Params.m_bInvert) {
swap( ptGdStart, ptGdEnd) ;
@@ -1964,6 +1977,117 @@ SawFinishing::CalculateStraightSectionToolPath( int nAuxId, int nClId)
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateStraightAlong5AToolPath( int nAuxId, int nClId)
{
// Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama
int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ;
SECTIONVECTOR vSections ;
if ( ! Split5ASection( nSectGrpId, vSections)) {
m_pMchMgr->SetLastError( 2719, "Error in SawFinishing : Splitting Section failed") ;
return false ;
}
// recupero il riferimento globale delle sezioni
Frame3d frSect ;
m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ;
// recupero il box globale delle sezioni
BBox3d b3Sect ;
m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ;
// Recupero da UserNotes il flag di estensione al bordo del grezzo
bool bExtend ;
if ( ! GetValInNotes( m_Params.m_sUserNotes, UN_EXTEND, bExtend))
bExtend = true ;
// se estensione non presente e Link di tipo Extended, lo forzo come Center
if ( ! bExtend && m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) {
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
}
// se link di tipo Standard, questa viene convertita in Center, per la lavorazione corrente si effettuano le rotazioni della lama
// sempre al di fuori del grezzo
if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) {
m_pMchMgr->SetWarning( 2655, "Warning in SawRoughing : Link not compatible with extension") ;
m_Params.m_nLeadLinkType = SAWFIN_LL_CENT ;
}
// Recupero ed elaboro la linea guida
Point3d ptGdStart, ptGdEnd ;
Vector3d vtGdDir ;
int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ;
if ( ! CalculateGuideLine( nGuideId, ptGdStart, ptGdEnd, vtGdDir, nSectGrpId, false))
return false ;
if ( m_Params.m_bInvert) {
swap( ptGdStart, ptGdEnd) ;
vtGdDir.Invert() ;
}
// recupero il box globale della linea guida
BBox3d b3Guide ;
m_pGeomDB->GetGlobalBBox( nGuideId, b3Guide) ;
// recupero il box del grezzo in globale
BBox3d b3Test ;
b3Test.Add( b3Sect) ;
b3Test.Add( b3Guide) ;
BBox3d b3Raw ;
if ( ! GetRawGlobBox( m_nPhase, b3Test, 10 * EPS_SMALL, b3Raw) || b3Raw.IsEmpty()) {
m_pMchMgr->SetLastError( 2703, "Error in SawFinishing : Empty RawBox") ;
return false ;
}
// valuto l'espressione dell'affondamento
ExeLuaSetGlobNumVar( "TH", 0) ;
ExeLuaSetGlobNumVar( "RB", b3Raw.GetMax().z - b3Raw.GetMin().z) ;
double dDepth ;
if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) {
m_pMchMgr->SetLastError( 2704, "Error in SawFinishing : Depth not computable") ;
return false ;
}
// creo gruppo per geometria di lavorazione
int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
if ( nPxId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nPxId, MCH_PATH + "1_1") ;
m_pGeomDB->SetMaterial( nPxId, GREEN) ;
// Imposto dati comuni
SetPathId( nPxId) ;
// recupero la TriMesh del grezzo in globale
PtrOwner<ISurfTriMesh> pStmRaw( CreateSurfTriMesh()) ;
if ( IsNull( pStmRaw))
return false ;
pStmRaw->AdjustTopology() ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) {
// recupero l'oggetto dal database con tale Id
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ;
if ( pGObj != nullptr) {
// recupero il frame in cui si trova
Frame3d frRaw ;
m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ;
// controllo che sia una Trimesh
if ( pGObj->GetType() == SRF_TRIMESH) {
SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ;
// lo aggiungo alla Trimesh complessiva
pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ;
}
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// elaboro le Section/SubSections
if ( ! CalcAlong5ACuts( vSections, frSect, bExtend, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw, pStmRaw))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::ExtendPathToRaw( PolyLine& PL, const ISurfTriMesh* pStmRaw, double dExtraOut) const
@@ -2312,21 +2436,20 @@ SawFinishing::CalculateSection( int nSectGrpId, ICurve*& pSect) const
typedef vector<INDASC> INDASCVECTOR ; // vettore di coppie indice, ascissa
INDASCVECTOR vIAsc ;
vIAsc.reserve( vpNucCrvs.size()) ;
for ( int i = 0 ; i < int( vpNucCrvs.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
Point3d ptStart ;
if ( ! vpNucCrvs[i]->GetStartPoint( ptStart))
return false ;
vIAsc.emplace_back( i, ptStart.x) ;
}
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b)
{ return a.second > b.second ; }) ;
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b) { return a.second > b.second ; }) ;
// unisco le diverse curve (ora aperte) in un unico profilo
PtrOwner<ICurveComposite> pCurve( CreateCurveComposite()) ;
if ( IsNull( pCurve))
return false ;
bool bFirst = true ;
for ( int i = 0 ; i < int( vpNucCrvs.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
if ( ! bFirst) {
Point3d ptStart ;
if ( ! vpNucCrvs[vIAsc[i].first]->GetStartPoint( ptStart) ||
@@ -2340,20 +2463,23 @@ SawFinishing::CalculateSection( int nSectGrpId, ICurve*& pSect) const
// offset radiale delle sezioni per il sovramateriale
double dOffsR = GetOffsR() ;
PtrOwner<ICurve> pOvrCrv ;
OffsetCurve OffsCrv ;
OffsCrv.Make( pCurve, dOffsR, ICurve::OFF_FILLET) ;
pOvrCrv.Set( OffsCrv.GetLongerCurve()) ;
PtrOwner<ICurve> pOvrCrv( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pOvrCrv) || ! pOvrCrv->IsValid())
return false ;
// ricavo dalla sezione la curva per centro in basso della lama
double dOffsX = 0.5 * m_TParams.m_dThick ;
PtrOwner<ICurve> pCrv ;
OffsetCurveOnX OffsCrvX ;
OffsCrvX.Make( pOvrCrv, dOffsX) ;
pCrv.Set( OffsCrvX.GetLongerCurve()) ;
if ( ! OffsCrvX.Make( pOvrCrv, dOffsX))
return false ;
PtrOwner<ICurve> pCrv( OffsCrvX.GetLongerCurve()) ;
if ( IsNull( pCrv) || ! pCrv->IsValid())
return false ;
// eseguo trim (se richiesto)
if ( IsNull( pCrv) || ! TrimSection( pCrv))
if ( ! TrimSection( pCrv))
return false ;
pSect = Release( pCrv) ;
@@ -2366,7 +2492,7 @@ bool
SawFinishing::TrimSection( ICurve* pCrv) const
{
// se parametri di accorciamento iniziale e finale sono nulli, non faccio alcunché
if ( m_Params.m_dStartAddLen > - EPS_SMALL && m_Params.m_dEndAddLen > -EPS_SMALL)
if ( m_Params.m_dStartAddLen > -EPS_SMALL && m_Params.m_dEndAddLen > -EPS_SMALL)
return true ;
// box della sezione in locale
@@ -2379,13 +2505,13 @@ SawFinishing::TrimSection( ICurve* pCrv) const
ptMin.x -= m_Params.m_dStartAddLen ;
ptMax.x += m_Params.m_dEndAddLen ;
double dDimX = ptMax.x - ptMin.x ;
double dDimY = ptMax.y - ptMin.y + 100 * EPS_SMALL ;
double dDimY = ptMax.y - ptMin.y + 100. * EPS_SMALL ;
// regione del box nel piano XY
PtrOwner<ISurfFlatRegion> pSfr( GetSurfFlatRegionRectangle( dDimX, dDimY)) ;
if ( IsNull( pSfr))
return false ;
pSfr->Translate( Vector3d( ptMin.x, ptMin.y - 50 * EPS_SMALL, ptMin.z)) ;
pSfr->Translate( Vector3d( ptMin.x, ptMin.y - 50. * EPS_SMALL, ptMin.z)) ;
// calcolo la classificazione della curva rispetto alla regione
CRVCVECTOR ccClass ;
@@ -2394,7 +2520,7 @@ SawFinishing::TrimSection( ICurve* pCrv) const
// determino l'intervallo di curva da conservare
Intervals inOk ;
for ( auto& ccOne : ccClass) {
for ( const CrvClass& ccOne : ccClass) {
if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M)
inOk.Add( ccOne.dParS, ccOne.dParE) ;
}
@@ -2406,6 +2532,289 @@ SawFinishing::TrimSection( ICurve* pCrv) const
return ( pCrv->TrimEndAtParam( dUmax) && pCrv->TrimStartAtParam( dUmin)) ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::Split5ASection( int nSectGrpId, SECTIONVECTOR& vSections) const
{
vSections.clear() ;
// recupero le sezioni
ICURVEPVECTOR vpSects ;
int nSectId = m_pGeomDB->GetFirstInGroup( nSectGrpId) ;
while ( nSectId != GDB_ID_NULL) {
// recupero il puntatore alla curva
vpSects.emplace_back( ::GetCurve( m_pGeomDB->GetGeoObj( nSectId))) ;
if ( vpSects.back() == nullptr)
return false ;
// passo alla successiva
nSectId = m_pGeomDB->GetNext( nSectId) ;
}
// elimino eventuali sottosquadra
ICRVCOMPOPOVECTOR vpNucCrvs ; vpNucCrvs.reserve( vpSects.size()) ;
for ( const auto& pSect : vpSects) {
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo) ||
! pCrvCompo->AddCurve( *pSect) ||
! pCrvCompo->RemoveUndercutOnY( LIN_TOL_STD, ANG_TOL_STD_DEG))
return false ;
vpNucCrvs.emplace_back( Release( pCrvCompo)) ;
}
// per ogni sezione vengono rimossi i tratti verticali
ICRVCOMPOPOVECTOR vSimpleSections ;
for ( int i = 0 ; i < ssize( vpNucCrvs) ; ++ i) {
// se tratto non valido, non lo considero
if ( IsNull( vpNucCrvs[i]) || ! vpNucCrvs[i]->IsValid())
return false ;
// oriento la curva corrente per X decrescenti
Point3d ptStart ; vpNucCrvs[i]->GetStartPoint( ptStart) ;
Point3d ptEnd ; vpNucCrvs[i]->GetEndPoint( ptEnd) ;
if ( ptEnd.x > ptStart.x)
vpNucCrvs[i]->Invert() ;
// approssimo per la presenza di archi e classifico i tratti
PolyLine PL ;
vpNucCrvs[i]->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ;
vpNucCrvs[i]->Clear() ;
vpNucCrvs[i]->FromPolyLine( PL) ;
INTVECTOR vnClass ;
if ( ! ClassifySection( vpNucCrvs[i], vnClass))
return false ;
// vettore delle parti di sezione validi senza tratti verticiali (e sottosquadra)
ICRVCOMPOPOVECTOR vpNucCrvsNoVert ; vpNucCrvsNoVert.reserve( vnClass.size()) ;
PtrOwner<ICurveComposite> pCompoTmp( nullptr) ;
for ( int j = 0 ; j < ssize( vnClass) ; ++ j) {
if ( vnClass[j] == CCL_VERT) {
if ( ! IsNull( pCompoTmp) && pCompoTmp->IsValid())
vpNucCrvsNoVert.emplace_back( ::Release( pCompoTmp)) ;
}
else {
if ( IsNull( pCompoTmp))
pCompoTmp.Set( CreateCurveComposite()) ;
const ICurve* pCrv = vpNucCrvs[i]->GetCurve( j) ;
if ( pCrv == nullptr || ! pCrv->IsValid())
return false ;
pCompoTmp->AddCurve( pCrv->Clone()) ;
}
}
erase_if( vpNucCrvsNoVert, []( const PtrOwner<ICurveComposite>& pCompo) { return ( pCompo == nullptr || ! pCompo->IsValid()) ; }) ;
for ( int j = 0 ; j < ssize( vpNucCrvsNoVert) ; ++ j) {
if ( ! vSimpleSections.emplace_back( ::Release( vpNucCrvsNoVert[j])))
return false ;
}
}
// dalle sezioni semplici recuperate eseguo l'Offset Radiale complessivo ( evito così interferenze con sezioni differenti)
ICURVEPVECTOR vMySimpleSections ; vMySimpleSections.resize( vSimpleSections.size()) ;
for ( int i = 0 ; i < ssize( vSimpleSections) ; ++ i)
vMySimpleSections[i] = vSimpleSections[i] ;
ICURVEPOVECTOR vMySections ;
if ( ! CalcOffsetCurves( vMySimpleSections, vMySections, GetOffsR()))
return false ;
for ( int i = 0 ; i < ssize( vMySections) ; ++ i) {
if ( vMySections[i] != nullptr && vMySections[i]->IsValid()) {
vSections.resize( vSections.size() + 1) ;
if ( ! vSections.back().pSection.Set( CreateCurveComposite()) || ! vSections.back().pSection->AddCurve( vMySections[i]->Clone()))
return false ;
}
}
erase_if( vSections, []( const SectionInfo& SectionInfo) {
return ( SectionInfo.pSection == nullptr || ! SectionInfo.pSection->IsValid()) ;
}) ;
// calcolo ordinamento delle curve secondo la X decrescente
typedef pair<int,double> INDASC ; // coppia indice, ascissa
typedef vector<INDASC> INDASCVECTOR ; // vettore di coppie indice, ascissa
INDASCVECTOR vIAsc ;
vIAsc.reserve( vSections.size()) ;
for ( int i = 0 ; i < ssize( vSections) ; ++ i) {
Point3d ptStart ;
if ( ! vSections[i].pSection->GetStartPoint( ptStart))
return false ;
vIAsc.emplace_back( i, ptStart.x) ;
}
sort( vIAsc.begin(), vIAsc.end(), []( const INDASC& a, const INDASC& b) { return a.second > b.second ; }) ;
for ( int nNewPos = 0 ; nNewPos < ssize( vIAsc) ; ++ nNewPos) {
int nOldPos = vIAsc[nNewPos].first ;
if ( nOldPos == nNewPos)
continue ;
swap( vSections[nNewPos], vSections[nOldPos]) ;
swap( vIAsc[nNewPos].first, vIAsc[nOldPos].first) ;
}
// !<-- NB:
// - Una Section semplice non presente tratti verticali e non presenta tratti in sottosquadra
// - Una Section semplice è orientata per X decrescente
// - Le sue SubSections sono anch'esse orientate per X decrescente
// recupero angolo di Split iniziale e finale per i tratti
double dAngDegSplit = 60. ;
double dAngUN = 0. ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LIMIT_ANG, dAngUN))
dAngDegSplit = max( 15. - EPS_ANG_SMALL, dAngUN) ;
// ---------------------------- funzioni ausiliarie semplici -------------------------------------
auto AddSubSection = [&]( SUBSECTIONVECTOR& vSubSections, PtrOwner<ICurveComposite>& pCompo, int nHeadSide) {
if ( IsNull( pCompo) || ! pCompo->IsValid())
return false ;
vSubSections.resize( vSubSections.size() + 1) ;
vSubSections.back().pSubSection.Set( ::Release( pCompo)) ;
vSubSections.back().nHeadSide = nHeadSide ;
return true ;
} ;
auto GetHeadSide = [&]( int nClass) {
if ( nClass == CCL_FALL)
return int( SAWFIN_HS_RIGHT) ;
else if ( nClass == CCL_RISE)
return int( SAWFIN_HS_LEFT) ;
else
return m_Params.m_nHeadSide ;
} ;
// per ogni sezione semplice
for ( int i = 0 ; i < ssize( vSections) ; ++ i) {
// riferimenti
SectionInfo& CurrSection = vSections[i] ;
SUBSECTIONVECTOR& vCurrSubSections = CurrSection.vSubSections ;
// elimino tutti i tratti all'inizio e alla fine della sezione con tangenza sotto i 60deg
if ( ! TrimVerticalSectionBounds( CurrSection.pSection, dAngDegSplit))
return false ;
// eseguo trim della parte iniziale e finale (se richiesto)
if ( ! TrimSection( CurrSection.pSection))
return false ;
// Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale)
INTVECTOR vnClass ;
if ( ! ClassifySection( CurrSection.pSection, vnClass))
return false ;
// se una sola classificazione presente
if ( ssize( vnClass) == 1) {
PtrOwner<ICurveComposite> pSubSection( CloneCurveComposite( CurrSection.pSection)) ;
return AddSubSection( vCurrSubSections, pSubSection, vnClass[0]) ;
}
// scrorro i tratti correnti
bool bCanSwapHead = true ;
for ( int i = 1 ; i < ssize( vnClass) ; ++ i) {
if ( i == 1) {
// inserisco il primo elemento
PtrOwner<ICurveComposite> pCompoSubSect( ConvertCurveToComposite( CurrSection.pSection->CopyParamRange( double( i - 1), double( i)))) ;
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, GetHeadSide( vnClass[0])))
return false ;
}
// classificazione corrente
const int& nCurrClass = vnClass[i] ;
// classificazione precedente
const int& nPrevClass = vnClass[i - 1] ;
// parametri per copia sotto-tratto corrente
double dUS = double( i) ;
double dUE = double( i + 1) ;
PtrOwner<ICurveComposite> pCompoSub( ConvertCurveToComposite( CurrSection.pSection->CopyParamRange( dUS, dUE))) ;
if ( IsNull( pCompoSub) || ! pCompoSub->IsValid())
return false ;
switch ( nCurrClass) {
// --- classificazione corrente Flat o Small
case CCL_FLAT :
case CCL_SMALL :
{
// a prescindere dai valori precedenti si aggiunge semplicemente il tratto di sezione
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
bCanSwapHead = ( bCanSwapHead && ( nPrevClass != CCL_RISE && nPrevClass != CCL_FALL)) ;
break ;
}
// --- classificazione corrente Fall (la testa deve essere a destra)
case CCL_FALL : {
// se la precedente è flat, veticale o small
if ( nPrevClass == CCL_FLAT || nPrevClass == CCL_SMALL) {
if ( vCurrSubSections.back().nHeadSide == SAWFIN_HS_RIGHT) {
// allungo il percorso precedente
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
// non posso swappare la testa
bCanSwapHead = false ;
}
else if ( bCanSwapHead) {
// inverto la testa del percorso precedente e mi collego
vCurrSubSections.back().nHeadSide = SAWFIN_HS_RIGHT ;
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
bCanSwapHead = false ;
}
else {
// nuovo percorso
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_RIGHT))
return false ;
}
}
// se la precedente è fall
else if ( nPrevClass == CCL_FALL) {
// allungo il percorso precedente
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
}
// se la precedente è Rise
else if ( nPrevClass == CCL_RISE) {
// definisco un nuovo percorso
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_RIGHT))
return false ;
}
break ;
}
// --- classificazione corrente Rise (la testa deve essere a sinistra)
case CCL_RISE : {
// se la precedente è flat, veticale o small
if ( nPrevClass == CCL_FLAT || nPrevClass == CCL_SMALL) {
if ( vCurrSubSections.back().nHeadSide == SAWFIN_HS_LEFT) {
// allungo il percorso precedente
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
// non posso swappare la testa
bCanSwapHead = false ;
}
else if ( bCanSwapHead) {
// inverto la testa del percorso precedente e mi collego
vCurrSubSections.back().nHeadSide = SAWFIN_HS_LEFT ;
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
bCanSwapHead = false ;
}
else {
// nuovo percorso
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_LEFT))
return false ;
}
}
// se la precedente è fall
else if ( nPrevClass == CCL_FALL) {
// definisco un nuovo percorso
PtrOwner<ICurveComposite> pCompoSubSect( ::Release( pCompoSub)) ;
if ( ! AddSubSection( vCurrSubSections, pCompoSubSect, SAWFIN_HS_LEFT))
return false ;
}
// se la precedente è Rise
else if ( nPrevClass == CCL_RISE) {
// allungo il percorso precedente
if ( ! vCurrSubSections.back().pSubSection->AddCurve( ::Release( pCompoSub)))
return false ;
}
break ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::AdaptGuideLineToRaw( Point3d& ptGdStart, Point3d& ptGdEnd, const Vector3d& vtGdDir, bool bExtend, const ISurfTriMesh* pStmRaw) const
@@ -2573,7 +2982,7 @@ SawFinishing::CalculateSectElevation( const Polygon3d& pgFacet, double& dElev) c
//----------------------------------------------------------------------------
bool
SawFinishing::CalculateGuideLine( int nGuideId, const ICurve* pSect, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir,
SawFinishing::CalculateGuideLine( int nGuideId, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir,
int nSectGrpId, bool bExtendToRawBox) const
{
// recupero la linea guida
@@ -2649,7 +3058,7 @@ SawFinishing::CalculateGuideLine( int nGuideId, const ICurve* pSect, Point3d& pt
//----------------------------------------------------------------------------
bool
SawFinishing::ClassifySection( ICurve* pCrv, INTVECTOR& vnClass)
SawFinishing::ClassifySection( ICurve* pCrv, INTVECTOR& vnClass) const
{
const ICurveComposite* pCompo = GetCurveComposite( pCrv) ;
if ( pCompo != nullptr) {
@@ -2872,6 +3281,228 @@ SawFinishing::CalcAlongStdCuts( ICurve* pSect, double dUmin, double dUmax,
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalcCAvSect5Ax( const ICurveComposite* pSubSect, const SECTIONVECTOR& vSections, const Vector3d& vtTool, const Vector3d& vtCorr,
const Point3d& ptP, double& dElev, bool& bOtherCollision) const
{
// verifico la validità della curva
if ( pSubSect == nullptr || ! pSubSect->IsValid())
return false ;
bOtherCollision = false ;
// definisco il numero di punti di campionamento progressivi
const int MAX_NUM = 3 ;
const double LINE_LEN = 1e4 ;
double dSqMaxElev = EPS_ZERO ;
PtrOwner<ICurveLine> pLineInters( CreateCurveLine()) ;
if ( IsNull( pLineInters) || ! pLineInters->Set( ptP, ptP + vtCorr * LINE_LEN))
return false ;
for ( int i = 0 ; i < MAX_NUM ; ++ i) {
if ( i > 0)
pLineInters->Translate( ( m_TParams.m_dThick) / ( MAX_NUM - 1) * vtTool) ;
Point3d ptLineS ; pLineInters->GetStartPoint( ptLineS) ;
IntersCurveCurve ICC( *pLineInters, *pSubSect) ;
for ( int j = ICC.GetIntersCount() - 1 ; j >= 0 ; -- j) {
IntCrvCrvInfo aInfo ;
if ( ICC.GetIntCrvCrvInfo( j, aInfo))
dSqMaxElev = max( dSqMaxElev, ( SqDist( ptLineS, ( aInfo.bOverlap ? aInfo.IciA[1].ptI : aInfo.IciA[0].ptI)))) ;
}
// controllo se la linea ricavata interseca le sezioni presenti
double dSafeShift = 1. + sqrt( dSqMaxElev) ;
pLineInters->Translate( dSafeShift * vtCorr) ;
for ( int j = 0 ; j < ssize( vSections) ; ++ j) {
if ( vSections[j].pSection != nullptr && vSections[j].pSection->IsValid()) {
IntersCurveCurve ICC( *pLineInters, *vSections[j].pSection) ;
if ( ICC.GetIntersCount() > 0) {
bOtherCollision = true ;
return true ;
}
}
}
pLineInters->Translate( - dSafeShift * vtCorr) ; // ritorno in posizione originale
}
dElev = sqrt( dSqMaxElev) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend,
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
const BBox3d& b3Raw, const ISurfTriMesh* pStmRaw)
{
// se non ho sezioni da lavorare, non faccio nulla
if ( vSections.empty()) {
m_pMchMgr->SetWarning( 2752, "Warning in SawFinishing : No machinable path") ;
return true ;
}
// determino angolo limite di inclinazione dell'utensile
double dAngDegSplit = 60. ;
double dAngUN = 0. ;
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LIMIT_ANG, dAngUN))
dAngDegSplit = max( 15. - EPS_ANG_SMALL, dAngUN) ;
double dCosToolLimit = cos( dAngDegSplit * DEGTORAD) ;
// determino quota Zmassima dal Box del grezzo in globale
double dRawMaxZ = b3Raw.GetMax().z ;
// scorro le sezioni
for ( int nSect = 0 ; nSect < ssize( vSections) ; ++ nSect) {
// recupero la sezione
const SectionInfo& Section = vSections[nSect] ;
if ( Section.pSection == nullptr || ! Section.pSection->IsValid())
continue ;
// scorro le SubSection ottenute
for ( int nSubSect = 0 ; nSubSect < ssize( Section.vSubSections) ; ++ nSubSect) {
// recupero la SubSection corrente, se non valida, passo alla successiva
const SubSectionInfo& SubSection = Section.vSubSections[nSubSect] ;
PtrOwner<ICurveComposite> pSubSect( CloneCurveComposite( SubSection.pSubSection)) ;
if ( pSubSect == nullptr || ! pSubSect->IsValid())
continue ;
// essendo l'utensile inclinato e la testa con orientamento forzato è meglio estendere la sezione per evitare lavorazioni
// a filo dei suoi bordi
pSubSect->ExtendStartByLen( 50. * EPS_SMALL) ;
pSubSect->ExtendEndByLen( 50. * EPS_SMALL) ;
// calcolo della lunghezza dello step e del numero di step complessivi
double dStep = max( m_Params.m_dSideStep, 10. * EPS_SMALL) ;
double dLen ;
if ( ! pSubSect->GetLength( dLen))
return false ;
double dL = dLen ;
if ( dL < 10. * EPS_SMALL)
return true ;
int nStep = static_cast<int>( ceil( dL / dStep)) ;
dStep = dL / nStep ;
nStep ++ ;
// Ciclo sulle passate
double dLastElev ;
Point3d ptStartPrev ;
for ( int i = 0 ; i <= nStep ; ++ i) {
// coordinate nel punto, del versore correzione e del versore utensile
double dLcurr = i * dStep ;
double dU ; pSubSect->GetParamAtLength( dLcurr, dU) ;
Point3d ptP ;
Vector3d vtTan, vtPerp ;
if ( ! pSubSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP, &vtTan) || ! vtTan.Normalize())
return false ;
Vector3d vtCorr = GetToGlob( vtTan, frSect) ;
vtCorr.Rotate( vtGdDir, m_Params.m_bInvert ? - ANG_RIGHT : ANG_RIGHT) ;
Vector3d vtTool = GetToGlob( vtTan, frSect) ;
// determino la posizione della testa
if ( vtTool.z < - EPS_ZERO)
vtTool.Invert() ; // NB. vtTool deve sempre avere la componente Z come positiva
// se lama più inclinata della soglia, passo allo step successivo
if ( vtCorr * Z_AX < dCosToolLimit)
continue ;
// verifico posizionando la lama nel punto corrente se devo sposarmi per evitare collisione con la sezione
double dSectElev = 0. ;
bool bOtherColl = false ;
if ( ! CalcCAvSect5Ax( pSubSect, vSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dSectElev, bOtherColl)) {
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
return false ;
}
// se collisione con altra sezione, passo allo step successivo ( non inserisco la passata corrente)
if ( bOtherColl)
continue ;
// definisco gli estremi del tratto rettilineo in globale
Point3d ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dSectElev ;
Point3d ptStart = ptPCAvSect ;
Point3d ptEnd = ptPCAvSect + vtGdDir * ( Dist( ptGdStart, ptGdEnd)) ;
// verifico eventuale estensione degli estremi sul grezzo
if ( bExtend) {
if ( ! AdaptGuideLineToRaw( ptStart, ptEnd, vtGdDir, bExtend, pStmRaw))
return false ;
}
// determino l'elevazione del taglio (considerando l'elevazione verticiale)
Vector3d vtThick = vtTool * m_TParams.m_dThick ;
double dElev, dElev2 ;
if ( ! GetElevation( m_nPhase, ptStart, ptEnd, Z_AX, dElev) ||
! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, Z_AX, dElev2)) {
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
return false ;
}
dElev = max( dElev, dElev2) ;
if ( dElev < EPS_SMALL)
dElev = max( max( dRawMaxZ - ptStart.z, dRawMaxZ - ptEnd.z), 0.) ;
// la confronto con il massimo affondamento e con la massima lavorazione della lama. Se sotto alla massima Depth allora riporto
// l'utensile in verticale e ricalcolo il punto più adatto in z per il tratto lineare
double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ;
if ( dElev > dMaxDepth) {
// modifica versore correzione e direzione utensile
vtTool.z = 0. ;
if ( ! vtTool.Normalize())
return false ;
vtCorr = Z_AX ;
double dElevTmp = 0. ;
if ( ! CalcCAvSect5Ax( pSubSect, vSections, GetToLoc( vtTool, frSect), GetToLoc( vtCorr, frSect), ptP, dElevTmp, bOtherColl)) {
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
return false ;
}
if ( bOtherColl)
continue ;
ptPCAvSect = GetToGlob( ptP, frSect) + vtCorr * dElevTmp ;
double dElev3 ;
if ( ! GetElevation( m_nPhase, ptPCAvSect, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtCorr, dElev3)) {
m_pMchMgr->SetLastError( 2708, "Error in SawFinishing : GetElevation") ;
return false ;
}
Point3d ptPTopRaw = ptPCAvSect + ( dElev3 - m_TParams.m_dDiam / 2.) * vtCorr ;
ptStart.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ;
ptEnd.z = max( ptPTopRaw.z - dMaxDepth, ptPCAvSect.z) ;
dElev = dMaxDepth ;
}
// Imposto dati comune
SetToolDir( vtTool) ;
SetCorrAuxDir( vtCorr) ;
// se diverso da precedente, eseguo il taglio
bool bFirst = ( i == 0) ;
dElev = dElev / max( EPS_SMALL, ( vtCorr * Z_AX)) ; // non serve fare il max, ma meglio prevenire...
if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10. * EPS_SMALL)) {
if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) {
if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false))
return false ;
}
else {
if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, bExtend, false, bFirst))
return false ;
}
// salvo dati correnti
dLastElev = dElev ;
ptStartPrev = ptStart ;
}
}
// se ZigZag e non centrato aggiungo risalita
if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG && m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) {
// recupero distanza di sicurezza
double dSafeZ = GetSafeZ() ;
// lunghezza di approccio/retrazione
double dAppr = m_Params.m_dStartPos ;
// aggiungo retrazione
Point3d ptNewEnd ;
if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, Z_AX, dSafeZ, dLastElev, dAppr))
return false ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SawFinishing::CalcAlongOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
+25 -2
View File
@@ -25,6 +25,22 @@ class ICurveComposite ;
class ISurfTriMesh ;
class Polygon3d ;
// Definizione strutture per Section/SubSection ------------------------------
struct SubSectionInfo {
PtrOwner<ICurveComposite> pSubSection ;
int nHeadSide ;
SubSectionInfo()
: pSubSection( nullptr), nHeadSide( -1) {} ;
} ;
typedef std::vector<SubSectionInfo> SUBSECTIONVECTOR ;
struct SectionInfo {
PtrOwner<ICurveComposite> pSection ;
SUBSECTIONVECTOR vSubSections ;
SectionInfo()
: pSection( nullptr), vSubSections( SUBSECTIONVECTOR{}) {} ;
} ;
typedef std::vector<SectionInfo> SECTIONVECTOR ;
//----------------------------------------------------------------------------
class SawFinishing : public Machining
{
@@ -86,22 +102,29 @@ class SawFinishing : public Machining
bool CalculateCurvedAlongToolPath( int nAuxId, int nClId) ;
bool CalculateCurvedAcrossToolPath( int nAuxId, int nClId) ;
bool CalculateStraightSectionToolPath( int nAuxId, int nClId) ;
bool CalculateStraightAlong5AToolPath( int nAuxId, int nClId) ;
bool TrimVerticalSectionBounds( ICurveComposite* pSect, double dAngDeg) const ;
bool CalculateOffsetSection( int nSectGrpId, const Frame3d& frSec, ICurve*& pSect) const ;
bool CalculateSection( int nSectGrpId, ICurve*& pSect) const ;
bool TrimSection( ICurve* pCrv) const ;
bool Split5ASection( int nSectGrpId, SECTIONVECTOR& vSubSections) const ;
bool AdaptGuideLineToRaw( Point3d& ptGdStart, Point3d& ptGdEnd, const Vector3d& vtGdDir, bool bExtend, const ISurfTriMesh* pStmRaw) const ;
bool ExtendPathToRaw( PolyLine& PL, const ISurfTriMesh* pStmRaw, double dExtraOut) const ;
bool CalculateSectElevation( const Polygon3d& pgFacet, double& dElev) const ;
bool CalculateGuideLine( int nGuideId, const ICurve* pSect, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir,
bool CalculateGuideLine( int nGuideId, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir,
int nSectGrpId, bool bExtendToRawBox) const ;
bool ClassifySection( ICurve* pCrv, INTVECTOR& vnClass) ;
bool ClassifySection( ICurve* pCrv, INTVECTOR& vnClass) const ;
bool CalcCAvSect5Ax( const ICurveComposite* pSubSect, const SECTIONVECTOR& vSections, const Vector3d& vtTool, const Vector3d& vtCorr, const Point3d& ptP,
double& dElev, bool& bOtherCollision) const ;
bool CalcAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect, bool bExtend, const Point3d& ptGdStart,
const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, double dRaxMaxZ,
const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw) ;
bool CalcAlongStdCuts( ICurve* pSect, double dUmin, double dUmax, bool bSkipMin, bool bSkipMax, bool bInvert, const Frame3d& frSect,
bool bExtend, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr, const ISurfTriMesh* pStmRaw) ;
bool CalcAlong5ACuts( const SECTIONVECTOR& vSections, const Frame3d& frSect, bool bExtend,
const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth,
const BBox3d& b3Raw, const ISurfTriMesh* pStmRaw) ;
bool CalcAlongOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bExtend, bool bVert) ;
bool CalcAlongZigZagCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir,
+2 -1
View File
@@ -391,7 +391,8 @@ SawFinishingData::VerifyStepType( int nVal) const
bool
SawFinishingData::VerifySubType( int nVal) const
{
return ( nVal == SAWFIN_SUB_ALONG || nVal == SAWFIN_SUB_ACROSS) ;
return ( nVal == SAWFIN_SUB_ALONG || nVal == SAWFIN_SUB_ACROSS || nVal == SAWFIN_SUB_SECTION ||
nVal == SAWFIN_SUB_ALONG_5A) ;
}
//----------------------------------------------------------------------------