410 lines
16 KiB
Lua
410 lines
16 KiB
Lua
-- BatchProcessNew.lua by Egalware s.r.l. 2025/04/24
|
|
|
|
-- Intestazioni
|
|
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'
|
|
|
|
-- 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')
|
|
EgtOpenFile( WIN.FILE)
|
|
|
|
-- 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 Serramenti', 'ERROR')
|
|
return
|
|
end
|
|
if not EgtExistsFile( sMachDir .. '\\Window\\WinData.lua') then
|
|
EgtOutBox( 'La macchina corrente non è configurata per lavorare serramenti', 'Lavora Serramenti', 'ERROR')
|
|
return
|
|
end
|
|
|
|
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
|
EgtRemoveBaseMachineDirFromPackagePath()
|
|
EgtAddToPackagePath( sMachDir .. '\\Window\\?.lua')
|
|
|
|
-- Segnalazione avvio
|
|
EgtOutLog( '*** Window Process Start ***', 1)
|
|
|
|
-- Carico le librerie
|
|
_G.package.loaded.WinData = nil
|
|
_G.package.loaded.WinExec = nil
|
|
_G.package.loaded.WinLib = nil
|
|
_G.package.loaded.FeatureData = nil
|
|
_G.package.loaded.MachiningLib = nil
|
|
|
|
local WinExec = require( 'WinExec')
|
|
|
|
-- Carico i dati globali
|
|
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
|
|
WinExec.GetToolsFromDB()
|
|
|
|
-- TODO da gestire eventuali errori bloccanti
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function WriteErrToLogFile( nErr, sMsg, nRot, idCut, idTask)
|
|
local hFile = io.open( sTxtLogFile, 'a')
|
|
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
|
hFile:write( sMsg .. '\n')
|
|
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
|
hFile:write( 'CUTID=' .. tostring( idCut or 0) .. '\n')
|
|
hFile:write( 'TASKID=' .. tostring( idTask or 0) .. '\n')
|
|
hFile:close()
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** Recupero i pezzi da processare ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function MyProcessInputData()
|
|
-- Recupero le travi selezionate
|
|
local nId = EgtGetFirstInGroup( GDB_ID.ROOT)
|
|
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
|
|
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
|
|
if #PARTS == 0 then
|
|
EgtOutBox( 'Non ci sono pezzi', 'Lavora Pezzi', 'ERROR')
|
|
return false
|
|
else
|
|
-- recupero tutte le dimensioni necessarie
|
|
local sOut = ''
|
|
for i = 1, #PARTS do
|
|
PARTS[i].b3Raw = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[i].id, 'GeoRaw') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
PARTS[i].b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[i].id, 'Geo') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
local idFrame = EgtGetFirstNameInGroup( EgtGetFirstNameInGroup( PARTS[i].id, 'GeoRaw'), 'AuxFrame')
|
|
PARTS[i].frame = EgtFR( idFrame)
|
|
sOut = sOut .. PARTS[i].sName .. ', '
|
|
end
|
|
sOut = sOut:sub( 1, -3)
|
|
EgtOutLog( 'Pezzi selezionati : ' .. sOut, 1)
|
|
end
|
|
|
|
EgtDeselectAll()
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function GetDispOffsetFromNotes( nPieceIndex)
|
|
local bAllOffsetsAreOk = false
|
|
|
|
PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetX = 0 -- dovrà essere calcolato in base alle lavorazioni
|
|
PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetY = EgtGetInfo( PARTS[nPieceIndex].id, 'OFFY_1', 'd')
|
|
PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetZ = EgtGetInfo( PARTS[nPieceIndex].id, 'OFFZ_1', 'd')
|
|
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetX = 0 -- dovrà essere calcolato in base alle lavorazioni
|
|
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetY = EgtGetInfo( PARTS[nPieceIndex].id, 'OFFY_2', 'd')
|
|
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetZ = EgtGetInfo( PARTS[nPieceIndex].id, 'OFFZ_2', 'd')
|
|
|
|
-- controllo se tutti gli offset siano settati
|
|
if PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetY and PARTS[nPieceIndex].DispOffsets.Phase1.dOffsetZ and
|
|
PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetY and PARTS[nPieceIndex].DispOffsets.Phase2.dOffsetZ then
|
|
bAllOffsetsAreOk = true
|
|
end
|
|
|
|
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
|
|
---------------------------------------------------------------------
|
|
local function AddOverMaterialToRaw( PARTS)
|
|
for i = 1, #PARTS do
|
|
|
|
-- prima di aggiungere sovramateriale al grezzo, calcolo dimensioni del finito
|
|
local b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[i].id, 'Geo') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
PARTS[i].b3Part = b3Part
|
|
PARTS[i].dPartLength = PARTS[i].b3Part:getDimX()
|
|
PARTS[i].dPartWidth = PARTS[i].b3Part:getDimY()
|
|
PARTS[i].dPartHeight = PARTS[i].b3Part:getDimZ()
|
|
|
|
-- recupero sovramateriale
|
|
PARTS[i].RawOffset = {}
|
|
-- recupero info sovramateriale
|
|
PARTS[i].RawOffset.dOverMatIn = EgtGetInfo( PARTS[i].id, 'OVERMAT_IN', 'd') or 5
|
|
PARTS[i].RawOffset.dOverMatOut = EgtGetInfo( PARTS[i].id, 'OVERMAT_OUT', 'd') or 5
|
|
PARTS[i].RawOffset.dOverMatLeft = EgtGetInfo( PARTS[i].id, 'OVERMAT_LEFT', 'd') or 5
|
|
PARTS[i].RawOffset.dOverMatRight = EgtGetInfo( PARTS[i].id, 'OVERMAT_RIGHT', 'd') or 5
|
|
|
|
PARTS[i].dRawLength = PARTS[i].RawOffset.dOverMatLeft + PARTS[i].dPartLength + PARTS[i].RawOffset.dOverMatRight
|
|
PARTS[i].dRawWidth = PARTS[i].RawOffset.dOverMatOut + PARTS[i].dPartWidth + PARTS[i].RawOffset.dOverMatIn
|
|
PARTS[i].dRawHeight = PARTS[i].dPartHeight
|
|
|
|
EgtModifyRawPartSize( PARTS[i].idRaw, PARTS[i].dRawLength, PARTS[i].dRawWidth, PARTS[i].dPartHeight)
|
|
|
|
local vtMove = Vector3d( PARTS[i].RawOffset.dOverMatLeft, PARTS[i].RawOffset.dOverMatOut, 0)
|
|
EgtMovePartInRawPart( PARTS[i].id, vtMove)
|
|
|
|
-- TODO da controllare, se ruotato di 180° bisognerebbe prendere dOverMatIn. Lo stesso per la X
|
|
PARTS[i].OffsetPartToRaw = {}
|
|
PARTS[i].OffsetPartToRaw.X = PARTS[i].RawOffset.dOverMatLeft
|
|
PARTS[i].OffsetPartToRaw.Y = PARTS[i].RawOffset.dOverMatOut
|
|
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)
|
|
|
|
-- si crea il grezzo
|
|
CreateRaws( PARTS)
|
|
|
|
-- allineo i pezzi come orientamento richiesto dalla macchina
|
|
AlignRawsToTable( PARTS)
|
|
|
|
-- aggiungo sovramateriale ai grezzi
|
|
AddOverMaterialToRaw( PARTS)
|
|
|
|
-- recupero offset per posizionamento
|
|
for i = 1, #PARTS do
|
|
PARTS[i].DispOffsets = {}
|
|
PARTS[i].DispOffsets.Phase1 = {}
|
|
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
|
|
end
|
|
end
|
|
|
|
-- si dispongono i pezzi sulla tavola
|
|
local bDispOk, sErr = WinData.ExecDisposition( PARTS)
|
|
if not bDispOk then
|
|
if not sErr then
|
|
sErr = 'Errore non gestito in WinData.ExecDisposition'
|
|
end
|
|
EgtOutBox( sErr, 'ProcessWin', 'ERROR', 'OK')
|
|
return false
|
|
end
|
|
|
|
-- Impostazione dell'attrezzaggio di default
|
|
local bOk = EgtImportSetup()
|
|
if not bOk then
|
|
EgtImportSetup( 'Default')
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** Inserimento delle lavorazioni ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function MyProcessFeatures()
|
|
local bOk = WinExec.ProcessFeatures( PARTS)
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** Esecuzione ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
-- script principale
|
|
|
|
local sFlag = ''
|
|
if WIN.FLAG == 0 then
|
|
sFlag = 'CHECK+GENERATE'
|
|
else
|
|
sFlag = 'FLAG='..tostring( WIN.FLAG)
|
|
end
|
|
local sLog = 'BatchProcess : ' .. WIN.FILE .. ', ' .. ( WIN.MACHINE or EgtGetCurrMachineName()) .. ', ' .. sFlag
|
|
EgtOutLog( sLog)
|
|
|
|
|
|
-- 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)
|
|
|
|
if not MyProcessInputData() then return end
|
|
|
|
if not MyProcessPieces() then return end
|
|
|
|
if not GetDataConfig() then return end
|
|
|
|
-- Abilito Vmill
|
|
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
|
|
|
if not MyProcessFeatures() then return end
|
|
|
|
|
|
-- Imposto Nome file CN
|
|
local _, sName, _ = EgtSplitPath( WIN.FILE)
|
|
EgtSetInfo( EgtGetCurrMachGroup(), 'NcName', sName .. '.cnc')
|
|
|
|
|
|
-- 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)'
|
|
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 '')
|
|
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)
|
|
local bIsGenerationEnabled = ( EgtVerifyKeyOption( 110) == false)
|
|
if bIsGenerationEnabled then
|
|
EgtOutLog( ' +++ Generating NC part program >>>')
|
|
-- TODO gestire generazione
|
|
end
|
|
|
|
-- *** Eseguo stima tempi ***
|
|
EgtOutLog( ' +++ Estimating T&L >>>')
|
|
if not EgtEstimate( '', 'EgtCAM5 - ' .. WIN.FILE) then
|
|
-- TODO gestire errori in stima
|
|
end
|
|
|
|
|
|
EgtOutLog( ' +++ BatchProcess completed')
|