Nuova versione BatchProcess:

- gestione WIN.FLAG ( per ora valori ammessi 0, 1 e 2)
- Cancellato funzioni non più utilizzate
- Aggiunta nuove funzioni scrittura file di log
- Aggiunta stima tempi
This commit is contained in:
andrea.villa
2026-02-19 09:33:25 +01:00
parent f793af4d44
commit e623f2d789
2 changed files with 192 additions and 178 deletions
+176 -176
View File
@@ -5,35 +5,54 @@ require( 'EgtBase')
_ENV = EgtProtectGlobal()
EgtEnableDebug( false)
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-- TODO DA CANCELLARE!!!! quando verrà passato automaticamente da programma
--local WIN = {}
--WIN.BASEDIR = 'C:\\EgtData\\Window\\CAMAuto'
--WIN.FILE = 'C:\\Temp\\Window.nge'
--WIN.FILE = 'C:\\Temp\\TestSerramenti\\4.bwe'
--WIN.MACHINE = 'Saomad-Just3500'
--WIN.FLAG = 2
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-- Imposto direttorio libreria specializzata per serramenti
EgtAddToPackagePath( WIN.BASEDIR .. '\\LuaLibs\\?.lua')
-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre
EgtAddToPackagePath( WIN.BASEDIR .. '\\Strategies\\?.lua')
local sTxtLogFile = EgtChangePathExtension( WIN.FILE, '.txt')
-- carico il progetto
EgtOpenFile( WIN.FILE)
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
local nMachGroupId = EgtGetFirstMachGroup()
if not nMachGroupId then
EgtOutLog( 'Errore! Nessun gruppo di lavorazione presente!')
return
end
EgtSetCurrMachGroup( nMachGroupId)
-- controlli preliminari
local sMachDir = EgtGetCurrMachineDir()
local sMachine = WIN.MACHINE
EgtResetCurrMachGroup()
if not sMachDir then
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Serramenti', 'ERROR')
WIN.ERR = 11
WIN.MSG = 'Errore nel caricamento della macchina corrente'
WriteErrToLogFile( WIN.ERR, WIN.MSG)
return
end
if not EgtExistsFile( sMachDir .. '\\Window\\WinData.lua') then
EgtOutBox( 'La macchina corrente non è configurata per lavorare serramenti', 'Lavora Serramenti', 'ERROR')
WIN.ERR = 11
WIN.MSG = 'La macchina corrente non è configurata per lavorare serramenti'
WriteErrToLogFile( WIN.ERR, WIN.MSG)
return
end
if not EgtSetCurrMachine( sMachine) then
WIN.ERR = 11
WIN.MSG = 'Error selecting machine : ' .. sMachine
WriteErrToLogFile( WIN.ERR, WIN.MSG)
return
end
local sTxtLogFile = EgtChangePathExtension( WIN.FILE, '.txt')
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
EgtRemoveBaseMachineDirFromPackagePath()
@@ -50,6 +69,8 @@ _G.package.loaded.FeatureData = nil
_G.package.loaded.MachiningLib = nil
local WinExec = require( 'WinExec')
local WinLib = require( 'WinLib')
local JSON = require( 'JSON')
-- Carico i dati globali
local WinData = require( 'WinData')
@@ -57,9 +78,6 @@ local WinData = require( 'WinData')
-- Variabili globali
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
-- Colore del grezzo
local ColA = Color3d( 255, 165, 0, 30)
-------------------------------------------------------------------------------------------------------------
local function GetDataConfig()
-- recupero utensili dal magazzino
@@ -69,6 +87,25 @@ local function GetDataConfig()
return true
end
-------------------------------------------------------------------------------------------------------------
-- scrittura JSON risultati
-- TODO da migliorare/completare
local function WriteResultToJson( RESULT)
local sData = JSON:encode_pretty( RESULT)
-- Salvataggio e visualizzazione tabella
local sOutFile = EgtChangePathExtension( WIN.FILE, '.json')
local DestFh = io.open( sOutFile, 'w+')
if not DestFh then
EgtOutBox( 'Error opening ' .. sOutFile, 'TestJson', 'ERROR')
return false
end
DestFh:write( sData)
DestFh:close()
return true
end
-------------------------------------------------------------------------------------------------------------
local function WriteErrToLogFile( nErr, sMsg, nRot, idCut, idTask)
local hFile = io.open( sTxtLogFile, 'a')
@@ -80,20 +117,23 @@ local function WriteErrToLogFile( nErr, sMsg, nRot, idCut, idTask)
hFile:close()
end
local function WriteTimeToLogFile( dTime)
local hFile = io.open( sTxtLogFile, 'a')
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
hFile:close()
end
-------------------------------------------------------------------------------------------------------------
-- *** Recupero i pezzi da processare ***
-------------------------------------------------------------------------------------------------------------
local function MyProcessInputData()
-- Recupero le travi selezionate
local nId = EgtGetFirstInGroup( GDB_ID.ROOT)
local nId = EgtGetFirstPart()
while nId do
-- Per capire se è un pezzo controllo una nota, servirebbe info dedicata, oppure essere sicuri che vengano passati solo pezzi
if EgtGetInfo( nId, 'OFFY_1', 'd') then
-- TODO caricare il file di costanti
-- si processano solo BOTTOMRAIL (WIN_PART_TYPES.BOTTOMRAIL = 2) o STANDARD (WIN_PART_TYPES.STD = 3)
if EgtGetInfo( nId, 'PART_TYPE', 'd') == 2 or EgtGetInfo( nId, 'PART_TYPE', 'd') == 3 then
table.insert( PARTS, { id = nId, sName = ( EgtGetName( nId) or ( 'Id=' .. tonumber( nId)))})
-- TODO RIMUOVERE! Bisogna sempre prendere tuttti i pezzi all'interno del file. Devono arrivare solo i pezzi da mettere nella macchinata
if #PARTS == 2 then
break
end
end
nId = EgtGetNext( nId)
end
@@ -139,30 +179,6 @@ local function GetDispOffsetFromNotes( nPieceIndex)
return bAllOffsetsAreOk
end
-------------------------------------------------------------------------------------------------------------
local function GetDispOffsetFromInput( nPieceIndex)
-- assegno alle stringhe i valori letti, in modo che vengano proposti quelli nel dialogo
local sOffYPh1 = EgtIf( PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetY, tostring( PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetY), tostring( PARTS[nPieceIndex].dPartWidth / 2))
local sOffZPh1 = EgtIf( PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetZ, tostring( PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetZ), '0')
local sOffYPh2 = EgtIf( PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetY, tostring( PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetY), tostring( PARTS[nPieceIndex].dPartWidth / 2))
local sOffZPh2 = EgtIf( PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetZ, tostring( PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetZ), '0')
local vInp = EgtDialogBox( 'Dati di disposizione pezzo: ' .. PARTS[nPieceIndex].sName,
{'Sporgenza laterale FASE1', sOffYPh1}, {'Posizione Z FASE1', sOffZPh1},
{'Sporgenza laterale FASE2', sOffYPh2}, {'Posizione Z FASE2', sOffZPh2})
if not vInp or #vInp == 0 then
return false
end
-- salvo input nei valori che utilizzerò dopo
PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetY = tonumber( vInp[1])
PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetZ = tonumber( vInp[2])
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetY = tonumber( vInp[3])
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetZ = tonumber( vInp[4])
return true
end
---------------------------------------------------------------------
-- Crea il grezzo che verrà messo in macchina
---------------------------------------------------------------------
@@ -200,83 +216,18 @@ local function AddOverMaterialToRaw( PARTS)
end
end
---------------------------------------------------------------------
-- Crea il grezzo che verrà messo in macchina
---------------------------------------------------------------------
local function CreateRaws( PARTS)
for i = 1, #PARTS do
-- si crea un grezzo "finto" (un cubo da 100mm) nell'origine del pezzo, verrà poi dimensionato uan volta adeguato con i vari sovramateriali
PARTS[i].idRaw = EgtAddRawPart( PARTS[i].frame:getOrigin(), 100, 100, 100, ColA)
EgtAddPartToRawPart( PARTS[i].id, ORIG(), PARTS[i].idRaw)
end
end
---------------------------------------------------------------------
-- Allinea i pezzi in base a come devono essere disposti sulla tavola
---------------------------------------------------------------------
-- TODO in questa fase bisogna già sapere qual è la prima fase e posizionare il pezzo di conseguenza
-- TODO (bassa priorità) adesso allinea sempre in X, ma bisognerebbe farlo in base ad un parametro in WINDATA che dice come si dispongono in macchina
local function AlignRawsToTable( PARTS)
for i = 1, #PARTS do
-- allineo il pezzo all'interno del grezzo
local dRotX, dRotY, dRotZ = GetFixedAxesRotABCFromFrame( PARTS[i].frame)
-- se devo ruotare
if abs( dRotZ) > GEO.EPS_ANG_SMALL then
EgtRotatePartInRawPart( PARTS[i].id, Z_AX(), -dRotZ)
end
-- sposto punto in basso a sinistra del pezzo sul punto in basso a sinistra del grezzo
local b3Part = EgtGetBBoxGlob( PARTS[i].id, GDB_BB.ONLY_VISIBLE)
local dPartPosX = b3Part:getMin():getX()
local dPartPosY = b3Part:getMin():getY()
local dPartPosZ = b3Part:getMin():getZ()
local b3Raw = EgtGetRawPartBBox( PARTS[i].idRaw)
local dRawPosX = b3Raw:getMin():getX()
local dRawPosY = b3Raw:getMin():getY()
local dRawPosZ = b3Raw:getMin():getZ()
local vtMove = Vector3d( dRawPosX - dPartPosX, dRawPosY - dPartPosY, dRawPosZ - dPartPosZ)
EgtMovePartInRawPart( PARTS[i].id, vtMove)
end
return true
end
-------------------------------------------------------------------------------------------------------------
-- *** Funzione per trovare nome MachGroup ***
-------------------------------------------------------------------------------------------------------------
local function NewMachGroupName()
local nMachGroupId = EgtGetFirstMachGroup()
if not nMachGroupId then return '1' end
local nMaxMachGroup = 0
while nMachGroupId do
local sMachGroupName = EgtGetMachGroupName( nMachGroupId)
local nMachGroupName = tonumber( sMachGroupName)
if nMachGroupName > nMaxMachGroup then
nMaxMachGroup = nMachGroupName
end
nMachGroupId = EgtGetNextMachGroup( nMachGroupId)
end
return tostring( nMaxMachGroup + 1)
end
-------------------------------------------------------------------------------------------------------------
-- *** Inserimento delle travi nel grezzo ***
-------------------------------------------------------------------------------------------------------------
local function MyProcessPieces()
-- creo macchinata
--local MachGroupName = NewMachGroupName()
--local nMachGroup = EgtAddMachGroup( MachGroupName)
-- recupero macchinata (è sempre la prima e ce n'è solo una)
local nMachGroup = EgtGetFirstMachGroup()
EgtSetCurrMachGroup( nMachGroup)
for i = 1, #PARTS do
PARTS[i].idRaw = EgtGetRawPartFromPart( PARTS[i].id)
end
---- si crea il grezzo
--CreateRaws( PARTS)
-- allineo i pezzi come orientamento richiesto dalla macchina
--AlignRawsToTable( PARTS)
-- aggiungo sovramateriale ai grezzi
AddOverMaterialToRaw( PARTS)
@@ -288,10 +239,6 @@ local function MyProcessPieces()
PARTS[i].DispOffsets.Phase2 = {}
local bInsertedAllOffs = GetDispOffsetFromNotes( i)
-- se non sono settati nelle note, li chiedo
if not bInsertedAllOffs then
bInsertedAllOffs = GetDispOffsetFromInput( i)
end
-- se non sono stati inseriti o c'è stato un errore esco subito
if not bInsertedAllOffs then
return false
@@ -317,91 +264,126 @@ local function MyProcessPieces()
return true
end
-------------------------------------------------------------------------------------------------------------
-- *** Inserimento delle lavorazioni ***
-------------------------------------------------------------------------------------------------------------
local function MyProcessFeatures()
local bOk = WinExec.ProcessFeatures( PARTS)
return true
end
-------------------------------------------------------------------------------------------------------------
-- *** Esecuzione ***
-------------------------------------------------------------------------------------------------------------
-- WIN.FLAG :
-- 0 = generazione e stima, esegue solo un aggiornamento (eventuale) delle lavorazioni
-- 1 = da processare completamente, applicazione lavorazioni, simulazione, generazioen e stima
-- 2 = da processare in preverifica, applicazione lavorazioni e stima
-- script principale
-- In generale va completamente riprocessato
local bToProcess = true
local bToRecalc = false
local bCheckNoSim = false
local sFlag = ''
if WIN.FLAG == 0 then
sFlag = 'CHECK+GENERATE'
-- se il progetto deve essere completamente riprocessato
if WIN.FLAG == 1 then
bToProcess = true
-- se deve essere fatta la preverifica, senza simulazione
elseif WIN.FLAG == 2 then
bToProcess = true
bCheckNoSim = true
-- altrimenti solo aggiornato (se necessario)
else
sFlag = 'FLAG='..tostring( WIN.FLAG)
bToProcess = false
end
local sLog = 'BatchProcess : ' .. WIN.FILE .. ', ' .. ( WIN.MACHINE or EgtGetCurrMachineName()) .. ', ' .. sFlag
local sLog = 'BatchProcess : ' .. WIN.FILE .. ', ' .. ( WIN.MACHINE or EgtGetCurrMachineName()) .. ', ' .. 'FLAG='..tostring( WIN.FLAG)
EgtOutLog( sLog)
-- Se da elaborare
EgtOutLog( ' +++ Processing Parts >>>')
-- se bisogna processare
if bToProcess then
-- Se da elaborare
EgtOutLog( ' +++ Processing Parts >>>')
-- nascondo geometrie varie
local vAuxId = { EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Profile'), EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Area*'), EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Aux')}
EgtSetStatus( vAuxId, GDB_ST.OFF)
-- nascondo geometrie varie
local vAuxId = { EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Profile'), EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Area*'), EgtGetFirstNameInGroup( GDB_ID.ROOT, 'Aux')}
EgtSetStatus( vAuxId, GDB_ST.OFF)
if not MyProcessInputData() then return end
if not MyProcessInputData() then return end
if not MyProcessPieces() then return end
if not MyProcessPieces() then return end
if not GetDataConfig() then return end
if not GetDataConfig() then return end
-- Abilito Vmill
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
-- Abilito Vmill
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
if not MyProcessFeatures() then return end
WinExec.ProcessFeatures( PARTS)
-- Imposto Nome file CN
local _, sName, _ = EgtSplitPath( WIN.FILE)
EgtSetInfo( EgtGetCurrMachGroup(), 'NcName', sName .. '.cnc')
-- Imposto Nome file CN
local _, sName, _ = EgtSplitPath( WIN.FILE)
EgtSetInfo( EgtGetCurrMachGroup(), 'NcName', sName .. '.cnc')
-- Salvo il progetto
EgtSaveFile( WIN.FILE)
-- Salvo il progetto
EgtSaveFile( WIN.FILE)
-- *** Eseguo simulazione con verifica collisione in cieco ***
local bSimOk, nErr, sErr = EgtSimulate()
if not bSimOk then
if nErr == MCH_SHE.INIT then
WIN.ERR = 19
WIN.MSG = 'Error starting simulation'
elseif nErr == MCH_SHE.COLLISION then
WIN.ERR = 22
WIN.MSG = 'Head-part collision'
elseif nErr == MCH_SHE.OUTSTROKE then
WIN.ERR = 23
WIN.MSG = 'Axis outstroke ' .. sErr
elseif nErr == MCH_SHE.SPECIAL then
WIN.ERR = 24
WIN.MSG = 'Special error ' .. sErr
else
WIN.ERR = 25
WIN.MSG = 'General failure (contact supplier)'
-- altrimenti è solo da ricalcolare (eventualmente)
else
-- se cambiata configurazione macchina da ultima elaborazione, devo aggiornare
if EgtCompareFilesLastWriteTime( WIN.FILE, sMachDir .. '\\Tools\\Tools.data') == -1 or
EgtCompareFilesLastWriteTime( WIN.FILE, sMachDir .. '\\' .. sMachine ..'.mlde') == -1 then
bToRecalc = true
end
WIN.ROT = 0
WIN.CUTID = 0
WIN.TASKID = 0
local vItem = EgtSplitString( sErr, ';') or {}
for i = 1, #vItem do
vItem[i] = EgtTrim( vItem[i] or '')
EgtOutLog( ' +++ Loading Project already processed >>>')
-- Passo in modalità lavora
EgtSetCurrMachGroup( EgtGetLastMachGroup())
-- Se necessario eseguo aggiornamento con setup corrente e ricalcolo delle lavorazioni
if bToRecalc then
EgtOutLog( ' +++ Recalculating all dispositions and machinings >>>')
EgtImportSetup()
EgtApplyAllMachinings()
-- Salvo il progetto
EgtSaveFile( WIN.FILE)
end
end
-- se è da riprocessare o da ricalcolare, si lancia simulazione e calcolo stima tempi
if bToProcess or bToRecalc then
-- simulazione e generazione eseguiti se non è la pre-verifica per stima tempi
if not bCheckNoSim then
-- *** Eseguo simulazione con verifica collisione in cieco ***
local bSimOk, nErr, sErr = EgtSimulate()
if not bSimOk then
if nErr == MCH_SHE.INIT then
WIN.ERR = 19
WIN.MSG = 'Error starting simulation'
elseif nErr == MCH_SHE.COLLISION then
WIN.ERR = 22
WIN.MSG = 'Head-part collision'
elseif nErr == MCH_SHE.OUTSTROKE then
WIN.ERR = 23
WIN.MSG = 'Axis outstroke ' .. sErr
elseif nErr == MCH_SHE.SPECIAL then
WIN.ERR = 24
WIN.MSG = 'Special error ' .. sErr
else
WIN.ERR = 25
WIN.MSG = 'General failure (contact supplier)'
end
WIN.ROT = 0
WIN.CUTID = 0
WIN.TASKID = 0
local vItem = EgtSplitString( sErr, ';') or {}
for i = 1, #vItem do
vItem[i] = EgtTrim( vItem[i] or '')
if string.find( vItem[i], 'CUTID', 1, true) then
WIN.CUTID = EgtGetVal( vItem[i], 'CUTID', 'i') or 0
elseif string.find( vItem[i], 'TASKID', 1, true) then
WIN.TASKID = EgtGetVal( vItem[i], 'TASKID', 'i') or 0
end
end
WriteErrToLogFile( WIN.ERR, WIN.MSG, WIN.ROT, WIN.CUTID, WIN.TASKID)
-- TODO gestire collisione su feature specifica!!!!!!!!!!!!!!!!!!!!!!!!!!!!
WinExec.AddApplyResultToGlobalList( WIN.ERR, WIN.CUTID, WIN.MSG)
WIN.RESULT = WinLib.TableCopyDeep( RESULT)
WriteResultToJson( RESULT)
return
end
end
WriteErrToLogFile( WIN.ERR, WIN.MSG, WIN.ROT, WIN.CUTID, WIN.TASKID)
-- TODO gestire collisione su feature specifica!!!!!!!!!!!!!!!!!!!!!!!!!!!!
BeamExec.AddApplyResultToGlobalList( WIN.ERR, WIN.CUTID, WIN.MSG)
WIN.RESULT = WinLib.TableCopyDeep( RESULT)
WriteResultToJson( RESULT)
return
end
-- *** Genero programma CN *** ( se richiesto)
@@ -414,8 +396,26 @@ end
-- *** Eseguo stima tempi ***
EgtOutLog( ' +++ Estimating T&L >>>')
if not EgtEstimate( '', 'EgtCAM5 - ' .. WIN.FILE) then
-- TODO gestire errori in stima
WIN.ERR = 21
WIN.MSG = 'Error estimating production time : ' .. WIN.FILE
WriteErrToLogFile( WIN.ERR, WIN.MSG)
WinExec.AddApplyResultToGlobalList( WIN.ERR, 0, WIN.MSG)
WIN.RESULT = WinLib.TableCopyDeep( RESULT)
WriteResultToJson( RESULT)
return
end
local Ttot = EgtGetInfo( EgtGetCurrMachGroup(), 'Ttot', 'd')
local sTime = 'Total Time = ' .. EgtNumToString( Ttot, 1)
EgtOutLog( sTime)
-- Scrittura tempo totale stimato di lavorazione
WriteTimeToLogFile( Ttot)
RESULT[#RESULT+1] = { dTime = Ttot, sType = 'Time'}
-- Riporto risultati in tabella globale WIN
WIN.RESULT = WinLib.TableCopyDeep( RESULT)
-- Scrittura json risultati
WriteResultToJson( RESULT)
EgtOutLog( ' +++ BatchProcess completed')
+16 -2
View File
@@ -33,8 +33,9 @@ EgtMdbSave()
-------------------------------------------------------------------------------------------------------------
-- *** variabili globali ***
-------------------------------------------------------------------------------------------------------------
TOOLS = nil
MACHININGS = nil
TOOLS = {}
MACHININGS = {}
RESULT = {} -- tabella contenente il risultato, feature per feature, dell'applicazione della strategia scelta e il resoconto dell'analisi fatta
-------------------------------------------------------------------------------------------------------------
-- *** COSTANTI *** TODO -> DA SPOSTARE IN WINDATA???
@@ -192,6 +193,17 @@ function WinExec.GetToolsFromDB()
end
-------------------------------------------------------------------------------------------------------------
function WinExec.AddApplyResultToGlobalList( nErr, idCut, sMsg)
RESULT[#RESULT+1] = {
sType = 'Part',
idCut = idCut,
idTask = 0,
nErr = nErr,
sMsg = sMsg
}
end
-------------------------------------------------------------------------------------------------------------
-- *** Inserimento delle lavorazioni nelle travi ***
-------------------------------------------------------------------------------------------------------------
@@ -218,6 +230,8 @@ local function CollectFeatures( vProc, Part, nIndexPart)
Proc.sType = sType
Proc.b3Box = EgtGetBBoxGlob( ProcId, GDB_BB.STANDARD)
Proc.nPhase = EgtGetInfo( ProcId, 'PHASE', 'i') or nil
Proc.idCut = EgtGetInfo( EgtGetParent( EgtGetParent( ProcId)), 'CUTID', 'i') or 0
Proc.idTask = EgtGetInfo( ProcId, 'TASKID', 'i') or 0
-- se esiste la geometria
if Proc.b3Box and not Proc.b3Box:isEmpty() then