diff --git a/EgtMachKernel.vcxproj b/EgtMachKernel.vcxproj index a330e7c..a512e30 100644 --- a/EgtMachKernel.vcxproj +++ b/EgtMachKernel.vcxproj @@ -282,6 +282,7 @@ copy $(TargetPath) \EgtProg\Dll64 Create + @@ -423,6 +424,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtMachKernel.vcxproj.filters b/EgtMachKernel.vcxproj.filters index cffc386..69e13c7 100644 --- a/EgtMachKernel.vcxproj.filters +++ b/EgtMachKernel.vcxproj.filters @@ -219,6 +219,9 @@ Source Files\Machinings + + Source Files\Operations + @@ -638,6 +641,9 @@ Header Files + + Header Files + diff --git a/OperationConst.h b/OperationConst.h index 58f012c..3632e3f 100644 --- a/OperationConst.h +++ b/OperationConst.h @@ -1,13 +1,13 @@ //---------------------------------------------------------------------------- -// EgalTech 2017-2017 +// EgalTech 2017-2019 //---------------------------------------------------------------------------- -// File : OperationConst.h Data : 17.08.17 Versione : 1.8h1 +// File : OperationConst.h Data : 28.05.19 Versione : 2.1e5 // Contenuto : Costanti per le operazioni. // // // // Modifiche : 17.08.17 DS Creazione modulo. -// +// 25.05.19 DS Aggiunte SurfRoughing e SurfFinishing. // //---------------------------------------------------------------------------- @@ -28,7 +28,9 @@ static const std::string s_OpeClass[] = {"", "EMkSawRoughing", "EMkSawFinishing", "EMkGenMachining", - "EMkChiseling"} ; + "EMkChiseling", + "EMkSurfRoughing", + "EMkSurfFinishing"} ; //---------------------------------------------------------------------------- // Dal tipo numerico restituisce la classe della operazione @@ -46,6 +48,8 @@ GetOperationClass( int nOpeType) case OPER_SAWFINISHING : return s_OpeClass[8] ; case OPER_GENMACHINING : return s_OpeClass[9] ; case OPER_CHISELING : return s_OpeClass[10] ; + case OPER_SURFROUGHING : return s_OpeClass[11] ; + case OPER_SURFFINISHING : return s_OpeClass[12] ; } return s_OpeClass[0] ; } @@ -75,6 +79,10 @@ GetOperationType( const std::string& sOpeClass) return OPER_GENMACHINING ; else if ( sOpeClass == s_OpeClass[10]) return OPER_CHISELING ; + else if ( sOpeClass == s_OpeClass[11]) + return OPER_SURFROUGHING ; + else if ( sOpeClass == s_OpeClass[12]) + return OPER_SURFFINISHING ; else return OPER_NULL ; } \ No newline at end of file diff --git a/SurfFinishing.cpp b/SurfFinishing.cpp new file mode 100644 index 0000000..2ba6a18 --- /dev/null +++ b/SurfFinishing.cpp @@ -0,0 +1,1669 @@ +//---------------------------------------------------------------------------- +// EgalTech 2019-2019 +//---------------------------------------------------------------------------- +// File : SurfFinishing.cpp Data : 28.05.19 Versione : 2.1e5 +// Contenuto : Implementazione gestione finitura superfici. +// +// Note : Questa lavorazione è sempre espressa nel riferimento globale. +// +// Modifiche : 28.05.19 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "MachMgr.h" +#include "DllMain.h" +#include "SurfFinishing.h" +#include "OperationConst.h" +#include "GeoConst.h" +#include "/EgtDev/Include/EXeCmdLogOff.h" +#include "/EgtDev/Include/EXeConst.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkCurveArc.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EgkOffsetCurve.h" +#include "/EgtDev/Include/EgkOffsetCurveOnX.h" +#include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EGkCAvToolSurfTm.h" +#include "/EgtDev/Include/EGkIntervals.h" +#include "/EgtDev/Include/EGkUserObjFactory.h" +#include "/EgtDev/Include/EGnStringKeyVal.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +// per far dimenticare macro di WinUser.h +#undef GetClassName + +using namespace std ; + +//------------------------------ Errors -------------------------------------- +// 2701 = "Error in SurfFinishing : UpdateToolData failed" +// 2702 = "Error in SurfFinishing : AdjustGeometry failed" +// 2703 = "Error in SurfFinishing : Empty RawBox" +// 2704 = "Error in SurfFinishing : Depth not computable" +// 2705 = "Error in SurfFinishing : CalculateToolAndCorrVersors" +// 2706 = "Error in SurfFinishing : ApproxWithLines" +// 2707 = "Error in SurfFinishing : Guide Line not along X or Y" +// 2708 = "Error in SurfFinishing : GetElevation" +// 2709 = "Error in SurfFinishing : CalculateAlongToolPath failed" +// 2710 = "Error in SurfFinishing : CalculateAcrossToolPath failed" +// 2711 = "Error in SurfFinishing : axes values not calculable" +// 2712 = "Error in SurfFinishing : outstroke xx" +// 2713 = "Error in SurfFinishing : link movements not calculable" +// 2714 = "Error in SurfFinishing : link outstroke xx" +// 2715 = "Error in SurfFinishing : post apply not calculable" + +//---------------------------------------------------------------------------- +USEROBJ_REGISTER( GetOperationClass( OPER_SURFFINISHING), SurfFinishing) ; + +//---------------------------------------------------------------------------- +const string& +SurfFinishing::GetClassName( void) const +{ + return USEROBJ_GETNAME( SurfFinishing) ; +} + +//---------------------------------------------------------------------------- +SurfFinishing* +SurfFinishing::Clone( void) const +{ + // alloco oggetto + SurfFinishing* pSrF = new(nothrow) SurfFinishing ; + // eseguo copia dei dati + if ( pSrF != nullptr) { + try { + pSrF->m_vId = m_vId ; + pSrF->m_pMchMgr = m_pMchMgr ; + pSrF->m_nPhase = m_nPhase ; + pSrF->m_Params = m_Params ; + pSrF->m_TParams = m_TParams ; + pSrF->m_nStatus = m_nStatus ; + pSrF->m_nPaths = m_nPaths ; + } + catch( ...) { + delete pSrF ; + return nullptr ; + } + } + // ritorno l'oggetto + return pSrF ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Dump( string& sOut, bool bMM, const char* szNewLine) const +{ + sOut += GetClassName() + "[mm]" + szNewLine ; + sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ; + sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ; + for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) + sOut += m_Params.ToString( i) + szNewLine ; + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) + sOut += m_TParams.ToString( i) + szNewLine ; + sOut += KEY_NUM + EQUAL + ToString( m_nPaths) + szNewLine ; + sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Save( int nBaseId, STRVECTOR& vString) const +{ + try { + int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 ; + vString.insert( vString.begin(), nSize, "") ; + int k = - 1 ; + if ( ! SetVal( KEY_IDS, m_vId, vString[++k])) + return false ; + for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) + vString[++k] = m_Params.ToString( i) ; + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) + vString[++k] = m_TParams.ToString( i) ; + if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k])) + return false ; + if ( ! SetVal( KEY_NUM, m_nPaths, vString[++k])) + return false ; + if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) + return false ; + } + catch( ...) { + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Load( const STRVECTOR& vString, int nBaseGdbId) +{ + int nSize = int( vString.size()) ; + // lista identificativi geometrie da lavorare + int k = - 1 ; + if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId)) + return false ; + for ( auto& Sel : m_vId) + Sel.nId += nBaseGdbId ; + // parametri lavorazione + for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { + int nKey ; + if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) { + if ( m_Params.IsOptional( i)) + -- k ; + else + return false ; + } + } + // parametri utensile + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { + int nKey ; + if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i) + return false ; + } + // parametri di stato + while ( k < nSize - 1) { + // separo chiave da valore + string sKey, sVal ; + SplitFirst( vString[++k], "=", sKey, sVal) ; + // leggo + if ( sKey == KEY_PHASE) { + if ( ! FromString( sVal, m_nPhase)) + return false ; + } + else if ( sKey == KEY_NUM) { + if ( ! FromString( sVal, m_nPaths)) + return false ; + } + else if ( sKey == KEY_STAT) { + if ( ! FromString( sVal, m_nStatus)) + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +SurfFinishing::SurfFinishing( void) +{ + m_Params.m_sName = "*" ; + m_Params.m_sToolName = "*" ; + m_TParams.m_sName = "*" ; + m_TParams.m_sHead = "*" ; + m_dTHoldLen = 0 ; + m_dTHoldDiam = 0 ; + m_nStatus = MCH_ST_TO_VERIFY ; + m_nPaths = 0 ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Prepare( const string& sSawName) +{ + // verifico il gestore lavorazioni + if ( m_pMchMgr == nullptr) + return false ; + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero il gestore DB lavorazioni della macchina corrente + MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; + if ( pMMgr == nullptr) + return false ; + // ricerca della lavorazione di libreria con il nome indicato + const SurfFinishingData* pDdata = GetSurfFinishingData( pMMgr->GetMachining( sSawName)) ; + if ( pDdata == nullptr) + return false ; + m_Params = *pDdata ; + // ricerca dell'utensile usato dalla lavorazione + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + m_TParams = *pTdata ; + m_Params.m_sToolName = m_TParams.m_sName ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SetParam( int nType, bool bVal) +{ + switch ( nType) { + case MPA_INVERT : + if ( bVal != m_Params.m_bInvert) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_bInvert = bVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SetParam( int nType, int nVal) +{ + switch ( nType) { + case MPA_SUBTYPE : + if ( ! m_Params.VerifySubType( nVal)) + return false ; + if ( nVal != m_Params.m_nSubType) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_nSubType = nVal ; + return true ; + case MPA_LEADINTYPE : + if ( ! m_Params.VerifyLeadInType( nVal)) + return false ; + if ( nVal != m_Params.m_nLeadInType) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_nLeadInType = nVal ; + return true ; + case MPA_LEADLINKTYPE : + if ( ! m_Params.VerifyLeadLinkType( nVal)) + return false ; + if ( nVal != m_Params.m_nLeadLinkType) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_nLeadLinkType = nVal ; + return true ; + case MPA_LEADOUTTYPE : + if ( ! m_Params.VerifyLeadOutType( nVal)) + return false ; + if ( nVal != m_Params.m_nLeadOutType) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_nLeadOutType = nVal ; + return true ; + case MPA_SCC : + if ( ! m_Params.VerifySolCh( nVal)) + return false ; + if ( nVal != m_Params.m_nSolCh) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_nSolCh = nVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SetParam( int nType, double dVal) +{ + switch ( nType) { + case MPA_SPEED : + if ( ! m_TParams.VerifySpeed( dVal)) + return false ; + if ( AreSameAngValue( dVal, m_TParams.m_dSpeed)) + dVal = 0 ; + m_Params.m_dSpeed = dVal ; + return true ; + case MPA_FEED : + if ( AreSameLenValue( dVal, m_TParams.m_dFeed)) + dVal = 0 ; + if ( ! AreSameLenValue( dVal, m_Params.m_dFeed)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dFeed = dVal ; + return true ; + case MPA_STARTFEED : + if ( AreSameLenValue( dVal, m_TParams.m_dStartFeed)) + dVal = 0 ; + if ( ! AreSameLenValue( dVal, m_Params.m_dStartFeed)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dStartFeed = dVal ; + return true ; + case MPA_ENDFEED : + if ( AreSameLenValue( dVal, m_TParams.m_dEndFeed)) + dVal = 0 ; + if ( ! AreSameLenValue( dVal, m_Params.m_dEndFeed)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dEndFeed = dVal ; + return true ; + case MPA_TIPFEED : + if ( AreSameLenValue( dVal, m_TParams.m_dTipFeed)) + dVal = 0 ; + if ( ! AreSameLenValue( dVal, m_Params.m_dTipFeed)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dTipFeed = dVal ; + return true ; + case MPA_OFFSR : + if ( AreSameLenValue( dVal, m_TParams.m_dOffsR)) + dVal = UNKNOWN_PAR ; + if ( ! AreSameLenValue( dVal, m_Params.m_dOffsR)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dOffsR = dVal ; + return true ; + case MPA_DEPTH: { + string sVal = ToString( dVal) ; + if ( sVal != m_Params.m_sDepth) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sDepth = sVal ; + } return true ; + case MPA_STARTPOS : + if ( ! AreSameLenValue( dVal, m_Params.m_dStartPos)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dStartPos = dVal ; + return true ; + case MPA_SIDESTEP : + if ( ! AreSameLenValue( dVal, m_Params.m_dSideStep)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dSideStep = dVal ; + return true ; + case MPA_SIDEANGLE : + if ( abs( dVal - m_Params.m_dSideAngle) > EPS_MACH_LEN_PAR) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dSideAngle = dVal ; + return true ; + case MPA_LITANG : + if ( abs( dVal - m_Params.m_dLiTang) > EPS_MACH_LEN_PAR) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dLiTang = dVal ; + return true ; + case MPA_LIPERP : + if ( abs( dVal - m_Params.m_dLiPerp) > EPS_MACH_LEN_PAR) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dLiPerp = dVal ; + return true ; + case MPA_LOTANG : + if ( abs( dVal - m_Params.m_dLoTang) > EPS_MACH_LEN_PAR) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dLoTang = dVal ; + return true ; + case MPA_LOPERP : + if ( abs( dVal - m_Params.m_dLoPerp) > EPS_MACH_LEN_PAR) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dLoPerp = dVal ; + return true ; + case MPA_APPROX : + if ( ! AreSameLenValue( dVal, m_Params.m_dApprox)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_dApprox = dVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SetParam( int nType, const string& sVal) +{ + switch ( nType) { + case MPA_TOOL : { + const ToolData* pTdata ; + if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata)) + return false ; + if ( ! SameTool( m_TParams, *pTdata)) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sToolName = sVal ; + m_Params.m_ToolUuid = pTdata->m_Uuid ; + m_TParams = *pTdata ; + } return true ; + case MPA_DEPTH_STR : + if ( sVal != m_Params.m_sDepth) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sDepth = sVal ; + return true ; + case MPA_SYSNOTES : + if ( sVal != m_Params.m_sSysNotes) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sSysNotes = sVal ; + return true ; + case MPA_USERNOTES : + if ( sVal != m_Params.m_sUserNotes) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sUserNotes = sVal ; + return true ; + case MPA_INITANGS : + if ( sVal != m_Params.m_sInitAngs) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sInitAngs = sVal ; + return true ; + case MPA_BLOCKEDAXIS : + if ( sVal != m_Params.m_sBlockedAxis) + m_nStatus |= MCH_ST_PARAM_MODIF ; + m_Params.m_sBlockedAxis = sVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SetGeometry( const SELVECTOR& vIds) +{ + // verifico validità gestore DB geometrico + if ( m_pGeomDB == nullptr) + return false ; + // reset della geometria corrente + m_vId.clear() ; + // verifico che gli identificativi rappresentino delle entità ammissibili + for ( const auto& Id : vIds) { + // test sull'entità + int nSubs ; + if ( ! VerifyGeometry( Id, nSubs)) { + string sOut = "Entity " + ToString( Id) + " skipped by SurfFinishing" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + continue ; + } + // posso aggiungere alla lista + m_vId.emplace_back( Id) ; + } + // aggiorno lo stato + m_nStatus |= MCH_ST_GEO_MODIF ; + // restituisco presenza geometria da lavorare + return ( ! m_vId.empty()) ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Preview( bool bRecalc) +{ + // non esiste preview, si fa apply + return Apply( bRecalc, false) ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Apply( bool bRecalc, bool bPostApply) +{ + // reset numero tagli nella lavorazione + int nCurrPaths = m_nPaths ; + m_nPaths = 0 ; + + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // aggiorno dati geometrici dell'utensile + bool bToolChanged = true ; + if ( ! UpdateToolData( &bToolChanged)) { + m_pMchMgr->SetLastError( 2701, "Error in SurfFinishing : UpdateToolData failed") ; + return false ; + } + + // verifico se necessario continuare nell'aggiornamento + if ( ! bRecalc && ! bToolChanged && + ( m_nStatus == MCH_ST_OK || ( ! bPostApply && m_nStatus == MCH_ST_NO_POSTAPPL))) { + m_nPaths = nCurrPaths ; + LOG_DBG_INFO( GetEMkLogger(), "SurfFinishing apply skipped : status already ok") ; + return true ; + } + m_nStatus = MCH_ST_TO_VERIFY ; + + // recupero gruppo per geometria ausiliaria + int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; + bool bChain = false ; + // se non c'è, lo aggiungo + if ( nAuxId == GDB_ID_NULL) { + nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nAuxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nAuxId, MCH_AUX) ; + m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; + bChain = true ; + } + // altrimenti, se chiesto ricalcolo, lo svuoto + else if ( bRecalc) { + m_pGeomDB->EmptyGroup( nAuxId) ; + bChain = true ; + } + + // rendo corrente l'utensile usato nella lavorazione + if ( ! m_pMchMgr->SetCalcTool( m_TParams.m_sName, m_TParams.m_sHead, m_TParams.m_nExit)) { + m_pMchMgr->SetLastError( 2702, "Error in SurfFinishing : Tool loading failed") ; + return false ; + } + // recupero i dati del portautensile + int nToolId = m_pMchMgr->GetCalcTool() ; + m_dTHoldLen = 0 ; + m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ; + m_dTHoldDiam = 0 ; + m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ; + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) { + m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Chaining failed") ; + return false ; + } + + // recupero gruppo per geometria di lavorazione (Cutter Location) + int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; + // se non c'è, lo aggiungo + if ( nClId == GDB_ID_NULL) { + nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nClId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nClId, MCH_CL) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nClId) ; + + // lavoro ogni singola catena + bool bOk = true ; + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId)) + bOk = false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + if ( ! bOk) + return false ; + + // assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso + CalcAndSetBBox( nClId) ; + + // eseguo aggiornamento assi macchina e collegamento con operazione precedente + if ( ! Update( bPostApply)) + return false ; + + // aggiorno stato della lavorazione + m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ; + // dichiaro successiva da aggiornare + UpdateFollowingOperationsStatus( MCH_ST_OTH_MODIF) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Update( bool bPostApply) +{ + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // se lavorazione vuota, esco + if ( m_nPaths == 0) { + LOG_WARN( GetEMkLogger(), "Warning in SurfFinishing : No machinable path") + return true ; + } + + // imposto eventuale asse bloccato da lavorazione + if ( ! m_Params.m_sBlockedAxis.empty()) { + string sAxis, sVal ; + Split( m_Params.m_sBlockedAxis, "=", true, sAxis, sVal) ; + double dVal = 0 ; + FromString( sVal, dVal) ; + m_pMchMgr->ClearRotAxisBlock() ; + m_pMchMgr->SetRotAxisBlock( sAxis, dVal) ; + } + + // calcolo gli assi macchina + string sHint = ExtractHint( m_Params.m_sUserNotes) ; + if ( ! m_Params.m_sInitAngs.empty()) + sHint = m_Params.m_sInitAngs ; + if ( ! CalculateAxesValues( sHint)) { + string sInfo = m_pMchMgr->GetOutstrokeInfo() ; + if ( sInfo.empty()) + m_pMchMgr->SetLastError( 2711, "Error in SurfFinishing : axes values not calculable") ; + else + m_pMchMgr->SetLastError( 2712, "Error in SurfFinishing : outstroke ") ; + return false ; + } + + // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione + if ( ! AdjustStartEndMovements()) { + string sInfo = m_pMchMgr->GetOutstrokeInfo() ; + if ( sInfo.empty()) + m_pMchMgr->SetLastError( 2713, "Error in SurfFinishing : link movements not calculable") ; + else + m_pMchMgr->SetLastError( 2714, "Error in SurfFinishing : link outstroke ") ; + return false ; + } + + // esecuzione eventuali personalizzazioni + if ( bPostApply && ! PostApply()) { + m_pMchMgr->SetLastError( 2715, "Error in SurfFinishing : post apply not calculable") ; + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetParam( int nType, bool& bVal) const +{ + switch ( nType) { + case MPA_INVERT : + bVal = m_Params.m_bInvert ; + return true ; + } + bVal = false ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetParam( int nType, int& nVal) const +{ + switch ( nType) { + case MPA_TYPE : + nVal = MT_SURFFINISHING ; + return true ; + case MPA_SUBTYPE : + nVal = m_Params.m_nSubType ; + return true ; + case MPA_LEADINTYPE : + nVal = m_Params.m_nLeadInType ; + return true ; + case MPA_LEADLINKTYPE : + nVal = m_Params.m_nLeadLinkType ; + return true ; + case MPA_LEADOUTTYPE : + nVal = m_Params.m_nLeadOutType ; + return true ; + case MPA_SCC : + nVal = m_Params.m_nSolCh ; + return true ; + } + nVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetParam( int nType, double& dVal) const +{ + switch ( nType) { + case MPA_SPEED : + dVal = GetSpeed() ; + return true ; + case MPA_FEED : + dVal = GetFeed() ; + return true ; + case MPA_STARTFEED : + dVal = GetStartFeed() ; + return true ; + case MPA_ENDFEED : + dVal = GetEndFeed() ; + return true ; + case MPA_TIPFEED : + dVal = GetTipFeed() ; + return true ; + case MPA_OFFSR : + dVal =GetOffsR() ; + return true ; + case MPA_STARTPOS : + dVal = m_Params.m_dStartPos ; + return true ; + case MPA_SIDESTEP : + dVal = m_Params.m_dSideStep ; + return true ; + case MPA_SIDEANGLE : + dVal = m_Params.m_dSideAngle ; + return true ; + case MPA_LITANG : + dVal = m_Params.m_dLiTang ; + return true ; + case MPA_LIPERP : + dVal = m_Params.m_dLiPerp ; + return true ; + case MPA_LOTANG : + dVal = m_Params.m_dLoTang ; + return true ; + case MPA_LOPERP : + dVal = m_Params.m_dLoPerp ; + return true ; + case MPA_APPROX : + dVal = m_Params.m_dApprox ; + return true ; + } + dVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetParam( int nType, string& sVal) const +{ + switch ( nType) { + case MPA_NAME : + sVal = m_Params.m_sName ; + return true ; + case MPA_TOOL : + sVal = m_Params.m_sToolName ; + return true ; + case MPA_DEPTH_STR : + sVal = m_Params.m_sDepth ; + return true ; + case MPA_TUUID : + sVal = ToString( m_Params.m_ToolUuid) ; + return true ; + case MPA_UUID : + sVal = ToString( m_Params.m_Uuid) ; + return true ; + case MPA_SYSNOTES : + sVal = m_Params.m_sSysNotes ; + return true ; + case MPA_USERNOTES : + sVal = m_Params.m_sUserNotes ; + return true ; + case MPA_INITANGS : + sVal = m_Params.m_sInitAngs ; + return true ; + case MPA_BLOCKEDAXIS : + sVal = m_Params.m_sBlockedAxis ; + return true ; + } + sVal = "" ; + return false ; +} + +//---------------------------------------------------------------------------- +const ToolData& +SurfFinishing::GetToolData( void) const +{ + return m_TParams ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::UpdateToolData( bool* pbChanged) +{ + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero l'utensile nel DB utensili + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + // verifico se sono diversi (ad esclusione del nome) + m_TParams.m_sName = pTdata->m_sName ; + bool bChanged = ! SameTool( m_TParams, *pTdata) ; + // aggiorno comunque i parametri + m_TParams = *pTdata ; + // eventuali segnalazioni + if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { + string sLog = "Warning in SurfFinishing : tool name changed (" + + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; + LOG_INFO( GetEMkLogger(), sLog.c_str()) ; + m_Params.m_sToolName = m_TParams.m_sName ; + } + if ( bChanged) { + string sLog = "Warning in SurfFinishing : tool data changed (" + + m_Params.m_sToolName + ")" ; + LOG_INFO( GetEMkLogger(), sLog.c_str()) ; + } + // se definito parametro di ritorno, lo assegno + if ( pbChanged != nullptr) + *pbChanged = bChanged ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetGeometry( SELVECTOR& vIds) const +{ + // restituisco l'elenco delle entità + vIds = m_vId ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const +{ + // compenso il raggio dell'utensile + ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::VerifyGeometry( SelData Id, int& nSubs) +{ + // ammessi : curve o superfici + + // per ora accetto solo curve + const ICurve* pCurve = nullptr ; + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + // se direttamente la curva + if ( Id.nSub == SEL_SUB_ALL) { + pCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ; + if ( pCurve != nullptr) { + if ( pCurve->GetType() == CRV_COMPO) + nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; + else + nSubs = 0 ; + } + } + // altrimenti sottocurva di composita + else { + const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; + if ( pCompo != nullptr) + pCurve = pCompo->GetCurve( Id.nSub) ; + nSubs = 0 ; + } + return ( pCurve != nullptr) ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetCurves( SelData Id, ICURVEPLIST& lstPC) +{ + // ammessi : curve + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + if ( pGObj == nullptr) + return false ; + // ne recupero il riferimento globale + Frame3d frGlob ; + if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) + return false ; + // se curva + if ( ( pGObj->GetType() & GEO_CURVE) != 0) { + PtrOwner pCurve ; + // se direttamente curva + if ( Id.nSub == SEL_SUB_ALL) { + // recupero la curva + const ICurve* pOriCurve = ::GetCurve( pGObj) ; + if ( pOriCurve == nullptr) + return false ; + // la duplico + pCurve.Set( pOriCurve->Clone()) ; + // se estrusione mancante, imposto default + Vector3d vtExtr ; + if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + pCurve->SetExtrusion( Z_AX) ; + } + // altrimenti sottocurva di composita + else { + // recupero la composita + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo == nullptr) + return false ; + // recupero la curva semplice + const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; + if ( pOriCurve == nullptr) + return false ; + // la duplico + pCurve.Set( pOriCurve->Clone()) ; + // recupero estrusione e spessore + Vector3d vtExtr ; + if ( ! pCompo->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + vtExtr = Z_AX ; + pCurve->SetExtrusion( vtExtr) ; + double dThick ; + if ( pCompo->GetThickness( dThick)) + pCurve->SetThickness( dThick) ; + } + if ( IsNull( pCurve)) + return false ; + // la porto in globale + pCurve->ToGlob( frGlob) ; + // la restituisco + lstPC.emplace_back( Release( pCurve)) ; + return true ; + } + else + return false ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::Chain( int nGrpDestId) +{ + // vettore puntatori alle curve + ICURVEPOVECTOR vpCrvs ; + vpCrvs.reserve( m_vId.size()) ; + // vettore selettori delle curve originali + SELVECTOR vInds ; + // recupero tutte le curve e le porto in globale + for ( const auto& Id : m_vId) { + // prendo le curve + ICURVEPLIST lstPC ; + if ( ! GetCurves( Id, lstPC)) { + string sOut = "Entity " + ToString( Id) + " skipped by Pocketing" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + } + for ( auto pCrv : lstPC) { + vpCrvs.emplace_back( pCrv) ; + vInds.emplace_back( Id) ; + } + } + // preparo i dati per il concatenamento + bool bFirst = true ; + Point3d ptNear = ORIG ; + double dToler = 10 * EPS_SMALL ; + ChainCurves chainC ; + chainC.Init( true, dToler, int( vpCrvs.size())) ; + for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) { + // recupero la curva e il suo riferimento + ICurve* pCrv = vpCrvs[i] ; + if ( pCrv == nullptr) + continue ; + // recupero i dati della curva necessari al concatenamento e li assegno + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || + ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) + return false ; + if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd)) + return false ; + // se prima curva, assegno inizio della ricerca + if ( bFirst) { + ptNear = ptStart + 10 * EPS_SMALL * vtStart ; + bFirst = false ; + } + } + // recupero i percorsi concatenati + int nCount = 0 ; + INTVECTOR vnId2 ; + while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { + // creo una curva composita + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // estrusione e spessore + Vector3d vtExtr = Z_AX ; + double dThick = 0 ; + // vettore Id originali + SELVECTOR vId2 ; + vId2.reserve( vnId2.size()) ; + // recupero le curve semplici e le inserisco nella curva composita + for ( size_t i = 0 ; i < vnId2.size() ; ++ i) { + int nId = abs( vnId2[i]) - 1 ; + bool bInvert = ( vnId2[i] < 0) ; + vId2.emplace_back( vInds[nId]) ; + // recupero la curva + ICurve* pCrv = vpCrvs[nId] ; + // se necessario, la inverto + if ( bInvert) + pCrv->Invert() ; + // recupero eventuali estrusione e spessore + Vector3d vtTemp ; + if ( pCrv->GetExtrusion( vtTemp)) { + vtExtr = vtTemp ; + double dTemp ; + if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick)) + dThick = dTemp ; + } + // la aggiungo alla curva composta + if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler)) + return false ; + } + // se non sono state inserite curve, vado oltre + if ( pCrvCompo->GetCurveCount() == 0) + continue ; + // imposto estrusione e spessore + pCrvCompo->SetExtrusion( vtExtr) ; + pCrvCompo->SetThickness( dThick) ; + // aggiorno il nuovo punto vicino + pCrvCompo->GetEndPoint( ptNear) ; + // se utile, approssimo con archi + if ( ! ApproxWithArcsIfUseful( pCrvCompo)) + return false ; + // creo nuovo gruppo + int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; + if ( nPathId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ; + m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( vId2)) ; + // inserisco la curva composita nel gruppo destinazione + int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::Release( pCrvCompo)) ; + if ( nNewId == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::ProcessPath( int nPathId, int nPvId, int nClId) +{ + // recupero gruppo per geometria temporanea + const string GRP_TEMP = "Temp" ; + int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ; + // se non c'è, lo aggiungo + if ( nTempId == GDB_ID_NULL) { + nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nTempId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nTempId, GRP_TEMP) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nTempId) ; + // in ogni caso lo dichiaro temporaneo e non visibile + m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ; + m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ; + + // verifico sia una curva chiusa (deve delimitare l'area da svuotare) + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) + return false ; + ICurve* pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( nCrvId)) ; + if ( pCrv == nullptr || ! pCrv->IsClosed()) { + m_pMchMgr->SetLastError( 2402, "Error in Pocketing : Open Contour") ; + return false ; + } + + // copio la curva composita da elaborare + int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; + if ( nCopyId == GDB_ID_NULL) + return false ; + ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; + + // recupero estrusione e spessore + Vector3d vtExtr = Z_AX ; + pCompo->GetExtrusion( vtExtr) ; + double dThick ; + pCompo->GetThickness( dThick) ; + + // verifico sia piana e sistemo senso antiorario visto dalla direzione di estrusione + Plane3d plPlane ; double dArea ; + if ( ! pCompo->GetArea( plPlane, dArea)) { + m_pMchMgr->SetLastError( 2403, "Error in Pocketing : Contour Not Flat") ; + return false ; + } + if ( abs( plPlane.GetVersN() * vtExtr) < cos( 10 * EPS_ANG_SMALL)) { + m_pMchMgr->SetLastError( 2404, "Error in Pocketing : Tool Dir not perpendicular to Flat Area") ; + return false ; + } + if ( plPlane.GetVersN() * vtExtr * dArea < 0) + pCompo->Invert() ; + + // unisco le parti allineate + if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true)) + return false ; + + // recupero il box del grezzo in globale + BBox3d b3Raw ; + if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) { + m_pMchMgr->SetLastError( 2405, "Error in Pocketing : Empty RawBox") ; + return false ; + } + + // valuto l'espressione dell'affondamento + ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; + double dDepth ; + string sMyDepth = m_Params.m_sDepth ; + if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { + m_pMchMgr->SetLastError( 2406, "Error in Pocketing : Depth not computable") ; + return false ; + } + + // recupero nome del path + string sPathName ; + m_pGeomDB->GetName( nPathId, sPathName) ; + + // assegno il versore fresa + Vector3d vtTool = vtExtr ; + + // se richiesta lavorazione + if ( nClId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, BLUE) ; + + // verifico se archi vanno approssimati con segmenti di retta + int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; + bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || + ( nSplitArcs == SPLAR_NO_XY_PLANE && ! vtExtr.IsZplus()) || + ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; + + // assegno il vettore estrazione al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; + + // Imposto dati comuni + SetPathId( nPxId) ; + SetToolDir( vtTool) ; + + // Eseguo la lavorazione a seconda del tipo + double dElev = dDepth ; + if ( ! AddZigZag( pCompo, vtTool, vtExtr, dDepth, dElev, bSplitArcs)) + return false ; + } + + // incremento numero di percorsi + ++ m_nPaths ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddZigZag( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) +{ + // recupero distanze di sicurezza + double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; + double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + + // calcolo curva offsettata del raggio utensile + sovramateriale + extra + double dTRad = 0.5 * m_TParams.m_dDiam ; + double dOffs = dTRad ; + double dExtra = min( 0.1 * m_TParams.m_dDiam, 2.0) ; + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCompo, - ( dOffs + dExtra), ICurve::OFF_FILLET)) { + m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; + return false ; + } + + // ciclo sulle curve risultanti + bool bStart = true ; + while ( OffsCrv.GetCurveCount() > 0) { + + // recupero la prima curva di offset + PtrOwner pOffs( CreateCurveComposite()) ; + if ( IsNull( pOffs) || ! pOffs->AddCurve( OffsCrv.GetLongerCurve())) { + m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; + return false ; + } + + // determino il riferimento di base e il box della svuotatura + Frame3d frPocket ; + Point3d ptCen ; pCompo->GetCentroid( ptCen) ; + frPocket.Set( ptCen, vtExtr) ; + frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; + pOffs->ToLoc( frPocket) ; + + // calcolo i percorsi di svuotatura + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! CalcZigZag( pOffs, vpCrvs)) + return false ; + + // li correggo per non interferire con le superfici + PtrOwner pCAvTlStm( CreateCAvToolSurfTm()) ; + if ( IsNull( pCAvTlStm)) + return false ; + pCAvTlStm->SetStdTool( m_TParams.m_dLen + GetOffsR(), + m_TParams.m_dDiam / 2 + GetOffsR(), + m_TParams.m_dCornRad + GetOffsR()) ; + // recupero le superfici TriMesh dei pezzi in lavorazione + int nRawId = m_pMchMgr->GetFirstRawPart() ; + int nPartId = m_pMchMgr->GetFirstPartInRawPart( nRawId) ; + int nLayId = m_pGeomDB->GetFirstGroupInGroup( nPartId) ; + int nEntId = m_pGeomDB->GetFirstInGroup( nLayId) ; + while ( nEntId != GDB_ID_NULL) { + if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH) + break ; + nEntId = m_pGeomDB->GetNext( nEntId) ; + } + if ( nEntId != GDB_ID_NULL) { + const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nEntId)) ; + if ( pStm == nullptr) + return false ; + // recupero il riferimento della superficie + Frame3d frSurf ; + if ( ! m_pGeomDB->GetGlobFrame( nEntId, frSurf)) + return false ; + // approssimo la curva con una polilinea + PolyLine PL ; + if ( ! vpCrvs[0]->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return false ; + // eventuale aggiunta di punti per garantire max distanza + const double MIN_DIST = 1. ; + const double MAX_DIST = 50. ; + double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ; + if ( ! PL.AdjustForMaxSegmentLen( dDist)) + return false ; + // porto nel riferimento della superficie + PL.LocToLoc( frPocket, frSurf) ; + // porto i dati geometrici in locale alla superficie + Vector3d vtAxL = vtTool ; + vtAxL.ToLoc( frSurf) ; + Vector3d vtMoveL = vtAxL ; + // traslo della lunghezza utensile diminuita dell'affondamento + PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ; + // imposto dati + pCAvTlStm->SetSurfTm( *pStm) ; + // eseguo CAv + if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox)) + return false ; + // contro-traslo della lunghezza utensile + PL.Translate( - vtAxL * m_TParams.m_dLen) ; + // riporto la polilinea nel riferimento della curva + PL.LocToLoc( frSurf, frPocket) ; + // elimino i punti allineati + PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; + // creo una curva composita a partire dalla polilinea + PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ; + if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) + return false ; + // sostituisco la vecchia curva con la nuova + vpCrvs[0].Set( Release( pCompo )) ; + } + // ciclo sui percorsi + for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) { + // ciclo sulle curve elementari + int nMaxInd = vpCrvs[k]->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = vpCrvs[k]->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( pCrvC->Clone()) ; + if ( IsNull( pCurve)) + return false ; + pCurve->ToGlob( frPocket) ; + // se prima entità + if ( i == 0 ) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // determino inizio attacco + Point3d ptP1 ; + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, ptP1)) + return false ; + // determino elevazione su inizio attacco + double dStElev = dElev ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // se inizio, approccio globale al punto iniziale + if ( bStart) { + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) { + m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; + return false ; + } + bStart = false ; + } + // altrimenti, approccio di collegamento + else { + if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) { + m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; + return false ; + } + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr)) { + m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; + return false ; + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + double dEndElev = dElev ; + Point3d ptP1 ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, ptP1)) { + m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; + return false ; + } + // se non è ultimo tratto, aggiungo retrazione di collegamento + if ( k < int( vpCrvs.size()) - 1) { + if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) { + m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; + return false ; + } + } + // altrimenti aggiungo retrazione finale + else { + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) { + m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ; + return false ; + } + } + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::CalcZigZag( const ICurveComposite* pOffs, + ICRVCOMPOPOVECTOR& vpCrvs) +{ + // ingombro del contorno offsettato + BBox3d b3Pocket ; + pOffs->GetLocalBBox( b3Pocket) ; + Point3d ptMin ; double dDimX, dDimY, dDimZ ; + b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; + + // lunghezza del contorno offsettato + double dLen ; pOffs->GetLength( dLen) ; + + // passi in Y + int nYStep = static_cast( ceil( ( dDimY - 20 * EPS_SMALL) / GetSideStep())) ; + double dYStep = ( nYStep > 0 ? ( dDimY - 20 * EPS_SMALL) / nYStep : 0) ; + + // tratto valido + struct Section { + bool bActive ; + Point3d ptS ; + Point3d ptE ; + double dOs ; + double dOe ; + } ; + // raccolta di tratti + typedef std::vector> VECVECSECT ; + + VECVECSECT vvSec ; + vvSec.resize( nYStep + 1) ; + + // calcolo le linee di svuotatura + int nCount = 0 ; + for ( int i = 0 ; i <= nYStep ; ++ i) { + // determino senso + bool bPlus = (( i % 2) == 0) ; + // definisco la linea + PtrOwner pLine( CreateCurveLine()) ; + const double EXP_LEN = 1.0 ; + Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ; + if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { + m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; + return false ; + } + // calcolo la classificazione della curva rispetto al contorno esterno offsettato + IntersCurveCurve intCC( *pLine, *pOffs) ; + CRVCVECTOR ccClass ; + if ( ! intCC.GetCurveClassification( 0, ccClass)) { + m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; + return false ; + } + // determino gli intervalli di curva da conservare + Intervals inOk ; + for ( auto& ccOne : ccClass) { + if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M) + inOk.Add( ccOne.dParS, ccOne.dParE) ; + } + // inserisco i tratti validi (secondo X+ i pari, secondo X- i dispari) + double dParS, dParE ; + bool bFound = ( bPlus ? inOk.GetFirst( dParS, dParE) : inOk.GetLast( dParE, dParS)) ; + while ( bFound) { + // determino i dati della sezione + Section Sect ; + Sect.bActive = true ; + pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, Sect.ptS) ; + pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, Sect.ptE) ; + pOffs->GetParamAtPoint( Sect.ptS, Sect.dOs, 10 * EPS_SMALL) ; + pOffs->GetParamAtPoint( Sect.ptE, Sect.dOe, 10 * EPS_SMALL) ; + // inserisco nel contenitore + vvSec[i].emplace_back( Sect) ; + ++ nCount ; + // recupero successivo intervallo + bFound = ( bPlus ? inOk.GetNext( dParS, dParE) : inOk.GetPrev( dParE, dParS)) ; + } + } + + // dominio del contorno + double dUmin, dUmax ; + pOffs->GetDomain( dUmin, dUmax) ; + double dUspan = dUmax - dUmin ; + + // creo i percorsi di svuotatura + vpCrvs.reserve( nCount) ; + int nI = -1, nJ = -1 ; + while ( true) { + // se sezione non valida + if ( nI < 0 || nJ < 0) { + // ricerco la prima valida + for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) { + for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) { + if ( vvSec[k][l].bActive) { + nI = k ; + nJ = l ; + } + } + } + // se trovata, creo nuova curva composita + if ( nI >= 0 && nJ >= 0) { + // creo la curva + vpCrvs.emplace_back( CreateCurveComposite()) ; + // aggiungo punto iniziale + vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ; + } + // altrimenti, esco + else + break ; + } + // determino senso + bool bPlus = (( nI % 2) == 0) ; + // aggiungo la sezione alla curva + Section& Sec = vvSec[nI][nJ] ; + Sec.bActive = false ; + vpCrvs.back()->AddLine( vvSec[nI][nJ].ptE) ; + // cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno + double dUstart = Sec.dOe ; + double dUref = ( bPlus ? INFINITO : - INFINITO) ; + int nNextI = -1 ; + int nNextJ = -1 ; + int li = nJ + 1 ; + for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) { + for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) { + if ( ! vvSec[k][l].bActive) + continue ; + double dU = vvSec[k][l].dOs ; + if ( bPlus) { + if ( dU < dUstart) + dU += dUspan ; + if ( dU < dUref) { + dUref = dU ; + nNextI = k ; + nNextJ = l ; + } + } + else { + if ( dU > dUstart) + dU -= dUspan ; + if ( dU > dUref) { + dUref = dU ; + nNextI = k ; + nNextJ = l ; + } + } + } + li = 0 ; + } + // se trovato, aggiungo il tratto di contorno e continuo + if ( nNextI != -1) { + PtrOwner pCopy ; + if ( bPlus) { + if ( dUref > dUmax) + dUref -= dUspan ; + pCopy.Set( pOffs->CopyParamRange( dUstart, dUref)) ; + if ( ! IsNull( pCopy)) { + double dCLen ; pCopy->GetLength( dCLen) ; + if ( dCLen > 0.5 * dLen) { + pCopy.Set( pOffs->CopyParamRange( dUref, dUstart)) ; + if ( ! IsNull( pCopy)) + pCopy->Invert() ; + } + } + } + else { + if ( dUref < dUmin) + dUref += dUspan ; + pCopy.Set( pOffs->CopyParamRange( dUref, dUstart)) ; + if ( ! IsNull( pCopy)) { + pCopy->Invert() ; + double dCLen ; pCopy->GetLength( dCLen) ; + if ( dCLen > 0.5 * dLen) + pCopy.Set( pOffs->CopyParamRange( dUstart, dUref)) ; + } + } + BBox3d b3Copy ; + if ( ! IsNull( pCopy)) + pCopy->GetLocalBBox( b3Copy) ; + if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) { + vpCrvs.back()->AddCurve( Release( pCopy)) ; + nI = nNextI ; + nJ = nNextJ ; + } + else { + nI = -1 ; + nJ = -1 ; + } + } + else { + nI = -1 ; + nJ = -1 ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + SetFlag( 1) ; + // se sopra attacco c'è spazio per sicurezza o approccio + double dSafeDist = dSafeZ ; + if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { + // se distanza di sicurezza minore di distanza di inizio + if ( dSafeDist < dAppr + 10 * EPS_SMALL) { + // 1 -> punto sopra inizio + Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; + if ( AddRapidStart( ptP1) == GDB_ID_NULL) + return false ; + } + else { + // 1a -> punto sopra inizio + Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; + Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ; + if ( ( AddRapidStart( ptP1a) == GDB_ID_NULL)) + return false ; + // 1b -> punto appena sopra inizio + if ( ( dElev + dAppr) > EPS_SMALL) { + SetFlag( 0) ; + if ( AddRapidMove( ptP1b) == GDB_ID_NULL) + return false ; + } + } + // affondo al punto iniziale + SetFlag( 0) ; + SetFeed( GetTipFeed()) ; + if ( AddLinearMove( ptP) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( AddRapidStart( ptP) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + // se sopra attacco c'è spazio per approccio + if ( ( dElev + dAppr) > 10 * EPS_SMALL) { + // 1b -> punto appena sopra inizio + Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; + if ( ( dElev + dAppr) > EPS_SMALL) { + SetFlag( 0) ; + if ( AddRapidMove( ptP1b) == GDB_ID_NULL) + return false ; + } + // affondo al punto iniziale + SetFlag( 0) ; + SetFeed( GetTipFeed()) ; + if ( AddLinearMove( ptP) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( AddRapidMove( ptP) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + // se sopra uscita c'è spazio per approccio + if ( ( dElev + dAppr) > 10 * EPS_SMALL) { + // 4 -> movimento di risalita sopra il punto finale + SetFeed( GetEndFeed()) ; + Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; + if ( AddLinearMove( ptP4) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + // se sopra uscita c'è spazio per sicurezza o approccio + double dSafeDist = dSafeZ ; + if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { + if ( dSafeDist < dAppr + 10 * EPS_SMALL) { + // 4 -> movimento di risalita sopra il punto finale + SetFeed( GetEndFeed()) ; + Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; + if ( AddLinearMove( ptP4) == GDB_ID_NULL) + return false ; + } + else { + // 4a -> movimento di risalita appena sopra il punto finale + Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; + if ( dElev + dAppr > EPS_SMALL) { + SetFeed( GetEndFeed()) ; + if ( AddLinearMove( ptP4a) == GDB_ID_NULL) + return false ; + } + // 4b -> movimento di risalita sopra il punto finale + Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ; + if ( AddRapidMove( ptP4b) == GDB_ID_NULL) + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, Point3d& ptP1) +{ + ptP1 = ptStart ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN) +{ + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, Point3d& ptP1) +{ + ptP1 = ptEnd ; + return true ; +} diff --git a/SurfFinishing.h b/SurfFinishing.h new file mode 100644 index 0000000..a95468d --- /dev/null +++ b/SurfFinishing.h @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------------- +// EgalTech 2019-2019 +//---------------------------------------------------------------------------- +// File : SurfFinishing.h Data : 28.05.19 Versione : 2.1e5 +// Contenuto : Dichiarazione della classe SurfFinishing. +// +// +// +// Modifiche : 28.05.19 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "Machining.h" +#include "SurfFinishingData.h" +#include "ToolData.h" +#include "MachiningConst.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EgtNumUtils.h" + +//---------------------------------------------------------------------------- +class SurfFinishing : public Machining +{ + public : // IUserObj + SurfFinishing* Clone( void) const override ; + const std::string& GetClassName( void) const override ; + bool Dump( std::string& sOut, bool bMM = true, const char* szNewLine = "\n") const override ; + bool ToSave( void) const override + { return true ; } + bool Save( int nBaseId, STRVECTOR& vString) const override ; + bool Load( const STRVECTOR& vString, int nBaseGdbId) override ; + + public : // Operation + int GetType( void) const override + { return OPER_SAWFINISHING ; } + bool IsEmpty( void) const override + { return ( m_nPaths == 0) ; } + bool UpdateStatus( int nModif) override + { m_nStatus |= nModif ; return true ; } + + protected : // Operation + int GetSolCh( void) const override + { return m_Params.m_nSolCh ; } + bool AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const override ; + + public : // Machining + bool Prepare( const std::string& sSawName) override ; + bool SetParam( int nType, bool bVal) override ; + bool SetParam( int nType, int nVal) override ; + bool SetParam( int nType, double dVal) override ; + bool SetParam( int nType, const std::string& sVal) override ; + bool SetGeometry( const SELVECTOR& vIds) override ; + bool Preview( bool bRecalc) override ; + bool Apply( bool bRecalc, bool bPostApply) override ; + bool Update( bool bPostApply) override ; + bool GetParam( int nType, bool& bVal) const override ; + bool GetParam( int nType, int& nVal) const override ; + bool GetParam( int nType, double& dVal) const override ; + bool GetParam( int nType, std::string& sVal) const override ; + bool UpdateToolData( bool* pbChanged = nullptr) override ; + const ToolData& GetToolData( void) const override ; + bool GetGeometry( SELVECTOR& vIds) const override ; + + public : + SurfFinishing( void) ; + + private : + bool VerifyGeometry( SelData Id, int& nSubs) ; + bool GetCurves( SelData Id, ICURVEPLIST& lstPC) ; + bool Chain( int nGrpDestId) ; + bool ProcessPath( int nPathId, int nPvId, int nClId) ; + bool AddZigZag( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) ; + bool CalcZigZag( const ICurveComposite* pOffs, ICRVCOMPOPOVECTOR& vpCrvs) ; + bool AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, Point3d& ptP1) ; + bool AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN) ; + bool AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, Point3d& ptP1) ; + + private : + double GetSpeed() const + { return ( IsNullAngValue( m_Params.m_dSpeed) ? m_TParams.m_dSpeed : m_Params.m_dSpeed) ; } + double GetFeed() const + { return ( IsNullLenValue( m_Params.m_dFeed) ? m_TParams.m_dFeed : m_Params.m_dFeed) ; } + double GetStartFeed() const + { return ( IsNullLenValue( m_Params.m_dStartFeed) ? m_TParams.m_dStartFeed : m_Params.m_dStartFeed) ; } + double GetEndFeed() const + { return ( IsNullLenValue( m_Params.m_dEndFeed) ? m_TParams.m_dEndFeed : m_Params.m_dEndFeed) ; } + double GetTipFeed() const + { return ( IsNullLenValue( m_Params.m_dTipFeed) ? m_TParams.m_dTipFeed : m_Params.m_dTipFeed) ; } + double GetOffsR() const + { return ( IsUnknownValue( m_Params.m_dOffsR) ? m_TParams.m_dOffsR : m_Params.m_dOffsR) ; } + double GetSideStep( void) const + { return Clamp( m_Params.m_dSideStep, std::min( 0.1 * m_TParams.m_dDiam, 1.0), m_TParams.m_dDiam) ; } + + private : + SELVECTOR m_vId ; // identificativi entità geometriche da lavorare + SurfFinishingData m_Params ; // parametri lavorazione + ToolData m_TParams ; // parametri utensile + double m_dTHoldLen ; // lunghezza del porta-utensile + double m_dTHoldDiam ; // diametro del porta-utensile + int m_nStatus ; // stato di aggiornamento della lavorazione + int m_nPaths ; // numero di percorsi di lavoro generati +} ;