//---------------------------------------------------------------------------- // EgalTech 2015-2023 //---------------------------------------------------------------------------- // File : Drilling.cpp Data : 20.12.23 Versione : 2.5l47 // Contenuto : Implementazione gestione forature. // // Note : Questa lavorazione è sempre espressa nel riferimento globale. // // Modifiche : 21.05.15 DS Creazione modulo. // 20.12.23 RE Forature multiple con aggregati. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "Drilling.h" #include "OperationConst.h" #include "/EgtDev/Include/EXeCmdLogOff.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkUserObjFactory.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EGkGeoFrame3d.h" using namespace std ; //------------------------------ Errors -------------------------------------- // 2101 = "Error in Drilling : UpdateToolData failed" // 2102 = "Error in Drilling : Offset not computable" // 2103 = "Error in Drilling : Overlap not computable" // 2104 = "Error in Drilling : Depth not computable" // 2105 = "Error in Drilling : Drill with zero depth" // 2106 = "Error in Drilling : Entity xx skipped because missing aggregate from bottom" // 2107 = "Error in Drilling : Entity xx skipped because too far from part sides" // 2108 = "Error in Drilling : Chaining failed" // 2109 = "Error in Drilling : axes values not calculable" // 2110 = "Error in Drilling : outstroke xx" // 2111 = "Error in Drilling : link movements not calculable" // 2112 = "Error in Drilling : link outstroke xx" // 2113 = "Error in Drilling : post apply not calculable" // 2114 = "Error in Drilling : blind hole not reversible" // 2115 = "Error in Drilling : Mirror for Double calculation failed" // 2116 = "Error in Drilling : multi drilling head without valid tools" // 2117 = "Error in Drilling : incorrect multi drilling head" // 2118 = "Error in Drilling : Tool loading failed" // 2151 = "Warning in Drilling : Skipped entity (xx)" // 2152 = "Warning in Drilling : No machinable path" // 2153 = "Warning in Drilling : Tool name changed (xx)" // 2154 = "Warning in Drilling : Tool data changed (xx)" // 2155 = "Warning in Drilling : Drill bit too short for Hole " // 2156 = "Warning in Drilling : Skipped by Standard Drilling " // 2157 = "Warning in Drilling : Skipped by Peck Drilling " //---------------------------------------------------------------------------- // definizione delle costanti const int IND_TOOL_INVALID = -1 ; const int IND_HOLE_INVALID = -1 ; //---------------------------------------------------------------------------- // struttura semplificata del foro struct Hole { int nOriId ; // identificativo della geometria di origine Point3d ptIni ; // punto iniziale Vector3d vtDir ; // direzione di riferimento (dal fondo verso l'inizio) double dDiam ; // diametro double dThick ; // lunghezza della geometria originale double dLen ; // lunghezza dell'asse bool bBlind ; // flag per cieco/passante // eventuale tipo ( standard, ribassato, svasato) ? Hole( void) : nOriId( GDB_ID_NULL), ptIni(), vtDir(), dDiam( 0), dThick( 0), dLen( 0), bBlind( true) {} } ; // struttura avanzata per fori nel caso di MultiHeadDrills struct HoleInfo { Hole hole ; // foro bool bDrill = false ; // flag per indicare se il foro alla fine verrà lavorato bool bTempDrill = false ; // [per test maschera ( se durante un test viene lavorato o no)] int nTempTool = IND_TOOL_INVALID ; // [per test maschera ( indice utensile che lo lavora durante un test)] bool bForToolM = false ; // flag per indicare se il tool main lavorerà questo foro int nIndHoleToolM = IND_HOLE_INVALID ; // se il foro verrà svuotato, contiene l'indice del foro del tool principale // --- vettori ordinati --- INTVECTOR vToolHole ; // []-> indice del foro di inserimento del tool principale INTVECTOR vIndTools ; // []-> indice del tool che svuoterà il foro corrente VCT3DVECTOR vVtAux ; // []-> vettore ausiliario per tale condifgurazione int nIndTool = IND_TOOL_INVALID ; // indice del tool che alla fine lavorerà il foro Vector3d vtAux ; // vettore ausiliario del tool principale per lavorare il foro corrente Point3d ptBtn ; // punto interno alla base del foro int nIndInSelVector = 0 ; // indice nel vettore m_vId ( id fori selezionati) } ; // struttura avanzata per il tool, per MultiHeadDrills struct ToolInfo { const ToolData* pTool ; // puntatore per utensile ( nullo se utensile non presente) Point3d ptToolTip ; // punto finale del tool ( per ptBtn del foro) ToolInfo( void) : pTool( nullptr) {} ToolInfo( const ToolData* pT) : pTool( pT) {} } ; // struttura per foratura con MultiHeadDrills struct MHDrill { int nInd_id_hole ; // indice foro Vector3d vtAux ; // vettore ausiliario per tale foratura MHDrill( int nIndH, Vector3d vtA) : nInd_id_hole( nIndH), vtAux( vtA) {} ; } ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_DRILLING), Drilling) ; //---------------------------------------------------------------------------- const string& Drilling::GetClassName( void) const { return USEROBJ_GETNAME( Drilling) ; } //---------------------------------------------------------------------------- Drilling* Drilling::Clone( void) const { // alloco oggetto Drilling* pDri = new(nothrow) Drilling ; // eseguo copia dei dati if ( pDri != nullptr) { try { pDri->m_vId = m_vId ; pDri->m_pMchMgr = m_pMchMgr ; pDri->m_nPhase = m_nPhase ; pDri->m_Params = m_Params ; pDri->m_TParams = m_TParams ; pDri->m_nStatus = m_nStatus ; pDri->m_nDrillings = m_nDrillings ; pDri->m_bTiltingTab = m_bTiltingTab ; pDri->m_vtTiltingAx = m_vtTiltingAx ; pDri->m_bAboveHead = m_bAboveHead ; pDri->m_bAggrBottom = m_bAggrBottom ; pDri->m_vIdUndrilledHoles = m_vIdUndrilledHoles ; } catch( ...) { delete pDri ; return nullptr ; } } // ritorno l'oggetto return pDri ; } //---------------------------------------------------------------------------- bool Drilling::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_nDrillings) + szNewLine ; sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool Drilling::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_nDrillings, vString[++k])) return false ; if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) return false ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::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_nDrillings)) return false ; } else if ( sKey == KEY_STAT) { if ( ! FromString( sVal, m_nStatus)) return false ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- Drilling::Drilling( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_Params.m_sDepth = "TH" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_nStatus = MCH_ST_TO_VERIFY ; m_nDrillings = 0 ; m_bTiltingTab = false ; m_bAboveHead = true ; m_bAggrBottom = false ; m_dDistBottom = 0 ; m_vIdUndrilledHoles = {} ; } //---------------------------------------------------------------------------- bool Drilling::Prepare( const string& sDriName) { // 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 DrillingData* pDdata = GetDrillingData( pMMgr->GetMachining( sDriName)) ; 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 Drilling::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 Drilling::SetParam( int nType, int nVal) { switch ( nType) { case MPA_SUBTYPE : if ( nVal != m_Params.m_nSubType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nSubType = 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 Drilling::SetParam( int nType, double dVal) { switch ( nType) { case MPA_SPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dSpeed) > EPS_MACH_ANG_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSpeed = dVal ; return true ; case MPA_FEED : if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dFeed = dVal ; return true ; case MPA_STARTFEED : if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dStartFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartFeed = dVal ; return true ; case MPA_ENDFEED : if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dEndFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndFeed = dVal ; return true ; case MPA_TIPFEED : if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dTipFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dTipFeed = 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 ( abs( dVal - m_Params.m_dStartPos) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartPos = dVal ; return true ; case MPA_STARTSLOWLEN : if ( abs( dVal - m_Params.m_dStartSlowLen) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartSlowLen = dVal ; return true ; case MPA_ENDSLOWLEN : if ( abs( dVal - m_Params.m_dEndSlowLen) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndSlowLen = dVal ; return true ; case MPA_THROUADDLEN : if ( abs( dVal - m_Params.m_dThroughAddLen) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dThroughAddLen = dVal ; return true ; case MPA_STEP : if ( abs( dVal - m_Params.m_dStep) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStep = dVal ; return true ; case MPA_RETURNPOS : if ( abs( dVal - m_Params.m_dReturnPos) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dReturnPos = dVal ; return true ; case MPA_OVERLAP : { string sVal = ToString( dVal) ; if ( sVal != m_Params.m_sOverlap) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sOverlap = sVal ; } return true ; case MPA_STARTADDLEN : if ( abs( dVal - m_Params.m_dStartAddLen) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartAddLen = dVal ; return true ; case MPA_ENDADDLEN : if ( abs( dVal - m_Params.m_dEndAddLen) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndAddLen = dVal ; return true ; case MPA_OFFSET : { string sVal = ToString( dVal) ; if ( sVal != m_Params.m_sOverlap) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sOffset = sVal ; } return true ; } return false ; } //---------------------------------------------------------------------------- bool Drilling::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_OVERLAP_STR : if ( sVal != m_Params.m_sOverlap) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sOverlap = sVal ; return true ; case MPA_OFFSET_STR : if ( sVal != m_Params.m_sOffset) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sOffset = 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 Drilling::SetGeometry( const SELVECTOR& vIds) { // verifico validità gestore generale e gestore DB geometrico if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) return false ; // reset della geometria corrente m_vId.clear() ; // se lavorazione standard if ( m_Params.m_nSubType == DRI_SUB_STD) { // verifico che gli identificativi rappresentino dei fori (il corretto diametro è verificato dopo) for ( int i = 0 ; i < int( vIds.size()) ; ++ i) { // recupero i dati del foro Hole hole ; if ( ! GetHoleData( vIds[i], hole)) { string sInfo = "Warning in Drilling : Skipped entity " + ToString( vIds[i].nId) ; m_pMchMgr->SetWarning( 2151, sInfo) ; continue ; } // posso aggiungere alla lista m_vId.push_back( vIds[i]) ; } } // altrimenti se lavorazione lungo curve else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE) { // verifico che gli identificativi rappresentino delle curve for ( int i = 0 ; i < int( vIds.size()) ; ++ i) { if ( ( m_pGeomDB->GetGeoType( vIds[i].nId) & GEO_CURVE) == 0) { string sInfo = "Warning in Drilling : Skipped entity " + ToString( vIds[i].nId) ; m_pMchMgr->SetWarning( 2151, sInfo) ; continue ; } // posso aggiungere alla lista m_vId.push_back( vIds[i]) ; } } // aggiorno lo stato m_nStatus |= MCH_ST_GEO_MODIF ; // restituisco presenza geometria da lavorare return ( ! m_vId.empty()) ; } //---------------------------------------------------------------------------- bool Drilling::Preview( bool bRecalc) { // reset numero forature nella lavorazione m_nDrillings = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // recupero gruppo per geometria di Preview int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; // se non c'è, lo aggiungo if ( nPvId == GDB_ID_NULL) { nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nPvId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPvId, MCH_PV) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nPvId) ; // aggiorno dati geometrici dell'utensile if ( ! UpdateToolData()) { m_pMchMgr->SetLastError( 2101, "Error in Drilling : UpdateToolData failed") ; return false ; } // se lavorazione standard if ( m_Params.m_nSubType == DRI_SUB_STD) return StandardProcess( bRecalc, nPvId, GDB_ID_NULL) ; // se altrimenti lavorazione lungo curve else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE) return AlongCurveProcess( bRecalc, nPvId, GDB_ID_NULL) ; // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool Drilling::Apply( bool bRecalc, bool bPostApply) { // reset numero forature nella lavorazione int nCurrDrillings = m_nDrillings ; m_nDrillings = 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( 2101, "Error in Drilling : UpdateToolData failed") ; return false ; } // verifico se necessario continuare nell'aggiornamento if ( ! bRecalc && ! bToolChanged && ( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) { // confermo i percorsi di lavorazione m_nDrillings = nCurrDrillings ; string sLog = string( "Drilling apply skipped : status ") + ( m_nStatus == MCH_ST_OK ? "already ok" : "no postapply") ; LOG_DBG_INFO( GetEMkLogger(), sLog.c_str()) ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ; LOG_DBG_INFO( GetEMkLogger(), "Update done") ; // esco con successo return true ; } m_nStatus = MCH_ST_TO_VERIFY ; // 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) ; // elimino eventuale gruppo geometria simmetrica per lavorazione in doppio int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ; if ( nDblId != GDB_ID_NULL) { m_pGeomDB->Erase( nDblId) ; nDblId = GDB_ID_NULL ; } // 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( 2118, "Error in Drilling : Tool loading failed") ; return false ; } // se lavorazione standard if ( m_Params.m_nSubType == DRI_SUB_STD) { if ( ! StandardProcess( bRecalc, GDB_ID_NULL, nClId)) return false ; } // se altrimenti lavorazione lungo curve else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE) { if ( ! AlongCurveProcess( bRecalc, GDB_ID_NULL, nClId)) return false ; } // altrimenti errore else 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 ; // se lavorazione in doppio, aggiungo geometria della parte simmetrica if ( ! CalcMirrorByDouble( nClId, m_Params.m_sUserNotes)) { m_pMchMgr->SetLastError( 2115, "Error in Drilling : Mirror for Double calculation failed") ; 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(), "Drilling apply done") ; return true ; } //---------------------------------------------------------------------------- bool Drilling::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_nDrillings == 0) { m_pMchMgr->SetWarning( 2152, "Warning in Drilling : No machinable hole") ; return true ; } // elimino le entità CLIMB, RISE e HOME della lavorazione, potrebbero falsare i calcoli degli assi (in ogni casi vengono riaggiunte dopo) RemoveClimbRiseHome() ; // 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( 2109, "Error in Drilling : axes values not calculable") ; else m_pMchMgr->SetLastError( 2110, "Error in Drilling : 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( 2111, "Error in Drilling : link movements not calculable") ; else m_pMchMgr->SetLastError( 2112, "Error in Drilling : 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( 2113, sErr) ; else m_pMchMgr->SetLastError( 2113, "Error in Drilling : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::VerifyMultiParallelFixedDrills( void) { // se aggregato da sotto, sicuramente con una sola punta bool bAggrBottom = IsAggrBottom( m_TParams.m_sHead) ; if ( bAggrBottom) return false ; // se una sola uscita, inutile continuare int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( m_TParams.m_sHead) ; if ( nExitCnt == 1) return false ; // verifico che le uscite siano fisse int nSelectType = m_pMchMgr->GetCurrMachine()->GetHeadSelectType( m_TParams.m_sHead) ; if ( nSelectType != MCH_SLT_FIXEDEXITS) return false ; // recupero la direzione dell'utensile principale Point3d ptMainExit ; Vector3d vtMainTool, vtMainAux ; m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( m_TParams.m_sHead, m_TParams.m_nExit, ptMainExit, vtMainTool, vtMainAux) ; // verifico ci sia almeno un'altra uscita attrezzata parallela a quella principale for ( int nT = 0 ; nT < nExitCnt ; ++ nT) { if ( nT + 1 == m_TParams.m_nExit) continue ; string sToolName ; if ( m_pMchMgr->GetLoadedTool( m_TParams.m_sHead, nT + 1, sToolName) && ! sToolName.empty()) { // recupero la tipologia di utensile int nType = TT_NONE ; string sCurrTool ; m_pMchMgr->TdbGetCurrToolParam( TPA_NAME, sCurrTool) ; if ( m_pMchMgr->TdbSetCurrTool( sToolName)) { m_pMchMgr->TdbGetCurrToolParam( TPA_TYPE, nType) ; if ( ! IsEmptyOrSpaces( sCurrTool)) m_pMchMgr->TdbSetCurrTool( sCurrTool) ; } // verifico punta o fresa con direzione corretta Point3d ptExit ; Vector3d vtTool, vtAux ; if ( ( ( nType & TF_DRILLBIT) != 0 || nType == TT_MILL_STD) && m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux(m_TParams.m_sHead, nT + 1, ptExit, vtTool, vtAux) && AreSameVectorApprox( vtTool, vtMainTool)) return true ; } } // non è stato trovato niente return false ; } //---------------------------------------------------------------------------- bool Drilling::StandardProcess( bool bRecalc, int nPvId, int nClId) { // se ho almeno un'altra punta fissa parallela alla principale ... if ( VerifyMultiParallelFixedDrills()) { TABMHDRILL tabDrills ; double dMHOff = 0 ; if ( ! MultiHeadDrilling( m_vId, nClId, tabDrills, dMHOff)) return false ; if ( tabDrills.empty()) return true ; for ( int i = 0 ; i < int( tabDrills.size()) ; ++i) { // se richiesto preview if ( nPvId != GDB_ID_NULL) { if ( ! GenerateHolePv( i, m_vId[tabDrills[i].nInd_id_hole], MCH_PATH, nPvId)) return false ; // creo la regione di ingombro del foro int nDriId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetLastGroupInGroup( nPvId)) ; GenerateHoleRegionPv( nDriId, 1, nPvId) ; } // se richiesta lavorazione if ( nClId != GDB_ID_NULL) { if ( ! GenerateHoleCl( i, m_vId[tabDrills[i].nInd_id_hole], MCH_PATH, nClId, dMHOff, tabDrills[i].vtAux)) return false ; } } return true ; } // ... altrimenti elaboro i singoli fori for ( int i = 0 ; i < int( m_vId.size()) ; ++ i) { const auto& vId = m_vId[i] ; // se richiesto preview if ( nPvId != GDB_ID_NULL) { if ( ! GenerateHolePv( i, vId, MCH_PATH, nPvId)) return false ; // creo la regione di ingombro del foro int nDriId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetLastGroupInGroup( nPvId)) ; GenerateHoleRegionPv( nDriId, 1, nPvId) ; } // se richiesta lavorazione if ( nClId != GDB_ID_NULL) { if ( ! GenerateHoleCl( i, vId, MCH_PATH, nClId)) return false ; } } return true ; } //---------------------------------------------------------------------------- bool Drilling::CalcDrilledHolesByConfig( VECTORHOLE& vHoles, int nMyInd, int nIndConfig, INTVECTOR& vIndDrilled) { /* restituisce quali fori non ancora svuotati vengono svuotati con la configurazione di indice nIndConfig per il foro nMyInd-esimo */ // controllo dei parametri if ( nMyInd < 0 || nMyInd >= int( vHoles.size()) || nIndConfig < 0 || nIndConfig >= int( vHoles[nMyInd].vIndTools.size())) return false ; vIndDrilled.clear() ; if ( vHoles.empty()) return true ; // dichiarazione variabili di supporto int nMainHole = vHoles[nMyInd].vToolHole[nIndConfig] ; Vector3d vtMainAux = vHoles[nMyInd].vVtAux[nIndConfig] ; // scorro tutti i fori for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { // se foro i-esimo già lavorato, passo al successivo if ( vHoles[i].bDrill) continue ; // se il foro i-esimo è il corrente, lo inserisco ( è svuotato in quanto nella configurazione) if ( i == nMyInd) { vIndDrilled.emplace_back( i) ; continue ; } // se il foro i-esimo è quello in cui il tool è posizionato, lo inserisco ( idem) else if ( i == nMainHole) { vIndDrilled.emplace_back( i) ; continue ; } else { // se foro i-esimo viene svuotato mettendo il tool principale nel foro nMainHole-esimo e con lo // stesso orientamento della configurazione corrente, inserisco il foro for ( int j = 0 ; j < int( vHoles[i].vToolHole.size()) ; ++ j) { if ( vHoles[i].vToolHole[j] == nMainHole && AreSameVectorApprox( vHoles[i].vVtAux[j], vtMainAux)) vIndDrilled.emplace_back( i) ; } } } return true ; } //---------------------------------------------------------------------------- bool Drilling::GetClosestHolesToHole( const VECTORHOLE& vHoles, int nMyInd, bool bDrilled, INTVECTOR& vInds) { /* funzione che restutisce gli indici dei fori Drilled/nonDrilled più vicini al foro nMyInd-esimo */ // controllo dei parametri if ( nMyInd < 0 || nMyInd >= int( vHoles.size())) return false ; vInds.clear() ; if ( vHoles.empty()) return true ; // scorro i fori double dMinDist = INFINITO ; for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { // escludo il foro nInd-esimo if ( i == nMyInd) continue ; // se foro di tipologia opposta, passo al successivo if ( vHoles[i].bDrill != bDrilled) continue ; // calcolo la distanza tra i due fori double dSqDist = SqDist( vHoles[nMyInd].hole.ptIni, vHoles[i].hole.ptIni) ; if ( dSqDist < dMinDist) { dMinDist = dSqDist ; vInds.clear() ; vInds.emplace_back( i) ; } else if ( abs( dSqDist - dMinDist) < 100 * SQ_EPS_SMALL) vInds.emplace_back( i) ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::EraseDuplicatedConfigs( VECTORHOLE& vHoles) { /* funzione per rimuovere le configurazioni tra loro equivalenti */ // scorro il vettore dei fori if ( vHoles.empty()) return true ; // analizzo il primo foro selezionato e scorro le configurazioni for ( int nC = 0 ; nC < int( vHoles[0].vIndTools.size()) - 1 ; ++ nC) { for ( int nC1 = nC + 1 ; nC1 < int( vHoles[0].vToolHole.size()) ; ++ nC1) { if ( vHoles[0].vToolHole[nC] == vHoles[0].vToolHole[nC1] && vHoles[0].vIndTools[nC] == vHoles[0].vIndTools[nC1] && ( AreSameVectorApprox( vHoles[0].vVtAux[nC], vHoles[0].vVtAux[nC1]) || ( ! vHoles[0].vVtAux[nC].IsValid() && ! vHoles[0].vVtAux[nC1].IsValid()))) { // controllo se vale anche per gli altri fori bool bSame = true ; for ( int i = 1 ; i < int( vHoles.size()) && bSame ; ++ i) { bSame = ( vHoles[i].vToolHole[nC] == vHoles[i].vToolHole[nC1] && vHoles[i].vIndTools[nC] == vHoles[i].vIndTools[nC1] && ( AreSameVectorApprox( vHoles[i].vVtAux[nC], vHoles[i].vVtAux[nC1]) || ( ! vHoles[i].vVtAux[nC].IsValid() && ! vHoles[i].vVtAux[nC1].IsValid()))) ; } if ( bSame) { for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) { vHoles[k].vToolHole.erase( vHoles[k].vToolHole.begin() + nC1) ; vHoles[k].vIndTools.erase( vHoles[k].vIndTools.begin() + nC1) ; vHoles[k].vVtAux.erase( vHoles[k].vVtAux.begin() + nC1) ; } -- nC1 ; } } } } return true ; } //---------------------------------------------------------------------------- bool Drilling::KeepMinRotatedConfigs( VECTORHOLE& vHoles, const Vector3d vtAux, const Vector3d vtTool) { /* riduco il numero di cobinazioni in base a vtAux */ // se non ho fori, allora esco if ( vHoles.empty()) return true ; // scorro il vettore dei fori for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { Vector3d vtMinAndDegAux ; double dMinAngDeg = ANG_FULL ; for ( int j = 0 ; j < int( vHoles[i].vVtAux.size()) ; ++ j) { // se non valido, passo al successivo if ( ! vHoles[i].vVtAux[j].IsValid()) continue ; // calcolo l'angolo con segno della configurazione rispetto a vtAux double dAngDeg ; bool bDet ; if ( ! vHoles[i].vVtAux[j].GetRotation( vtAux, vtTool, dAngDeg, bDet)) return false ; // conservo l'angolo minimo if ( abs( dAngDeg) < dMinAngDeg) { dMinAngDeg = abs( dAngDeg) ; vtMinAndDegAux = vHoles[i].vVtAux[j] ; } } for ( int j = 0 ; j < int( vHoles[i].vVtAux.size()) ; ++ j) { // se vettore ausiliario corrente diverso da quello minimo e non presente tra le configurazioni // valide, allora rendo invalida la configurazione if ( vHoles[i].vVtAux[j].IsValid() && ! AreSameOrOppositeVectorApprox( vHoles[i].vVtAux[j], vtMinAndDegAux)) { vHoles[i].vToolHole[j] = IND_TOOL_INVALID ; vHoles[i].vIndTools[j] = IND_TOOL_INVALID ; vHoles[i].vVtAux[j] = V_INVALID ; } } } // cancello tutte le configurazioni invalide int nSize = int( vHoles[0].vIndTools.size()) ; for ( int j = 0 ; j < nSize ; ++ j) { bool bInvalid = true ; for ( int i = 0 ; i < int( vHoles.size()) && bInvalid ; ++ i) bInvalid = ( vHoles[i].vIndTools[j] == IND_TOOL_INVALID && vHoles[i].vToolHole[j] == IND_TOOL_INVALID && ! vHoles[i].vVtAux[j].IsValid()) ; if ( bInvalid) { for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) { vHoles[k].vToolHole.erase( vHoles[k].vToolHole.begin() + j) ; vHoles[k].vIndTools.erase( vHoles[k].vIndTools.begin() + j) ; vHoles[k].vVtAux.erase( vHoles[k].vVtAux.begin() + j) ; } ; -- nSize ; -- j ; } } return true ; } //---------------------------------------------------------------------------- bool Drilling::CalcMultyHeadUndrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vIdUndrilledHoles) { /* funzione per calcolare gli Id dei fori fori non svuotati */ // se non ho fori, ho finito vIdUndrilledHoles.clear() ; if ( vHoles.empty()) return true ; // scorro sui fori for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { // scorro sulle configurazioni trovate bool bIsUndrilled = true ; for ( int j = 0 ; j < int( vHoles[i].vIndTools.size()) && bIsUndrilled ; ++ j) bIsUndrilled = ( vHoles[i].vIndTools[j] == IND_TOOL_INVALID && vHoles[i].vToolHole[j] == IND_TOOL_INVALID && ! vHoles[i].vVtAux[j].IsValid()) ; // se foro non svuotabile, lo inserisco nel vettore if ( bIsUndrilled) vIdUndrilledHoles.emplace_back( vHoles[i].hole.nOriId) ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::CheckBasedConfig( const VECTORHOLE& vHoles, int nIndHole, int& nValidConfig, bool& bBaseCase) { // controllo dei parametri if ( nIndHole < 0 || nIndHole >= int( vHoles.size())) return false ; if ( vHoles.empty()) return false ; bBaseCase = false ; nValidConfig = 0 ; Vector3d vtAuxRef ; for ( int i = 0 ; i < int( vHoles[nIndHole].vIndTools.size()) ; ++ i) { if ( vHoles[nIndHole].vIndTools[i] != IND_TOOL_INVALID) { ++ nValidConfig ; if ( nValidConfig == 1) vtAuxRef = vHoles[nIndHole].vVtAux[i] ; else { // controllo se i versori ausiliari sono opposti if ( ! AreOppositeVectorApprox( vtAuxRef, vHoles[nIndHole].vVtAux[i])) return true ; } } } bBaseCase = ( nValidConfig == 1 || nValidConfig == 2) ; return true ; } //---------------------------------------------------------------------------- bool Drilling::MultiHeadOrderConfig( TABMHDRILL& tabDrills, const VECTORHOLE& vHoles, const Vector3d& vtTool, const Vector3d& vtAux) { /* funzione per riordinare le calate; viene creato un frame mediante vtTool e vtAux e si ordinano i punti in locale a tale frame in base alla vicinanza che hanno dal punto minimo del boxXY */ // se non ho calate, non faccio nulla if ( tabDrills.empty()) return true ; // creo il sistema di riferimento locale Frame3d frOrder ; if ( ! frOrder.Set( ORIG, vtTool, vtAux)) return false ; // creo un vettore con i punti sulla base superiore dei fori in locale a tale frame // li inserisco anche nel Box PNTVECTOR vPtLoc ; BBox3d BBoxOrder ; for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i) { vPtLoc.emplace_back( GetToLoc( vHoles[tabDrills[i].nInd_id_hole].hole.ptIni, frOrder)) ; BBoxOrder.Add( vPtLoc.back()) ; } // recupero il punto minimo del Box Point3d ptMinBoxOrder = BBoxOrder.GetMin() ; // cerco l'indice della tabDrills il cui foro è più vicino al punto di minimo del box trovato int nIndClosestHole = 0 ; double dSqMinDist = INFINITO ; for ( int i = 0 ; i < int( vPtLoc.size()) ; ++ i) { double dCurrSqDist = SqDist( vPtLoc[i], ptMinBoxOrder) ; if ( dCurrSqDist < dSqMinDist) { dSqMinDist = dCurrSqDist ; nIndClosestHole = i ; } } // metto l'indice trovato in prima posizione swap( tabDrills[nIndClosestHole], tabDrills[0]) ; // una volta determinato il primo foro struct OrderTabDrill { int nInd_id_hole ; Point3d ptIni ; OrderTabDrill( int nInH, Point3d ptI) : nInd_id_hole( nInH), ptIni( ptI) {} ; } ; vector vOrderedTab ; for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i) vOrderedTab.emplace_back( tabDrills[i].nInd_id_hole, vHoles[tabDrills[i].nInd_id_hole].hole.ptIni) ; // per sicurezza ... if ( vOrderedTab.empty()) return false ; // prendo come riferimento il primo punto Point3d ptRef = vOrderedTab[0].ptIni ; double dMinSqDist = INFINITO ; int nIndexSwitch = -1 ; // ordino le successioni di calate for ( int i = 0 ; i < int( vOrderedTab.size()) - 1 ; ++ i) { for ( int j = i + 1 ; j < int( vOrderedTab.size()) ; ++ j) { Point3d ptS = vOrderedTab[j].ptIni ; double dSqCurrDist = SqDist( ptS, ptRef) ; if ( dSqCurrDist < dMinSqDist) { dMinSqDist = dSqCurrDist ; nIndexSwitch = j ; } } if ( nIndexSwitch != i + 1) { swap( vOrderedTab[nIndexSwitch], vOrderedTab[i + 1]) ; swap( tabDrills[nIndexSwitch], tabDrills[i + 1]) ; } ptRef = vOrderedTab[i + 1].ptIni ; dMinSqDist = INFINITO ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::GetHoleBestConfig( VECTORHOLE& vHoles, int nInd, TABMHDRILL& tabDrills, const Vector3d& vtAux, const Vector3d& vtTool, int& nOkHole) { // salvo gli indici dei fori ( non ancora svuotati) che vengono svuotati con la sola consifugrazione presente int nMaxDrilledHoles = - 1 ; INTVECTOR vInds ; int nRefConfig = -1 ; // scorro le configurazioni presenti for ( int i = 0 ; i < int( vHoles[nInd].vToolHole.size()) ; ++ i) { // se configurazione non valida passo alla successiva if ( vHoles[nInd].vToolHole[i] == IND_TOOL_INVALID || /*&&*/ vHoles[nInd].vIndTools[i] == IND_TOOL_INVALID || /*&&*/ ! vHoles[nInd].vVtAux[i].IsValid()) continue ; // determino se esiste la prima configurazione ammissibile per tale foro INTVECTOR vIndsTemp ; if ( ! CalcDrilledHolesByConfig( vHoles, nInd, i, vIndsTemp)) return false ; if ( int( vIndsTemp.size()) > nMaxDrilledHoles) { nMaxDrilledHoles = int( vIndsTemp.size()) ; nRefConfig = i ; vInds = vIndsTemp ; } else if ( int( vIndsTemp.size()) == nMaxDrilledHoles) { double dAngDeg0, dAngDeg1 ; bool bDet0, bDet1 ; if ( ! vHoles[nInd].vVtAux[nRefConfig].GetRotation( vtAux, vtTool, dAngDeg0, bDet0) || ! vHoles[nInd].vVtAux[i].GetRotation( vtAux, vtTool, dAngDeg1, bDet1)) return false ; if ( abs( dAngDeg0) > abs( dAngDeg1) + EPS_ANG_SMALL) { nRefConfig = i ; vInds = vIndsTemp ; } } } // assegno flag per fori svuotati for ( int i = 0 ; i < int( vInds.size()) ; ++ i) vHoles[vInds[i]].bDrill = true ; // assegno posizioni di ToolMain if ( nRefConfig != -1) { tabDrills.emplace_back( vHoles[nInd].vToolHole[nRefConfig], vHoles[nInd].vVtAux[nRefConfig]) ; nOkHole += int( vInds.size()) ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& tabDrills, double& dMHOff) { // controllo parametri tabDrills.clear() ; if ( vId.empty()) return true ; // gestore degli utensili ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero il nome della testa e il numero di uscite string sHead ; m_pMchMgr->GetCurrMachine()->GetCurrHead( sHead) ; int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( sHead) ; // Recupero i dati degli utensili montati sulla testa int nMainToolInd = -1 ; VECTORTOOL vTools ; vTools.reserve( nExitCnt) ; // ricavo gli utensili presenti sulle uscite for ( int nT = 0 ; nT < nExitCnt ; ++ nT) { string sToolName ; if ( ! m_pMchMgr->GetLoadedTool( sHead, nT + 1, sToolName) || sToolName.empty()) { // non c'è utensile vTools.emplace_back( nullptr) ; continue ; } // se presente e valido const ToolData* pTdata = pTMgr->GetTool( sToolName) ; vTools.emplace_back( pTdata) ; // imposto il tool di riferimento come il tool m_TParams if ( pTdata->m_Uuid == m_TParams.m_Uuid) nMainToolInd = nT ; } // se non ho utensili attivi o validi, errore if ( nMainToolInd == -1 || vTools.empty()) { m_pMchMgr->SetLastError( 2116, "Error in Drilling : multi drilling head without valid tools") ; return false ; } // recupero i dati dell'uscita dell'utensile principale Vector3d vtTool, vtAux ; Point3d ptExit ; m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( sHead, nMainToolInd + 1, ptExit, vtTool, vtAux) ; vTools[nMainToolInd].ptToolTip = ptExit - vtTool * vTools[nMainToolInd].pTool->m_dLen ; if ( vtAux.IsSmall() && m_pMchMgr->GetCurrMachine()->GetCurrRotAxes() == 0) vtAux = FromUprightOrtho( vtTool) ; if ( vtTool.IsSmall() || vtAux.IsSmall()) { m_pMchMgr->SetLastError( 2117, "Error in Drilling : incorrect multi drilling head") ; return false ; } // carico gli altri dati della testa con le sue uscite for ( int nT = 0 ; nT < nExitCnt ; ++ nT) { // se utensile principale, salto al successivo if ( nT == nMainToolInd) continue ; // se non attrezzato, salto al successivo if ( vTools[nT].pTool == nullptr) continue ; // recupero i dati dell'uscita Point3d ptExit ; Vector3d vtCurrDir, vtCurrAux ; m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( sHead, nT + 1, ptExit, vtCurrDir, vtCurrAux) ; // controllo abbia la stessa direzione del principale, altrimenti disattrezzo if ( ! AreSameVectorApprox( vtCurrDir, vtTool)) { vTools[nT].pTool = nullptr ; continue ; } // assegno tip utensile vTools[nT].ptToolTip = ptExit - vtCurrDir * vTools[nT].pTool->m_dLen ; } // Recupero le geometrie dei fori bool bSomeHoleOk = false ; VECTORHOLE vHoles( vId.size()) ; for ( int nH = 0 ; nH < int( vId.size()) ; ++ nH) { Hole hole ; if ( ! GetHoleData( m_vId[nH], hole)) { string sInfo = "Warning in Drilling : Skipped entity " + ToString( m_vId[nH]) ; m_pMchMgr->SetWarning( 2151, sInfo) ; continue ; } // se richiesta inversione e foro passante, provvedo if ( m_Params.m_bInvert) { if ( hole.bBlind) { m_pMchMgr->SetLastError( 2114, "Error in Drilling : blind hole not reversible") ; return false ; } else { hole.ptIni -= hole.vtDir * hole.dThick ; hole.vtDir.Invert() ; } } // se lavorazione del foro non arriva al suo fondo, lo considero cieco if ( hole.dLen < hole.dThick - 10 * EPS_SMALL) hole.bBlind = true ; vHoles[nH].hole = hole ; vHoles[nH].nIndInSelVector = nH ; bSomeHoleOk = true ; } if ( ! bSomeHoleOk) return true ; // imposto eventuale asse bloccato da lavorazione SetBlockedRotAxis( m_Params.m_sBlockedAxis) ; // applico eventuali blocchi di assi rotanti m_pMchMgr->ApplyRotAxisBlock() ; // calcolo la maschera di corrispondenza tra utensili e fori if ( ! CalcMask( vHoles, vTools, nMainToolInd, vtTool, vtAux)) return false ; // riduco il numeor di configurazioni in base a vtAux if ( ! KeepMinRotatedConfigs( vHoles, vtAux, vtTool)) return false ; // calcolo i fori non svuotati if ( ! CalcMultyHeadUndrilledHoles( vHoles, m_vIdUndrilledHoles)) return false ; // per ogni foro non svuotato, segnalo il Warning int nNoDrillHoles = int( m_vIdUndrilledHoles.size()) ; if ( ! m_vIdUndrilledHoles.empty()) { string sIndHoles = "" ; for ( int i = 0 ; i < nNoDrillHoles ; ++ i) sIndHoles.append( ToString( m_vIdUndrilledHoles[i]) + ( i != nNoDrillHoles - 1 ? ", " : "")) ; string sInfo = "Warning in Drilling : Skipped entities " + sIndHoles ; m_pMchMgr->SetWarning( 2151, sInfo) ; } // se non posso svuotare nessun foro, esco if ( nNoDrillHoles == int( vHoles.size())) return true ; // numero di fori lavorati int nOkHole = 0 ; // se c'è un solo foro va sicuramente bene if ( int( vHoles.size()) == 1 && ! vHoles[0].vVtAux.empty()) { vHoles[0].bForToolM = true ; vHoles[0].nIndTool = nMainToolInd ; vHoles[0].nIndHoleToolM = 0 ; vHoles[0].vtAux = vHoles[0].vVtAux[0] ; } // calcolo la massima differenza di lunghezza tra il primo tool e gli altri ( così l'elevazione finale rimane compatibile) double dRefLen = vTools[nMainToolInd].pTool->m_dTLen ; double dOffMax = 0 ; for ( int nT = 0 ; nT < int( vTools.size()) && nNoDrillHoles != int( vHoles.size()) ; ++ nT) { if ( vTools[nT].pTool == nullptr || nT == nMainToolInd) continue ; if ( vTools[nT].pTool->m_dTLen > dRefLen + dOffMax) dOffMax = vTools[nT].pTool->m_dTLen - dRefLen ; } dMHOff = dOffMax ; /* Inizio a considerare i fori che presentano meno configurazioni per essere svuotati. Esso sono i più critici, quindi vengono gestiti per primi, scremando quindi le configurazioni degli altri fori. Parto ad analizzare i fori svuotabili con una sola possibile configurazione */ // cerco le configurazioni di base ( quelle con 1 o due configurazioni opposte) for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { // se foro già lavorato passo al successivo if ( vHoles[i].bDrill) continue ; // se il foro i-esimo non è base, passo al successivo int nValidConfig ; bool bBaseCase ; if ( ! CheckBasedConfig( vHoles, i, nValidConfig, bBaseCase)) return false ; if ( ! bBaseCase) continue ; // salvo gli indici dei fori ( non ancora svuotati) che vengono svuotati con la sola configurazione presente if ( ! GetHoleBestConfig( vHoles, i, tabDrills, vtAux, vtTool, nOkHole)) return false ; } // se nessun foro svuotabile, esco ( fino a prova contraria non esco mai...) if ( tabDrills.empty()) return false ; /* Una volta scremate le configurazioni critiche, cerco i fori non svuotati più vicini ad essi. L'idea è che avendo svuotato i fori a signola configurazione, ottengo meno combinazioni per i fori ad esso adiacenti... l'idea si ripete per tutti i fori successivi */ // per vicinanza cerco gli altri fori oltre ai casi base while ( nOkHole < int( vHoles.size()) - nNoDrillHoles) { INTVECTOR vNextInds ; if ( ! GetClosestHolesToHole( vHoles, tabDrills.back().nInd_id_hole, false, vNextInds) || vNextInds.empty() || ! GetHoleBestConfig( vHoles, vNextInds[0], tabDrills, vtAux, vtTool, nOkHole)) return false ; } // per sicurezza ... if ( tabDrills.empty()) return false ; /* Analizzando i fori in base alle possibili combinazioni, ho riempito la tabella delle forature multiple con lavorazioni sparse tra loro, riordino quindi le discese degli utensili in base alla vicinanza dei fori svuotati dal Tool principale */ if ( ! MultiHeadOrderConfig( tabDrills, vHoles, vtTool, vtAux)) return false ; return true ; } //---------------------------------------------------------------------------- bool Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, const Vector3d& vtTool, const Vector3d& vtAux) { /* funzione per il calcolo della maschera di compatibilità tra un insieme di utensili e un insieme di fori */ // controllo dei parametri if ( vHoles.empty() || vTools.empty()) return false ; // recupero il valore di tolleranza sul diametro double dDiamToler = GetHoleDiamToler() ; int nExitCnt = int( vTools.size()) ; int nNullTools = 0 ; for ( int i = 0 ; i < int( vTools.size()) ; ++ i) { if ( vTools[i].pTool == nullptr) ++ nNullTools ; } // in ogni foro i-esimo inserisco il Tool principale for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { // resetto le variabili di controllo di svuotatura temporanea per tutti i fori for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) { vHoles[j].bTempDrill = false ; vHoles[j].nTempTool = -1 ; } // verifica validità del foro i-esimo per il Tool principale Hole Hole_i = vHoles[i].hole ; if ( ! MultiHeadVerifyHole( Hole_i, vTools[nIndMT].pTool, dDiamToler, m_vId[vHoles[i].nIndInSelVector])) continue ; int nStat ; DBLVECTOR vAng1, vAng2 ; // angoli per allineare versore T del tool principale con vtDir del foro i-esimo if ( ! m_pMchMgr->GetCalcAngles( Hole_i.vtDir, V_NULL, nStat, vAng1, vAng2)) continue ; Vector3d vtTnew ; // check che versore T sia allineato con vtDir if ( ! m_pMchMgr->GetCalcToolDirFromAngles( vAng1, vtTnew) || ! AreSameVectorApprox( vtTnew, Hole_i.vtDir)) continue ; Vector3d vtAnew ; // nuova configurazione del versore A ottenuta if ( ! m_pMchMgr->GetCalcAuxDirFromAngles( vAng1, vtAnew)) continue ; if ( vtAnew.IsSmall() && m_pMchMgr->GetCurrMachine()->GetCurrRotAxes() == 0) vtAnew = vtAux ; // creo un nuovo sistema di riferimento centrato nel Tool principale Frame3d frMT ; frMT.Set( vTools[nIndMT].ptToolTip, vtTool, vtAux) ; if ( ! frMT.IsValid()) return false ; // creo un frame nel foro i-esimo orientato come il frame sul tool principale ( origine nella base interna del foro) Frame3d frHMT ; frHMT.Set( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen, vtTnew, vtAnew) ; if ( ! frHMT.IsValid()) return false ; // numero di forature inserendo il Tool principale nel foro i-esimo int nDrills = 1 ; // setto le variabili temporanee per il foro i-esimo vHoles[i].bTempDrill = true ; vHoles[i].nTempTool = nIndMT ; // controllo la compatibilità tra le geometrie dei Tool e dei fori CheckOtherHolesWithTools( vHoles, vTools, nIndMT, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ; // controllo quanti fori sono riuscito a svuotare e setto i loro parametri di foratura if ( nDrills == nExitCnt - nNullTools) { // se ho svuotato il numero corretto di fori ... for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) { if ( vHoles[nD].bTempDrill) { vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che svuota questo foro vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario A del tool principale } else { // rendo tutto non valido vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ; vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ; vHoles[nD].vVtAux.push_back( V_INVALID) ; } } } else { for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) vHoles[nD].bTempDrill = false ; } // se la testa può ruotare if ( nStat < 0) { // inizio a scorrere tutti i tools for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT) { if ( vTools[nT].pTool == nullptr || nT == nIndMT) continue ; // cerco se ho un foro j-esimo adatto per quella punta for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) { Hole Hole_j = vHoles[j].hole ; if ( i == j || ! AreSameVectorApprox( Hole_j.vtDir, Hole_i.vtDir) || ! MultiHeadVerifyHole( Hole_j, vTools[nT].pTool, dDiamToler, m_vId[vHoles[j].nIndInSelVector])) continue ; // resetto le variabili di controllo di foratura temporanea per tutti i fori for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) { vHoles[k].bTempDrill = false ; vHoles[k].nTempTool = IND_TOOL_INVALID ; } // calcolo il vettore uscente dal tool Main e diretto al tool nT-esimo Vector3d vtRefT = vTools[nT].ptToolTip - vTools[nIndMT].ptToolTip ; // calcolo il vettore uscente dal foro i-esimo e diretto al foro j-esimo Vector3d vtRefH = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen - ( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen) ; // se le distanze sono compatibili if ( abs( vtRefH.Len() - vtRefT.Len()) < EPS_SMALL) { // rioriento il frame sul foro i-esimo Point3d ptHj = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen ; ptHj.ToLoc( frHMT) ; Vector3d vtProjB( ptHj.x, ptHj.y, 0) ; Point3d ptTt = vTools[nT].ptToolTip ; ptTt.ToLoc( frMT) ; Vector3d vtProjA( ptTt.x, ptTt.y, 0) ; double dAngle ; vtProjA.GetAngleXY( vtProjB, dAngle) ; frHMT.Rotate( frHMT.Orig(), frHMT.VersZ(), dAngle) ; nDrills = 1 ; // foratura nel foro i-esimo e j-esimo CheckOtherHolesWithTools( vHoles, vTools, nIndMT, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ; // setto le variabili temporanee per il foro i-esimo vHoles[i].bTempDrill = true ; vHoles[i].nTempTool = nIndMT ; // controllo quanti fori sono riuscito a lavorare in questo nuovo sistema di riferimento if ( nDrills == nExitCnt - nNullTools) { for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) { if ( vHoles[nD].bTempDrill) { vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che lavora questo foro vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario del tool principale } else { // rendo tutto non valido vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ; vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ; vHoles[nD].vVtAux.push_back( V_INVALID) ; } } } else { for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) vHoles[nD].bTempDrill = false ; } } } } } } // cancello le configurazioni identiche tra loro ( possono capitare quando i tools sono già // allineati con i fori) EraseDuplicatedConfigs( vHoles) ; return true ; } //---------------------------------------------------------------------------- bool Drilling::CheckOtherHolesWithTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndTM, int nIndHTM, Hole holeICP, const Frame3d& frMT, const Frame3d& frHMT, double dDiamToler, int& nDrills) { /* supponendo di inserire il tool principale nel foro nIndTM-esimo vengono controllate le compatibilità tra gli altri utensili e gli altri fori */ // controllo parametri if ( vHoles.empty() || vTools.empty()) return true ; if ( nIndTM < 0 || nIndTM >= int( vTools.size()) || nIndHTM < 0 || nIndHTM >= int( vHoles.size()) || ! frMT.IsValid() || ! frHMT.IsValid() || nDrills < 0 || nDrills > max( int( vHoles.size()), int( vTools.size()))) return false ; // definisco il punto dove cade il tool principale Hole holeTM = holeICP ; // copia del foro i-esimo // ciclo su tutti i tools for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT) { if ( vTools[nT].pTool == nullptr || nT == nIndTM) continue ; // esprimo il punto finale del tool t-esimo nel sistema di riferimento del Tool principale Point3d ptETt = vTools[nT].ptToolTip ; ptETt.ToLoc( frMT) ; // cerco se ho un foro j-esimo adatto per quella punta for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) { Hole Hole_j = vHoles[j].hole ; // copia del foro j-esimo // controllo che il foro j-esimo non sia l'i-esimo, che non sia stato già precedentemente lavorato // da un altro tool t'-esimo e che vtDir del foro i-esimo coincida con vtDir del foro j-esimo // e che il tool t-esimo sia compatibile con il foro j-esimo if ( nIndHTM == j || vHoles[j].bTempDrill || ! AreSameVectorApprox( Hole_j.vtDir, holeTM.vtDir) || ! MultiHeadVerifyHole( Hole_j, vTools[nT].pTool, dDiamToler, m_vId[vHoles[j].nIndInSelVector])) continue ; // esprimo il foro j-esimo nel sistema di riferimento del Tool principale centrato nel foro i-esimo Point3d ptHj = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen ; ptHj.ToLoc( frHMT) ; // controllo la compatibilità if ( AreSamePointApprox( ptHj, ptETt)) { // aggiorno il numero di fori lavorati ++ nDrills ; // aggiorno le variabili temporanee vHoles[j].bTempDrill = true ; vHoles[j].nTempTool = nT ; // non controllo gli altri vertici per la punta t-esima break ; } } } return true ; } //---------------------------------------------------------------------------- bool Drilling::MultiHeadVerifyHole( Hole& hole, const ToolData* Tool, double dDiamToler, SelData Id) { /* funzione per verificare la compatibilità tra un utensile e un foro, vengono controllati i diametri, le profondità e i percorsi dal basso */ // verifico che il diamtro del tool sia compatibile con quello del foro if ( ! VerifyDiameter( hole.dDiam, Tool->m_dDiam, dDiamToler)) return false ; // imposto elevazione da lunghezza foro con possibilità di sovrascrittura da info double dElev = hole.dLen ; double dMaxElev ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) { dElev = dMaxElev ; hole.ptIni += hole.vtDir * ( dElev - hole.dLen) ; hole.dLen = dElev ; } // limito lunghezza foro a massima lavorazione della punta double dAddLen = ( hole.bBlind ? 0. : m_Params.m_dThroughAddLen) ; if ( ( dElev + dAddLen) > Tool->m_dMaxMat + EPS_SMALL) { hole.dLen = Tool->m_dMaxMat + max( hole.dLen - dElev, 0.) ; hole.bBlind = true ; } if ( ! VerifyHoleFromBottom( hole, Id)) return false ; return true ; } //---------------------------------------------------------------------------- bool Drilling::AlongCurveProcess( bool bRecalc, int nPvId, int nClId) { // 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 ; } // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 2108, "Error in Drilling : Chaining failed") ; return false ; } // calcolo ogni singola catena int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, nPvId, nClId)) return false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::Chain( int nGrpDestId) { // vettore puntatori alle curve ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( m_vId.size()) ; // recupero tutte le curve e le porto in globale for ( const auto& Id : m_vId) { // prendo curva vpCrvs.emplace_back( GetCurve( Id)) ; // ne verifico la validità if ( IsNull( vpCrvs.back())) { string sInfo = "Warning in Drilling : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2151, sInfo) ; vpCrvs.back().Reset() ; } } // 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( m_vId[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) ; // 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 ; } //---------------------------------------------------------------------------- ICurve* Drilling::GetCurve( SelData Id) { // 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 Drilling::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) ; // recupero la curva composita int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; // recupero nome del path string sPName ; m_pGeomDB->GetName( nPathId, sPName) ; // valuto l'espressione dell'offset e della sovrapposizione ExeLuaSetGlobNumVar( "D", m_TParams.m_dDiam) ; double dOffset ; if ( ! ExeLuaEvalNumExpr( m_Params.m_sOffset, &dOffset)) { m_pMchMgr->SetLastError( 2102, "Error in Drilling : Offset not computable") ; return false ; } double dOverlap ; if ( ! ExeLuaEvalNumExpr( m_Params.m_sOverlap, &dOverlap)) { m_pMchMgr->SetLastError( 2103, "Error in Drilling : Overlap not computable") ; return false ; } // disabilito eventuale registrazione comandi EXE (riabilitazione automatica) CmdLogOff cmdLogOff ; // genero le circonferenze int nCount = 0 ; int nFirstId = ExeCreateCirclesAlongCurve( nTempId, nCrvId, dOffset, dOverlap, m_Params.m_dStartAddLen, m_Params.m_dEndAddLen, m_TParams.m_dDiam, &nCount) ; // se richiesta anteprima if ( nPvId != GDB_ID_NULL) { // creo l'anteprima dei fori for ( int i = 0 ; i < nCount ; ++ i) { // identificativo circonferenza int nId = nFirstId + i ; // calcolo il preview del foro if ( ! GenerateHolePv( i, nId, sPName + "_", nPvId)) return false ; } // creo la regione di ingombro dei fori GenerateHoleRegionPv( nFirstId, nCount, nPvId) ; } // se richiesta lavorazione if ( nClId != GDB_ID_NULL) { // creo lavorazione dei fori for ( int i = 0 ; i < nCount ; ++ i) { // identificativo circonferenza int nId = nFirstId + i ; // calcolo la lavorazione del foro if ( ! GenerateHoleCl( i, nId, sPName + "_", nClId)) return false ; } } return true ; } //---------------------------------------------------------------------------- bool Drilling::GenerateHolePv( int nInd, const SelData& nCircId, const string& sPName, int nPvId) { // creo gruppo per geometria di lavorazione del foro int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, sPName + ToString( nInd + 1)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nCircId)) ; m_pGeomDB->SetMaterial( nPathId, GREEN) ; // recupero il valore di tolleranza sul diametro double dDiamTol = GetHoleDiamToler() ; // recupero i dati del foro Hole hole ; if ( ! GetHoleData( nCircId, hole) || ! VerifyDiameter( hole.dDiam, m_TParams.m_dDiam, dDiamTol)) { m_pGeomDB->Erase( nPathId) ; string sInfo = "Warning in Drilling : Skipped entity " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2151, sInfo) ; return true ; } // limito lunghezza foro a massima lavorazione della punta if ( hole.dLen > m_TParams.m_dMaxMat + EPS_SMALL) { hole.dLen = m_TParams.m_dMaxMat ; string sInfo = "Warning in Drilling : Drill bit too short for Hole " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2155, sInfo) ; } // inserisco circonferenza che rappresenta il foro PtrOwner pCrvArc( CreateCurveArc()) ; if ( IsNull( pCrvArc) || ! pCrvArc->Set( hole.ptIni, hole.vtDir, 0.5 * m_TParams.m_dDiam)) return false ; // assegno il versore estrusione e lo spessore pCrvArc->SetExtrusion( hole.vtDir) ; pCrvArc->SetThickness( - hole.dLen) ; // inserisco nel DB int nDriId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrvArc)) ; // assegno nome e colore m_pGeomDB->SetName( nDriId, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nDriId, LIME) ; // aggiorno numero forature ++ m_nDrillings ; return true ; } //---------------------------------------------------------------------------- bool Drilling::GenerateHoleCl( int nInd, const SelData& nCircId, const string& sPName, int nClId, double dMHOff, Vector3d vtA) { // creo gruppo per geometria di lavorazione del foro int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, sPName + ToString( nInd + 1)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nCircId)) ; m_pGeomDB->SetMaterial( nPathId, GREEN) ; // recupero il valore di tolleranza sul diametro double dDiamTol = GetHoleDiamToler() ; // recupero i dati del foro Hole hole ; if ( ! GetHoleData( nCircId, hole) || ! VerifyDiameter( hole.dDiam, m_TParams.m_dDiam, dDiamTol)) { m_pGeomDB->Erase( nPathId) ; string sInfo = "Warning in Drilling : Skipped entity " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2151, sInfo) ; return true ; } // se richiesta inversione e foro passante, provvedo if ( m_Params.m_bInvert) { if ( hole.bBlind) { m_pMchMgr->SetLastError( 2114, "Error in Drilling : blind hole not reversible") ; return false ; } else { hole.ptIni -= hole.vtDir * hole.dThick ; hole.vtDir.Invert() ; } } // se lavorazione del foro non arriva al suo fondo, lo considero cieco if ( hole.dLen < hole.dThick - 10 * EPS_SMALL) hole.bBlind = true ; // imposto elevazione da lunghezza foro con possibilità di sovrascrittura da info double dElev = hole.dLen ; double dMaxElev ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) { dElev = dMaxElev ; hole.ptIni += hole.vtDir * ( dElev - hole.dLen) ; hole.dLen = ( hole.dLen > 10 * EPS_SMALL ? max( dElev, 10 * EPS_SMALL) : dElev) ; } // limito lunghezza foro a massima lavorazione della punta double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ; if ( ( dElev + dAddLen) > m_TParams.m_dMaxMat + EPS_SMALL) { hole.dLen = m_TParams.m_dMaxMat + max( hole.dLen - dElev, 0.) ; hole.bBlind = true ; string sInfo = "Warning in Drilling : Drill bit too short for Hole " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2155, sInfo) ; } // verifico se tavola basculante bool bTiltTab = false ; m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab, m_vtTiltingAx) && bTiltTab) ; // verifico se testa da sopra (Z+) m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ; // verifiche per foro verso il basso m_bAggrBottom = false ; if ( ! VerifyHoleFromBottom( hole, nCircId)) return false ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPathId, KEY_EXTR, hole.vtDir) ; // assegno i punti di inizio e fine al gruppo del percorso m_pGeomDB->SetInfo( nPathId, KEY_START, hole.ptIni) ; m_pGeomDB->SetInfo( nPathId, KEY_END, hole.ptIni) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPathId, KEY_ELEV, hole.dLen) ; // foro normale if ( m_Params.m_dStep < EPS_SMALL || m_Params.m_dStep > hole.dLen - EPS_SMALL) { if ( DoStandardDrilling( hole, nCircId, nPathId, dMHOff, vtA)) { // aggiorno numero forature ++ m_nDrillings ; } else { m_pGeomDB->Erase( nPathId) ; string sInfo = "Warning in Drilling : Skipped by Standard Drilling " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2156, sInfo) ; } } else { if ( DoPeckDrilling( hole, nCircId, nPathId, dMHOff, vtA)) { // aggiorno numero forature ++ m_nDrillings ; } else { m_pGeomDB->Erase( nPathId) ; string sInfo = "Warning in Drilling : Skipped by Peck Drilling " + ToString( nCircId) ; m_pMchMgr->SetWarning( 2157, sInfo) ; } } return true ; } //---------------------------------------------------------------------------- bool Drilling::GenerateHoleRegionPv( int nFirstId, int nCount, int nPvId) { // raggio dei fori double dRad = m_TParams.m_dDiam / 2 ; // extra raggio double dExtraR = GetExtraROnDrillRegion() ; // gruppo di inserimento int nGroupId = m_pGeomDB->GetLastGroupInGroup( nPvId) ; // creo polyline che unisce i centri PolyLine PL ; for ( int i = 0 ; i < nCount ; ++ i) { int nId = nFirstId + i ; const ICurveArc* pArc = GetCurveArc( m_pGeomDB->GetGeoObj( nId)) ; if ( pArc == nullptr) return false ; PL.AddUPoint( i, pArc->GetCenter()) ; } // calcolo la regione ISurfFlatRegion* pSfr = nullptr ; // se polilinea con almeno due punti if ( PL.GetPointNbr() > 1) { // ne derivo una curva composita PtrOwner pCompo1( CreateCurveComposite()) ; if ( IsNull( pCompo1) || ! pCompo1->FromPolyLine( PL)) return false ; // calcolo la regione pSfr = GetSurfFlatRegionFromFatCurve( Release( pCompo1), dRad + dExtraR, false, true) ; if ( pSfr == nullptr) return false ; } // altrimenti else { // approssimo l'unico foro pSfr = GetSurfFlatRegionDisk( dRad + dExtraR) ; if ( pSfr == nullptr) return false ; Point3d ptCen ; PL.GetFirstPoint( ptCen) ; pSfr->Translate( ptCen - ORIG) ; } // inserisco la regione nel DB int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGroupId, pSfr) ; if ( nRId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; // la copio anche come regione ridotta int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nGroupId) ; if ( nRrId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- bool Drilling::VerifyDiameter( double dHdiam, double dTdiam, double dDiamTol) { // imposto minima tolleranza if ( abs( dDiamTol) < 10 * EPS_SMALL) dDiamTol = 10 * EPS_SMALL ; // se tolleranza in più o in meno if ( dDiamTol > 0) return ( abs( dHdiam - dTdiam) < dDiamTol) ; // altrimenti tolleranza solo in meno return ( dTdiam < dHdiam + 10 * EPS_SMALL && dTdiam > dHdiam + dDiamTol - 10 * EPS_SMALL) ; } //---------------------------------------------------------------------------- bool Drilling::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool Drilling::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_DRILLING ; return true ; case MPA_SUBTYPE : nVal = m_Params.m_nSubType ; return true ; case MPA_SCC : nVal = m_Params.m_nSolCh ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Drilling::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_STARTPOS : dVal = m_Params.m_dStartPos ; return true ; case MPA_STARTSLOWLEN : dVal = m_Params.m_dStartSlowLen ; return true ; case MPA_ENDSLOWLEN : dVal = m_Params.m_dEndSlowLen ; return true ; case MPA_THROUADDLEN : dVal = m_Params.m_dThroughAddLen ; return true ; case MPA_STEP : dVal = m_Params.m_dStep ; return true ; case MPA_RETURNPOS : dVal = m_Params.m_dReturnPos ; 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 Drilling::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_OVERLAP_STR : sVal = m_Params.m_sOverlap ; return true ; case MPA_OFFSET_STR : sVal = m_Params.m_sOffset ; 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& Drilling::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool Drilling::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 ; // salvo posizione TC, testa e uscita originali string sOrigTcPos = m_TParams.m_sTcPos ; string sOrigHead = m_TParams.m_sHead ; int nOrigExit = m_TParams.m_nExit ; // verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita) bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ; // aggiorno comunque i parametri m_TParams = *pTdata ; // se definito attrezzaggio, aggiorno i parametri che ne possono derivare string sTcPos ; string sHead ; int nExit ; if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) { if ( sOrigTcPos != sTcPos || sOrigHead != sHead || nOrigExit != nExit) bChanged = true ; m_TParams.m_sTcPos = sTcPos ; m_TParams.m_sHead = sHead ; m_TParams.m_nExit = nExit ; } else { if ( sOrigTcPos != pTdata->m_sTcPos || sOrigHead != pTdata->m_sHead || nOrigExit != pTdata->m_nExit) bChanged = true ; } // eventuali segnalazioni if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { string sInfo = "Warning in Drilling : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; m_pMchMgr->SetWarning( 2153, sInfo) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sInfo = "Warning in Drilling : tool data changed (" + m_Params.m_sToolName + ")" ; m_pMchMgr->SetWarning( 2154, sInfo) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool Drilling::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool Drilling::GetHoleData( SelData Id, Hole& hole) { PtrOwner pMyArc ; // deve essere un arco o una composita formata da un arco const ICurveArc* pArc = GetCurveArc( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pArc == nullptr) { const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ; if ( pCompo == nullptr || ! pCompo->IsACircle( 100 * EPS_SMALL, ptCen, vtN, dRad, bCCW)) return false ; pMyArc.Set( CreateCurveArc()) ; if ( IsNull( pMyArc) || ! pMyArc->Set( ptCen, vtN, dRad)) return false ; Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; pMyArc->SetExtrusion( vtExtr) ; double dThick = 0 ; pCompo->GetThickness( dThick) ; pMyArc->SetThickness( dThick) ; pArc = pMyArc ; } // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return false ; // deve avere estrusione Vector3d vtExtr ; if ( ! pArc->GetExtrusion( vtExtr)) return false ; if ( vtExtr.IsSmall()) vtExtr = pArc->GetNormVersor() ; // recupero spessore double dThick = 0 ; pArc->GetThickness( dThick) ; // se diretto come asse Z, recupero distanza da fondo dei grezzi interessati dal foro double dRbDist = 0 ; Vector3d vtExtrG = vtExtr ; vtExtrG.ToGlob( frGlob) ; if ( vtExtrG.IsZplus()) GetDistanceFromRawBottom( m_nPhase, Id.nId, EPS_SMALL, dRbDist) ; // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; ExeLuaSetGlobNumVar( "RB", dRbDist) ; double dDepth ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 2104, "Error in Drilling : Depth not computable") ; return false ; } if ( abs( dDepth) < EPS_SMALL) { m_pMchMgr->SetLastError( 2105, "Error in Drilling : Drill with zero depth") ; return false ; } // assegno Id hole.nOriId = Id.nId ; // ne recupero il diametro hole.dDiam = 2 * pArc->GetRadius() ; // ne recupero il centro hole.ptIni = pArc->GetCenter() + ( dThick > 0 ? vtExtr * dThick : V_NULL) ; hole.ptIni.ToGlob( frGlob) ; // ne recupero versore direzione e lunghezze hole.vtDir = vtExtr ; hole.vtDir.ToGlob( frGlob) ; hole.vtDir.Normalize() ; hole.dThick = abs( dThick) ; hole.dLen = abs( dDepth) ; // per default è cieco hole.bBlind = true ; // se dichiarato passante o no (1/0) int nOpen ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "Open="), nOpen)) hole.bBlind = ( nOpen == 0) ; // se verticale ed arriva fino al fondo grezzo, allora passante else if ( hole.vtDir.IsZplus() && hole.dThick > dRbDist - EPS_SMALL) hole.bBlind = false ; // altrimenti determino la distanza del fondo del foro dal bordo opposto del grezzo else { const double BLIND_TOL = 10 ; double dBackElev ; if ( GetElevation( m_nPhase, hole.ptIni, - hole.vtDir, dBackElev) && ( dBackElev - hole.dThick) <= BLIND_TOL) hole.bBlind = false ; } return true ; } //---------------------------------------------------------------------------- bool Drilling::VerifyHoleFromBottom( const Hole& hole, SelData Id) { // se non è foro dal basso in alto, esco if ( hole.vtDir.z > MIN_ZDIR_TOP_TOOL) return true ; // se c'è testa non dall'alto o tavola basculante, esco if ( ! m_bAboveHead || m_bTiltingTab) return true ; // recupero dati di eventuale rinvio da sotto if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) { string sOut = "Error in Drilling : Entity " + ToString( Id) + " skipped because missing aggregate from bottom" ; m_pMchMgr->SetLastError( 2106, sOut) ; return false ; } // calcolo la distanza minima del punto dal contorno del grezzo double dDist ; Vector3d vtDir ; if ( ! GetMinDistanceFromRawSide( m_nPhase, hole.ptIni, 0, m_AggrBottom.vtMDir, MCH_AGB_DELTAMAX_MDIR, dDist, vtDir) || dDist > m_AggrBottom.dDMax) { string sOut = "Error in Drilling : Entity " + ToString( Id) + " skipped because too far from part sides" ; m_pMchMgr->SetLastError( 2107, sOut) ; return false ; } // assegno direzione di accesso e segnalazione di utilizzo aggregato da sotto m_vtAggrBottom = vtDir ; m_bAggrBottom = true ; m_dDistBottom = dDist ; return true ; } //---------------------------------------------------------------------------- bool Drilling::DoStandardDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA) { // aggiusto alcuni parametri del ciclo di foratura double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ; if ( abs( m_TParams.m_dStartFeed - m_TParams.m_dFeed) < EPS_SMALL) dStartSlowLen = 0 ; double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ; if ( abs( m_TParams.m_dTipFeed - m_TParams.m_dFeed) < EPS_SMALL) dEndSlowLen = 0 ; if ( ( dStartSlowLen + dEndSlowLen) > hole.dLen) { dStartSlowLen = dStartSlowLen / ( dStartSlowLen + dEndSlowLen) * hole.dLen ; dEndSlowLen = hole.dLen - dStartSlowLen ; } double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ; bool bStartSlow = ( dStartSlowLen > EPS_SMALL) ; bool bStd = ( ( hole.dLen - dStartSlowLen - dEndSlowLen) > EPS_SMALL) ; bool bEndSlow = ( dEndSlowLen > EPS_SMALL) ; // determino l'elevazione double dElev = 0 ; GetElevation( m_nPhase, hole.ptIni, hole.vtDir, m_TParams.m_dDiam / 2, hole.vtDir, dElev) ; // determino alcune caratteristiche dell'utensile double dTExtrLen = max( 0.0, m_TParams.m_dTLen - m_TParams.m_dLen) ; // necessità di spezzatura per robot bool bSplitArcs = GetSplitArcs( V_NULL) ; // imposto dati comuni SetPathId( nPathId) ; SetToolDir( hole.vtDir) ; // 1 -> punto approccio (se con aggregato da sotto è una sequenza di approccio) SetFlag( 1) ; double dSafeZ = GetSafeZ() ; double dSafeAggrBottZ = GetSafeAggrBottZ() ; double dAppr = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ; Point3d ptP1 = hole.ptIni + hole.vtDir * ( dAppr + dElev + dTExtrLen + dMHOff) ; if ( m_bAggrBottom) { Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { // punto ruotato Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAppr + dTExtrLen) ; Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) return false ; // vado al punto standard SetAuxDir( m_vtAggrBottom) ; SetFlag( 0) ; if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; } // se altrimenti con rotazione per minimizzare la sporgenza else if ( m_AggrBottom.nType == 3) { // punto standard ruotato Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; // la rotazione viene eseguita nel movimento successivo al punto sopra l'inizio lavorazione SetAuxDir( m_vtAggrBottom) ; SetFlag( 0) ; } // altrimenti rinvio normale else { SetAuxDir( m_vtAggrBottom) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; SetFlag( 0) ; } if ( AddRapidMove( ptP1, bSplitArcs) == GDB_ID_NULL) return false ; } else { if ( ! vtA.IsSmall()) SetAuxDir( vtA) ; if ( AddRapidStart( ptP1) == GDB_ID_NULL) return false ; } SetFlag( 0) ; // 2 -> punto fuori (se diverso dal precedente) if ( m_Params.m_dStartPos < dAppr) { Point3d ptP2 = hole.ptIni + hole.vtDir * ( m_Params.m_dStartPos + dTExtrLen) ; if ( AddRapidMove( ptP2, bSplitArcs) == GDB_ID_NULL) return false ; } // 3 -> punto termine velocità ridotta iniziale (se previsto) if ( bStartSlow) { SetFeed( GetStartFeed()) ; if ( ! bStd && ! bEndSlow) SetFlag( 101) ; // fondo del foro Point3d ptP3 = hole.ptIni - hole.vtDir * dStartSlowLen ; if ( ! bStd && ! bEndSlow) ptP3 -= hole.vtDir * dAddLen ; if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) return false ; } // 4 -> punto termine velocità standard (se risulta) if ( bStd) { SetFeed( GetFeed()) ; if ( ! bEndSlow) SetFlag( 101) ; // fondo del foro Point3d ptP4 = hole.ptIni - hole.vtDir * ( hole.dLen - dEndSlowLen) ; if ( ! bEndSlow) ptP4 -= hole.vtDir * dAddLen ; if ( AddLinearMove( ptP4, bSplitArcs) == GDB_ID_NULL) return false ; } // 5 -> punto termine velocità finale ridotta (se previsto) if ( bEndSlow) { SetFeed( GetTipFeed()) ; SetFlag( 101) ; // fondo del foro Point3d ptP5 = hole.ptIni - hole.vtDir * ( hole.dLen + dAddLen) ; if ( AddLinearMove( ptP5, bSplitArcs) == GDB_ID_NULL) return false ; } // 6 -> ritorno all'approccio del foro SetFeed( GetEndFeed()) ; SetFlag( 104) ; // risalita sopra il foro if ( AddLinearMove( ptP1, bSplitArcs) == GDB_ID_NULL) return false ; // 7 -> punto fuori (se uso aggregato da sotto) if ( m_bAggrBottom) { // se con rotazione per minimizzare la sporgenza if ( m_AggrBottom.nType == 3) { // imposto rotazione su punto standard Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; } SetFlag( 0) ; // vado al punto Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_OUT) == GDB_ID_NULL) return false ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAppr + dTExtrLen) ; Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidMove( ptP00, bSplitArcs, MCH_CL_AGB_UP) == GDB_ID_NULL) return false ; } } // reset dati di movimento ResetMoveData() ; return true ; } //---------------------------------------------------------------------------- bool Drilling::DoPeckDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA) { // aggiusto alcuni parametri del ciclo di foratura double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ; if ( abs( m_TParams.m_dStartFeed - m_TParams.m_dFeed) < EPS_SMALL) dStartSlowLen = 0 ; double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ; if ( abs( m_TParams.m_dTipFeed - m_TParams.m_dFeed) < EPS_SMALL) dEndSlowLen = 0 ; if ( ( dStartSlowLen + dEndSlowLen) > hole.dLen) { dStartSlowLen = dStartSlowLen / ( dStartSlowLen + dEndSlowLen) * hole.dLen ; dEndSlowLen = hole.dLen - dStartSlowLen ; } double dStdLen = hole.dLen - dStartSlowLen - dEndSlowLen ; double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ; double dReturnPos = m_Params.m_dReturnPos ; bool bStartSlow = ( dStartSlowLen > EPS_SMALL) ; bool bStd = ( dStdLen > EPS_SMALL) ; bool bEndSlow = ( dEndSlowLen > EPS_SMALL) ; // determino l'elevazione double dElev = 0 ; GetElevation( m_nPhase, hole.ptIni, hole.vtDir, m_TParams.m_dDiam / 2, hole.vtDir, dElev) ; // determino alcune caratteristiche dell'utensile double dTExtrLen = max( 0.0, m_TParams.m_dTLen - m_TParams.m_dLen) ; // necessità di spezzatura per robot bool bSplitArcs = GetSplitArcs( V_NULL) ; // imposto dati comuni SetPathId( nPathId) ; SetToolDir( hole.vtDir) ; // 1 -> punto approccio SetFlag( 1) ; double dSafeZ = GetSafeZ() ; double dSafeAggrBottZ = GetSafeAggrBottZ() ; double dAppr = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ; Point3d ptP1 = hole.ptIni + hole.vtDir * ( dAppr + dElev + dTExtrLen + dMHOff) ; if ( m_bAggrBottom) { Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { // punto ruotato Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAppr + dTExtrLen) ; Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) return false ; // vado al punto standard SetFlag( 0) ; SetAuxDir( m_vtAggrBottom) ; if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; } // se altrimenti con rotazione per minimizzare la sporgenza else if ( m_AggrBottom.nType == 3) { // punto standard ruotato Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; // la rotazione viene eseguita nel movimento successivo al punto sopra l'inizio lavorazione SetAuxDir( m_vtAggrBottom) ; SetFlag( 0) ; } // altrimenti rinvio normale else { SetAuxDir( m_vtAggrBottom) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; SetFlag( 0) ; } if ( AddRapidMove( ptP1, bSplitArcs) == GDB_ID_NULL) return false ; } else { if ( ! vtA.IsSmall()) SetAuxDir( vtA) ; if ( AddRapidStart( ptP1) == GDB_ID_NULL) return false ; } SetFlag( 0) ; // 2 -> punto fuori (se diverso dal precedente) if ( m_Params.m_dStartPos < dAppr) { Point3d ptP2 = hole.ptIni + hole.vtDir * ( m_Params.m_dStartPos + dTExtrLen) ; if ( AddRapidMove( ptP2, bSplitArcs) == GDB_ID_NULL) return false ; } // ciclo di affondamento a step const double MIN_STEP = 1 ; const double APPR_STEP = 1 ; const double MIN_MOVE = 1 ; double dStep = max( m_Params.m_dStep, MIN_STEP) ; int nStep = int( ceil( hole.dLen / dStep)) ; dStep = hole.dLen / nStep ; if ( dReturnPos < - dStep + APPR_STEP + MIN_MOVE) dReturnPos = - dStep + APPR_STEP + MIN_MOVE ; double dCurrLen = 0 ; for ( int i = 1 ; i <= nStep ; ++ i) { // se non è primo step faccio retrazione e riaffondo if ( i != 1) { // retrazione SetFeed( GetEndFeed()) ; SetFlag( 103) ; // punto di scarico truciolo Point3d ptPr = hole.ptIni + hole.vtDir * dReturnPos ; if ( AddLinearMove( ptPr, bSplitArcs) == GDB_ID_NULL) return false ; // riaffondo SetFeed( GetEndFeed()) ; SetFlag( 0) ; Point3d ptPa = hole.ptIni - hole.vtDir * ( dCurrLen - APPR_STEP) ; if ( AddLinearMove( ptPa, bSplitArcs) == GDB_ID_NULL) return false ; } // lunghezza di fine step double dEndLen = dCurrLen + dStep ; // 3 -> punto termine velocità ridotta iniziale (se previsto) if ( bStartSlow && ( i == 1 || dCurrLen < dStartSlowLen + EPS_SMALL)) { // lunghezza di esecuzione double dLen = min( dStartSlowLen, dEndLen) ; // determino se arrivo in fondo al foro bool bHoleEnd = ( ! bStd && ! bEndSlow && dLen > hole.dLen - EPS_SMALL) ; // determino se arrivo in fondo allo step bool bStepEnd = ( dLen > dEndLen - EPS_SMALL) ; // assegno parametri SetFeed( GetStartFeed()) ; if ( bHoleEnd) SetFlag( 101) ; // fondo del foro else if ( bStepEnd) SetFlag( 102) ; // fondo dello step // movimento Point3d ptP3 = hole.ptIni - hole.vtDir * dLen ; if ( bHoleEnd) ptP3 -= hole.vtDir * dAddLen ; if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) return false ; // aggiorno posizione e verifico se step completato dCurrLen = dLen ; if ( bHoleEnd || bStepEnd) continue ; } // 4 -> punto termine velocità standard (se risulta) if ( bStd && dCurrLen < dStartSlowLen + dStdLen + EPS_SMALL) { // lunghezza di esecuzione double dLen = min( hole.dLen - dEndSlowLen, dEndLen) ; // determino se arrivo in fondo al foro bool bHoleEnd = ( ! bEndSlow && dLen > hole.dLen - EPS_SMALL) ; // determino se arrivo in fondo allo step bool bStepEnd = ( dLen > dEndLen - EPS_SMALL) ; // assegno parametri SetFeed( GetFeed()) ; if ( bHoleEnd) SetFlag( 101) ; // fondo del foro else if ( bStepEnd) SetFlag( 102) ; // fondo dello step // movimento Point3d ptP4 = hole.ptIni - hole.vtDir * dLen ; if ( bHoleEnd) ptP4 -= hole.vtDir * dAddLen ; if ( AddLinearMove( ptP4, bSplitArcs) == GDB_ID_NULL) return false ; // aggiorno posizione e verifico se step completato dCurrLen = dLen ; if ( bHoleEnd || bStepEnd) continue ; } // 5 -> punto termine velocità finale ridotta (se previsto) if ( bEndSlow) { // lunghezza di esecuzione double dLen = dEndLen ; // determino se arrivo in fondo al foro bool bHoleEnd = ( dLen > hole.dLen - EPS_SMALL) ; // sono sempre in fondo allo step // assegno parametri SetFeed( GetTipFeed()) ; if ( bHoleEnd) SetFlag( 101) ; // fondo del foro else SetFlag( 102) ; // fondo dello step // movimento Point3d ptP5 = hole.ptIni - hole.vtDir * dLen ; if ( bHoleEnd) ptP5 -= hole.vtDir * dAddLen ; if ( AddLinearMove( ptP5, bSplitArcs) == GDB_ID_NULL) return false ; // aggiorno posizione dCurrLen = dLen ; } } // 6 -> ritorno all'approccio del foro SetFeed( GetEndFeed()) ; SetFlag( 104) ; // risalita sopra il foro if ( AddLinearMove( ptP1, bSplitArcs) == GDB_ID_NULL) return false ; // 7 -> punto fuori (se uso aggregato da sotto) if ( m_bAggrBottom) { // se con rotazione per minimizzare la sporgenza if ( m_AggrBottom.nType == 3) { // imposto rotazione su punto standard Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; } // vado al punto SetFlag( 0) ; Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_OUT) == GDB_ID_NULL) return false ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAppr + dTExtrLen) ; Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidMove( ptP00, bSplitArcs, MCH_CL_AGB_UP) == GDB_ID_NULL) return false ; } } // reset dati di movimento ResetMoveData() ; return true ; }