diff --git a/BatchProcessNew.lua b/BatchProcessNew.lua index 312d3d8..5a0947c 100644 --- a/BatchProcessNew.lua +++ b/BatchProcessNew.lua @@ -214,9 +214,6 @@ end local sLog = 'BatchProcess : ' .. BEAM.FILE .. ', ' .. ( BEAM.MACHINE or EgtGetCurrMachineName()) .. ', ' .. sFlag EgtOutLog( sLog) --- TODO forzatura calcolo con prerotazioni. Cancellare dopo che è stata aggiunta la gestione corretta -local bCalcBestPieceUnloadPosition = true or BEAM.FLAG == 10 - -- Dati dei file -- TODO spostare a quando flag ~= 6 e 9 local sDir, sTitle = EgtSplitPath( BEAM.FILE) @@ -551,7 +548,7 @@ if bToProcess then end -- Sistemo le travi nel grezzo - local bPbOk, sPbErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, nil, PARTS, BEAM.FLAG ~= 6, bCalcBestPieceUnloadPosition) + local bPbOk, sPbErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, nil, PARTS, BEAM.FLAG ~= 6, false) if not bPbOk then BEAM.ERR = 18 BEAM.MSG = sPbErr @@ -640,7 +637,7 @@ if bToProcess then BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig) PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON) TIMER:stopElapsed('Json') - PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bCalcBestPieceUnloadPosition) + PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], false) -- sovramateriale in testa al pezzo local dDeltaS = max( PARTS[i].dPosX - ( dBarLen - dLen), 0) @@ -693,8 +690,8 @@ if bToProcess then -- TODO gestire errori e messaggi di ritorno in questo caso if not GetDataConfig() then return end - BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) - BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition) + BeamExec.GetProcessings( PARTS, false) + BeamExec.GetCombinationMatrix( PARTS, false) BeamExec.ProcessMachinings( PARTS) -- si cancella gruppo temporaneo contenente entità da cancellare diff --git a/FlipRot.lua b/FlipRot.lua new file mode 100644 index 0000000..f8e670a --- /dev/null +++ b/FlipRot.lua @@ -0,0 +1,242 @@ +-- Process.lua by Egalware s.r.l. 2024/04/02 +-- Gestione calcolo disposizione e lavorazioni per Travi +-- Si opera sulla macchina corrente +-- 2024/04/02 PRIMA VERSIONE + + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Travi +EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua') +-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre +EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua') +EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua') + +-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi +local sMachDir = EgtGetCurrMachineDir() +if not sMachDir then + EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR') + return +end +if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then + EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR') + return +end + +-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie +EgtRemoveBaseMachineDirFromPackagePath() +EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua') + +-- Segnalazione avvio +EgtOutLog( '*** Beam Process Start ***', 1) + +-- Carico le librerie +_G.package.loaded.BasicCustomerStrategies = nil +_G.package.loaded.BeamExec = nil +_G.package.loaded.BeamLib = nil +_G.package.loaded.DiceCut = nil +_G.package.loaded.FaceData = nil +_G.package.loaded.FeatureLib = nil +_G.package.loaded.Identity = nil +_G.package.loaded.Logs = nil +_G.package.loaded.MachiningLib = nil +_G.package.loaded.PreSimulationLib = nil +_G.package.loaded.LeadInOutLib = nil +-- strategie di base sempre presenti +_G.package.loaded['HEADCUT\\HEADCUT'] = nil +_G.package.loaded['TAILCUT\\TAILCUT'] = nil +-- libreria macchina +_G.package.loaded.BeamDataNew = nil +-- libreria calcolo tempo esecuzione +_G.package.loaded.TimeLib = nil + +-- TODO controllare se c'è un modo migliore per resettare librerie delle strategie caricate precedentemente +-- Per ottimizzare potremmo anche ciclare solo fino al numero di strategie raggiunto per il momento. +-- Infatti difficile ci siano 9999 strategie. +-- reset strategie caricate come librerie +for i = 1, 9999 do + local idSTRTemp = EgtReplaceString( EgtNumToString( i/10000, -4), '0.', '') + local sLibraryToReload = "STR" .. idSTRTemp .. "\\STR" .. idSTRTemp + if _G.package.loaded[sLibraryToReload] then + _G.package.loaded[sLibraryToReload] = nil + end +end +local vtCoreStrategiesNames = EgtFindAllFiles( BEAM.BASEDIR .. '\\StrategyLibs\\*.lua') +for i = 1, #vtCoreStrategiesNames do + local sCurrentName = EgtSplitString( vtCoreStrategiesNames[i], '.')[1] + if _G.package.loaded[sCurrentName] then + _G.package.loaded[sCurrentName] = nil + end +end + + +-- Variabili globali +PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo + +-- Carico i dati globali +local BeamData = require( 'BeamDataNew') +-- carico librerie +local BeamExec = require( 'BeamExec') +local BeamLib = require( 'BeamLib') + +------------------------------------------------------------------------------------------------------------- +-- *** Recupero trave (E' SEMPRE E SOLO UNA) *** +------------------------------------------------------------------------------------------------------------- +local function MyProcessInputData() + -- Recupero il pezzo e i suoi dati + local nId = EgtGetFirstPart() + if nId then + table.insert( PARTS, { nInd = #PARTS + 1, id = nId, sName = ( EgtGetName( nId) or ( 'Id=' .. tonumber( nId)))}) + local Ls = EgtGetFirstNameInGroup( PARTS[1].id, 'Box') + local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD) + if not b3Solid then + return false + end + PARTS[1].b3PartOriginal = b3Solid + else + return false + end + + return true +end + +------------------------------------------------------------------------------------------------------------- +local function GetDataConfig() + -- recupero utensili dal magazzino + BeamExec.GetToolsFromDB() + -- TODO da gestire eventuali errori bloccanti + return true +end + +------------------------------------------------------------------------------------------------------------- +-- *** Inserimento delle travi nel grezzo *** +------------------------------------------------------------------------------------------------------------- +local function MyProcessBeams() + -- Lunghezza totale delle travi + local dLen = PARTS[1].b3PartOriginal:getDimX() + local dRawW = PARTS[1].b3PartOriginal:getDimY() + local dRawH = PARTS[1].b3PartOriginal:getDimZ() + + -- Determinazione minimo grezzo scaricabile + BeamExec.CalcMinUnloadableRaw( dRawW, dRawH) + + local dOvmHead = BeamData.OVM_HEAD or 10 + local dOvmMid = BeamData.OVM_MID or 10 + + local dRawL = max( dLen + dOvmHead + dOvmMid, BeamData.dMinRaw) + + -- Recupero info pezzi + local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, true) + if not bOk then + EgtOutLog( sErr) + return false + end + + return true +end + +------------------------------------------------------------------------------------------------------------- +-- *** Inserimento delle lavorazioni nelle travi *** +------------------------------------------------------------------------------------------------------------- +local function MyProcessFeatures() + + BeamExec.GetProcessings( PARTS, true) + BeamExec.GetCombinationMatrix( PARTS, true) + BeamExec.ProcessMachinings( PARTS) + local nErrCnt = 0 + local nWarnCnt = 0 + local sOutput = '' + for i = 1, #RESULT do + local sMsg = '' + if RESULT[i].sType == 'Feature' then + sMsg = RESULT[i].ChosenStrategy.sInfo + elseif RESULT[i].sType == 'Part' then + sMsg = RESULT[i].sMsg + end + sMsg = string.gsub( sMsg or '', '\n', ' ', 10) + sMsg = string.gsub( sMsg or '', '\r', ' ', 10) + -- trovata almeno una strategia e feature lavorata completamente + if RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Completed' then + sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg or '') + + -- trovata almeno una strategia ma nessuna applicabile oppure non trovata alcuna strategia + elseif RESULT[i].sType == 'Feature' + and ( ( RESULT[i].ChosenStrategy.sStatus == 'Not-Applicable') + or ( not RESULT[i].ChosenStrategy.sStrategyName)) then + + nErrCnt = nErrCnt + 1 + if #sMsg == 0 then + sMsg = 'No applicable strategy found' + end + sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg) + else + -- segnalazione scarico pezzo standard, incompleto o a caduta + if RESULT[i].sType == 'Part' and ( RESULT[i].nErr == -100 or RESULT[i].nErr == -101 or RESULT[i].nErr == -102) then + -- nulla da segnalare + + -- feature incompleta e altro + elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then + nWarnCnt = nWarnCnt + 1 + sMsg = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg + sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg) + + end + end + end + + -- si calcolano alternative + TIMER:startElapsed('Alternatives') + BeamExec.ProcessAlternatives( PARTS) + TIMER:stopElapsed('Alternatives') + + -- cancello gruppo temporaneo + local idTempGroup = BeamLib.GetTempGroup() + EgtErase( idTempGroup) + + if #sOutput > 0 then EgtOutLog( sOutput) end + if nErrCnt > 0 then + EgtOutBox( sOutput, 'Lavora Travi', 'ERRORS') + return false + elseif nWarnCnt > 0 then + EgtOutBox( sOutput, 'Lavora Travi', 'WARNINGS') + return true + end + + return true +end + +------------------------------------------------------------------------------------------------------------- +-- *** Esecuzione *** +------------------------------------------------------------------------------------------------------------- + +-- calcolo tempo esecuzione +TIMER:start() +EgtOutLog( ' Execution timer started') + +-- script principale + +if not MyProcessInputData() then return end + +-- recupero parametri generali da progetto +BeamExec.GetGeneralParameters() + +-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella +BeamLib.CreateTempGroup() + +if not MyProcessBeams() then return end + +if not GetDataConfig() then return end + +-- Abilito Vmill +EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1') + +MyProcessFeatures() + +-- log tempi di esecuzione +if EgtGetDebugLevel() >= 3 then + TIMER:logAllElapsed() +end + diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 870d833..da8fe19 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -251,28 +251,28 @@ function BeamExec.GetStrategiesFromJSONinBD( sAISetupConfigName) end end +-- TODO prevedere parametri per preferire carico del pezzo verticale oppure orizzontale? ------------------------------------------------------------------------------------------------------------- -- funzione che controlla validità delle combinazioni proposte -local function IsCombinationAvailable( sCombination, nUnloadPos, bSquareSection, GeneralParameters, bCalcBestPieceUnloadPosition) +local function IsCombinationAvailable( sCombination, nUnloadPos, GeneralParameters, bIsFlipRot) -- PREROTATION : flip-rot, si considerano tutte le posizioni possibili, a meno che non si voglia come da BTL - if bCalcBestPieceUnloadPosition and GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION' then + if bIsFlipRot and GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION' then local nRotation90 = EgtIf( nUnloadPos + 1 > 4, nUnloadPos + 1 - 4, nUnloadPos + 1) local nRotation180 = EgtIf( nUnloadPos + 2 > 4, nUnloadPos + 2 - 4, nUnloadPos + 2) local nExtraRotation = EgtIf( nUnloadPos + 3 > 4, nUnloadPos + 3 - 4, nUnloadPos + 3) - if not bSquareSection and ( nUnloadPos == 2 or nUnloadPos == 4) then + -- se fase di unload disabilitata e soluzioni con terza rotazione sempre disabilitate + if string.sub( sCombination, nUnloadPos, nUnloadPos) ~= '1' or string.sub( sCombination, nExtraRotation, nExtraRotation) == '1' then + return false + elseif GeneralParameters.GEN_sPiecesLoadingPosition == 'STD_PRE_ROTATION' and ( nUnloadPos == 2 or nUnloadPos == 4) then return false else - if string.sub( sCombination, nUnloadPos, nUnloadPos) ~= '1' or string.sub( sCombination, nExtraRotation, nExtraRotation) == '1' then + if ( not BeamData.ROT90 or GeneralParameters.GEN_sPiecesLoadingPosition == 'STD_PRE_ROTATION') and string.sub( sCombination, nRotation90, nRotation90) == '1' then + return false + elseif not BeamData.ROT180 and string.sub( sCombination, nRotation180, nRotation180) == '1' then return false else - if not BeamData.ROT90 and string.sub( sCombination, nRotation90, nRotation90) == '1' then - return false - elseif not BeamData.ROT180 and string.sub( sCombination, nRotation180, nRotation180) == '1' then - return false - else - return true - end + return true end end -- se invece si è nel caso standard di calcolo @@ -286,7 +286,7 @@ local function IsCombinationAvailable( sCombination, nUnloadPos, bSquareSection, end -- STANDARD : posizione di scarico come posizionamento iniziale else - local ExtraRotation = nUnloadPos + 3 + local ExtraRotation = EgtIf( nUnloadPos + 3 > 4, nUnloadPos + 3 - 4, nUnloadPos + 3) if nUnloadPos ~= 1 then return false elseif string.sub( sCombination, nUnloadPos, nUnloadPos) == '1' and string.sub( sCombination, ExtraRotation, ExtraRotation) == '0' then @@ -305,12 +305,16 @@ local function IsCombinationAvailable( sCombination, nUnloadPos, bSquareSection, end ------------------------------------------------------------------------------------------------------------- -function BeamExec.GetAvailableCombinations( PartInfo, bCalcBestPieceUnloadPosition) +function BeamExec.GetAvailableCombinations( PartInfo, bIsFlipRot) local CombinationList = {} CombinationList.Rotations = {0, 0, 0, 0} -- indice rotazione attiva, per calcolo collect feature + local nCycles = 1 + + -- se si sta calcolando il migliore posizionamento del pezzo, verifico se sono ammesse le combinazioni con pezzo invertito + if bIsFlipRot and PartInfo.GeneralParameters.GEN_bAllowPieceInversion then + nCycles = 2 + end - -- se sto effettivamente calcolando, il pezzo è già in posizione e non può essere invertito. Se sono in preverifica, allora devo considerare anche eventuali inversioni del pezzo - local nCycles = EgtIf( bCalcBestPieceUnloadPosition and PartInfo.GeneralParameters.GEN_sPiecesLoadingPosition == 'BEST_POSITION', 2, 1) -- verifico tutte le combinazioni che possono essere considerate for nInvertIndex = 1, nCycles do for nUnloadPos = 1, 4 do @@ -318,7 +322,7 @@ function BeamExec.GetAvailableCombinations( PartInfo, bCalcBestPieceUnloadPositi local nBitIndexCombination = BeamLib.DecimalToBinary( i) local sBitIndexCombination = BeamLib.CalculateStringBinaryFormat( nBitIndexCombination, 4) -- si calcolano le combinazioni all'inizio, ottimizzando calcolo della collect solo nelle rotazioni che possono essere considerate - if IsCombinationAvailable( sBitIndexCombination, nUnloadPos, PartInfo.bSquareSection, PartInfo.GeneralParameters, bCalcBestPieceUnloadPosition) then + if IsCombinationAvailable( sBitIndexCombination, nUnloadPos, PartInfo.GeneralParameters, bIsFlipRot) then local Combination = {} Combination.sBitIndexCombination = sBitIndexCombination Combination.nUnloadPos = nUnloadPos @@ -354,7 +358,7 @@ end ------------------------------------------------------------------------------------------------------------- -- *** funzioni posizionamento pezzi all'interno della barra *** ------------------------------------------------------------------------------------------------------------- -function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, bCreateMachGroup, bCalcBestPieceUnloadPosition) +function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, bCreateMachGroup, bIsFlipRot) -- gruppo per geometrie temporanee local idTempGroup = BeamLib.GetTempGroup() @@ -504,7 +508,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig) PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON) TIMER:stopElapsed('Json') - PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bCalcBestPieceUnloadPosition) + PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bIsFlipRot) PARTS[i].idTempGroup = idTempGroup else @@ -966,7 +970,6 @@ local function CalculateStrategies( vProcSingleRot, Part) -- eseguo file config con i parametri di default local CurrentStrategy = {} CurrentStrategy = RunStrategyLibraries( Proc.AvailableStrategies[nIndexCurrentStrategy].sStrategyId) - -- TODO in caso di ulteriore ciclo dovuto a errori imprevisti, controllare se questa strategia è quella che ha dato errore e disabilitarla senza calcolare nulla -- controllo che le librerie siano state effettivamente caricate if CurrentStrategy.Config and CurrentStrategy.Script then -- eseguo la strategia solo come calcolo fattibilità e voto. Non si applicano le lavorazioni. Si passa la Proc e i parametri personalizzati @@ -1224,8 +1227,8 @@ local function PrintFeatures( vProc, Part) end ------------------------------------------------------------------------------------------------------------- -function BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) - -- recupero tutti i processing di tutti i pezzi in tutte le rotazioni +-- funzione che recupera tutti i processing di tutti i pezzi in tutte le rotazioni +function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola EgtSetTableAreaOffset( 2000, 2000, 2000, 2000) @@ -1235,7 +1238,8 @@ function BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) local vProcRot = {} -- se è prerotazione, oltre al ciclo normale, si devono verificare anche invertiti - local nCycles = EgtIf( bCalcBestPieceUnloadPosition and PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION', 2, 1) + local bCalcInverted = bIsFlipRot and PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion + local nCycles = EgtIf( bCalcInverted, 2, 1) -- per ogni inversione for nInvertIndex = 1, nCycles do -- per ogni rotazione @@ -1246,7 +1250,7 @@ function BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) if PARTS[nPart].CombinationList.Rotations[nRotIndex] == 1 then -- recupero le feature di lavorazione della trave table.insert( vProcRot, CollectFeatures( PARTS[nPart], nIndex)) - + -- recupero informazioni ausiliarie feature e dipendenze tra feature stesse -- TODO le dipendenze cambiano in base alla rotazione del pezzo? probabilmente no vProcRot[nIndex] = GetFeatureInfoAndDependency( vProcRot[nIndex], PARTS[nPart]) @@ -1260,7 +1264,8 @@ function BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) PARTS[nPart].b3Raw = EgtGetRawPartBBox( PARTS[nPart].idRaw) PARTS[nPart].b3Part = EgtGetBBoxGlob( PARTS[nPart].idBoxTm, GDB_BB.STANDARD) end - if bCalcBestPieceUnloadPosition and PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION' then + -- se si devono calcolare anche gli invertiti + if bCalcInverted then -- inversione pezzo testa-coda BeamLib.InvertRawPart( PARTS[nPart], 2) -- aggiorno info pezzo @@ -1436,115 +1441,130 @@ end ------------------------------------------------------------------------------------------------------------- -- funzione che calcola le combinazioni di rotazione per lavorare la trave e sceglie la migliore -local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bReProcessEmptyChosenStrategy) +local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bReProcessEmptyChosenStrategy, BitCombinationListToReprocess) local CombinationsList = { dAllCombinationsTotalTime = 0} -- calcolo per tutte le combinazioni disponibili precedentemente verificate for i = 1, #PartInfo.CombinationList do - local bRot90, bRot180 - local SingleCombination = {} - local nUnloadPos = PartInfo.CombinationList[i].nUnloadPos - SingleCombination.nRotations = 0 - SingleCombination.dTotalTimeToMachine = 0 - SingleCombination.dTotalQuality = 0 - SingleCombination.dTotalCompletionIndex = 0 - SingleCombination.nComplete = 0 - SingleCombination.nNotComplete = 0 - SingleCombination.nNotExecute = 0 - SingleCombination.sBitIndexCombination = PartInfo.CombinationList[i].sBitIndexCombination - -- TODO se pezzo invertito bisogna considerare le rotazioni nell'array dalla 5 alla 8 - SingleCombination.bPartInCombiIsInverted = PartInfo.CombinationList[i].bPartInCombiIsInverted - SingleCombination.nUnloadPos = nUnloadPos - -- creo liste dei proc suddivisi per rotazione - SingleCombination.Rot0 = {} - SingleCombination.Rot90 = {} - SingleCombination.Rot180 = {} + local bToProcess = false + -- controllo se debbano essere ricalcolate solo alcune soluzioni + if BitCombinationListToReprocess and #BitCombinationListToReprocess > 0 then + for c = 1, #BitCombinationListToReprocess do + if PartInfo.CombinationList[i].sBitIndexCombination == BitCombinationListToReprocess[c].sBitIndexCombination and + PartInfo.CombinationList[i].bPartInCombiIsInverted == BitCombinationListToReprocess[c].bPartInCombiIsInverted then + bToProcess = true + end + end + else + bToProcess = true + end + -- si riprocessano tutte a meno che non sia indicata una specifica da riprovare + if bToProcess then + local bRot90, bRot180 + local SingleCombination = {} + local nUnloadPos = PartInfo.CombinationList[i].nUnloadPos + SingleCombination.nRotations = 0 + SingleCombination.dTotalTimeToMachine = 0 + SingleCombination.dTotalQuality = 0 + SingleCombination.dTotalCompletionIndex = 0 + SingleCombination.nComplete = 0 + SingleCombination.nNotComplete = 0 + SingleCombination.nNotExecute = 0 + SingleCombination.sBitIndexCombination = PartInfo.CombinationList[i].sBitIndexCombination + -- TODO se pezzo invertito bisogna considerare le rotazioni nell'array dalla 5 alla 8 + SingleCombination.bPartInCombiIsInverted = PartInfo.CombinationList[i].bPartInCombiIsInverted + SingleCombination.nUnloadPos = nUnloadPos + -- creo liste dei proc suddivisi per rotazione + SingleCombination.Rot0 = {} + SingleCombination.Rot90 = {} + SingleCombination.Rot180 = {} - -- ciclo su tutte le feature, ad eccezione dei tagli testa/coda che dipendono dal risultato delle altre - -- tagli testa e coda vengono aggiunti sempre alla fine - for nProc = 1, #ProcessingsOnPart.Rotation[1] do - -- Si controlla sempre la rotazione 1 perchè la dipendenza di una feature da un'altra non dipende dalla rotazione - -- se feature disattivata perchè eseguita da master a lei associata dichiaro comunque eseguita - if ProcessingsOnPart.Rotation[1][nProc].nFlg == 0 and ProcessingsOnPart.Rotation[1][nProc].nIndexMasterProc then - ProcessingsOnPart.Rotation[1][nProc].nIndexRotation = nUnloadPos - table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[1][nProc]) - SingleCombination.nComplete = SingleCombination.nComplete + 1 - else - if not ID.IsHeadCut( ProcessingsOnPart.Rotation[1][nProc]) and not ID.IsTailCut( ProcessingsOnPart.Rotation[1][nProc]) then - -- ciclo sulle rotazioni - local nNextRot = nUnloadPos + -- ciclo su tutte le feature, ad eccezione dei tagli testa/coda che dipendono dal risultato delle altre + -- tagli testa e coda vengono aggiunti sempre alla fine + for nProc = 1, #ProcessingsOnPart.Rotation[1] do + -- Si controlla sempre la rotazione 1 perchè la dipendenza di una feature da un'altra non dipende dalla rotazione + -- se feature disattivata perchè eseguita da master a lei associata dichiaro comunque eseguita + if ProcessingsOnPart.Rotation[1][nProc].nFlg == 0 and ProcessingsOnPart.Rotation[1][nProc].nIndexMasterProc then + ProcessingsOnPart.Rotation[1][nProc].nIndexRotation = nUnloadPos + table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[1][nProc]) + SingleCombination.nComplete = SingleCombination.nComplete + 1 + else local nOffsetIndex = EgtIf( SingleCombination.bPartInCombiIsInverted, 4, 0) - local ResultsList = {} - for nRotation = 1, 3 do - -- se rotazione abilitata da combinazione - if string.sub( PartInfo.CombinationList[i].sBitIndexCombination, nNextRot, nNextRot) == '1' then - local CurrProc = ProcessingsOnPart.Rotation[nNextRot+nOffsetIndex][nProc] - -- se è ultima rotazione oppure se feature non impatta su misura laser, allora è valida e può essere effettivamente considerata - if nNextRot == nUnloadPos or not( CurrProc.bHindersLaserMeasure) then - -- se non è settata la ChosenStrtegy, provo a cercare comunque tra quelle disponibili - if not CurrProc.ChosenStrategy and bReProcessEmptyChosenStrategy then - CurrProc = GetFeatureBestStrategy( CurrProc, PartInfo) - end - -- controllo se è stata scelta una strategia - if CurrProc.ChosenStrategy then - local Proc = {} - Proc.nRotation = nNextRot - table.insert( Proc, CurrProc) - table.insert( ResultsList, Proc) + if not ID.IsHeadCut( ProcessingsOnPart.Rotation[1][nProc]) and not ID.IsTailCut( ProcessingsOnPart.Rotation[1][nProc]) then + -- ciclo sulle rotazioni + local nNextRot = nUnloadPos + local ResultsList = {} + for nRotation = 1, 3 do + -- se rotazione abilitata da combinazione + if string.sub( PartInfo.CombinationList[i].sBitIndexCombination, nNextRot, nNextRot) == '1' then + local CurrProc = ProcessingsOnPart.Rotation[nNextRot+nOffsetIndex][nProc] + -- se è ultima rotazione oppure se feature non impatta su misura laser, allora è valida e può essere effettivamente considerata + if nNextRot == nUnloadPos or not( CurrProc.bHindersLaserMeasure) then + -- se non è settata la ChosenStrtegy, provo a cercare comunque tra quelle disponibili + if not CurrProc.ChosenStrategy and bReProcessEmptyChosenStrategy then + CurrProc = GetFeatureBestStrategy( CurrProc, PartInfo) + end + -- controllo se è stata scelta una strategia + if CurrProc.ChosenStrategy then + local Proc = {} + Proc.nRotation = nNextRot + table.insert( Proc, CurrProc) + table.insert( ResultsList, Proc) + end end end + nNextRot = EgtIf( nNextRot + 1 > 4, nNextRot + 1 - 4, nNextRot + 1) end - nNextRot = EgtIf( nNextRot + 1 > 4, nNextRot + 1 - 4, nNextRot + 1) - end - -- se la feature può essere lavorata in almeno una rotazione - if #ResultsList > 0 then - local Proc, Data = GetProcBestMachRotationFromList( ResultsList, PartInfo) - Proc.nIndexRotation = Data.nIndexRotation - -- inserisco la Proc nell'apposita lista - if Data.nIndexRotation == nUnloadPos then - table.insert( SingleCombination.Rot0, Proc) - elseif Data.nIndexRotation == nUnloadPos + 1 then - table.insert( SingleCombination.Rot90, Proc) - bRot90 = true + -- se la feature può essere lavorata in almeno una rotazione + if #ResultsList > 0 then + local Proc, Data = GetProcBestMachRotationFromList( ResultsList, PartInfo) + Proc.nIndexRotation = Data.nIndexRotation + -- inserisco la Proc nell'apposita lista + if Data.nIndexRotation == nUnloadPos then + table.insert( SingleCombination.Rot0, Proc) + elseif Data.nIndexRotation == nUnloadPos + 1 then + table.insert( SingleCombination.Rot90, Proc) + bRot90 = true + else + table.insert( SingleCombination.Rot180, Proc) + bRot180 = true + end + + SingleCombination.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + Data.dTimeToMachine + SingleCombination.dTotalQuality = SingleCombination.dTotalQuality + Data.dQuality + SingleCombination.dTotalCompletionIndex = SingleCombination.dTotalCompletionIndex + Data.dCompletionIndex + SingleCombination.nComplete = SingleCombination.nComplete + EgtIf( Data.bComplete, 1, 0) + SingleCombination.nNotComplete = SingleCombination.nNotComplete + EgtIf( Data.bNotComplete, 1, 0) + SingleCombination.nNotExecute = SingleCombination.nNotExecute + EgtIf( Data.bNotApplicable, 1, 0) + SingleCombination.nIndexInCombinationList = i + SingleCombination.nIndexRotation = nUnloadPos else - table.insert( SingleCombination.Rot180, Proc) - bRot180 = true + ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nIndexRotation = nUnloadPos + ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nFlg = 0 + table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc]) + SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1 end - - SingleCombination.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + Data.dTimeToMachine - SingleCombination.dTotalQuality = SingleCombination.dTotalQuality + Data.dQuality - SingleCombination.dTotalCompletionIndex = SingleCombination.dTotalCompletionIndex + Data.dCompletionIndex - SingleCombination.nComplete = SingleCombination.nComplete + EgtIf( Data.bComplete, 1, 0) - SingleCombination.nNotComplete = SingleCombination.nNotComplete + EgtIf( Data.bNotComplete, 1, 0) - SingleCombination.nNotExecute = SingleCombination.nNotExecute + EgtIf( Data.bNotApplicable, 1, 0) - SingleCombination.nIndexInCombinationList = i - SingleCombination.nIndexRotation = nUnloadPos else - ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nIndexRotation = nUnloadPos - ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nFlg = 0 - table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc]) - SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1 - end - else - if ID.IsHeadCut( ProcessingsOnPart.Rotation[1][nProc]) then - SingleCombination.nIndexHeadCutInVProc = nProc - elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1][nProc]) then - SingleCombination.nIndexTailCutInVProc = nProc + if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexHeadCutInVProc = nProc + elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexTailCutInVProc = nProc + end end end end + -- aggiungo rotazioni + SingleCombination.nRotations = EgtIf( bRot90, 1, 0) + EgtIf( bRot180, 1, 0) + + -- aggiungo tempo totale considerando le rotazioni -- TODO per il momento la rotazione impiega 1 minuto. Serve configurare? + SingleCombination.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + ( SingleCombination.nRotations * 1) + + -- aggiungo la combinazione all'elenco delle combinazioni disponibili + table.insert( CombinationsList, SingleCombination) + -- aggiorno tempo totale di tutte le combinazioni + CombinationsList.dAllCombinationsTotalTime = CombinationsList.dAllCombinationsTotalTime + SingleCombination.dTotalTimeToMachine end - -- aggiungo rotazioni - SingleCombination.nRotations = EgtIf( bRot90, 1, 0) + EgtIf( bRot180, 1, 0) - - -- aggiungo tempo totale considerando le rotazioni -- TODO per il momento la rotazione impiega 1 minuto. Serve configurare? - SingleCombination.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + ( SingleCombination.nRotations * 1) - - -- aggiungo la combinazione all'elenco delle combinazioni disponibili - table.insert( CombinationsList, SingleCombination) - -- aggiorno tempo totale di tutte le combinazioni - CombinationsList.dAllCombinationsTotalTime = CombinationsList.dAllCombinationsTotalTime + SingleCombination.dTotalTimeToMachine end -- si calsola il total rating @@ -1554,10 +1574,10 @@ local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bRePro end ------------------------------------------------------------------------------------------------------------- -function BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition) +function BeamExec.GetCombinationMatrix( PARTS, bIsFlipRot) -- ricerca strategia di lavorazione per ogni pezzo e applicazione lavorazioni for nPart = 1, #PARTS do - local nCycles = EgtIf( bCalcBestPieceUnloadPosition and PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION', 2, 1) + local nCycles = EgtIf( bIsFlipRot and PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion, 2, 1) -- per ogni inversione for nInvertIndex = 1, nCycles do -- calcolo della migliore strategia per ogni rotazione del pezzo @@ -1574,7 +1594,8 @@ function BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition) PARTS[nPart].b3Raw = EgtGetRawPartBBox( PARTS[nPart].idRaw) PARTS[nPart].b3Part = EgtGetBBoxGlob( PARTS[nPart].idBoxTm, GDB_BB.STANDARD) end - if bCalcBestPieceUnloadPosition and PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition ~= 'BTL_POSITION' then + -- se bisogna invertire + if bIsFlipRot and PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion then -- inversione del pezzo testa-coda BeamLib.InvertRawPart( PARTS[nPart], 2) -- aggiorno info pezzo @@ -1899,5 +1920,357 @@ function BeamExec.ProcessMachinings( PARTS) return ( nTotErr == 0), RESULT end +------------------------------------------------------------------------------------------------------------- +function BeamExec.ProcessAlternatives( PARTS) + -- ciclo sui pezzi + local BestCombination = {} + local nPart = 1 + local nOrd = 1 + local nMaxReProcessCycles = EgtClamp( PARTS[nPart].GeneralParameters.GEN_nMaxReProcessCycles, 1, 3) + local bTryToReProcess = false + + -- se non serve trovare altre soluzioni, si esce subito + if not ( PARTS[nPart].GeneralParameters.GEN_bTestAlternative and not PARTS[nPart].bSquareSection) or not PARTS[nPart].GeneralParameters.GEN_bGetAlternativesNesting2D then + return + end + + -- si copia il MachGroup originale + local nOriginalMachGroup = EgtGetCurrMachGroup() + local sMachGroupName = EgtGetMachGroupName( nOriginalMachGroup) + local sTempMachGroupName = sMachGroupName .. '_A' + + local nTempMachGroupName = EgtCopyMachGroup( sMachGroupName, sTempMachGroupName) + EgtSetCurrMachGroup( nTempMachGroupName) + EgtRemoveAllOperations() + BeamLib.CreateAddGroup( PARTS[nPart].id, sTempMachGroupName) + -- si aggiorna il raw dopo averlo copiato + PARTS[nPart].idRaw = EgtGetFirstRawPart() + + -- si riporta pezzo in posizione iniziale + -- se combinazione prevedeva inversione, si rigira il pezzo + if PARTS[nPart].bPartInCombiIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], -2) + end + -- si ribalta il pezzo in posizione iniziale + BeamLib.RotateRawPart( PARTS[nPart], 1 - PARTS[nPart].nInitialPosition) + + local TotalCombiToTest = {} + -- se serve calcolare soluzione alternativa ruotata di 90° + if PARTS[nPart].GeneralParameters.GEN_bTestAlternative and not PARTS[nPart].bSquareSection then + local CombinationListToCheck = {} + for i = 1, #PARTS[nPart].CombinationList do + local nUnloadPos = PARTS[nPart].nInitialPosition + local nOtherSimilarUnloadPos = EgtIf( nUnloadPos + 2 > 4, nUnloadPos + 2 - 4, nUnloadPos + 2) + -- restano abilitate soluzioni ruotate di 90° o 270° rispetto alla migliore soluzione trovata nella prima analisi + if PARTS[nPart].CombinationList[i].nUnloadPos ~= nUnloadPos and PARTS[nPart].CombinationList[i].nUnloadPos ~= nOtherSimilarUnloadPos then + table.insert( CombinationListToCheck, { sBitIndexCombination = PARTS[nPart].CombinationList[i].sBitIndexCombination, + bPartInCombiIsInverted = PARTS[nPart].CombinationList[i].bPartInCombiIsInverted}) + end + end + -- se c'è almeno una combinazione da testare + if #CombinationListToCheck > 0 then + table.insert( TotalCombiToTest, CombinationListToCheck) + end + end + + -- se serve calcolare posizione per ottimizzazione tagli in nesting (le soluzioni non possono avere ribaltamenti) + if PARTS[nPart].GeneralParameters.GEN_bGetAlternativesNesting2D then + -- POSIZIONE 0 (e invertito) + local sCombinationToCheck = BeamLib.StringReplaceChar( '0000', PARTS[nPart].nInitialPosition, "1") + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck}}) + if PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion then + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck, bPartInCombiIsInverted = true}}) + end + + -- POSIZIONE 180 (e invertito) + if PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition == 'STD_PRE_ROTATION' then + local nOtherPosition = EgtIf( PARTS[nPart].nInitialPosition + 2 > 4, PARTS[nPart].nInitialPosition + 2 - 4, PARTS[nPart].nInitialPosition + 2) + sCombinationToCheck = BeamLib.StringReplaceChar( '0000', nOtherPosition, "1") + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck}}) + if PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion then + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck, bPartInCombiIsInverted = true}}) + end + end + -- POSIZIONE 90/270 (e invertito) + if PARTS[nPart].GeneralParameters.GEN_sPiecesLoadingPosition == 'FULL_PRE_ROTATION' then + local nOtherPosition = EgtIf( PARTS[nPart].nInitialPosition + 1 > 4, PARTS[nPart].nInitialPosition + 1 - 4, PARTS[nPart].nInitialPosition + 1) + sCombinationToCheck = BeamLib.StringReplaceChar( '0000', nOtherPosition, "1") + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck}}) + if PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion then + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck, bPartInCombiIsInverted = true}}) + end + nOtherPosition = EgtIf( PARTS[nPart].nInitialPosition + 3 > 4, PARTS[nPart].nInitialPosition + 3 - 4, PARTS[nPart].nInitialPosition + 3) + sCombinationToCheck = BeamLib.StringReplaceChar( '0000', nOtherPosition, "1") + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck}}) + if PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion then + table.insert( TotalCombiToTest, {{ sBitIndexCombination = sCombinationToCheck, bPartInCombiIsInverted = true}}) + end + end + end + + -- fino a che ci sono soluzioni da testare + for z = 1, #TotalCombiToTest do + -- si svuota il machgroup e si resettano le variabili + EgtRemoveAllOperations() + MACHININGS = {} + MACHININGS.Info = {} + nOrd = 1 + local nCycles = 1 + + local bCombinationFound = true + -- la parte di applicazione lavorazioni può essere lanciata più volte in caso della presenza di errori + local bProcess = true + while bProcess do + bProcess = false + + -- si ricavano tutte le combinazioni possibili + local CombinationListFromMatrix = GetCombinationListFromMatrix( PROCESSINGS[nPart], PARTS[nPart], nCycles > 1, TotalCombiToTest[z]) + -- se ci sono soluzioni possibili + if #CombinationListFromMatrix > 0 then + BestCombination = GetBestCombination( CombinationListFromMatrix, PARTS[nPart]) + -- se la soluzione alternativa migliore è completa, allora la verifico, altrimenti si tiene la migliore in assoluto + if BestCombination.nNotComplete == 0 and BestCombination.nNotExecute == 0 then + + -- compilazione della vProc finale contenente le feature da lavorare nella giusta rotazione + local vProc, MatrixResult = GetProcessingListFromCombination( BestCombination) + + -- si mette subito il pezzo nella fase + EgtSetCurrPhase( 1) + + -- si sposta il pezzo nella posizione originale, di quando è stata fatta la collect. In questo modo tutti i dati calcolati nella collect restano validi. + -- Altrimenti bisognava ricalcolare tutto, aumentando tempo di calcolo. + local vtRawOffsetPos = PARTS[nPart].b3Raw:getMin() - EgtGetRawPartBBox( PARTS[nPart].idRaw):getMin() + local nRawId = PARTS[nPart].idRaw + while nRawId and abs( vtRawOffsetPos:len()) > 0 do + EgtKeepRawPart( nRawId) + EgtMoveRawPart( nRawId, vtRawOffsetPos) + nRawId = EgtGetNextRawPart( nRawId) + end + + if BestCombination.bPartInCombiIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], 2) + end + + -- se la posizione iniziale non è calcolata, significa che non ci sono feature da eseguire. Solo taglio testa/coda + if not MatrixResult.nInitialPosition then + MatrixResult.nInitialPosition = 1 + MACHININGS.Info.nHeadCutRotation = 1 + MACHININGS.Info.nSplitCutRotation = 1 + -- altrimenti si fanno tutti i calcoli + else + -- TODO serve ancora ordinare le feature con nuovo metodo di calcolo ottimizzazione lavorazioni? + -- ordinamento di base delle feature + vProc = OrderFeatures( vProc) + + -- esegue le strategie migliori che ha precedentemente scelto e salva le lavorazioni nella lista globale + MACHININGS = CalculateMachinings( vProc, PARTS[nPart], MatrixResult.nInitialPosition) + -- se non sono sono settate le rotazioni di lavorazione di testa e coda, significa che le feature da eseguire non sono state eseguite per qualche problema. Si forza rotazione 1 + if not MACHININGS.Info.nHeadCutRotation or not MACHININGS.Info.nSplitCutRotation then + MACHININGS.Info.nHeadCutRotation = 1 + MACHININGS.Info.nSplitCutRotation = 1 + end + end + + local nOffsetIndex = EgtIf( BestCombination.bPartInCombiIsInverted, 4, 0) + -- aggiunge tagli testa e coda in fasi opportune + local nRotHeadCut = MatrixResult.nInitialPosition + MACHININGS.Info.nHeadCutRotation - 1 + if nRotHeadCut > 4 then + nRotHeadCut = nRotHeadCut - 4 + end + nRotHeadCut = nRotHeadCut + nOffsetIndex + local nRotSplitCut = MatrixResult.nInitialPosition + MACHININGS.Info.nSplitCutRotation - 1 + if nRotSplitCut > 4 then + nRotSplitCut = nRotSplitCut - 4 + end + nRotSplitCut = nRotSplitCut + nOffsetIndex + -- setto nella Proc l'indice rotazione nella quale deve essere lavorata + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].nIndexRotation = nRotHeadCut + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].nIndexRotation = nRotSplitCut + + -- si imposta flag rotazione per taglio di testa + if MACHININGS.Info.nHeadCutRotation == 2 then + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bDown = nil + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bSide = true + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bStd = nil + elseif MACHININGS.Info.nHeadCutRotation == 3 then + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bDown = true + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bSide = nil + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bStd = nil + else + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bDown = nil + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bSide = nil + PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bStd = true + end + -- si imposta flag rotazione per taglio di coda + if MACHININGS.Info.nSplitCutRotation == 2 then + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bDown = nil + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bSide = true + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bStd = nil + elseif MACHININGS.Info.nSplitCutRotation == 3 then + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bDown = true + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bSide = nil + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bStd = nil + else + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bDown = nil + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bSide = nil + PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bStd = true + end + + local vProcHeadTail = {} + table.insert( vProcHeadTail, PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc]) + table.insert( vProcHeadTail, PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc]) + + MACHININGS = CalculateMachinings( vProcHeadTail, PARTS[nPart], MatrixResult.nInitialPosition) + + -- finiti i calcoli di applicazione delle lavorazioni, si riporta il pezzo nello zero della fase + nRawId = PARTS[nPart].idRaw + while nRawId and abs( vtRawOffsetPos:len()) > 0 do + EgtKeepRawPart( nRawId) + EgtMoveRawPart( nRawId, -vtRawOffsetPos) + nRawId = EgtGetNextRawPart( nRawId) + end + + local bAreAllMachiningApplyOk + local sErr + local bSplitAlreadyExecuted = false + local bSplitExecutedOnRot = false + local nPhase = EgtGetCurrPhase() + local idDisp = EgtGetPhaseDisposition( nPhase) + EgtSetInfo( idDisp, 'TYPE', 'START') + EgtSetInfo( idDisp, 'ORD', nOrd) + + -- creazione effettiva delle lavorazioni + MACHININGS.Info = {} + local nCurrPosition = 1 + local nInitialPosition = MatrixResult.nInitialPosition + BestCombination.nInitialPosition = MatrixResult.nInitialPosition + + -- se c'è almeno una lavorazione in posizionamento con trave ribaltata + if MatrixResult.bSomeFeatureDown then + local nRotation = EgtIf( nInitialPosition + 2 > 4, nInitialPosition + 2 - 4, nInitialPosition + 2) + BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) + nCurrPosition = nRotation + EgtSetInfo( idDisp, 'ROT', -2) + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'DOWN') + bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot + bProcess = bProcess or bTryToReProcess + end + + -- se c'è almeno una lavorazione in posizionamento con trave ruotata + if MatrixResult.bSomeFeatureSide then + -- se ci sono state lavorazioni in rotazione precedente devo creare altra fase. Altrimenti già creata da prima + if MatrixResult.bSomeFeatureDown then + BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) + nPhase = EgtGetCurrPhase() + idDisp = EgtGetPhaseDisposition( nPhase) + EgtSetInfo( idDisp, 'ORD', nOrd) + -- se c'è già stata separazione + if bSplitAlreadyExecuted then + EgtSetInfo( idDisp, 'TYPE', 'MID2') + else + EgtSetInfo( idDisp, 'TYPE', 'MID') + end + -- se combinazione prevede inversione, si gira il pezzo + if BestCombination.bPartInCombiIsInverted and not PARTS[nPart].bIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], 2) + end + end + local nRotation = EgtIf( nInitialPosition + 1 > 4, nInitialPosition + 1 - 4, nInitialPosition + 1) + BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) + nCurrPosition = nRotation + EgtSetInfo( idDisp, 'ROT', -1) + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'SIDE') + bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot + bProcess = bProcess or bTryToReProcess + end + + -- se ci sono state lavorazioni in rotazione precedente devo creare altra fase. Altrimenti già creata da prima + if MatrixResult.bSomeFeatureDown or MatrixResult.bSomeFeatureSide then + BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) + nPhase = EgtGetCurrPhase() + idDisp = EgtGetPhaseDisposition( nPhase) + EgtSetInfo( idDisp, 'ORD', nOrd) + -- se c'è già stata separazione + if bSplitAlreadyExecuted then + EgtSetInfo( idDisp, 'TYPE', 'END2') + else + EgtSetInfo( idDisp, 'TYPE', 'MID') + end + -- se combinazione prevede inversione, si gira il pezzo + if BestCombination.bPartInCombiIsInverted and not PARTS[nPart].bIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], 2) + end + end + + BeamLib.RotateRawPart( PARTS[nPart], nInitialPosition - 1) + + -- aggiunta lavorazioni in ultima fase + _, _, _, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'STD') + bProcess = bProcess or bTryToReProcess + + -- se bisogna riprocessare, si annulla tutto + nCycles = nCycles + 1 + if bProcess and nCycles <= nMaxReProcessCycles then + -- azzero liste + MACHININGS = {} + MACHININGS.Info = {} + RESULT = {} + EgtRemoveAllOperations() + -- si riporta pezzo in posizione iniziale + -- se combinazione prevedeva inversione, si rigira il pezzo + if BestCombination.bPartInCombiIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], -2) + end + -- si ribalta il pezzo in posizione iniziale + BeamLib.RotateRawPart( PARTS[nPart], 1 - nInitialPosition) + else + bProcess = false + end + else + bCombinationFound = false + end + else + bCombinationFound = false + end + end + nOrd = nOrd + 1 + -- se ho trovato almeno una combinazione possibile + if bCombinationFound then + -- ===== finiti i pezzi, si scarica il restante ===== + local idRestPart = EgtGetNextRawPart( PARTS[#PARTS].idRaw) + if idRestPart and EgtGetRawPartBBox( idRestPart):getDimX() >= BeamData.dMinRaw then + BeamLib.AddPhaseWithRawParts( idRestPart, BeamData.ptOriXR, BeamData.dPosXR, 0) + local nPhase = EgtGetCurrPhase() + local idDisp = EgtGetPhaseDisposition( nPhase) + EgtSetInfo( idDisp, 'TYPE', 'REST') + EgtSetInfo( idDisp, 'ORD', nOrd) + end + -- Aggiornamento finale di tutto + EgtSetCurrPhase( 1) + local bApplOk, _, _ = EgtApplyAllMachinings() + -- se non ci sono errori, soluzione alternativa valida + if bApplOk then + -- TODO scrivere info su pezzo! + end + + -- se ultima combinazione, si esce e non si riporta in posizione inizale. Verrà infatti cancellata + if z == #TotalCombiToTest then break end + + -- si riporta pezzo in posizione iniziale + -- se combinazione prevedeva inversione, si rigira il pezzo + if BestCombination.bPartInCombiIsInverted then + BeamLib.InvertRawPart( PARTS[nPart], -2) + end + -- si ribalta il pezzo in posizione iniziale + BeamLib.RotateRawPart( PARTS[nPart], 1 - BestCombination.nInitialPosition) + end + + end + + -- si cancella eventuale mach group creato per le alternative + EgtRemoveMachGroup( nTempMachGroupName) + +end + ------------------------------------------------------------------------------------------------------------- return BeamExec diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 34baa4c..ab8d022 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -328,6 +328,18 @@ function BeamLib.RotateRawPart( Part, nNumberOfRotations) end end +------------------------------------------------------------------------------------------------------------- +function BeamLib.CreateAddGroup( PartId, sGroupName) + AddGrpId = EgtGroup( PartId or GDB_ID.NULL) + if not AddGrpId then + return false + end + -- assegno nome, flag di layer per gruppo di lavoro e colore + EgtSetName( AddGrpId, sGroupName) + EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) + EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 25)) +end + ------------------------------------------------------------------------------------------------------------- function BeamLib.CreateOrEmptyAddGroup( PartId) -- recupero i dati del gruppo aggiuntivo @@ -341,15 +353,9 @@ function BeamLib.CreateOrEmptyAddGroup( PartId) EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) return EgtEmptyGroup( AddGrpId) end + -- altrimenti lo creo - AddGrpId = EgtGroup( PartId or GDB_ID.NULL) - if not AddGrpId then - return false - end - -- assegno nome, flag di layer per gruppo di lavoro e colore - EgtSetName( AddGrpId, sMchGrp) - EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) - EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 25)) + BeamLib.CreateAddGroup( PartId, sMchGrp) return true end @@ -769,6 +775,11 @@ function BeamLib.GetBlockedAxis( nToolIndex, sBlockedAxis, b3Raw, vtTool, vtOut) return '' end +------------------------------------------------------------------------------------------------------------- +function BeamLib.StringReplaceChar( sOriginal, nPosition, sChar) + return sOriginal:sub( 1, nPosition-1) .. sChar .. sOriginal:sub( nPosition+1) +end + ------------------------------------------------------------------------------------------------------------- function BeamLib.BinaryToDecimal( dNumber) local sNumberToConvert = tostring( dNumber) diff --git a/LuaLibs/MachiningLib.lua b/LuaLibs/MachiningLib.lua index 76e1306..d8e8ea2 100644 --- a/LuaLibs/MachiningLib.lua +++ b/LuaLibs/MachiningLib.lua @@ -1420,9 +1420,9 @@ function MachiningLib.AddOperations( MACHININGS, Part, sRotation) bSplitExecuted = true MACHININGS.Info.bSplitExecuted = true - BeamLib.AddPhaseWithRawParts( MACHININGS[i].Proc.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET) + BeamLib.AddPhaseWithRawParts( Part.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET) -- se grezzo successivo senza pezzi e finale, va tolto - local nNextRawId = EgtGetNextRawPart( MACHININGS[i].Proc.idRaw) + local nNextRawId = EgtGetNextRawPart( Part.idRaw) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BeamData.dMinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end diff --git a/Process.lua b/Process.lua index 1ef58aa..344415e 100644 --- a/Process.lua +++ b/Process.lua @@ -15,9 +15,6 @@ EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua') EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua') EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua') --- TODO forzatura calcolo con prerotazioni. Cancellare dopo che è stata aggiunta la gestione corretta -local bCalcBestPieceUnloadPosition = true - -- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi local sMachDir = EgtGetCurrMachineDir() if not sMachDir then @@ -290,7 +287,7 @@ local function MyProcessBeams() end -- Sistemo le travi nel grezzo - local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, bCalcBestPieceUnloadPosition) + local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, false) if not bOk then EgtOutLog( sErr) EgtOutBox( sErr, 'Lavora Travi', 'ERROR') @@ -305,8 +302,8 @@ end ------------------------------------------------------------------------------------------------------------- local function MyProcessFeatures() - BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition) - BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition) + BeamExec.GetProcessings( PARTS, false) + BeamExec.GetCombinationMatrix( PARTS, false) BeamExec.ProcessMachinings( PARTS) local nErrCnt = 0 local nWarnCnt = 0 diff --git a/Strategies/GeneralParameters.json b/Strategies/GeneralParameters.json index 077696b..8e918ce 100644 --- a/Strategies/GeneralParameters.json +++ b/Strategies/GeneralParameters.json @@ -1,10 +1,10 @@ [ { - "nGroup": "MACHINE", + "nGroup": "PIECE LOADING", "sName": "GEN_sPiecesLoadingPosition", "sNameNge": "GEN_PIECES_LOADING", - "sValue": "BEST_POSITION", + "sValue": "BTL_POSITION", "sDescriptionShort": "Part loading position", "sDescriptionLong": "", "sType": "combo", @@ -12,24 +12,57 @@ "Choices": [ { "sValue": "BTL_POSITION", - "sDescriptionShort": "Last piece position as BTL", + "sDescriptionShort": "Loading position from BTL, no pre-rotation", "sDescriptionLong": "", "sMessageId": "" }, { - "sValue": "BEST_ROTATION", - "sDescriptionShort": "Allow piece rotations", + "sValue": "STD_PRE_ROTATION", + "sDescriptionShort": "Get Best loading position from 0° and 180°", "sDescriptionLong": "", "sMessageId": "" }, { - "sValue": "BEST_POSITION", - "sDescriptionShort": "Allow piece rotation and inversion", + "sValue": "FULL_PRE_ROTATION", + "sDescriptionShort": "Get Best loading position in each piece rotation", "sDescriptionLong": "", "sMessageId": "" } ] }, + { + "nGroup": "PIECE LOADING", + "sName": "GEN_bAllowPieceInversion", + "sNameNge": "ADMIT_INVERSION", + "sValue": "false", + "sDescriptionShort": "Allow piece inversion", + "sDescriptionLong": "", + "sType": "b", + "sMessageId": " ", + "sMinUserLevel": "1" + }, + { + "nGroup": "PIECE LOADING", + "sName": "GEN_bTestAlternative", + "sNameNge": "TEST_ALTERNATIVE", + "sValue": "false", + "sDescriptionShort": "Enable the possibility to load the piece 90° turned", + "sDescriptionLong": "", + "sType": "b", + "sMessageId": " ", + "sMinUserLevel": "1" + }, + { + "nGroup": "PIECE LOADING", + "sName": "GEN_bGetAlternativesNesting2D", + "sNameNge": "GET_ALTERNATIVES_NEST2D", + "sValue": "false", + "sDescriptionShort": "Enable material optimization function in nesting", + "sDescriptionLong": "", + "sType": "b", + "sMessageId": " ", + "sMinUserLevel": "1" + }, { "nGroup": "MACHINE", "sName": "GEN_sPieceRotation",