From 5d77408018aa0c4088577770e8bca60d24cfe833 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Thu, 30 Jan 2025 16:54:30 +0100 Subject: [PATCH] EgtMachKernel : - prima implementazione forature con utensili selezionabili. --- Drilling.cpp | 565 ++++++++++++++++++++++++++++++++++++++++++--------- Drilling.h | 9 +- 2 files changed, 477 insertions(+), 97 deletions(-) diff --git a/Drilling.cpp b/Drilling.cpp index 2ab4e21..b59d35b 100644 --- a/Drilling.cpp +++ b/Drilling.cpp @@ -60,11 +60,22 @@ using namespace std ; // 2156 = "Warning in Drilling : Skipped by Standard Drilling " // 2157 = "Warning in Drilling : Skipped by Peck Drilling " +//---------------------------------------------------------------------------- +// debug +#define ENABLE_DEBUG_MULTIHEAD_HOLES 0 + //---------------------------------------------------------------------------- // definizione delle costanti const int IND_TOOL_INVALID = -1 ; const int IND_HOLE_INVALID = -1 ; +//---------------------------------------------------------------------------- +// definizione tipologia foratura +const int DRILL_TYPE_ERR = 0 ; +const int DRILL_TYPE_STD = 1 ; // 1 tool +const int DRILL_TYPE_MULTI_FIXED = 2 ; // più utensili fissi +const int DRILL_TYPE_MULTI_SEL = 3 ; // più utensili selezionabili + //---------------------------------------------------------------------------- // struttura semplificata del foro struct Hole { @@ -112,10 +123,13 @@ struct ToolInfo { // struttura per foratura con MultiHeadDrills struct MHDrill { - int nInd_id_hole ; // indice foro - Vector3d vtAux ; // vettore ausiliario per tale foratura + int nInd_id_hole ; // indice foro + Vector3d vtAux ; // vettore ausiliario per tale foratura + INTVECTOR vActiveExist ; // nel caso di più utensili selezionabili, contiene gli indici delle uscite attive MHDrill( int nIndH, Vector3d vtA) : nInd_id_hole( nIndH), vtAux( vtA) {} ; + MHDrill( int nIndH, Vector3d vtA, INTVECTOR vAE) + : nInd_id_hole( nIndH), vtAux( vtA), vActiveExist( vAE) {} ; } ; @@ -746,21 +760,21 @@ Drilling::Update( bool bPostApply) } //---------------------------------------------------------------------------- -bool +int Drilling::VerifyMultiParallelFixedDrills( void) { // se aggregato da sotto, sicuramente con una sola punta bool bAggrBottom = IsAggrBottom( m_TParams.m_sHead) ; if ( bAggrBottom) - return false ; + return DRILL_TYPE_STD ; // se una sola uscita, inutile continuare int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( m_TParams.m_sHead) ; if ( nExitCnt == 1) - return false ; + return DRILL_TYPE_STD ; // verifico che le uscite siano fisse int nSelectType = m_pMchMgr->GetCurrMachine()->GetHeadSelectType( m_TParams.m_sHead) ; - if ( nSelectType != MCH_SLT_FIXEDEXITS) - return false ; + if ( nSelectType != MCH_SLT_FIXEDEXITS && nSelectType != MCH_SLT_MULTIEXITS) + return DRILL_TYPE_STD ; // 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) ; @@ -781,28 +795,55 @@ Drilling::VerifyMultiParallelFixedDrills( void) // 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 ; + m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( m_TParams.m_sHead, nT + 1, ptExit, vtTool, vtAux) && + AreSameVectorApprox( vtTool, vtMainTool)) { + if ( nSelectType == MCH_SLT_FIXEDEXITS) + return DRILL_TYPE_MULTI_FIXED ; + else + return DRILL_TYPE_MULTI_SEL ; + } } } // non è stato trovato niente - return false ; + return DRILL_TYPE_STD ; } //---------------------------------------------------------------------------- bool Drilling::StandardProcess( bool bRecalc, int nPvId, int nClId) { - // se ho almeno un'altra punta fissa parallela alla principale ... - if ( VerifyMultiParallelFixedDrills()) { + // recupero il tipo di lavorazione + int nDrillType = VerifyMultiParallelFixedDrills() ; + // eseguo la lavorazione richiesta + switch ( nDrillType) { + case DRILL_TYPE_STD : { + // 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 ; + } + } + } + break ; + case DRILL_TYPE_MULTI_FIXED : { TABMHDRILL tabDrills ; double dMHOff = 0 ; - if ( ! MultiHeadDrilling( m_vId, nClId, tabDrills, dMHOff)) + if ( ! MultiHeadDrilling( m_vId, nClId, true, tabDrills, dMHOff)) return false ; if ( tabDrills.empty()) return true ; - for ( int i = 0 ; i < int( tabDrills.size()) ; ++i) { + 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)) @@ -817,25 +858,53 @@ Drilling::StandardProcess( bool bRecalc, int nPvId, int nClId) 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 ; + break ; + case DRILL_TYPE_MULTI_SEL : { + // eseguo il MultiHead drilling per gruppo a forare + TABMHDRILL tabDrills ; + double dMHOff = 0 ; + if ( ! MultiHeadDrilling( m_vId, nClId, false, 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 ; + } + + #if ENABLE_DEBUG_MULTIHEAD_HOLES + LOG_ERROR( GetEMkLogger(), ( " --- Tool main in " + ToString( m_vId[tabDrills[i].nInd_id_hole].nId)).c_str()) ; + string sActiveTool = "" ; + for ( int _a = 0 ; _a < int( tabDrills[i].vActiveExist.size()) ; ++ _a) + sActiveTool.append( "->" + ToString( tabDrills[i].vActiveExist[_a])) ; + LOG_ERROR( GetEMkLogger(), ( " Uscite attive : " + sActiveTool).c_str()) ; + string s_vtAux = "{" ; + s_vtAux.append( ToString( tabDrills[i].vtAux.x) + ", ") ; + s_vtAux.append( ToString( tabDrills[i].vtAux.y) + ", ") ; + s_vtAux.append( ToString( tabDrills[i].vtAux.z) + "}") ; + LOG_ERROR( GetEMkLogger(), ( " vtAux : " + s_vtAux).c_str()) ; + #endif + // ---------------------------------------------------------- + } } + break ; + case DRILL_TYPE_ERR : + return false ; + default : + break ; + } return true ; } @@ -935,6 +1004,218 @@ Drilling::GetClosestHolesToHole( const VECTORHOLE& vHoles, int nMyInd, bool bDri return true ; } +//---------------------------------------------------------------------------- +bool +Drilling::OrderConfigsForSelectableTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndToolMain, TABMHDRILL& vDrills) +{ + // se non ho fori, allora non faccio nulla + vDrills.clear() ; + if ( vHoles.empty()) + return true ; + + // recupero gli indici dei fori non lavorabili + INTVECTOR vIndUndrilledHoles ; + 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 lavorabile, lo inserisco nel vettore + if ( bIsUndrilled) + vIndUndrilledHoles.emplace_back( i) ; + } + + // recupero il numero di fori totali + int nHoles = int( vHoles.size()) ; + // recupero il numero di fori non lavorabili + int nUndrilledHoles = int( vIndUndrilledHoles.size()) ; + // se i due valori coincidono, allora ho finito + if ( nHoles == nUndrilledHoles) + return true ; + + // considero tutti i fori come non lavorati + for ( int i = 0 ; i < nHoles ; ++ i) + vHoles[i].bTempDrill = false ; + + // inizializzo contatore di fori lavorati + int nDrilledHoles = 0 ; + + // finchè non lavoro tutti i fori ammissibili + const int MAXTRY = 5000 ; + int nCont = 0 ; + while ( nDrilledHoles < nHoles - nUndrilledHoles && nCont < MAXTRY) { + // cerco la(e) configurazione(i) che lavora(no) più fori + INTVECTOR vIndBestConfigs ; + GetConfigsWithMoreDrilledHoles( vHoles, vIndBestConfigs) ; + // se non ho trovato nessuna configurazione, allora non faccio nulla + if ( vIndBestConfigs.empty()) + break ; + int nBestConfig = vIndBestConfigs[0] ; + ChooseBestConfigForSelectableTools( vHoles, nIndToolMain, vIndBestConfigs, nBestConfig) ; + // imposto bTempDrill per i fori in esame + INTVECTOR vIndActiveExits ; + int nRefHole = 0 ; + for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { + if ( ! vHoles[i].bTempDrill && + vHoles[i].vIndTools[nBestConfig] != IND_TOOL_INVALID && + vHoles[i].vToolHole[nBestConfig] != IND_TOOL_INVALID && + vHoles[i].vVtAux[nBestConfig].IsValid()) { + // flag per lavorazione temporanea + vHoles[i].bTempDrill = true ; + // aumento contatore fori lavorati + ++ nDrilledHoles ; + // ricavo la testa su cui è montato l'utensile + vIndActiveExits.emplace_back( vTools[vHoles[i].vIndTools[nBestConfig]].pTool->m_nExit) ; + // memorizzo un foro di riferimento + nRefHole = i ; + } + } + // inserisco la configurazione per la lavorazione + vDrills.emplace_back( vHoles[nRefHole].vToolHole[nBestConfig], + vHoles[nRefHole].vVtAux[nBestConfig], + vIndActiveExits) ; + // incremento contatore tentativi massimi + ++ nCont ; + } + // se ho superato i tentativi massimi, errore + if ( nCont == MAXTRY) { + vDrills.clear() ; + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Drilling::ChooseBestConfigForSelectableTools( const VECTORHOLE& vHoles, int nIndToolMain, + INTVECTOR& vConfInds, int& nBestConf) +{ + /* + algoritmo Greedy per la scelta della miglior configurazione per tool selezionabili + */ + + // se non ho fori, allora ho finito + if ( vHoles.empty()) + return true ; + // se non ho configurazioni, allora ho finito + if ( vConfInds.empty()) + return true ; + // per sicurezza la prima configurazione è la migliore ( decisione temporanea ) + nBestConf = vConfInds[0] ; + // se ho una sola configurazione, allora è quella ottimale + if ( int( vConfInds.size()) == 1) + return true ; + + + // euristicamente considero accettabili solo le configurazioni dove compare il tool principale + // ( se non la trovo scelgo semplicemente la prima ) + INTVECTOR vConfInds_Greedy0 ; + for ( int nC = 0 ; nC < int( vConfInds.size()) ; ++ nC) { + int nMyConfig = vConfInds[nC] ; + for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { + if ( ! vHoles[i].bTempDrill && + vHoles[i].vIndTools[nMyConfig] == nIndToolMain && + vHoles[i].vToolHole[nMyConfig] != IND_TOOL_INVALID && + vHoles[i].vVtAux[nMyConfig].IsValid()) { + vConfInds_Greedy0.emplace_back( vConfInds[nC]) ; + break ; + } + } + } + // se ho meno di due configurazioni, ho trovato quella "ottimale" + if ( int( vConfInds_Greedy0.size()) < 2) { + if ( ! vConfInds_Greedy0.empty()) + nBestConf = vConfInds_Greedy0[0] ; + return true ; + } + + // cerco tra le configurazioni trovate, quella che inserisce il tool main in un foro non lavorato + INTVECTOR vConfInds_Greedy1 ; + for ( int nC = 0 ; nC < int( vConfInds_Greedy0.size()) ; ++ nC) { + int nMyConfig = vConfInds_Greedy0[nC] ; + for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { + if ( ! vHoles[i].bTempDrill && + vHoles[i].vIndTools[nMyConfig] == nIndToolMain && + vHoles[i].vToolHole[nMyConfig] == i && + vHoles[i].vVtAux[nMyConfig].IsValid()) { + vConfInds_Greedy1.emplace_back( vConfInds_Greedy0[nC]) ; + break ; + } + } + } + // se ho meno di due configurazioni, ho trovato quella "ottimale" + if ( int( vConfInds_Greedy1.size()) < 2) { + if ( ! vConfInds_Greedy1.empty()) + nBestConf = vConfInds_Greedy1[0] ; + return true ; + } + + // ... servono altri test di ottimizzazione ? ... + nBestConf = vConfInds_Greedy1[0] ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Drilling::GetConfigsWithMoreDrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vInds) +{ + /* + controllando il parambetro bTempDrilled, la funzione restituisce la configurazione + ( le configurazioni ) che svuotano il maggior numero di fori + */ + + // se non ho fori, allora non faccio nulla + vInds.clear() ; + if ( vHoles.empty()) + return true ; + + // scrorro le configurazioni presenti + int nMaxDrilled = 0 ; + for ( int nC = 0 ; nC < int( vHoles[0].vToolHole.size()) ; ++ nC) { + // scorro i fori + int nCurrDrilled = 0 ; + for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) { + // se il foro è già lavorato, passo al successivo + if ( vHoles[nH].bTempDrill) + continue ; + // controllo se il foro non lavorato ha una configurazione valida + if ( vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID && + vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID && + vHoles[nH].vVtAux[nC].IsValid()) + ++ nCurrDrilled ; + } + if ( nCurrDrilled > nMaxDrilled) + nMaxDrilled = nCurrDrilled ; + } + // se non ho trovato configurazioni, vuol dire che tutti i fori sono lavorati o che non + // esiste una configurazione ammissibile + if ( nMaxDrilled == 0) + return true ; + + // cerco tutte le configurazioni che svuotano nMaxDrilled fori + for ( int nC = 0 ; nC < int( vHoles[0].vToolHole.size()) ; ++ nC) { + // scorro i fori + int nCurrDrilled = 0 ; + for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) { + // se il foro è già lavorato, passo al successivo + if ( vHoles[nH].bTempDrill) + continue ; + // controllo se il foro non lavorato ha una configurazione valida + if ( vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID && + vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID && + vHoles[nH].vVtAux[nC].IsValid()) + ++ nCurrDrilled ; + } + if ( nCurrDrilled == nMaxDrilled) + vInds.emplace_back( nC) ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool Drilling::EraseDuplicatedConfigs( VECTORHOLE& vHoles) @@ -1224,10 +1505,9 @@ Drilling::GetHoleBestConfig( VECTORHOLE& vHoles, int nInd, TABMHDRILL& tabDrills return true ; } - //---------------------------------------------------------------------------- bool -Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& tabDrills, double& dMHOff) +Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, bool bFixed, TABMHDRILL& tabDrills, double& dMHOff) { // controllo parametri tabDrills.clear() ; @@ -1251,7 +1531,7 @@ Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& tabDri for ( int nT = 0 ; nT < nExitCnt ; ++ nT) { string sToolName ; if ( ! m_pMchMgr->GetLoadedTool( sHead, nT + 1, sToolName) || sToolName.empty()) { - // non c'è utensile + // non c'è utensile vTools.emplace_back( nullptr) ; continue ; } @@ -1339,9 +1619,52 @@ Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& tabDri m_pMchMgr->ApplyRotAxisBlock() ; // calcolo la maschera di corrispondenza tra utensili e fori - if ( ! CalcMask( vHoles, vTools, nMainToolInd, vtTool, vtAux)) + if ( ! CalcMask( vHoles, vTools, bFixed, nMainToolInd, vtTool, vtAux)) return false ; + #if ENABLE_DEBUG_MULTIHEAD_HOLES + // Matrice ( #Configurazioni, #Fori ) + // Ogni cella contiene ( Indice Foro in cui inserire il tool Main, Indice del Tool che lavoro il foro corrente, vtAux ) + // Esempio ( Cella )_ij = ( A, B, vtAux)_ij : + // Nella configurazione i-esima il foro j esimo è lavorato dal tool B inserendo il tool principale nel foro A + // mantenendo un vettore ausiliario pari a vtAux + + int nSpace = 25 ; + // riga dei fori + string sHoleRow = " " ; // 10 spazi + for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) { + sHoleRow.append( "(" + ToString( i) + ")") ; + for ( int j = sHoleRow.length() ; j < ( i + 1) * nSpace + 10 ; ++ j) + sHoleRow.append( " ") ; + } + LOG_ERROR( GetEMkLogger(), sHoleRow.c_str()) ; + // scorro le configurazioni + for ( int nC = 0 ; ! vHoles.empty() && nC < int( vHoles[0].vIndTools.size()) ; ++ nC) { + string sRow = "(" + ToString( nC) + ") ->" ; + for ( int j = sRow.length() ; j < 10 ; ++ j) + sRow.append( " ") ; + for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) { + string sCell = "(" ; + if ( vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID && + vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID && + vHoles[nH].vVtAux[nC].IsValid()) { + sCell.append( ( ToString( vHoles[nH].vToolHole[nC]) + ", " + + ToString( vHoles[nH].vIndTools[nC]) + ", {" + + ToString( vHoles[nH].vVtAux[nC].x, 3) + ", " + + ToString( vHoles[nH].vVtAux[nC].y, 3) + ", " + + ToString( vHoles[nH].vVtAux[nC].z, 3) + "})").c_str()) ; + } + else + sCell.append( "-, -, {-, -, -})") ; + + for ( int j = sCell.length() ; j < nSpace ; ++ j) + sCell.append( " ") ; + sRow.append( sCell) ; + } + LOG_ERROR( GetEMkLogger(), sRow.c_str()) ; + } + #endif + // riduco il numero di configurazioni in base a vtAux if ( ! KeepMinRotatedConfigs( vHoles, vtAux, vtTool)) return false ; @@ -1383,63 +1706,74 @@ Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& tabDri } dMHOff = dOffMax ; - // Inizio a considerare i fori che presentano meno configurazioni per essere lavorati. - // Essi sono i più critici, quindi vengono gestiti per primi, scremando quindi le configurazioni degli altri. - // Parto ad analizzare i fori lavorabili con una sola possibile configurazione + // se testa fissa + if ( bFixed) { + // Inizio a considerare i fori che presentano meno configurazioni per essere lavorati. + // Essi sono i più critici, quindi vengono gestiti per primi, scremando quindi le configurazioni degli altri. + // Parto ad analizzare i fori lavorabili 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)) + // 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 lavorati) che vengono lavorati con la sola configurazione presente + if ( ! GetHoleBestConfig( vHoles, i, tabDrills, vtAux, vtTool, nOkHole)) + return false ; + } + // se nessun foro lavorabile, esco ( fino a prova contraria non esco mai...) + if ( tabDrills.empty()) return false ; - if ( ! bBaseCase) - continue ; - // salvo gli indici dei fori ( non ancora lavorati) che vengono lavorati con la sola configurazione presente - if ( ! GetHoleBestConfig( vHoles, i, tabDrills, vtAux, vtTool, nOkHole)) + + // Una volta scremate le configurazioni critiche, cerco i fori non lavorati più vicini ad essi. + // L'idea è che avendo lavorato 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()) - nUndrilleds) { + 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 lavorati dal Tool principale + if ( ! MultiHeadOrderConfig( tabDrills, vHoles, vtTool, vtAux)) return false ; } - // se nessun foro lavorabile, esco ( fino a prova contraria non esco mai...) - if ( tabDrills.empty()) - return false ; - - // Una volta scremate le configurazioni critiche, cerco i fori non lavorati più vicini ad essi. - // L'idea è che avendo lavorato 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()) - nUndrilleds) { - INTVECTOR vNextInds ; - if ( ! GetClosestHolesToHole( vHoles, tabDrills.back().nInd_id_hole, false, vNextInds) || - vNextInds.empty() || - ! GetHoleBestConfig( vHoles, vNextInds[0], tabDrills, vtAux, vtTool, nOkHole)) - return false ; + // se utensili selezionabili + else { + // Inizio a considerare le configurazioni che presentano più utensili attivi, decrementando + // con il numero di passsate gli utensili selezionati + if ( ! OrderConfigsForSelectableTools( vHoles, vTools, nMainToolInd, tabDrills)) + 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 lavorati 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) +Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, bool bFixed, 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 + un insieme di fori. + bFixed indica se i tool sono attivabili o meno */ // controllo dei parametri @@ -1467,9 +1801,10 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co Hole Hole_i = vHoles[i].hole ; if ( ! MultiHeadVerifyHole( Hole_i, vTools[nIndMT].pTool, dDiamToler, m_vId[vHoles[i].nIndInSelVector])) continue ; + + // angoli per allineare versore T del tool principale con vtDir del foro i-esimo 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 ; @@ -1484,7 +1819,7 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co vtAnew = vtAux ; // creo un nuovo sistema di riferimento centrato nel Tool principale - Frame3d frMT ; + Frame3d frMT ; frMT.Set( vTools[nIndMT].ptToolTip, vtTool, vtAux) ; if ( ! frMT.IsValid()) return false ; @@ -1501,9 +1836,35 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co // 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 lavorare e setto i loro parametri di foratura - if ( nDrills == nExitCnt - nNullTools) { // se ho lavorato il numero corretto di fori ... + + // se utensili non selezionabili + if ( bFixed) { + // controllo quanti fori sono riuscito a lavorare e setto i loro parametri di foratura + if ( nDrills == nExitCnt - nNullTools) { // se ho lavorato 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 lavora 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 utensili selezionabili + else { + // memorizzo la configurazione attuale for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) { + // se il foro è lavorabile, memorizzo la configurazione 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 @@ -1517,10 +1878,6 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co } } } - else { - for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) - vHoles[nD].bTempDrill = false ; - } // se la testa può ruotare if ( nStat < 0) { @@ -1567,9 +1924,33 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co // 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) { + + // se utensili non selezionabili + if ( bFixed) { + // 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 ; + } + } + // se utensili selezionabili + else { + // memorizzo la configurazione attuale 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 @@ -1584,10 +1965,6 @@ Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, co } } } - else { - for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) - vHoles[nD].bTempDrill = false ; - } } } } @@ -1619,7 +1996,7 @@ Drilling::CheckOtherHolesWithTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools nDrills < 0 || nDrills > max( int( vHoles.size()), int( vTools.size()))) return false ; - // definisco il punto dove cade il tool principale + // definisco il punto dove cade il tool principale Hole holeTM = holeICP ; // copia del foro i-esimo // ciclo su tutti i tools diff --git a/Drilling.h b/Drilling.h index 244388c..7faa331 100644 --- a/Drilling.h +++ b/Drilling.h @@ -87,20 +87,23 @@ class Drilling : public Machining bool VerifyHoleFromBottom( const Hole& hole, SelData Id) ; bool DoStandardDrilling( const Hole& hole, SelData Id, int nPathId, double nMHOff, const Vector3d& vtA) ; bool DoPeckDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA) ; - bool MultiHeadDrilling( const SELVECTOR& vId, int nClId, TABMHDRILL& vDrills, double& dMHOff) ; - bool CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT, const Vector3d& vtTool, const Vector3d& vtAux) ; + bool MultiHeadDrilling( const SELVECTOR& vId, int nClId, bool bFixed, TABMHDRILL& vDrills, double& dMHOff) ; + bool CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, bool bFixed, int nIndMT, const Vector3d& vtTool, const Vector3d& vtAux) ; bool CalcDrilledHolesByConfig( VECTORHOLE& vHoles, int nMyInd, int nIndConfig, INTVECTOR& vIndDrilled) ; bool EraseDuplicatedConfigs( VECTORHOLE& vHoles) ; bool KeepMinRotatedConfigs( VECTORHOLE& vHoles, const Vector3d vtAux, const Vector3d vtTool) ; bool CalcMultyHeadUndrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vIdUndrilledHoles) ; bool CheckBasedConfig( const VECTORHOLE& vHoles, int nIndHole, int& nValidConfig, bool& bBaseCase) ; bool GetClosestHolesToHole( const VECTORHOLE& vHoles, int nMyInd, bool bDrilled, INTVECTOR& vInds) ; + bool OrderConfigsForSelectableTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndToolMain, TABMHDRILL& vDrills) ; + bool GetConfigsWithMoreDrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vInds) ; + bool ChooseBestConfigForSelectableTools( const VECTORHOLE& vHoles, int nIndToolMain, INTVECTOR& vConfInds, int& nBestConf) ; bool CheckOtherHolesWithTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndTM, int nIndHTM, Hole holeICP, const Frame3d& frHTM, const Frame3d& frHMTOP, double dDiamToler, int& nDrills) ; bool GetHoleBestConfig( VECTORHOLE& vHoles, int nInd, TABMHDRILL& tabDrills, const Vector3d& vtAux, const Vector3d& vtTool, int& nOkHole) ; bool MultiHeadVerifyHole( Hole& hole, const ToolData* Tool, double dDiamToler, SelData Id) ; bool MultiHeadOrderConfig( TABMHDRILL& tabDrills, const VECTORHOLE& vHoles, const Vector3d& vtTool, const Vector3d& vtAux) ; - bool VerifyMultiParallelFixedDrills( void) ; + int VerifyMultiParallelFixedDrills( void) ; private : double GetSpeed() const