//---------------------------------------------------------------------------- // EgalTech 2015-2019 //---------------------------------------------------------------------------- // File : SawFinishing.cpp Data : 23.04.19 Versione : 2.1d3 // Contenuto : Implementazione gestione finitura superficie con lama. // // Note : Questa lavorazione è sempre espressa nel riferimento globale. // // Modifiche : 05.04.16 DS Creazione modulo. // 23.04.19 DS Aggiunte cornici curve. // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "SawFinishing.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/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkOffsetCurveOnX.h" #include "/EgtDev/Include/EGkSfrCreate.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 SawFinishing : UpdateToolData failed" // 2702 = "Error in SawFinishing : AdjustGeometry failed" // 2703 = "Error in SawFinishing : Empty RawBox" // 2704 = "Error in SawFinishing : Depth not computable" // 2705 = "Error in SawFinishing : CalculateToolAndCorrVersors" // 2706 = "Error in SawFinishing : ApproxWithLines" // 2707 = "Error in SawFinishing : Guide Line not along X or Y" // 2708 = "Error in SawFinishing : GetElevation" // 2709 = "Error in SawFinishing : CalculateAlongToolPath failed" // 2710 = "Error in SawFinishing : CalculateAcrossToolPath failed" // 2711 = "Error in SawFinishing : axes values not calculable" // 2712 = "Error in SawFinishing : outstroke xx" // 2713 = "Error in SawFinishing : link movements not calculable" // 2714 = "Error in SawFinishing : link outstroke xx" // 2715 = "Error in SawFinishing : post apply not calculable" // 2751 = "Warning in SawFinishing : Skipped entity (xx)" // 2752 = "Warning in SawFinishing : No machinable path" // 2753 = "Warning in SawFinishing : Tool name changed (xx)" // 2754 = "Warning in SawFinishing : Tool data changed (xx)" //---------------------------------------------------------------------------- const string MCH_SECTION = "Sect" ; const string MCH_GUIDE = "Guide" ; enum nCrvClass { CCL_SMALL = 0, CCL_VERT = 1, CCL_FLAT = 2, CCL_FALL = 3, CCL_RISE = 4 }; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_SAWFINISHING), SawFinishing) ; //---------------------------------------------------------------------------- const string& SawFinishing::GetClassName( void) const { return USEROBJ_GETNAME( SawFinishing) ; } //---------------------------------------------------------------------------- SawFinishing* SawFinishing::Clone( void) const { // alloco oggetto SawFinishing* pSaw = new(nothrow) SawFinishing ; // eseguo copia dei dati if ( pSaw != nullptr) { try { pSaw->m_vId = m_vId ; pSaw->m_bStraight = m_bStraight ; pSaw->m_pMchMgr = m_pMchMgr ; pSaw->m_nPhase = m_nPhase ; pSaw->m_Params = m_Params ; pSaw->m_TParams = m_TParams ; pSaw->m_nStatus = m_nStatus ; pSaw->m_nCuts = m_nCuts ; } catch( ...) { delete pSaw ; return nullptr ; } } // ritorno l'oggetto return pSaw ; } //---------------------------------------------------------------------------- bool SawFinishing::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 ; sOut += KEY_STRAIGHT + EQUAL + ToString( m_bStraight) + 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_nCuts) + szNewLine ; sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::Save( int nBaseId, STRVECTOR& vString) const { try { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 4 ; 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_nCuts, vString[++k])) return false ; if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) return false ; if ( ! SetVal( KEY_STRAIGHT, m_bStraight, vString[++k])) return false ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::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_nCuts)) return false ; } else if ( sKey == KEY_STAT) { if ( ! FromString( sVal, m_nStatus)) return false ; } else if ( sKey == KEY_STRAIGHT) { if ( ! FromString( sVal, m_bStraight)) return false ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- SawFinishing::SawFinishing( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_nStatus = MCH_ST_TO_VERIFY ; m_nCuts = 0 ; m_bStraight = true ; } //---------------------------------------------------------------------------- bool SawFinishing::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 SawFinishingData* pDdata = GetSawFinishingData( 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 SawFinishing::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 SawFinishing::SetParam( int nType, int nVal) { switch ( nType) { case MPA_HEADSIDE : if ( ! m_Params.VerifyHeadSide( nVal)) return false ; if ( nVal != m_Params.m_nHeadSide) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nHeadSide = nVal ; return true ; case MPA_STEPTYPE : if ( ! m_Params.VerifyStepType( nVal)) return false ; if ( nVal != m_Params.m_nStepType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nStepType = nVal ; return true ; 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_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_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 SawFinishing::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_VERTFEED : if ( AreSameLenValue( dVal, m_TParams.m_dFeed)) dVal = 0 ; if ( ! AreSameLenValue( dVal, m_Params.m_dVertFeed)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dVertFeed = 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_STEP : if ( ! AreSameLenValue( dVal, m_Params.m_dStep)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStep = 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 ; case MPA_STARTADDLEN : if ( ! AreSameLenValue( dVal, m_Params.m_dStartAddLen)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartAddLen = dVal ; return true ; case MPA_ENDADDLEN : if ( ! AreSameLenValue( dVal, m_Params.m_dEndAddLen)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndAddLen = dVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SawFinishing::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 SawFinishing::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 sInfo = "Warning in SawFinishing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2751, sInfo) ; 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 SawFinishing::Preview( bool bRecalc) { // non esiste preview, si fa apply return Apply( bRecalc, false) ; } //---------------------------------------------------------------------------- bool SawFinishing::Apply( bool bRecalc, bool bPostApply) { // reset numero tagli nella lavorazione int nCurrCuts = m_nCuts ; m_nCuts = 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 SawFinishing : 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))) { // confermo i percorsi di lavorazione m_nCuts = nCurrCuts ; LOG_DBG_INFO( GetEMkLogger(), "SawFinishing apply skipped : status already ok") ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; LOG_DBG_INFO( GetEMkLogger(), "Update done") ; // esco con successo return true ; } m_nStatus = MCH_ST_TO_VERIFY ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; // 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) ; bRecalc = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; } // se necessario, preparo geometria e la inserisco sotto la geometria ausiliaria if ( bRecalc && ! AdjustGeometry( nAuxId)) { m_pMchMgr->SetLastError( 2702, "Error in SawFinishing : AdjustGeometry 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) ; // calcolo le passate 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 ; } } else { if ( ! CalculateCurvedAlongToolPath( nAuxId, nClId)) { 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") ; return false ; } } else { if ( ! CalculateCurvedAcrossToolPath( nAuxId, nClId)) { m_pMchMgr->SetLastError( 2710, "Error in SawFinishing : CalculateAcrossToolPath failed") ; 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) ; LOG_DBG_INFO( GetEMkLogger(), "SawFinishing apply done") ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::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_nCuts == 0) { m_pMchMgr->SetWarning( 2752, "Warning in SawFinishing : No machinable path") ; return true ; } // imposto eventuale asse bloccato da lavorazione SetBlockedRotAxis( m_Params.m_sBlockedAxis) ; // 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 SawFinishing : axes values not calculable") ; else m_pMchMgr->SetLastError( 2712, "Error in SawFinishing : 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 SawFinishing : link movements not calculable") ; else m_pMchMgr->SetLastError( 2714, "Error in SawFinishing : link outstroke ") ; return false ; } // assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetAxesBBox() ; // esecuzione eventuali personalizzazioni string sErr ; if ( bPostApply && ! PostApply( sErr)) { if ( ! IsEmptyOrSpaces( sErr)) m_pMchMgr->SetLastError( 2715, sErr) ; else m_pMchMgr->SetLastError( 2715, "Error in SawFinishing : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool SawFinishing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_SAWFINISHING ; return true ; case MPA_HEADSIDE : nVal = m_Params.m_nHeadSide ; return true ; case MPA_STEPTYPE : nVal = m_Params.m_nStepType ; return true ; case MPA_SUBTYPE : nVal = m_Params.m_nSubType ; return true ; case MPA_LEADLINKTYPE : nVal = m_Params.m_nLeadLinkType ; return true ; case MPA_SCC : nVal = m_Params.m_nSolCh ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool SawFinishing::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_VERTFEED : dVal = GetVertFeed() ; 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_STEP : dVal = m_Params.m_dStep ; return true ; case MPA_APPROX : dVal = m_Params.m_dApprox ; return true ; case MPA_STARTADDLEN : dVal = m_Params.m_dStartAddLen ; return true ; case MPA_ENDADDLEN : dVal = m_Params.m_dEndAddLen ; return true ; } dVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool SawFinishing::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& SawFinishing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool SawFinishing::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 sInfo = "Warning in SawFinishing : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; m_pMchMgr->SetWarning( 2753, sInfo) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sInfo = "Warning in SawFinishing : tool data changed (" + m_Params.m_sToolName + ")" ; m_pMchMgr->SetWarning( 2754, sInfo) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const { // compenso il raggio dell'utensile ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::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( pGObj) ; if ( pCurve != nullptr) { if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; if ( pCompo != nullptr) pCurve = pCompo->GetCurve( Id.nSub) ; nSubs = 0 ; } return ( pCurve != nullptr) ; } //---------------------------------------------------------------------------- ICurve* SawFinishing::GetCurve( SelData Id) { // ammessi : curve o facce di polymesh // nel caso di facce si deve recuperare la linea di base // per ora accetto solo curve PtrOwner pCurve ; // se direttamente curva if ( Id.nSub == SEL_SUB_ALL) { // recupero e duplico la curva const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pOriCurve != nullptr) pCurve.Set( pOriCurve->Clone()) ; } // altrimenti sottocurva di composita else { // recupero la composita const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCompo != nullptr) { // duplico la curva semplice const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; if ( pOriCurve != nullptr) { pCurve.Set( pOriCurve->Clone()) ; // recupero estrusione e spessore Vector3d vtExtr ; if ( pCompo->GetExtrusion( vtExtr)) pCurve->SetExtrusion( vtExtr) ; double dThick ; if ( pCompo->GetThickness( dThick)) pCurve->SetThickness( dThick) ; } } } if ( IsNull( pCurve)) return nullptr ; // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return nullptr ; // la porto in globale pCurve->ToGlob( frGlob) ; // la restituisco return Release( pCurve) ; } //---------------------------------------------------------------------------- bool SawFinishing::AdjustGeometry( int nAuxId) { // sgrossatura di cornici diritte : due o più curve (sezioni e guida rettilinea) // sgrossatura di cornici curve : due curve (sezione e guida curva) size_t nCrvCount = m_vId.size() ; if ( nCrvCount >= 2) { // le sezioni devono essere chiuse, piane e giacere in uno stesso piano verticale ICURVEPOVECTOR vpSects ; vpSects.reserve( nCrvCount - 1) ; Vector3d vtN ; for ( size_t i = 0 ; i < nCrvCount - 1 ; ++ i) { vpSects.emplace_back( GetCurve( m_vId[i])) ; if ( IsNull( vpSects.back())) return false ; if ( ! vpSects.back()->IsClosed()) return false ; Plane3d plPlane ; if ( ! vpSects.back()->IsFlat( plPlane, false, 10 * EPS_SMALL) || abs( plPlane.GetVersN().z) > EPS_SMALL) return false ; if ( i == 0) vtN = plPlane.GetVersN() ; else { if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN)) return false ; } } // l'ultima curva è la guida PtrOwner pGuide( GetCurve( m_vId[nCrvCount-1])) ; if ( IsNull( pGuide)) return false ; // se linea -> cornici diritte (lama verticale) if ( pGuide->GetType() == CRV_LINE) m_bStraight = true ; // altrimenti curva -> cornici curve (lama orizzontale) else { m_bStraight = false ; // ammessa una sola sezione if ( nCrvCount > 2) return false ; // la guida deve giacere nel piano XY Plane3d plPlane ; if ( ! pGuide->IsFlat( plPlane, false, 10 * EPS_SMALL) || ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), Z_AX)) return false ; // verifiche sulla curva (che trasformo in composita) PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pGuide))) return false ; // converto in archi e rette pCompo->ArcsBezierCurvesToArcsPerpExtr( LIN_TOL_MID, ANG_TOL_STD_DEG) ; // verifiche sull'ampiezza dell'angolo al centro degli eventuali archi VerifyArcs( pCompo) ; // reinserisco nella curva originale pGuide.Set( Release( pCompo)) ; } // deve iniziare in comune con la prima sezione ed essere ivi perpendicolare Vector3d vtGdDir ; if ( ! pGuide->GetStartDir( vtGdDir) || ! AreSameOrOppositeVectorApprox( vtN, vtGdDir)) return false ; Point3d ptStStart, ptGdStart ; if ( ! vpSects[0]->GetStartPoint( ptStStart) || ! pGuide->GetStartPoint( ptGdStart) || ( ptGdStart - ptStStart) * vtGdDir > 10 * EPS_SMALL) return false ; // creo sottogruppo di ausiliario per le sezioni con riferimento avente // l'origine nel punto di inizio della guida e la Z opposta alla direzione della guida Frame3d frSect ; if ( ! frSect.Set( ptGdStart, - vtGdDir)) return false ; int nGrpSectId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, frSect) ; if ( nGrpSectId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nGrpSectId, MCH_SECTION) ; // inserisco le sezioni e ne sistemo il senso di rotazione come CCW for ( auto& pSect : vpSects) { pSect->ToLoc( frSect) ; double dArea ; pSect->GetAreaXY( dArea) ; if ( dArea < 0) pSect->Invert() ; if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpSectId, ::Release( pSect)) == GDB_ID_NULL) return false ; } // creo sottogruppo per la guida // inserisco la guida nel gruppo ausiliario int nGrpGuideId = m_pGeomDB->AddGroup( GDB_ID_NULL, nAuxId, Frame3d()) ; if ( nGrpGuideId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nGrpGuideId, MCH_GUIDE) ; if ( m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGrpGuideId, ::Release( pGuide)) == GDB_ID_NULL) return false ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateStraightAlongToolPath( int nAuxId, int nClId) { // Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama ICurve* pSect ; int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ; if ( ! CalculateSection( nSectGrpId, pSect)) return false ; PtrOwner pCrv( pSect) ; // 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 ed elaboro la linea guida Point3d ptGdStart, ptGdEnd ; Vector3d vtGdDir ; int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ; if ( ! CalculateGuideLine( nGuideId, b3Sect, ptGdStart, ptGdEnd, vtGdDir)) 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) ; // Determino versori fresa e correzione Vector3d vtTool, vtCorr ; if ( ! CalculateToolAndCorrVersors( vtGdDir, m_Params.m_nHeadSide, vtTool, vtCorr)) { m_pMchMgr->SetLastError( 2705, "Error in SawFinishing : CalculateToolAndCorrVersors") ; return false ; } // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; SetCorrAuxDir( vtCorr) ; // Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale) INTVECTOR vnClass ; ClassifySection( pCrv, vnClass) ; // Inizializzo contatore tagli m_nCuts = 0 ; // Passate sui lati verticali int nUmin = -1, nUmax = -1 ; for ( size_t i = 0 ; i < vnClass.size() ; ++ i) { // se lato verticale if ( vnClass[i] == CCL_VERT) { if ( nUmin < 0) nUmin = int( i) ; nUmax = int( i + 1) ; } // se lato non verticale e non piccolo o ultimo if ( ( vnClass[i] != CCL_VERT && vnClass[i] != CCL_SMALL) || i == vnClass.size() - 1) { if ( nUmin >= 0) { // eseguo la passata if ( ! CalcAlongVerticalCuts( pCrv, nUmin, nUmax, frSect, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw.GetMax().z, vtTool, vtCorr)) return false ; nUmin = - 1 ; } } } // Altre passate int nStatus = CCL_VERT ; nUmin = -1 ; nUmax = -1 ; bool bSkipMin = false, bSkipMax = false ; for ( size_t i = 0 ; i < vnClass.size() ; ++ i) { // se stato nullo (verticale) if ( nStatus == CCL_VERT) { if ( vnClass[i] == CCL_VERT || vnClass[i] == CCL_SMALL) continue ; else { nStatus = vnClass[i] ; nUmin = int( i) ; nUmax = int( i + 1) ; bSkipMin = true ; } } // altrimenti else { // se classe piatto e trovo salita o discesa, converto a questo if ( nStatus == CCL_FLAT && ( vnClass[i] == CCL_RISE || vnClass[i] == CCL_FALL)) nStatus = vnClass[i] ; // se si conserva la classe, aggiorno fine if ( vnClass[i] == nStatus || vnClass[i] == CCL_FLAT || vnClass[i] == CCL_SMALL) nUmax = int( i + 1) ; // altrimenti calcolo il tratto precedente else { // calcolo il tratto bSkipMax = ( vnClass[i] == CCL_VERT) ; bool bInvert = ( nStatus == CCL_RISE) ; if ( ! CalcAlongStdCuts( pCrv, nUmin, nUmax, bSkipMin, bSkipMax, bInvert, frSect, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw.GetMax().z, vtTool, vtCorr)) return false ; // aggiorno stato if ( vnClass[i] == CCL_VERT) nStatus = CCL_VERT ; else { nStatus = vnClass[i] ; nUmin = int( i) ; nUmax = int( i + 1) ; } bSkipMin = true ; } } } // se c'è qualcosa in sospeso if ( nStatus != CCL_VERT) { bSkipMax = false ; bool bInvert = ( nStatus == CCL_RISE) ; if ( ! CalcAlongStdCuts( pCrv, nUmin, nUmax, bSkipMin, bSkipMax, bInvert, frSect, ptGdStart, ptGdEnd, vtGdDir, dDepth, b3Raw.GetMax().z, vtTool, vtCorr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateStraightAcrossToolPath( int nAuxId, int nClId) { // Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama ICurve* pSect ; int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ; if ( ! CalculateSection( nSectGrpId, pSect)) return false ; PtrOwner pCrv( pSect) ; // 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 ed elaboro la linea guida Point3d ptGdStart, ptGdEnd ; Vector3d vtGdDir ; int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ; if ( ! CalculateGuideLine( nGuideId, b3Sect, ptGdStart, ptGdEnd, vtGdDir)) return false ; Vector3d vtDeltaSect = vtGdDir * ( vtGdDir * ( ptGdStart - frSect.Orig())) ; 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) ; // Determino versori fresa e correzione Vector3d vtTool, vtCorr ; if ( ! CalculateToolAndCorrVersors( vtGdDir, m_Params.m_nHeadSide, vtTool, vtCorr)) { m_pMchMgr->SetLastError( 2705, "Error in SawFinishing : CalculateToolAndCorrVersors") ; return false ; } // Approssimo la curva con una spezzata PolyLine PL ; if ( ! pCrv->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL)) { m_pMchMgr->SetLastError( 2706, "Error in SawFinishing : ApproxWithLines") ; return false ; } // Se standard, allungo inizio e fine della sezione dello spessore lama if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { // inizio PL.Invert() ; double dU ; Point3d ptP ; PL.GetLastUPoint( &dU, &ptP) ; PL.AddUPoint( dU, ptP + Vector3d( m_TParams.m_dThick, 0, 0)) ; PL.Invert() ; // fine PL.GetLastUPoint( &dU, &ptP) ; PL.AddUPoint( dU, ptP - Vector3d( m_TParams.m_dThick, 0, 0)) ; } // La porto in globale PL.ToGlob( frSect) ; PL.Translate( vtDeltaSect) ; if ( m_Params.m_bInvert) PL.Translate( ptGdStart - ptGdEnd) ; // Calcolo eventuale anticipo dell'inizio double dAddStart = 0 ; if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) { BBox3d b3PL ; PL.GetLocalBBox( b3PL) ; double dMaxElev = min( dDepth, b3Raw.GetMax().z - b3PL.GetMin().z) ; if ( dMaxElev > 0.0 && dMaxElev < 0.5 * m_TParams.m_dDiam) dAddStart = sqrt( dMaxElev * m_TParams.m_dDiam - dMaxElev * dMaxElev) ; else dAddStart = 0.5 * m_TParams.m_dDiam ; } // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; SetCorrAuxDir( vtCorr) ; // Inizializzo contatore tagli m_nCuts = 0 ; // Calcolo le passate double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ; double dL = Dist( ptGdStart, ptGdEnd) + dAddStart ; int nStep = static_cast( ceil( dL / dStep)) ; dStep = dL / nStep ; Point3d ptP ; for ( int i = 0 ; i <= nStep ; ++ i) { // vettore di spostamento Vector3d vtMove = vtGdDir * ( - dAddStart + i * dStep) ; // lavoro la sezione if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { if ( ! CalcAcrossOneWayCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth)) return false ; } else { bool bFirst = ( i == 0) ; if ( ! CalcAcrossZigZagCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth, bFirst)) return false ; } } // se ZigZag aggiungo risalita if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiungo retrazione Point3d ptEnd ; if ( ! GetCurrPos( ptEnd)) return false ; double dElev = b3Raw.GetMax().z - ptEnd.z ; if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateCurvedAlongToolPath( int nAuxId, int nClId) { // Ruoto di 90 deg la curva sezione nel suo piano int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ; int nCrvId = ExeGetFirstInGroup( nSectGrpId) ; m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, 90.0) ; // Recupero ed elaboro la sezione per portarla ad essere la curva del lato verso la cornice della lama ICurve* pSect ; if ( ! CalculateSection( nSectGrpId, pSect)) return false ; // Contro rotazione della curva m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ; PtrOwner pCrv( pSect) ; // recupero il riferimento globale della sezione Frame3d frSect ; m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ; // recupero il box globale della sezione BBox3d b3Sect ; m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ; // Recupero ed elaboro la linea guida int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ; // recupero la linea guida ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ; if ( pGuide == nullptr) return false ; // recupero il suo riferimento Frame3d frGdL ; m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ; // porto la curva in globale (dovrebbe già avere riferimento globale) pGuide->ToGlob( frGdL) ; // 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 versore fresa come Z+ Vector3d vtTool = Z_AX ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; // Classifico i tratti a seconda della pendenza (salita, discesa, verticale, orizzontale) INTVECTOR vnClass ; ClassifySection( pCrv, vnClass) ; // Ripristino orientamento sezione con controrotazione pCrv->Rotate( ORIG, Z_AX, -90.0) ; // Inizializzo contatore tagli m_nCuts = 0 ; // Passate sui lati verticali int nUmin = -1, nUmax = -1 ; for ( size_t i = 0 ; i < vnClass.size() ; ++ i) { // se lato verticale if ( vnClass[i] == CCL_VERT) { if ( nUmin < 0) nUmin = int( i) ; nUmax = int( i + 1) ; } // se lato non verticale e non piccolo o ultimo if ( ( vnClass[i] != CCL_VERT && vnClass[i] != CCL_SMALL) || i == vnClass.size() - 1) { if ( nUmin >= 0) { // eseguo la passata if ( ! CalcCurvedAlongVerticalCuts( pCrv, nUmin, nUmax, frSect, pGuide, dDepth, b3Raw.GetMax().z, vtTool)) return false ; nUmin = - 1 ; } } } // Altre passate int nStatus = CCL_VERT ; nUmin = -1 ; nUmax = -1 ; bool bSkipMin = false, bSkipMax = false ; for ( size_t i = 0 ; i < vnClass.size() ; ++ i) { // se stato nullo (verticale) if ( nStatus == CCL_VERT) { if ( vnClass[i] == CCL_VERT || vnClass[i] == CCL_SMALL) continue ; else { nStatus = vnClass[i] ; nUmin = int( i) ; nUmax = int( i + 1) ; bSkipMin = true ; } } // altrimenti else { // se classe piatto e trovo salita o discesa, converto a questo if ( nStatus == CCL_FLAT && ( vnClass[i] == CCL_RISE || vnClass[i] == CCL_FALL)) nStatus = vnClass[i] ; // se si conserva la classe, aggiorno fine if ( vnClass[i] == nStatus || vnClass[i] == CCL_FLAT || vnClass[i] == CCL_SMALL) nUmax = int( i + 1) ; // altrimenti calcolo il tratto precedente else { // calcolo il tratto bSkipMax = ( vnClass[i] == CCL_VERT) ; bool bInvert = ( nStatus == CCL_RISE) ; if ( ! CalcCurvedAlongStdCuts( pCrv, nUmin, nUmax, bSkipMin, bSkipMax, bInvert, frSect, pGuide, dDepth, b3Raw.GetMax().z, vtTool)) return false ; // aggiorno stato if ( vnClass[i] == CCL_VERT) nStatus = CCL_VERT ; else { nStatus = vnClass[i] ; nUmin = int( i) ; nUmax = int( i + 1) ; } bSkipMin = true ; } } } // se c'è qualcosa in sospeso if ( nStatus != CCL_VERT) { bSkipMax = false ; bool bInvert = ( nStatus == CCL_RISE) ; if ( ! CalcCurvedAlongStdCuts( pCrv, nUmin, nUmax, bSkipMin, bSkipMax, bInvert, frSect, pGuide, dDepth, b3Raw.GetMax().z, vtTool)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateCurvedAcrossToolPath( int nAuxId, int nClId) { // Ruoto di 90 deg la curva sezione nel suo piano int nSectGrpId = m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_SECTION) ; int nCrvId = ExeGetFirstInGroup( nSectGrpId) ; m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, 90.0) ; // Recupero ed elaboro le sezioni per portarle ad essere la curva del centro in basso della lama ICurve* pSect ; if ( ! CalculateSection( nSectGrpId, pSect)) return false ; // Contro rotazione della curva m_pGeomDB->Rotate( nCrvId, ORIG, Z_AX, -90.0) ; PtrOwner pCrv( pSect) ; // recupero il riferimento globale della sezione Frame3d frSect ; m_pGeomDB->GetGroupGlobFrame( nSectGrpId, frSect) ; // recupero il box globale della sezione BBox3d b3Sect ; m_pGeomDB->GetGlobalBBox( nSectGrpId, b3Sect) ; // Recupero ed elaboro la linea guida int nGuideId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetFirstNameInGroup( nAuxId, MCH_GUIDE)) ; // recupero la linea guida ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ; if ( pGuide == nullptr) return false ; // recupero il suo riferimento Frame3d frGdL ; m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ; // porto la curva in globale (dovrebbe già avere riferimento globale) pGuide->ToGlob( frGdL) ; // 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) ; // Ripristino orientamento sezione con controrotazione pCrv->Rotate( ORIG, Z_AX, -90.0) ; // Approssimo la curva con una spezzata PolyLine PL ; if ( ! pCrv->ApproxWithLines( LIN_TOL_MID, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL)) { m_pMchMgr->SetLastError( 2706, "Error in SawFinishing : ApproxWithLines") ; return false ; } // Se standard, allungo inizio e fine della sezione dello spessore lama if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { // inizio PL.Invert() ; double dU ; Point3d ptP ; PL.GetLastUPoint( &dU, &ptP) ; PL.AddUPoint( dU, ptP + Vector3d( m_TParams.m_dThick, 0, 0)) ; PL.Invert() ; // fine PL.GetLastUPoint( &dU, &ptP) ; PL.AddUPoint( dU, ptP - Vector3d( m_TParams.m_dThick, 0, 0)) ; } // La porto in globale PL.ToGlob( frSect) ; // Imposto versore fresa come Z+ Vector3d vtTool = Z_AX ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; // Inizializzo contatore tagli m_nCuts = 0 ; // Punto iniziale guida Point3d ptPI ; Vector3d vtDirI ; pGuide->GetPointTang( 0, ICurve::FROM_PLUS, ptPI, vtDirI) ; // Calcolo le passate double dLenTot ; pGuide->GetLength( dLenTot) ; double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ; int nStep = static_cast( ceil( dLenTot / dStep)) ; dStep = dLenTot / nStep ; double dLen = 0 ; while ( dLen < dLenTot + 10 * EPS_SMALL) { double dU ; Point3d ptP ; Vector3d vtDir ; pGuide->GetParamAtLength( dLen, dU) ; pGuide->GetPointTang( dU, ICurve::FROM_MINUS, ptP, vtDir) ; // vettore di spostamento Vector3d vtMove = ptP - ptPI ; // angolo di rotazione double dAngRotDeg ; vtDirI.GetAngleXY( vtDir, dAngRotDeg) ; // vettore di correzione Vector3d vtCorr = vtDirI ; vtCorr.Rotate( Z_AX, dAngRotDeg - 90) ; // flag di inizio bool bFirst = ( dLen < EPS_SMALL) ; // se non è inizio bool bCorner = false ; Vector3d vtPrev ; if ( ! bFirst) { // verifico se grande rotazione (oltre 15 deg) Point3d ptPrev ; if ( ! GetCurrPos( ptPrev) || ! GetCurrCorr( vtPrev)) return false ; if ( vtPrev * vtCorr < cos( 15 * DEGTORAD)) { // calcolo dell'elevazione double dEndElev = 0 ; GetElevation( m_nPhase, ptPrev, vtPrev, dEndElev) ; // aggiungo retrazione double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dAppr = m_Params.m_dStartPos ; if ( ! AddRetract( ptPrev, vtPrev, dSafeZ, dEndElev, dAppr)) return false ; bCorner = true ; } } // imposto direzione attuale dopo i controlli SetCorrAuxDir( vtCorr) ; // lavoro la sezione if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { //if ( ! CalcAcrossOneWayCut( PL, vtMove, vtTool, vtCorr, b3Raw.GetMax().z, dDepth)) // return false ; } else { if ( ! CalcCurvedAcrossZigZagCut( PL, vtMove, ptP, dAngRotDeg, vtTool, vtCorr, vtPrev, dDepth, bFirst, bCorner)) return false ; } // passo al successivo dLen += dStep ; } // se ZigZag aggiungo risalita if ( m_Params.m_nStepType == SAWFIN_ST_ZIGZAG) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // recupero punto e versore correzione finali Point3d ptEnd ; Vector3d vtEnd ; if ( ! GetCurrPos( ptEnd) || ! GetCurrCorr( vtEnd)) return false ; // calcolo dell'elevazione double dEndElev = 0 ; GetElevation( m_nPhase, ptEnd, vtEnd, dEndElev) ; // aggiungo retrazione if ( ! AddRetract( ptEnd, vtEnd, dSafeZ, dEndElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateSection( int nSectGrpId, ICurve*& pSect) { // 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 ICURVEPOVECTOR vpNucCrvs ; vpNucCrvs.reserve( vpSects.size()) ; for ( const auto& pSect : vpSects) { PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->AddCurve( *pSect) || ! pCrvCompo->RemoveUndercutOnY( LIN_TOL_STD, ANG_TOL_STD_DEG)) return false ; vpNucCrvs.emplace_back( Release( pCrvCompo)) ; } // calcolo ordinamento delle curve secondo la X decrescente typedef pair INDASC ; // coppia indice, ascissa typedef vector INDASCVECTOR ; // vettore di coppie indice, ascissa INDASCVECTOR vIAsc ; vIAsc.reserve( vpNucCrvs.size()) ; for ( int i = 0 ; i < int( vpNucCrvs.size()) ; ++ 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 ; }) ; // unisco le diverse curve (ora aperte) in un unico profilo PtrOwner pCurve( CreateCurveComposite()) ; if ( IsNull( pCurve)) return false ; bool bFirst = true ; for ( int i = 0 ; i < int( vpNucCrvs.size()) ; ++ i) { if ( ! bFirst) { Point3d ptStart ; if ( ! vpNucCrvs[vIAsc[i].first]->GetStartPoint( ptStart) || ! pCurve->AddLine( ptStart)) return false ; } if ( ! pCurve->AddCurve( Release( vpNucCrvs[vIAsc[i].first]))) return false ; bFirst = false ; } // offset radiale delle sezioni per il sovramateriale double dOffsR = GetOffsR() ; PtrOwner pOvrCrv ; OffsetCurve OffsCrv ; OffsCrv.Make( pCurve, dOffsR, ICurve::OFF_FILLET) ; pOvrCrv.Set( OffsCrv.GetLongerCurve()) ; // ricavo dalla sezione la curva per centro in basso della lama double dOffsX = 0.5 * m_TParams.m_dThick ; PtrOwner pCrv ; OffsetCurveOnX OffsCrvX ; OffsCrvX.Make( pOvrCrv, dOffsX) ; pCrv.Set( OffsCrvX.GetLongerCurve()) ; // eseguo trim (se richiesto) if ( IsNull( pCrv) || ! TrimSection( pCrv)) return false ; pSect = Release( pCrv) ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::TrimSection( ICurve* pCrv) { // 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) return true ; // box della sezione in locale BBox3d b3Crv ; pCrv->GetBBox( Frame3d(), b3Crv) ; // riduco gli estremi in X Point3d ptMin = b3Crv.GetMin() ; Point3d ptMax = b3Crv.GetMax() ; 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 ; // regione del box nel piano XY PtrOwner pSfr( GetSurfFlatRegionRectangle( dDimX, dDimY)) ; if ( IsNull( pSfr)) return false ; pSfr->Translate( Vector3d( ptMin.x, ptMin.y - 50 * EPS_SMALL, ptMin.z)) ; // calcolo la classificazione della curva rispetto alla regione CRVCVECTOR ccClass ; if ( ! pSfr->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) return false ; // determino l'intervallo 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) ; } // eseguo trim double dUmin, dUmax ; if ( ! inOk.GetMinMax( dUmin, dUmax)) return false ; return ( pCrv->TrimEndAtParam( dUmax) && pCrv->TrimStartAtParam( dUmin)) ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateGuideLine( int nGuideId, const BBox3d& b3Sect, Point3d& ptGdStart, Point3d& ptGdEnd, Vector3d& vtGdDir) { // recupero la linea guida ICurve* pGuide = ::GetCurve( m_pGeomDB->GetGeoObj( nGuideId)) ; if ( pGuide == nullptr) return false ; // recupero il suo riferimento Frame3d frGdL ; m_pGeomDB->GetGlobFrame( nGuideId, frGdL) ; // porto la curva in globale (dovrebbe già avere riferimento globale) pGuide->ToGlob( frGdL) ; // recupero gli estremi della linea guida pGuide->GetStartPoint( ptGdStart) ; pGuide->GetEndPoint( ptGdEnd) ; // recupero la direzione della linea guida pGuide->GetStartDir( vtGdDir) ; // per ora ammesse solo linee guida rettilinee dirette lungo X o Y if ( ! AreSameOrOppositeVectorApprox( vtGdDir, X_AX) && ! AreSameOrOppositeVectorApprox( vtGdDir, Y_AX)) { m_pMchMgr->SetLastError( 2707, "Error in SawFinishing : Guide Line not along X or Y") ; return false ; } // 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 ; } // aggiusto la linea guida al bordo del box if ( AreSameVectorApprox( vtGdDir, X_AX)) { ptGdStart.x = b3Raw.GetMin().x ; ptGdEnd.x = b3Raw.GetMax().x ; } else if ( AreOppositeVectorApprox( vtGdDir, X_AX)) { ptGdStart.x = b3Raw.GetMax().x ; ptGdEnd.x = b3Raw.GetMin().x ; } else if ( AreSameVectorApprox( vtGdDir, Y_AX)) { ptGdStart.y = b3Raw.GetMin().y ; ptGdEnd.y = b3Raw.GetMax().y ; } else { ptGdStart.y = b3Raw.GetMax().y ; ptGdEnd.y = b3Raw.GetMin().y ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::ClassifySection( ICurve* pCrv, INTVECTOR& vnClass) { const ICurveComposite* pCompo = GetCurveComposite( pCrv) ; if ( pCompo != nullptr) { const ICurve* pSimpCrv = pCompo->GetFirstCurve() ; while ( pSimpCrv != nullptr) { // analizzo la curva Point3d ptStart, ptEnd ; pSimpCrv->GetStartPoint( ptStart) ; pSimpCrv->GetEndPoint( ptEnd) ; if ( AreSamePointXYEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) vnClass.push_back( CCL_SMALL) ; else if ( abs( ptEnd.x - ptStart.x) < EPS_SMALL) vnClass.push_back( CCL_VERT) ; else if ( abs( ptEnd.y - ptStart.y) < EPS_SMALL) vnClass.push_back( CCL_FLAT) ; else if ( ptEnd.y > ptStart.y) vnClass.push_back( CCL_RISE) ; else vnClass.push_back( CCL_FALL) ; // passo alla curva successiva pSimpCrv = pCompo->GetNextCurve() ; } } else { Point3d ptStart, ptEnd ; pCrv->GetStartPoint( ptStart) ; pCrv->GetEndPoint( ptEnd) ; if ( AreSamePointXYEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) vnClass.push_back( CCL_SMALL) ; else if ( abs( ptEnd.x - ptStart.x) < EPS_SMALL) vnClass.push_back( CCL_VERT) ; else if ( abs( ptEnd.y - ptStart.y) < EPS_SMALL) vnClass.push_back( CCL_FLAT) ; else if ( ptEnd.y > ptStart.y) vnClass.push_back( CCL_RISE) ; else vnClass.push_back( CCL_FALL) ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr) { // Ingombro del taglio BBox3d b3Cut ; for ( int i = nUmin ; i <= nUmax ; ++ i) { Point3d ptP ; if ( pSect->GetPointD1D2( i, ICurve::FROM_MINUS, ptP)) b3Cut.Add( ptP) ; } if ( b3Cut.IsEmpty()) return false ; // ascissa double dX = ( b3Cut.GetMin().x + b3Cut.GetMax().x) / 2 ; // Calcolo dello step tra le passate double dL = b3Cut.GetMax().y - b3Cut.GetMin().y ; if ( dL < 10 * EPS_SMALL) return true ; double dStep = max( m_Params.m_dStep, 10 * EPS_SMALL) ; int nStep = static_cast( ceil( dL / dStep)) ; dStep = dL / nStep ; // Ciclo sulle passate double dLastElev ; Point3d ptStartPrev ; for ( int i = 0 ; i <= nStep ; ++ i) { // ordinata double dY = b3Cut.GetMax().y - i * dStep ; // estremi del taglio Vector3d vtMove = dX * frSect.VersX() + dY * frSect.VersY() - 0.5 * m_TParams.m_dThick * vtTool ; Point3d ptStart = ptGdStart + vtMove ; Point3d ptEnd = ptGdEnd + vtMove ; // determino l'elevazione del taglio Vector3d vtThick = vtTool * m_TParams.m_dThick ; double dElev, dElev2 ; if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev) || ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, dElev2) ) { m_pMchMgr->SetLastError( 2708, "Error in SawFinishinging : 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 double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ; if ( dElev > dMaxDepth) { ptStart += Vector3d( 0, 0, dElev - dMaxDepth) ; ptEnd += Vector3d( 0, 0, dElev - dMaxDepth) ; dElev = dMaxDepth ; } // se diverso da precedente, eseguo il taglio bool bFirst = ( i == 0) ; if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) { if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, true)) return false ; } else { if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, true, 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 = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiungo retrazione Point3d ptNewEnd ; if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dLastElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAlongStdCuts( ICurve* pSect, double dUmin, double dUmax, bool bSkipMin, bool bSkipMax, bool bInvert, const Frame3d& frSect, const Point3d& ptGdStart, const Point3d& ptGdEnd, const Vector3d& vtGdDir, double dDepth, double dRawMaxZ, const Vector3d& vtTool, const Vector3d& vtCorr) { // Calcolo dello step tra le passate double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ; double dLmin, dLmax ; if ( ! pSect->GetLengthAtParam( dUmin, dLmin) || ! pSect->GetLengthAtParam( dUmax, dLmax)) return false ; double dL = dLmax - dLmin ; if ( dL < 10 * EPS_SMALL) return true ; int nStep = static_cast( ceil( dL / dStep)) ; dStep = dL / nStep ; // Ciclo sulle passate double dLastElev ; Point3d ptStartPrev ; bool bSkipIni = ( bInvert ? bSkipMax : bSkipMin) ; bool bSkipFin = ( bInvert ? bSkipMin : bSkipMax) ; int nIni = ( bSkipIni ? 1 : 0) ; int nFin = ( bSkipFin ? nStep - 1 : nStep) ; if ( nFin < nIni) return true ; for ( int i = nIni ; i <= nFin ; ++ i) { // calcolo del parametro double dLcurr = ( bInvert ? dLmax - i * dStep : dLmin + i * dStep) ; double dU ; pSect->GetParamAtLength( dLcurr, dU) ; // coordinate nel punto Point3d ptP ; pSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; // estremi del taglio Vector3d vtMove = ptP.x * frSect.VersX() + ptP.y * frSect.VersY() - 0.5 * m_TParams.m_dThick * vtTool ; Point3d ptStart = ptGdStart + vtMove ; Point3d ptEnd = ptGdEnd + vtMove ; // determino l'elevazione del taglio Vector3d vtThick = vtTool * m_TParams.m_dThick ; double dElev, dElev2 ; if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtCorr, dElev) || ! GetElevation( m_nPhase, ptStart + vtThick, ptEnd + vtThick, vtCorr, 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 double dMaxDepth = min( dDepth, m_TParams.m_dMaxMat) ; if ( dElev > dMaxDepth) { ptStart += Vector3d( 0, 0, dElev - dMaxDepth) ; ptEnd += Vector3d( 0, 0, dElev - dMaxDepth) ; dElev = dMaxDepth ; } // se diverso da precedente, eseguo il taglio bool bFirst = ( i == nIni) ; if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) { if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, false)) return false ; } else { if ( ! CalcAlongZigZagCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, 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 = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiungo retrazione Point3d ptNewEnd ; if ( ! GetCurrPos( ptNewEnd) || ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dLastElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAlongOneWayCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir, const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bVert) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // se attacco/uscita/collegamento esterno allungo inizio Point3d ptNewStart = ptStart ; if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { ptNewStart = ptStart - vtDir * dAppr ; } else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) { // distanza XY tra centro e bordo taglio double dDeltaT = 0 ; if ( dElev > 0.0 && dElev < 0.5 * m_TParams.m_dDiam) dDeltaT = sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) ; // modifico inizio ptNewStart = ptStart - vtDir * ( dDeltaT + dAppr) ; } // Sempre una sola passata // 1 -> approccio if ( ! AddApproach( ptNewStart, vtCorr, dSafeZ, dElev, dAppr)) return false ; // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; if ( m_Params.m_nLeadLinkType != SAWFIN_LL_OUT) SetFeed( GetTipFeed()) ; else SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; // 3 -> movimento di lato al punto finale SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptEnd) == GDB_ID_NULL) return false ; // 4 -> retrazione if ( ! AddRetract( ptEnd, vtCorr, dSafeZ, dElev, dAppr)) return false ; // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAlongZigZagCut( const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtDir, const Vector3d& vtTool, const Vector3d& vtCorr, double dElev, bool bVert, bool bFirst) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiorno inizio, fine e direzione movimento Point3d ptOriStart = ptStart ; Point3d ptOriEnd = ptEnd ; Point3d ptNewStart = ptStart ; Point3d ptNewEnd = ptEnd ; Vector3d vtNewDir = vtDir ; // se attacco/uscita/collegamento standard allungo inizio e fine dell'approccio if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { // modifico inizio ptNewStart = ptStart - vtDir * dAppr ; // modifico fine ptNewEnd = ptEnd + vtDir * dAppr ; } // se attacco/uscita/collegamento esterno allungo inizio e fine a fuori grezzo else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) { // distanza XY tra centro e bordo taglio double dDeltaT = 0 ; if ( dElev > 0.0 && dElev < 0.5 * m_TParams.m_dDiam) dDeltaT = sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) ; // modifico inizio ptNewStart = ptStart - vtDir * ( dDeltaT + dAppr) ; // modifico fine ptNewEnd = ptEnd + vtDir * ( dDeltaT + dAppr) ; } // le passate dispari sono al contrario if ( ( m_nCuts % 2) != 0) { swap( ptOriStart, ptOriEnd) ; swap( ptNewStart, ptNewEnd) ; vtNewDir.Invert() ; } // Sempre una sola passata // 1 -> approccio if ( bFirst || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { if ( ! AddApproach( ptNewStart, vtCorr, dSafeZ, dElev, dAppr)) return false ; } // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; // con attacco centrato sono sul materiale e devo usare feed di testa if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } // con attacco fuori sono in aria else { if ( bFirst) { SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } else { Point3d ptLast ; GetCurrPos( ptLast) ; double dDiff = ( ptNewStart - ptLast) * vtNewDir ; // se precedente e corrente sono fuori allo stesso modo if ( abs( dDiff) < 10 * EPS_SMALL) { // inizio nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } // se il precedente è più fuori else if ( dDiff > 0) { // allungo nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart - dDiff * vtNewDir) == GDB_ID_NULL) return false ; } // se il corrente è più fuori else { // allungo passata precedente if ( AddLinearMove( ptLast + dDiff * vtNewDir) == GDB_ID_NULL) return false ; // inizio nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } } } // 3 -> movimento di lato al punto finale if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewEnd) == GDB_ID_NULL) return false ; } else { SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptOriEnd) == GDB_ID_NULL) return false ; SetFeed( GetEndFeed()) ; if ( ! AreSamePointApprox( ptNewEnd, ptOriEnd) && AddLinearMove( ptNewEnd) == GDB_ID_NULL) return false ; } // 4 -> retrazione if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { if ( ! AddRetract( ptNewEnd, vtCorr, dSafeZ, dElev, dAppr)) return false ; } // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAcrossOneWayCut( const PolyLine& PL, const Vector3d& vtMove, const Vector3d& vtTool, const Vector3d& vtCorr, double dRawZ, double dDepth) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; Point3d ptP ; // 1 -> approccio bool bFound = PL.GetFirstPoint( ptP) ; if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.z = max( ptP.z, dRawZ - dDepth) ; double dElev = dRawZ - ptP.z ; if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr)) return false ; } // 2 -> movimento lungo la sezione Point3d ptPrev ; GetCurrPos( ptPrev) ; while ( bFound) { // se diverso da precedente, movimento al punto if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) { Vector3d vtDelta = ptP - ptPrev ; if ( vtDelta.z > - EPS_SMALL) SetFeed( GetFeed()) ; else { double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ; double dF = min( GetFeed(), dC * GetTipFeed()) ; SetFeed( dF) ; } if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; ptPrev = ptP ; } // recupero punto successivo bFound = PL.GetNextPoint( ptP) ; if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.z = max( ptP.z, dRawZ - dDepth) ; } } // 3-> retrazione { double dElev = dRawZ - ptP.z ; if ( ! AddRetract( ptP, vtCorr, dSafeZ, dElev, dAppr)) return false ; } // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcAcrossZigZagCut( const PolyLine& PL, const Vector3d& vtMove, const Vector3d& vtTool, const Vector3d& vtCorr, double dRawZ, double dDepth, bool bFirst) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // sezione da invertire bool bInvert = (( m_nCuts % 2) != 0) ; Point3d ptP ; bool bFound = ( bInvert ? PL.GetLastPoint( ptP) : PL.GetFirstPoint( ptP)) ; // 1 -> approccio if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.z = max( ptP.z, dRawZ - dDepth) ; if ( bFirst) { double dElev = dRawZ - ptP.z ; if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr)) return false ; } } // 2 -> movimento lungo la sezione Point3d ptPrev ; GetCurrPos( ptPrev) ; while ( bFound) { // se diverso da precedente, movimento al punto if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) { Vector3d vtDelta = ptP - ptPrev ; if ( vtDelta.z > - EPS_SMALL) SetFeed( GetFeed()) ; else { double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ; double dF = min( GetFeed(), dC * GetTipFeed()) ; SetFeed( dF) ; } if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; ptPrev = ptP ; } // recupero punto successivo bFound = ( bInvert ? PL.GetPrevPoint( ptP) : PL.GetNextPoint( ptP)) ; if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.z = max( ptP.z, dRawZ - dDepth) ; } } // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcCurvedAlongVerticalCuts( ICurve* pSect, int nUmin, int nUmax, const Frame3d& frSect, ICurve* pGuide, double dDepth, double dRawMaxZ, const Vector3d& vtTool) { // Ingombro del taglio BBox3d b3Cut ; for ( int i = nUmin ; i <= nUmax ; ++ i) { Point3d ptP ; if ( pSect->GetPointD1D2( i, ICurve::FROM_MINUS, ptP)) b3Cut.Add( ptP) ; } if ( b3Cut.IsEmpty()) return false ; // ordinata double dY = ( b3Cut.GetMin().y + b3Cut.GetMax().y) / 2 ; // Calcolo dello step tra le passate double dL = b3Cut.GetMax().x - b3Cut.GetMin().x ; if ( dL < 10 * EPS_SMALL) return true ; double dStep = max( m_Params.m_dStep, 10 * EPS_SMALL) ; int nStep = static_cast( ceil( dL / dStep)) ; dStep = dL / nStep ; // Ciclo sulle passate double dLastElev ; Point3d ptStartPrev ; for ( int i = 0 ; i <= nStep ; ++ i) { // ascissa double dX = b3Cut.GetMax().x - i * dStep ; // creo la curva di taglio double dOffs = dX ; Vector3d vtMove = ( dY - m_TParams.m_dThick / 2) * Z_AX ; OffsetCurve OffsCrv ; OffsCrv.Make( pGuide, dOffs, ICurve::OFF_FILLET) ; PtrOwner pCut( CreateCurveComposite()) ; if ( IsNull( pCut) || ! pCut->AddCurve( OffsCrv.GetLongerCurve())) return false ; VerifyArcs( pCut) ; pCut->SimpleOffset( SAWRF_OFFS, ICurve::OFF_FORCE_OPEN) ; pCut->Translate( vtMove) ; Point3d ptStart ; pCut->GetStartPoint( ptStart) ; // se diverso da precedente, eseguo il taglio bool bFirst = ( i == 0) ; if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) { if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { //if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, true)) // return false ; } else { if ( ! CalcCurvedAlongZigZagCut( pCut, vtTool, true, bFirst, dLastElev)) return false ; } } 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 = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiungo retrazione Point3d ptNewEnd ; Vector3d vtNewCorr ; if ( ! GetCurrPos( ptNewEnd) || ! GetCurrCorr( vtNewCorr) || ! AddRetract( ptNewEnd, vtNewCorr, dSafeZ, dLastElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcCurvedAlongStdCuts( ICurve* pSect, double dUmin, double dUmax, bool bSkipMin, bool bSkipMax, bool bInvert, const Frame3d& frSect, ICurve* pGuide, double dDepth, double dRawMaxZ, const Vector3d& vtTool) { // Calcolo dello step tra le passate double dStep = max( m_Params.m_dSideStep, 10 * EPS_SMALL) ; double dLmin, dLmax ; if ( ! pSect->GetLengthAtParam( dUmin, dLmin) || ! pSect->GetLengthAtParam( dUmax, dLmax)) return false ; double dL = dLmax - dLmin ; if ( dL < 10 * EPS_SMALL) return true ; int nStep = static_cast( ceil( dL / dStep)) ; dStep = dL / nStep ; // Ciclo sulle passate double dLastElev ; Point3d ptStartPrev ; bool bSkipIni = ( bInvert ? bSkipMax : bSkipMin) ; bool bSkipFin = ( bInvert ? bSkipMin : bSkipMax) ; int nIni = ( bSkipIni ? 1 : 0) ; int nFin = ( bSkipFin ? nStep - 1 : nStep) ; if ( nFin < nIni) return true ; for ( int i = nIni ; i <= nFin ; ++ i) { // calcolo del parametro double dLcurr = ( bInvert ? dLmax - i * dStep : dLmin + i * dStep) ; double dU ; pSect->GetParamAtLength( dLcurr, dU) ; // coordinate nel punto Point3d ptP ; pSect->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; // creo la curva di taglio double dOffs = ptP.x ; Vector3d vtMove = ( ptP.y - m_TParams.m_dThick / 2) * Z_AX ; OffsetCurve OffsCrv ; OffsCrv.Make( pGuide, dOffs, ICurve::OFF_FILLET) ; PtrOwner pCut( CreateCurveComposite()) ; if ( IsNull( pCut) || ! pCut->AddCurve( OffsCrv.GetLongerCurve())) return false ; VerifyArcs( pCut) ; pCut->SimpleOffset( SAWRF_OFFS, ICurve::OFF_FORCE_OPEN) ; pCut->Translate( vtMove) ; Point3d ptStart ; pCut->GetStartPoint( ptStart) ; // se diverso da precedente, eseguo il taglio bool bFirst = ( i == nIni) ; if ( bFirst || ! AreSamePointEpsilon( ptStart, ptStartPrev, 10 * EPS_SMALL)) { if ( m_Params.m_nStepType != SAWFIN_ST_ZIGZAG) { //if ( ! CalcAlongOneWayCut( ptStart, ptEnd, vtGdDir, vtTool, vtCorr, dElev, false)) // return false ; } else { if ( ! CalcCurvedAlongZigZagCut( Get( pCut), vtTool, false, bFirst, dLastElev)) return false ; } 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 = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // aggiungo retrazione Point3d ptNewEnd ; Vector3d vtNewCorr ; if ( ! GetCurrPos( ptNewEnd) || ! GetCurrCorr( vtNewCorr) || ! AddRetract( ptNewEnd, vtNewCorr, dSafeZ, dLastElev, dAppr)) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcCurvedAlongZigZagCut( const ICurve* pCut, const Vector3d& vtTool, bool bVert, bool bFirst, double& dEndElev) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // verifico se passata da invertire (indice dispari) bool bInvert = ( ( m_nCuts % 2) != 0) ; // recupero la passata PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( *pCut)) return false ; if ( bInvert) pCompo->Invert() ; // aggiorno inizio, fine e direzione movimento Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; Vector3d vtDirStart ; pCompo->GetStartDir( vtDirStart) ; Vector3d vtOrtStart = vtDirStart ; vtOrtStart.Rotate( Z_AX, ( bInvert ? 90 : -90)) ; Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; Vector3d vtDirEnd ; pCompo->GetEndDir( vtDirEnd) ; Vector3d vtOrtEnd = vtDirEnd ; vtOrtEnd.Rotate( Z_AX, ( bInvert ? 90 : -90)) ; Point3d ptNewStart = ptStart ; Point3d ptNewEnd = ptEnd ; // calcolo elevazioni all'inizio e alla fine double dTgElevStart = 0 ; GetElevation( m_nPhase, ptStart, - vtDirStart, dTgElevStart) ; double dOrtElevStart = 0 ; GetElevation( m_nPhase, ptStart, vtOrtStart, dOrtElevStart) ; double dTgElevEnd = 0 ; GetElevation( m_nPhase, ptEnd, vtDirEnd, dTgElevEnd) ; double dOrtElevEnd = 0 ; GetElevation( m_nPhase, ptEnd, vtOrtEnd, dOrtElevEnd) ; dEndElev = dOrtElevEnd ; // se attacco/uscita/collegamento standard allungo inizio e fine dell'approccio if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { // modifico inizio ptNewStart = ptStart - vtDirStart * dAppr ; // modifico fine ptNewEnd = ptEnd + vtDirEnd * dAppr ; } // se attacco/uscita/collegamento esterno allungo inizio e fine a fuori grezzo else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_OUT) { // distanza XY tra centro e bordo taglio double dDeltaTStart = 0 ; if ( dOrtElevStart > 0.0 && dOrtElevStart < 0.5 * m_TParams.m_dDiam) dDeltaTStart = sqrt( dOrtElevStart * m_TParams.m_dDiam - dOrtElevStart * dOrtElevStart) ; double dDeltaTEnd = 0 ; if ( dOrtElevEnd > 0.0 && dOrtElevEnd < 0.5 * m_TParams.m_dDiam) dDeltaTEnd = sqrt( dOrtElevEnd * m_TParams.m_dDiam - dOrtElevEnd * dOrtElevEnd) ; // modifico inizio ptNewStart = ptStart - vtDirStart * ( dTgElevStart + dDeltaTStart + dAppr) ; // modifico fine ptNewEnd = ptEnd + vtDirEnd * ( dTgElevEnd + dDeltaTEnd + dAppr) ; } // Sempre una sola passata SetCorrAuxDir( vtOrtStart) ; // 1 -> approccio if ( bFirst || m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { if ( ! AddApproach( ptNewStart, vtOrtStart, dSafeZ, dOrtElevStart, dAppr)) return false ; } else if ( m_Params.m_nLeadLinkType == SAWFIN_LL_STD) { // recupero ultimo punto inserito Point3d ptCurr ; GetCurrPos( ptCurr) ; // differenza tra corrente e nuovo lungo direzione ortogonale double dOrtStartDiff = ( ptNewStart - ptCurr) * vtOrtStart ; // se punto corrente più fuori, aggiungo punto fuori allo stesso modo sul nuovo if ( dOrtStartDiff < - 10 * EPS_SMALL) { Point3d ptOut = ptNewStart + ( - dOrtStartDiff * vtOrtStart) ; SetFlag( 0) ; SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( ! SameAsCurrPos( ptOut) && AddLinearMove( ptOut) == GDB_ID_NULL) return false ; } // se altrimenti più dentro, aggiungo punto fuori allo stesso modo sul corrente else if ( dOrtStartDiff > 10 * EPS_SMALL) { Point3d ptOut = ptCurr + ( dOrtStartDiff * vtOrtStart) ; SetFlag( 0) ; SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( ! SameAsCurrPos( ptOut) && AddLinearMove( ptOut) == GDB_ID_NULL) return false ; } } // 2 -> movimento in affondo al punto iniziale SetFlag( 0) ; // con attacco centrato sono sul materiale e devo usare feed di testa if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } // con attacco fuori sono in aria else { if ( bFirst) { SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } else { Point3d ptLast ; GetCurrPos( ptLast) ; double dDiff = ( ptNewStart - ptLast) * vtDirStart ; // se precedente e corrente sono fuori allo stesso modo if ( abs( dDiff) < 10 * EPS_SMALL) { // inizio nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } // se il precedente è più fuori else if ( dDiff > 0) { // allungo nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart - dDiff * vtDirStart) == GDB_ID_NULL) return false ; } // se il corrente è più fuori else { // allungo passata precedente if ( AddLinearMove( ptLast + dDiff * vtDirStart) == GDB_ID_NULL) return false ; // inizio nuova passata SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( AddLinearMove( ptNewStart) == GDB_ID_NULL) return false ; } } } // se non ci sono già, vado all'inizio dell'arco if ( ! SameAsCurrPos( ptStart) && AddLinearMove( ptStart) == GDB_ID_NULL) return false ; // 3 -> movimento di lato al punto finale const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ; Vector3d vtDirEnd ; pCrv->GetEndDir( vtDirEnd) ; Vector3d vtOrtEnd = vtDirEnd ; vtOrtEnd.Rotate( Z_AX, ( bInvert ? 90 : -90)) ; SetCorrAuxDir( vtOrtEnd) ; SetFeed( ( bVert ? GetVertFeed() : GetFeed())) ; if ( pCrv->GetType() == CRV_LINE) { if ( AddLinearMove( ptEnd) == GDB_ID_NULL) return false ; } else { Point3d ptCen ; pCrv->GetCenterPoint( ptCen) ; double dAngCen = GetCurveArc( pCrv)->GetAngCenter() ; if ( AddArcMove( ptEnd, ptCen, dAngCen, vtTool) == GDB_ID_NULL) return false ; } pCrv = pCompo->GetNextCurve() ; } if ( m_Params.m_nLeadLinkType != SAWFIN_LL_CENT) { SetFeed( GetEndFeed()) ; if ( ! SameAsCurrPos( ptNewEnd) && AddLinearMove( ptNewEnd) == GDB_ID_NULL) return false ; } // 4 -> retrazione if ( m_Params.m_nLeadLinkType == SAWFIN_LL_CENT) { if ( ! AddRetract( ptNewEnd, vtOrtEnd, dSafeZ, dOrtElevEnd, dAppr)) return false ; } // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalcCurvedAcrossZigZagCut( const PolyLine& PL, const Vector3d& vtMove, const Point3d& ptAxRot, double dAngRotDeg, const Vector3d& vtTool, const Vector3d& vtCorr, const Vector3d& vtPrev, double dDepth, bool bFirst, bool bCorner) { // recupero distanza di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // sezione da invertire bool bInvert = (( m_nCuts % 2) != 0) ; Point3d ptP ; bool bFound = ( bInvert ? PL.GetLastPoint( ptP) : PL.GetFirstPoint( ptP)) ; // 1 -> approccio if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.Rotate( ptAxRot, Z_AX, dAngRotDeg) ; double dElev = 0 ; GetElevation( m_nPhase, ptP, vtCorr, dElev) ; if ( dElev > dDepth) { ptP += ( dElev - dDepth) * vtCorr ; dElev = dDepth ; } if ( bFirst) { if ( ! AddApproach( ptP, vtCorr, dSafeZ, dElev, dAppr)) return false ; } else if ( bCorner) { if ( ! AddCornerApproach( ptP, vtCorr, vtPrev, dSafeZ, dElev, dAppr)) return false ; } } // 2 -> movimento lungo la sezione Point3d ptPrev ; GetCurrPos( ptPrev) ; while ( bFound) { // se diverso da precedente, movimento al punto if ( ! AreSamePointEpsilon( ptP, ptPrev, 10 * EPS_SMALL)) { Vector3d vtDelta = ptP - ptPrev ; if ( vtDelta.z > - EPS_SMALL) SetFeed( GetFeed()) ; else { double dC = sqrt( 1 + ( vtDelta.x * vtDelta.x + vtDelta.y * vtDelta.y) / ( vtDelta.z * vtDelta.z)) ; double dF = min( GetFeed(), dC * GetTipFeed()) ; SetFeed( dF) ; } if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; ptPrev = ptP ; } // recupero punto successivo bFound = ( bInvert ? PL.GetPrevPoint( ptP) : PL.GetNextPoint( ptP)) ; if ( bFound) { ptP += vtMove - 0.5 * m_TParams.m_dThick * vtTool ; ptP.Rotate( ptAxRot, Z_AX, dAngRotDeg) ; double dElev = 0 ; GetElevation( m_nPhase, ptP, vtCorr, dElev) ; if ( dElev > dDepth) { ptP += ( dElev - dDepth) * vtCorr ; dElev = dDepth ; } } } // incremento contatore passate ++ m_nCuts ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtCorr, double dSafeZ, double dElev, double dAppr) { // impongo minima distanza di approccio dAppr = max( dAppr, 1.0) ; // se distanza di sicurezza minore di distanza di inizio if ( dSafeZ < dAppr + 10 * EPS_SMALL) { // 1 -> punto sopra inizio Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ; if ( m_nCuts == 0) { SetFlag( 1) ; if ( AddRapidStart( ptP1) == GDB_ID_NULL) return false ; } else { SetFlag( 0) ; if ( ! SameAsCurrPos( ptP1) && AddRapidMove( ptP1) == GDB_ID_NULL) return false ; } } else { // 1a -> punto sopra inizio Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + vtCorr * ( dSafeZ - dAppr) ; if ( m_nCuts == 0) { SetFlag( 1) ; if ( AddRapidStart( ptP1a) == GDB_ID_NULL) return false ; } else { SetFlag( 0) ; if ( ! SameAsCurrPos( ptP1a) && AddRapidMove( ptP1a) == GDB_ID_NULL) return false ; } // 1b -> punto appena sopra inizio SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::AddCornerApproach( const Point3d& ptP, const Vector3d& vtCorr, const Vector3d& vtPrev, double dSafeZ, double dElev, double dAppr) { // impongo minima distanza di approccio dAppr = max( dAppr, 1.0) ; // recupero posizione precedente (correzione precedente è passata perchè già impostata la nuova) Point3d ptPrev ; if ( ! GetCurrPos( ptPrev)) return false ; // determino il numero di passi di interpolazione double dAngDeg = 0 ; vtCorr.GetAngleXY( vtPrev, dAngDeg) ; int nStep = int( abs( dAngDeg) / 15) ; // se distanza di sicurezza minore di distanza di inizio if ( dSafeZ < dAppr + 10 * EPS_SMALL) { // 1 -> punto sopra inizio Point3d ptP1 = ptP + vtCorr * ( dElev + dAppr) ; SetFlag( 0) ; for ( int i = 1 ; i <= nStep ; ++ i) { double dCoeff = i / double( nStep) ; Point3d ptOut = Media( ptPrev, ptP1, dCoeff) ; Vector3d vtOut = Media( vtPrev, vtCorr, dCoeff) ; vtOut.Normalize() ; SetCorrAuxDir( vtOut) ; AddRapidMove( ptOut) ; } } else { // 1a -> punto sopra inizio Point3d ptP1b = ptP + vtCorr * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + vtCorr * ( dSafeZ - dAppr) ; SetFlag( 0) ; for ( int i = 1 ; i <= nStep ; ++ i) { double dCoeff = i / double( nStep) ; Point3d ptOut = Media( ptPrev, ptP1a, dCoeff) ; Vector3d vtOut = Media( vtPrev, vtCorr, dCoeff) ; vtOut.Normalize() ; SetCorrAuxDir( vtOut) ; AddRapidMove( ptOut) ; } // 1b -> punto appena sopra inizio SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::AddRetract( const Point3d& ptP, const Vector3d& vtCorr, double dSafeZ, double dElev, double dAppr) { // impongo minima distanza di approccio dAppr = max( dAppr, 1.0) ; // se distanza di sicurezza minore di distanza di fine if ( dSafeZ < dAppr + 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtCorr * ( dElev + dAppr) ; if ( ! SameAsCurrPos( ptP4) && AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } else { // 4a -> movimento di risalita appena sopra il punto finale Point3d ptP4a = ptP + vtCorr * ( dElev + dAppr) ; SetFeed( GetEndFeed()) ; if ( ! SameAsCurrPos( ptP4a) && AddLinearMove( ptP4a) == GDB_ID_NULL) return false ; // 4b -> movimento di risalita sopra il punto finale Point3d ptP4b = ptP4a + vtCorr * ( dSafeZ - dAppr) ; if ( AddRapidMove( ptP4b) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SawFinishing::CalculateToolAndCorrVersors( const Vector3d& vtTang, int nHeadSide, Vector3d& vtTool, Vector3d& vtCorr) { // Versore fresa : annullo la componente in Z e normalizzo vtTool = vtTang ; vtTool.z = 0 ; if ( ! vtTool.Normalize()) return false ; // ruoto attorno a Zglob+ a seconda del lato mandrino if ( nHeadSide == SAW_HS_LEFT) vtTool.Rotate( Z_AX, 0, 1) ; else vtTool.Rotate( Z_AX, 0, -1) ; // Versore correzione vtCorr = Z_AX ; return true ; } //---------------------------------------------------------------------------- bool SawFinishing::GetHeightOnSection( const ICurve* pSect, double dX, double dYmin, double dYmax, double& dY) { // creo raggio per intersezione con direzione Y+ PtrOwnerpRay( CreateCurveLine()) ; if ( IsNull( pRay) || ! pRay->Set( Point3d( dX, dYmin - EPS_SMALL, 0), Point3d( dX, dYmax + EPS_SMALL, 0))) return false ; // eseguo intersezione (considero l'ultima, ovvero quella con Y maggiore) IntersCurveCurve intCC( *pRay, *pSect) ; IntCrvCrvInfo aInfo ; if ( intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo)) { // nel caso di sovrapposizione devo prendere la Y in basso del tratto dY = aInfo.IciA[0].ptI.y ; return true ; } // se non c'è intersezione assegno il minimo dY = dYmin ; return true ; }