Files
egwwindowlua/CAMAuto/LuaLibs/WinExec.lua
T
andrea.villa 28e38b0441 - Lavorazione profili nella fase opportuna
- Migliorie varie
2024-06-21 17:15:37 +02:00

483 lines
21 KiB
Lua

-- WinExec.lua by Egalware s.r.l. 2024/06/13
-- Libreria esecuzione lavorazioni per Serramenti
-- Tabella per definizione modulo
local WinExec = {}
-- Include
require( 'EgtBase')
-- Carico i dati globali
local WinData = require( 'WinData')
local WinLib = require( 'WinLib')
local ID = require( 'Identity')
local FeatureData = require( 'FeatureData')
local MachiningLib = require( 'MachiningLib')
-- carico librerie di lavorazione
_G.package.loaded.Drilling = nil
_G.package.loaded.Cutting = nil
_G.package.loaded.Pocketing = nil
_G.package.loaded.Milling = nil
_G.package.loaded.Profiling = nil
local Drilling = require( 'Drilling')
local Cutting = require( 'Cutting')
local Pocketing = require( 'Pocketing')
local Milling = require( 'Milling')
local Profiling = require( 'Profiling')
EgtOutLog( ' WinExec started', 1)
EgtMdbSave()
-------------------------------------------------------------------------------------------------------------
-- *** variabili globali ***
-------------------------------------------------------------------------------------------------------------
TOOLS = nil
MACHININGS = nil
-------------------------------------------------------------------------------------------------------------
-- *** COSTANTI *** TODO -> DA SPOSTARE IN WINDATA???
-------------------------------------------------------------------------------------------------------------
TH_DIAMETER_HSK63 = 63
TH_LENGTH_HSK63 = 75
SIDEANGLE_DOVETAIL = 15
-------------------------------------------------------------------------------------------------------------
-- *** funzioni di base ***
-------------------------------------------------------------------------------------------------------------
local function GetToolTypeNameFromToolTypeID( dToolTypeID)
if dToolTypeID == MCH_TY.DRILL_STD then
return 'DRILL_STD', 'DRILLBIT'
elseif dToolTypeID == MCH_TY.DRILL_LONG then
return 'DRILL_LONG', 'DRILLBIT'
elseif dToolTypeID == MCH_TY.SAW_STD then
return 'SAW_STD', 'SAWBLADE'
elseif dToolTypeID == MCH_TY.SAW_FLAT then
return 'SAW_FLAT', 'SAWBLADE'
elseif dToolTypeID == MCH_TY.MILL_STD then
return 'MILL_STD', 'MILL'
elseif dToolTypeID == MCH_TY.MILL_NOTIP then
return 'MILL_NOTIP', 'MILL'
elseif dToolTypeID == MCH_TY.MORTISE_STD then
return 'MORTISE_STD', 'MORTISE'
else
return nil
end
end
-------------------------------------------------------------------------------------------------------------
local function IsToolOk( Tool)
-- controllo che i dati necessari siano impostati
if Tool.dMaxMaterial and Tool.dDiameter and Tool.dLength and Tool.sHead and Tool.sUUID then
-- se DRILLBIT non ho altri dati
if Tool.sFamily == 'DRILLBIT' then
return true
-- altrimenti controllo dati aggiuntivi altre famiglie di utensili
elseif Tool.sFamily == 'MORTISE' then
if Tool.dCornerRadius then
return true
end
else
if Tool.dThickness then
return true
end
end
end
return false
end
-------------------------------------------------------------------------------------------------------------
function WinExec.GetToolsFromDB()
-- TODO gli utensili profilati devono essere messi in una lista a parte ad accesso diretto TOOLS['Prof1'] in modo da non dover scorrere la lista
-- dato che saranno molti e l'applicazione sarà diretta. Non serve ciclarli
-- creo lista globale utensili disponibili
TOOLS = {}
-- lista appoggio utensile
local Tool = {}
-- recupero tutti gli utensili : punte a forare, lame, frese e motoseghe
Tool.sName = EgtTdbGetFirstTool( MCH_TF.DRILLBIT + MCH_TF.SAWBLADE + MCH_TF.MILL + MCH_TF.MORTISE)
while Tool.sName ~= '' do
-- imposto utensile come corrente per recuperarne i dati
EgtTdbSetCurrTool( Tool.sName)
-- verifico se utensile disponibile in attrezzaggio attuale e che abbia un tipo ben definito
local bToolLoadedOnSetup, sToolTCPos = EgtFindToolInCurrSetup( Tool.sName)
local nToolTypeId = EgtTdbGetCurrToolParam( MCH_TP.TYPE)
local sToolType, sToolFamily = GetToolTypeNameFromToolTypeID( nToolTypeId)
-- se verifica condizioni minime, recupero tutti gli altri dati
if bToolLoadedOnSetup and sToolType then
-- TODO Tool.AName -> da rimuovere perchè non serve. Per il momento lo manteniamo solo perchè è più facile vedere e interpretare la lista utensili nella watch di zerobrane
-- Nell'utilizzo, si legge sempre il Tool.Name
Tool.AName = Tool.sName
Tool.sTcPos = sToolTCPos
Tool.sFamily = sToolFamily
Tool.sType = sToolType
Tool.nTypeId = nToolTypeId
Tool.dMaxMaterial = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT)
Tool.dDiameter = EgtTdbGetCurrToolParam( MCH_TP.DIAM)
Tool.dLength = EgtTdbGetCurrToolParam( MCH_TP.LEN)
Tool.dSpeed = EgtTdbGetCurrToolParam( MCH_TP.SPEED)
Tool.bIsCCW = Tool.dSpeed < 0
Tool.Feeds = {}
Tool.Feeds.dFeed = EgtTdbGetCurrToolParam( MCH_TP.FEED)
Tool.Feeds.dStartFeed = EgtTdbGetCurrToolParam( MCH_TP.STARTFEED)
Tool.Feeds.dEndFeed = EgtTdbGetCurrToolParam( MCH_TP.ENDFEED)
Tool.Feeds.dTipFeed = EgtTdbGetCurrToolParam( MCH_TP.TIPFEED)
-- TODO serve funzione in WinData che data la posizione dell'utensile e della testa, capisca il montaggio (testa sopra - testa sotto - aggregato - ecc...)
Tool.sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
Tool.SetupInfo = {}
Tool.SetupInfo = WinData.GetSetupInfo( Tool.sHead)
Tool.sUUID = EgtTdbGetCurrToolParam( MCH_TP.UUID)
Tool.sUserNotes = EgtTdbGetCurrToolParam( MCH_TP.USERNOTES)
Tool.dMaxDepth = EgtTdbGetCurrToolMaxDepth() or Tool.dMaxMaterial
Tool.ToolHolder = {}
Tool.ToolHolder.dDiameter = EgtTdbGetCurrToolThDiam() or TH_DIAMETER_HSK63 -- diametro standard HSK63
Tool.ToolHolder.dLength = EgtTdbGetCurrToolThLength() or TH_LENGTH_HSK63 -- lunghezza standard HSK63
-- parametri scritti nelle note
Tool.nDouble = EgtGetValInNotes( Tool.sUserNotes, 'DOUBLE')
-- lettura parametri non comuni ( famiglia DRILLBIT non ha parametri specifici)
if sToolFamily ~= 'DRILLBIT' then
Tool.dThickness = EgtTdbGetCurrToolParam( MCH_TP.THICK)
Tool.dLongitudinalOffset = EgtTdbGetCurrToolParam( MCH_TP.LONOFFSET)
Tool.dRadialOffset = EgtTdbGetCurrToolParam( MCH_TP.RADOFFSET)
-- recupero parametri propri delle frese
if sToolFamily == 'MILL' then
Tool.dStemDiameter = EgtTdbGetCurrToolParam( MCH_TP.STEMDIAM) or Tool.ToolHolder.dDiameter -- se non settato, considero diametro come ToolHolder
Tool.dSideAngle = EgtTdbGetCurrToolParam( MCH_TP.SIDEANG) or 0
-- verifico che parametri siano compatibili con una fresa a coda di rondine ( angolo di fianco standard Coda di rondine -> 15°)
Tool.bIsDoveTail = Tool.Type == 'MILL_NOTIP' and abs( abs( Tool.dSideAngle) - SIDEANGLE_DOVETAIL) < 1
-- verifico che sia una fresa tipo T-Mill o BlockHaus
Tool.dSideDepth = EgtGetValInNotes( Tool.sUserNotes, 'SIDEDEPTH') or 0 -- se non settato nell'utensile, dico che non ha massimo affondamento laterale
Tool.bIsTMill = Tool.dSideDepth > 0
Tool.dStep = EgtGetValInNotes( Tool.sUserNotes, 'STEP') or ( Tool.dMaxMaterial / 3) -- se non settato nell'utensile, considero metà del tagliente
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP') or floor( Tool.dDiameter / 3) -- se non settato nell'utensile, considero metà del diametro
Tool.bIsPen = abs( Tool.dSpeed) < 5
-- recupero parametri propri delle lame
elseif sToolFamily == 'SAWBLADE' then
Tool.bIsUsedForLongCut = EgtGetValInNotes( Tool.sUserNotes, 'LONGCUT') == 1 or false -- false coem valore di default
Tool.dStep = EgtGetValInNotes( Tool.sUserNotes, 'STEP') or Tool.dThickness -- se non settato nell'utensile, considero lo spessore lama
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP') or Tool.dMaxMaterial -- se non settato nell'utensile, considero un quarto del diametro
-- recupero parametri propri delle motoseghe
elseif sToolFamily == 'MORTISE' then
Tool.dDistance = EgtTdbGetCurrToolParam( MCH_TP.DIST) or 90 -- 90mm dimensione standard aggregato catena
Tool.bIsMortise = EgtGetValInNotes( Tool.sUserNotes, 'MORTISE') == 1
Tool.bIsChainSaw = not Tool.bIsMortise
Tool.dStep = EgtGetValInNotes( Tool.sUserNotes, 'STEP') or floor( Tool.dMaxMaterial / 3) -- se non settato nell'utensile, considero un terzo della lunghezza
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP') or ( Tool.dThickness - 1) -- se non settato nell'utensile, considero spessore catena meno 1mm di sicurezza
Tool.dCornerRadius = EgtTdbGetCurrToolParam( MCH_TP.CORNRAD)
Tool.dWidth = Tool.dDiameter
end
end
-- se tutti i dati necessari sono disponibili, inserisco utensile nella lista globale degli utensili disponibili
if IsToolOk( Tool) then
table.insert( TOOLS, Tool)
-- altrimenti scrivo nel log che l'utensile non è conforme
else
EgtOutLog( '*** ' .. Tool.sName .. ' : NOT-COMPLIANT ***', 1)
end
-- reset dati
Tool = {}
end
-- recupero utensile successivo ( punte a forare, lame, frese e motoseghe)
Tool.sName = EgtTdbGetNextTool( MCH_TF.DRILLBIT + MCH_TF.SAWBLADE + MCH_TF.MILL + MCH_TF.MORTISE)
end
end
-------------------------------------------------------------------------------------------------------------
-- *** Inserimento delle lavorazioni nelle travi ***
-------------------------------------------------------------------------------------------------------------
local function CollectFeatures( vProc, Part)
-- recupero le feature
local LayerId = {}
LayerId[1] = WinLib.GetAddGroup( Part.id)
LayerId[2] = EgtGetFirstNameInGroup( Part.id or GDB_ID.NULL, 'Processings')
for nInd = 1, 2 do
local ProcId = EgtGetFirstInGroup( LayerId[nInd] or GDB_ID.NULL)
while ProcId do
local nEntType = EgtGetType( ProcId)
if nEntType == GDB_TY.SRF_MESH or nEntType == GDB_TY.EXT_TEXT or
nEntType == GDB_TY.CRV_LINE or nEntType == GDB_TY.CRV_ARC or nEntType == GDB_TY.CRV_BEZ or nEntType == GDB_TY.CRV_COMPO then
local sType = EgtGetInfo( ProcId, 'FEATURE_TYPE', 's')
local nDo = EgtGetInfo( ProcId, 'DO', 'i') or 1
if sType and nDo == 1 then
local Proc = {}
Proc.idPart = Part.id
Proc.id = ProcId
Proc.nFlg = 1
Proc.sType = sType
Proc.b3Box = EgtGetBBoxGlob( ProcId, GDB_BB.STANDARD)
Proc.nPhase = EgtGetInfo( ProcId, 'PHASE', 'i') or nil
-- informazioni facce
Proc.AffectedFaces = WinLib.GetAffectedFaces( Proc, Part)
-- se esiste la geometria
if Proc.b3Box and not Proc.b3Box:isEmpty() then
-- calcolo dati specifici per tipologia di feature / lavorazione
-- se foro
if ID.IsDrilling( Proc) then
Proc = FeatureData.GetDrillingData( Proc)
end
-- se taglio
if ID.IsCutting( Proc) then
Proc = FeatureData.GetCuttingData( Proc)
end
-- se fresatura
if ID.IsMilling( Proc) then
Proc = FeatureData.GetMillingData( Proc)
end
-- se svuotatura
if ID.IsPocketing( Proc) then
Proc = FeatureData.GetPocketingData( Proc)
end
-- se profilatura
if ID.IsProfiling( Proc) then
Proc = FeatureData.GetProfilingData( Proc)
end
-- inserisco feature in lista
table.insert( vProc, Proc)
else
Proc.nFlg = 0
table.insert( vProc, Proc)
EgtOutLog( ' Feature ' .. tostring( Proc.idFeature) .. ' is empty (no geometry)')
end
end
end
ProcId = EgtGetNext( ProcId)
end
end
return vProc
end
-------------------------------------------------------------------------------------------------------------
local function GetFeatureInfoAndDependency( vProc, Part)
-- ciclo tutte le feature
for i = 1, #vProc do
local Proc = vProc[i]
-- controllo la feature con tutte le altre per recuperare le dipendenze
for j = 1, #vProc do
-- non si controlla la feature con se stessa
if i ~= j then
local ProcB = vProc[j]
-- TODO dipendenze da controllare :
-- * gruppo di forature con aggregato 2/3 uscite
-- * Se 'Left' e 'Out' hanno stesso profilo, vanno concatenati (anche 'Right' se consentito dalle dimensioni)
end
end
end
return vProc
end
-------------------------------------------------------------------------------------------------------------
-- Ordina le feature in base a fase di lavorazione
-- L'ordine è indicativamente:
-- 1) Tagli di testa
-- 2) Fori
-- 3) Scassi serratura/maniglia
-- 4) Profili testa
-- 5) Profili longitudinali
-- 6) Incontri/scontri
-- TODO Ordinamento da fare
local function OrderMachining( MACHININGS)
-- local vProcToSort = vProc
-- -- funzione di confronto. TRUE = B1 prima di B2. FALSE = B2 prima di B1
-- local function CompareFeatures( B1, B2)
-- -- se secondo disabilitato, va lasciato dopo
-- if B1.nFlg ~= 0 and B2.nFlg == 0 then
-- return true
-- elseif B1.nPhase and B2.nPhase and B1.nPhase < B2.nPhase then
-- return true
-- elseif B1.nPhase and B2.nPhase and B2.nPhase < B1.nPhase then
-- return true
-- -- altrimenti si inverte
-- else
-- return false
-- end
-- end
-- -- test della funzione di ordinamento
-- if EgtGetDebugLevel() >= 3 then
-- EgtOutLog( ' CompareFeatures Test ')
-- local bCompTest = true
-- for i = 1, #vProcToSort do
-- for j = i + 1, #vProcToSort do
-- local bComp1 = CompareFeatures( vProcToSort[i], vProcToSort[j])
-- local bComp2 = CompareFeatures( vProcToSort[j], vProcToSort[i])
-- if bComp1 == bComp2 then
-- bCompTest = false
-- EgtOutLog( string.format( ' ProcId : %d vs %d --> ERROR', vProcToSort[i].id, vProcToSort[j].id))
-- end
-- end
-- end
-- if bCompTest then
-- EgtOutLog( ' ALL OK')
-- end
-- end
-- -- eseguo ordinamento
-- table.sort( vProcToSort, CompareFeatures)
return true
end
-------------------------------------------------------------------------------------------------------------
-- applica le lavorazioni
local function AddMachinings( vProc, PARTS)
local bMachiningOk = true
for nFeatureIndex = 1, #vProc do
local Proc = vProc[nFeatureIndex]
local Part = PARTS[vProc[nFeatureIndex].nIndexPiece]
if ID.IsDrilling( Proc) then
bMachiningOk = Drilling.Make( Proc, Part)
end
-- se taglio
if ID.IsCutting( Proc) then
bMachiningOk = Cutting.Make( Proc, Part)
end
-- se fresatura
if ID.IsMilling( Proc) then
bMachiningOk = Milling.Make( Proc, Part)
end
-- se svuotatura
if ID.IsPocketing( Proc) then
bMachiningOk = Pocketing.Make( Proc, Part)
end
-- se profilatura
if ID.IsProfiling( Proc) then
bMachiningOk = Profiling.Make( Proc, Part)
end
end
return bMachiningOk
end
-------------------------------------------------------------------------------------------------------------
local function PrintFeatures( vProc, PARTS)
EgtOutLog( ' === PARTS ====')
for i = 1, #PARTS do
EgtOutLog( ' RawBox(' .. tostring( i) .. ') =' .. tostring( PARTS[i].RawBox))
end
EgtOutLog( ' === FEATURES ====')
for i = 1, #vProc do
local Proc = vProc[i]
local sOut = string.format( 'Id=%3d Flg=%2d Type=%s', Proc.id, Proc.nFlg, Proc.sType)
EgtOutLog( sOut)
end
end
-------------------------------------------------------------------------------------------------------------
local function CheckAndMovePawPart( nIdRawToMove, vtMove)
EgtMoveRawPart( nIdRawToMove, vtMove)
end
-------------------------------------------------------------------------------------------------------------
function WinExec.ProcessFeatures( PARTS)
-- ciclo sui pezzi
local nTotErr = 0
local Stats = {}
local vProc = {}
MACHININGS = {}
-- si recuperano tutte le feature di tutti i pezzi in una lista unica
for nPart = 1, #PARTS do
-- recupero le feature di lavorazione della trave
vProc = CollectFeatures( vProc, PARTS[nPart])
-- recupero informazioni ausiliarie feature e dipendenze tra feature dello stesso pezzo
vProc = GetFeatureInfoAndDependency( vProc, PARTS[nPart])
end
-- debug
if EgtGetDebugLevel() >= 1 then
PrintFeatures( vProc, PARTS)
end
EgtOutLog( ' *** AddMachinings ***', 1)
-- esegue le lavorazioni e le salva in lista
AddMachinings( vProc, PARTS)
-- ordina le lavorazioni
OrderMachining( MACHININGS)
-- scrivo lavorazioni prima fase
EgtSetCurrPhase( 1)
for i = 1, #MACHININGS do
if MACHININGS[i].AuxInfo.nPhase == 1 then
-- aggiunge effettivamente la lavorazione e restituisce gli ingombri
local bIsApplyOk, sErr, b3MachEncumbrance = MachiningLib.AddOperation( MACHININGS[i]) -- TODO ingombro lavorazione mi restituisce dati sbagliati. C'è un riferimento?
-- se feature di testa, sposto testa in base a ingombro lavorazione
if MACHININGS[i].Proc.bHeadProfile and b3MachEncumbrance then
local nIndexPart = ID.GetPieceIndexPart( PARTS, MACHININGS[i].Proc.idPart)
PARTS[nIndexPart].DispOffsets.Phase1.dOffsetX = b3MachEncumbrance:getMax():getX() - PARTS[nIndexPart].b3FinishedPart:getMin():getX() + 5
end
end
end
-- TODO lo spostamento, oltre a controllare le collisioni con il profilo di testa, deve anche considerare il pinzaggio del pezzo nel suo insieme?
-- Es.: basterebbe aggiungere un offset di 50mm per la testa, ma se metto 60mm, posso utilizzare una morsa in più che altrimenti avrei dovuto togliere per una collisione con una svuotatura
-- sposto pezzo per permettere pinzaggio migliore e non aver colisione in testa
for i = 1, #PARTS do
-- TODO Sbaglia a calcolare ingombro!!
--local vtMove = Vector3d( - PARTS[nIndexPart].DispOffsets.Phase1.dOffsetX, - PARTS[nIndexPart].DispOffsets.Phase1.dOffsetY, PARTS[nIndexPart].DispOffsets.Phase1.dOffsetZ)
local vtMove = Vector3d( -60, 0, 0)
if vtMove ~= V_NULL() then
CheckAndMovePawPart( PARTS[i].idRaw, vtMove)
end
end
-- scrivo lavorazioni seconda fase
EgtSetCurrPhase( 2)
for i = 1, #MACHININGS do
if MACHININGS[i].AuxInfo.nPhase == 2 then
-- aggiunge effettivamente la lavorazione
local bIsApplyOk, sErr, b3MachEncumbrance = MachiningLib.AddOperation( MACHININGS[i]) -- TODO ingombro lavorazione mi restituisce dati sbagliati. C'è un riferimento?
-- se feature di testa, sposto testa in base a ingombro lavorazione
if MACHININGS[i].Proc.bHeadProfile and b3MachEncumbrance then
local nIndexPart = ID.GetPieceIndexPart( PARTS, MACHININGS[i].Proc.idPart)
PARTS[nIndexPart].DispOffsets.Phase1.dOffsetX = PARTS[nIndexPart].b3FinishedPart:getMax():getX() - b3MachEncumbrance:getMin():getX() + 5
end
end
end
-- sposto pezzo per permettere pinzaggio migliore e non aver colisione in testa
for i = 1, #PARTS do
-- TODO Sbaglia a calcolare ingombro!!
-- local vtMove = Vector3d( PARTS[nIndexPart].DispOffsets.Phase2.dOffsetX, PARTS[nIndexPart].DispOffsets.Phase2.dOffsetY, PARTS[nIndexPart].DispOffsets.Phase2.dOffsetZ)
local vtMove = Vector3d( 60, 0, 0)
if vtMove ~= V_NULL() then
CheckAndMovePawPart( PARTS[i].idRaw, vtMove)
end
end
EgtOutLog( ' *** End AddMachinings ***', 1)
-- Aggiornamento finale di tutto
EgtSetCurrPhase( 1)
local bApplOk, sApplErrors, sApplWarns = EgtApplyAllMachinings()
if not bApplOk then
nTotErr = nTotErr + 1
table.insert( Stats, {nErr = 1, sMsg=sApplErrors})
end
return ( nTotErr == 0), Stats
end
-------------------------------------------------------------------------------------------------------------
return WinExec