Files
databeamnew/LuaLibs/BeamExec.lua
T
andrea.villa d45fc8e89b - Prima versione file INI interfaccia selezione strategie Beam&Wall
- BeamLib : nuova funzione 'LoadCustomParametersInStrategy'
- Piccoli aggiustamenti vari
2024-05-08 15:32:51 +02:00

887 lines
42 KiB
Lua

-- BeamExec.lua by Egalware s.r.l. 2024/04/02
-- Libreria esecuzione lavorazioni per Travi
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
-- Tabella per definizione modulo
local BeamExec = {}
-- Include
require( 'EgtBase')
-- Carico i dati globali
local BeamData = require( 'BeamData')
-- carico librerie
local BeamLib = require( 'BeamLib')
local ID = require( 'Identity')
local BCS = require( 'BasicCustomerStrategies')
local FeatureData = require( 'FeatureData')
local FaceData = require( 'FaceData')
local MachiningLib = require( 'MachiningLib')
EgtOutLog( ' BeamExec started', 1)
EgtMdbSetGeneralParam( MCH_GP.MAXDEPTHSAFE, BeamData.COLL_SIC)
EgtMdbSave()
-------------------------------------------------------------------------------------------------------------
-- *** variabili globali ***
-------------------------------------------------------------------------------------------------------------
TOOLS = nil
STRATEGIES = nil
-------------------------------------------------------------------------------------------------------------
-- *** COSTANTI *** TODO -> DA SPOSTARE IN BEAMDATA???
-------------------------------------------------------------------------------------------------------------
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.MaxMaterial and Tool.Diameter and Tool.Length and Tool.Head and Tool.UUID then
-- se DRILLBIT non ho altri dati
if Tool.Family == 'DRILLBIT' then
return true
-- altrimenti controllo dati aggiuntivi altre famiglie di utensili
else
if Tool.Thick then
return true
end
end
end
return false
end
-------------------------------------------------------------------------------------------------------------
function BeamExec.GetToolsFromDB()
-- creo lista globale utensili disponibili
TOOLS = {}
-- lista appoggio utensile
local Tool = {}
-- recupero tutti gli utensili : punte a forare, lame, frese e motoseghe
Tool.Name = EgtTdbGetFirstTool( MCH_TF.DRILLBIT + MCH_TF.SAWBLADE + MCH_TF.MILL + MCH_TF.MORTISE)
while Tool.Name ~= '' do
-- imposto utensile come corrente per recuperarne i dati
EgtTdbSetCurrTool( Tool.Name)
-- verifico se utensile disponibile in attrezzaggio attuale e che abbia un tipo ben definito
local bToolLoadedOnSetup, sToolTCPos = EgtFindToolInCurrSetup( Tool.Name)
local dToolTypeID = EgtTdbGetCurrToolParam( MCH_TP.TYPE)
local sToolType, sToolFamily = GetToolTypeNameFromToolTypeID( dToolTypeID)
-- 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.Name
Tool.TcPos = sToolTCPos
Tool.Family = sToolFamily
Tool.Type = sToolType
Tool.TypeID = dToolTypeID
Tool.MaxMaterial = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT)
Tool.Diameter = EgtTdbGetCurrToolParam( MCH_TP.DIAM)
Tool.Length = EgtTdbGetCurrToolParam( MCH_TP.LEN)
Tool.Speed = EgtTdbGetCurrToolParam( MCH_TP.SPEED)
Tool.IsCCW = Tool.Speed < 0
Tool.Feeds = {}
Tool.Feeds.Feed = EgtTdbGetCurrToolParam( MCH_TP.FEED)
Tool.Feeds.StartFeed = EgtTdbGetCurrToolParam( MCH_TP.STARTFEED)
Tool.Feeds.EndFeed = EgtTdbGetCurrToolParam( MCH_TP.ENDFEED)
Tool.Feeds.TipFeed = EgtTdbGetCurrToolParam( MCH_TP.TIPFEED)
-- TODO serve funzione in BeamData che data la posizione dell'utensile e della testa, capisca il montaggio (testa sopra - testa sotto - aggregato - ecc...)
Tool.Head = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
Tool.UUID = EgtTdbGetCurrToolParam( MCH_TP.UUID)
Tool.UserNotes = EgtTdbGetCurrToolParam( MCH_TP.USERNOTES)
Tool.MaxDepth = EgtTdbGetCurrToolMaxDepth() or Tool.MaxMaterial
Tool.ToolHolder = {}
Tool.ToolHolder.Diameter = EgtTdbGetCurrToolThDiam() or TH_DIAMETER_HSK63 -- diametro standard HSK63
Tool.ToolHolder.Length = EgtTdbGetCurrToolThLength() or TH_LENGTH_HSK63 -- lunghezza standard HSK63
-- parametri scritti nelle note
Tool.Double = EgtGetValInNotes( Tool.UserNotes, 'DOUBLE')
-- lettura parametri non comuni ( famiglia DRILLBIT non ha parametri specifici)
if sToolFamily ~= 'DRILLBIT' then
Tool.Thick = EgtTdbGetCurrToolParam( MCH_TP.THICK)
Tool.LongitudinalOffset = EgtTdbGetCurrToolParam( MCH_TP.LONOFFSET)
Tool.RadialOffset = EgtTdbGetCurrToolParam( MCH_TP.RADOFFSET)
-- recupero parametri propri delle frese
if sToolFamily == 'MILL' then
Tool.StemDiameter = EgtTdbGetCurrToolParam( MCH_TP.STEMDIAM) or Tool.ThDiameter -- se non settato, considero diametro come ToolHolder
Tool.SideAngle = 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.IsDoveTail = Tool.Type == 'MILL_NOTIP' and abs( abs( Tool.SideAngle) - SIDEANGLE_DOVETAIL) < 1
-- verifico che sia una fresa tipo T-Mill o BlockHaus
Tool.SideDepth = EgtGetValInNotes( Tool.UserNotes, 'SIDEDEPTH') or 0 -- se non settato nell'utensile, dico che non ha massimo affondamento laterale
Tool.IsTMill = Tool.SideDepth > 0
Tool.Step = EgtGetValInNotes( Tool.UserNotes, 'STEP') or ( Tool.MaxMaterial / 2) -- se non settato nell'utensile, considero metà del tagliente
Tool.SideStep = EgtGetValInNotes( Tool.UserNotes, 'SIDESTEP') or floor( Tool.Diameter / 2) -- se non settato nell'utensile, considero metà del diametro
-- recupero parametri propri delle lame
elseif sToolFamily == 'SAWBLADE' then
Tool.IsUsedForLongCut = EgtGetValInNotes( Tool.UserNotes, 'LONGCUT') == 1 or false -- false coem valore di default
Tool.Step = EgtGetValInNotes( Tool.UserNotes, 'STEP') or Tool.Thick -- se non settato nell'utensile, considero lo spessore lama
Tool.SideStep = EgtGetValInNotes( Tool.UserNotes, 'SIDESTEP') or floor( Tool.Diameter / 4) -- se non settato nell'utensile, considero un quarto del diametro
-- recupero parametri propri delle motoseghe
elseif sToolFamily == 'MORTISE' then
Tool.Distance = EgtTdbGetCurrToolParam( MCH_TP.DIST) or 90 -- 90mm dimensione standard aggregato catena
Tool.IsMortise = EgtGetValInNotes( Tool.UserNotes, 'MORTISE') == 1
Tool.IsChainSaw = not Tool.IsMortise
Tool.Step = EgtGetValInNotes( Tool.UserNotes, 'STEP') or ( Tool.Thick - 1) -- se non settato nell'utensile, considero spessore catena meno 1mm di sicurezza
Tool.SideStep = EgtGetValInNotes( Tool.UserNotes, 'SIDESTEP') or floor( Tool.MaxMaterial / 3) -- se non settato nell'utensile, considero un terzo della lunghezza
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.Name .. ' : NOT-COMPLIANT ***', 1)
end
-- reset dati
Tool = {}
end
-- recupero utensile successivo ( punte a forare, lame, frese e motoseghe)
Tool.Name = EgtTdbGetNextTool( MCH_TF.DRILLBIT + MCH_TF.SAWBLADE + MCH_TF.MILL + MCH_TF.MORTISE)
end
end
-------------------------------------------------------------------------------------------------------------
local function ImportFileJSON( sFileToImport)
local JSON = require( 'JSON')
local function readAll( sFileToImport)
local f = io.open( sFileToImport, "rb")
local content = f:read( "*all")
f:close()
return content
end
local content = readAll( sFileToImport)
return JSON:decode( content)
end
-------------------------------------------------------------------------------------------------------------
function BeamExec.GetStrategiesFromJSONinBD()
-- si legge il JSON contenente la configurazione da utilizzare (nome del file salvato nel BeamData)
local sMachDir = EgtGetCurrMachineDir()
if BeamData.STRATEGIES_CONFIG_FILE then
local sFile = sMachDir .. '\\Beam\\' .. BeamData.STRATEGIES_CONFIG_FILE
-- se non esiste file JSON, annullo la lista contenente le strategie
if not EgtExistsFile( sFile) then
STRATEGIES = nil
return
end
local FeaturesList = {}
FeaturesList = ImportFileJSON( sFile)
-- metto la tabella letta nella lista globale STRATEGIES
STRATEGIES = {}
STRATEGIES.Features = FeaturesList
end
end
-------------------------------------------------------------------------------------------------------------
-- *** funzioni posizionamento pezzi all'interno della barra ***
-------------------------------------------------------------------------------------------------------------
function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, vBeam, bMachGroupOk)
-- default per nuove costanti qualora non definite
BeamData.OVM_BLADE_HBEAM = ( BeamData.OVM_BLADE_HBEAM or 11)
BeamData.OVM_CHAIN_HBEAM = ( BeamData.OVM_CHAIN_HBEAM or 8)
-- sovramateriale intermedio nullo se non definito
dOvmMid = ( dOvmMid or 0)
-- Determinazione minimo grezzo scaricabile
BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
-- Creazione nuovo gruppo di lavoro
if not bMachGroupOk then
local sMgName = EgtGetMachGroupNewName( 'Mach_1')
local NewMgId = EgtAddMachGroup( sMgName)
if not NewMgId then
local sOut = 'Errore nella creazione del gruppo di lavoro ' .. sMgName
return false, sOut
end
end
-- Impostazione della tavola
EgtSetTable( 'Tab')
-- salvo nota con lunghezza grezzo
-- Recupero l'identificativo del gruppo di lavoro corrente
local nMGrpId = EgtGetCurrMachGroup()
-- Lunghezza della barra
local dBarLen = EgtGetInfo( nMGrpId, 'BARLEN', 'd')
if not dBarLen then
EgtSetInfo( nMGrpId, 'BARLEN', dRawL)
end
-- Area tavola
local b3Tab = EgtGetTableArea()
-- Calcolo posizione estremo TR/BR della tavola rispetto a sua origine in BL
local dPosY = EgtIf( BeamData.CENTER_BEAM, ( b3Tab:getDimY() + dRawW * EgtIf( BeamData.RIGHT_LOAD, -1, 1)) / 2, EgtIf( BeamData.RIGHT_LOAD, 0, b3Tab:getDimY()))
BeamData.OriXR = Point3d( b3Tab:getDimX(), dPosY, 0)
BeamData.PosXR = EgtIf( BeamData.RIGHT_LOAD, MCH_CR.BR, MCH_CR.TR)
-- Impostazione dell'attrezzaggio di default
EgtImportSetup()
-- Inserimento dei pezzi con il loro grezzo
local Cnt = 0
local Len = dRawL
local nPrevRaw, dPrevDelta
local DeltaS = dOvmHead
local DeltaSMin = 0
local DeltaE = BeamData.OVM_MID
for i = 1, #vBeam do
-- assegno identificativo pezzo
local Pz = vBeam[i].Id
-- dati del pezzo
local b3Part = EgtGetBBoxGlob( Pz or GDB_ID.NULL, GDB_BB.EXACT)
local b3Solid = vBeam[i].Box
if b3Part:isEmpty() or b3Solid:isEmpty() then break end
EgtOutLog( 'PartSez=' .. EgtNumToString( b3Part:getDimY(), 1) .. 'x' .. EgtNumToString( b3Part:getDimZ(), 1), 3)
-- se sezione compatibile e lunghezza disponibile sufficiente
local PartLen = b3Solid:getDimX()
local PartWidth = b3Solid:getDimY()
local PartHeight = b3Solid:getDimZ()
local NextLen = Len - DeltaS - PartLen - DeltaE
if (( abs( PartWidth - dRawW) < 100 * GEO.EPS_SMALL and abs( PartHeight - dRawH) < 100 * GEO.EPS_SMALL) or
( abs( PartHeight - dRawW) < 100 * GEO.EPS_SMALL and abs( PartWidth - dRawH) < 100 * GEO.EPS_SMALL)) and
NextLen + DeltaE >= 0 then
-- eventuale sovramateriale di testa
if i > 1 then
if vBeam[i].PosX then
DeltaS = max( vBeam[i].PosX - ( dRawL - Len), DeltaSMin)
else
DeltaS = max( dOvmMid - DeltaE, 0)
end
end
-- dimensioni del grezzo
local CrawLen = min( PartLen + DeltaS + DeltaE, Len)
local Delta = CrawLen - PartLen - DeltaS
-- creo e posiziono il grezzo
local nRaw = EgtAddRawPart( Point3d(0,0,0), CrawLen, dRawW, dRawH, BeamData.RAWCOL)
EgtMoveToCornerRawPart( nRaw, BeamData.OriXR, BeamData.PosXR)
EgtMoveRawPart( nRaw, Vector3d( Len - dRawL, 0, 0))
-- assegno ordine in lavorazione
Cnt = Cnt + 1
EgtSetInfo( nRaw, 'ORD', Cnt)
-- creo o pulisco gruppo geometrie aggiuntive
if not BeamLib.CreateOrEmptyAddGroup( Pz) then
local sOut = 'Error creating Additional Group in Part ' .. tostring( Pz)
return false, sOut
end
-- aggiungo faccia per taglio iniziale al pezzo
BeamLib.AddPartStartFace( Pz, b3Solid)
-- se sovramateriale di testa, lo notifico
if DeltaS > 0.09 then
EgtSetInfo( nRaw, 'HOVM', DeltaS)
if nPrevRaw then
EgtSetInfo( nPrevRaw, 'BDST', DeltaS + dPrevDelta)
end
end
if DeltaE > 0.09 then
EgtSetInfo( nRaw, 'TOVM', DeltaE)
end
-- aggiungo faccia per taglio finale al pezzo
BeamLib.AddPartEndFace( Pz, b3Solid)
-- inserisco il pezzo nel grezzo
EgtDeselectPartObjs( Pz)
local ptPos = b3Part:getMin() - b3Solid:getMin() + Vector3d( Delta, ( dRawW - PartWidth) / 2, ( dRawH - PartHeight) / 2)
EgtAddPartToRawPart( Pz, ptPos, nRaw)
if abs( PartWidth - dRawW) > 100 * GEO.EPS_SMALL then
-- rotazione attorno a centro geometria complessiva del pezzo
EgtRotatePartInRawPart( Pz, X_AX(), 90)
-- correggo per eccentricità solido rispetto a geometria complessiva del pezzo
local vtEccOri = b3Solid:getCenter() - b3Part:getCenter()
local vtEccRot = Vector3d( vtEccOri)
vtEccRot:rotate( X_AX(), 90)
EgtMovePartInRawPart( Pz, ( vtEccOri - vtEccRot))
end
-- aggiorno la lunghezza residua della barra
Len = Len - CrawLen
-- aggiorno grezzo precedente
nPrevRaw = nRaw
dPrevDelta = Delta
else
local sOut = 'Error: part L(' .. EgtNumToString( PartLen, 1) .. ') too big for raw part L(' .. EgtNumToString( Len - 0.1, 1) .. ')'
return false, sOut
end
-- se rimasto troppo poco grezzo, esco
--if Len < BeamData.MinRaw then break end
DeltaS = 0
end
if nPrevRaw then
EgtSetInfo( nPrevRaw, 'BDST', 10000)
end
-- Se rimasto materiale aggiungo grezzo dell'avanzo
if Len > 10 then
local nRaw = EgtAddRawPart( Point3d(0,0,0), Len, dRawW, dRawH, BeamData.RAWCOL)
EgtMoveToCornerRawPart( nRaw, BeamData.OriXR, BeamData.PosXR)
EgtMoveRawPart( nRaw, Vector3d( Len - dRawL, 0, 0))
-- assegno ordine in lavorazione
Cnt = Cnt + 1
EgtSetInfo( nRaw, 'ORD', Cnt)
end
return true
end
-------------------------------------------------------------------------------------------------------------
function BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
if BeamData.GetMinUnloadableRaw then
BeamData.MinRaw = BeamData.GetMinUnloadableRaw( dRawW, dRawH)
else
local H_S = 200
local H_L = 400
-- Determinazione minimo grezzo scaricabile
if dRawH <= H_S then
BeamData.MinRaw = BeamData.MINRAW_S
elseif dRawH <= H_L then
local Coeff = ( dRawH - H_S) / ( H_L - H_S)
BeamData.MinRaw = ( 1 - Coeff) * BeamData.MINRAW_S + Coeff * BeamData.MINRAW_L
else
BeamData.MinRaw = BeamData.MINRAW_L
end
end
end
-------------------------------------------------------------------------------------------------------------
-- *** Inserimento delle lavorazioni nelle travi ***
-------------------------------------------------------------------------------------------------------------
local function GetStrategiesFromGlobalList( Proc)
-- cerco tra le feature
for i = 1, #STRATEGIES.Features do
-- se trovo la feature
if Proc.Prc == STRATEGIES.Features[i].Prc and Proc.Grp == STRATEGIES.Features[i].Grp then
-- cerco tra le topologie
for j = 1, #STRATEGIES.Features[i].Topologies do
-- se trovo la topologia
if Proc.Topology.Name == STRATEGIES.Features[i].Topologies[j].Name then
-- ritorno le strategie disponibili per la feature che sto analizzando
return STRATEGIES.Features[i].Topologies[j].Strategies
end
end
end
end
return nil
end
-------------------------------------------------------------------------------------------------------------
local function GetStrategies( Proc)
local AvailableStrategiesForProc = nil
-- se la lista STRATEGIES è stata letta da JSON (quindi non è vuota), ritorno le strategie possibili
if STRATEGIES and #STRATEGIES.Features > 0 then
AvailableStrategiesForProc = GetStrategiesFromGlobalList( Proc)
end
-- se non ho trovato strategie disponibili nel JSON, o se JSON non presente, lancio script che setta le strategie in modo statico, come definito con cliente
if not AvailableStrategiesForProc then
AvailableStrategiesForProc = BCS.GetStrategiesFromBasicCustomerStrategies( Proc)
end
return AvailableStrategiesForProc
end
-------------------------------------------------------------------------------------------------------------
local function GetFeatureForcedStrategy( Proc)
-- cerco nelle note se è stata forzata una strategia specifica
local sStrategyId = EgtGetInfo( Proc.Id, 'STRATEGY', 's')
-- se è presente la strategia forzata
if sStrategyId then
-- eseguo file config con i parametri di default
local StrategyData = require( sStrategyId .. '\\' .. sStrategyId .. 'Config')
-- se ID strategia non esiste oppure ID letto in NGE è differente da quello letto nella strategia, esco subito
if not StrategyData or StrategyData.StrategyId ~= sStrategyId then
return nil
end
-- salvo che questa strategia è stata forzata, e che quindi ho già letto il file config con i parametri di default
-- quando si calcolerà la lavorazione non servirà leggere/riverificare i parametri di default
StrategyData.ForcedStrategy = true
-- cerco e aggiorno i parametri come sono settati nel processing
for i = 1, #StrategyData.Parameters do
local sParameterToRead = StrategyData.StrategyId .. '_' .. StrategyData.Parameters[i].Name
ForcedParameterForProc = EgtGetInfo( Proc.Id, sParameterToRead, 's')
-- se ho trovato il valore, lo sovrascrivo al default
if ForcedParameterForProc then
StrategyData.Parameters[i].Value = ForcedParameterForProc
end
end
-- ritorno la lista strategia con parametri
local StrategyToProc = {}
table.insert( StrategyToProc, StrategyData)
return StrategyToProc
end
return nil
end
-------------------------------------------------------------------------------------------------------------
local function CollectFeatures( PartId, Part)
-- recupero le feature
local vProc = {}
local LayerId = {}
LayerId[1] = BeamLib.GetAddGroup( PartId)
LayerId[2] = EgtGetFirstNameInGroup( PartId 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 nGrp = EgtGetInfo( ProcId, 'GRP', 'i')
local nPrc = EgtGetInfo( ProcId, 'PRC', 'i')
local nDo = EgtGetInfo( ProcId, 'DO', 'i') or 1
if nGrp and nPrc and nDo == 1 then
local Proc = {}
Proc.PartId = PartId
Proc.Id = ProcId
-- id della feature btl ( se non presente info, si prende id dell'entità geometrica)
Proc.FeatureId = EgtGetInfo( Proc.Id, 'PRID', 's') or Proc.Id
Proc.Grp = nGrp
Proc.Prc = nPrc
Proc.Flg = 1
Proc.Fct = EgtSurfTmFacetCount( ProcId) or 0
Proc.CutId = EgtGetInfo( EgtGetParent( EgtGetParent( ProcId)), 'CUTID', 'i') or 0
Proc.TaskId = EgtGetInfo( ProcId, 'TASKID', 'i') or 0
Proc.Box = EgtGetBBoxGlob( ProcId, GDB_BB.STANDARD)
EgtOutLog( '------Feature ' .. Proc.FeatureId .. '------')
-- se esiste la geometria
if Proc.Box and not Proc.Box:isEmpty() then
-- TODO fare una funzione per recuperare i dati delle feature che non passano dal calcolo della topologia?
-- se foro calcolo altri dati
if ID.IsDrilling( Proc) then
-- assegno diametro e facce di ingresso e uscita (dati tabelle sempre per riferimento)
Proc.Diam, Proc.Len, Proc.Fcs, Proc.Fce = FeatureData.GetDrillingData( Proc)
end
-- informazioni facce e topologia
Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc)
-- calcolo topologia solo se necessario, altrimenti si sfruttano le informazioni della feature BTL
Proc.Topology = {}
if FeatureData.NeedTopologyFeature( Proc) then
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
Proc.Topology = FeatureData.ClassifyTopology( Proc, Part)
else
Proc.Topology.Family = 'FEATURE'
Proc.Topology.Name = 'FEATURE'
end
-- se topologia feature riconosciuta, oppure da non calcolare perchè il riconoscimento topologico è basato sulla feature stessa
if Proc.Topology.Name ~= 'NOT_IMPLEMENTED' then
-- TODO Funzione 'GetMainFaces' da scrivere
Proc.MainFaces = FaceData.GetMainFaces( Proc)
-- se la processing ha una strategia forzata, riporto tutto nella proc
local vForcedStrategy = GetFeatureForcedStrategy( Proc)
if vForcedStrategy then
Proc.AvailableStrategies = vForcedStrategy
-- altrimenti cerco tra le strategie disponibili
else
Proc.AvailableStrategies = GetStrategies( Proc)
end
-- se ci sono strategie disponibili, aggiungo a lista delle feature da lavorare
if Proc.AvailableStrategies and #Proc.AvailableStrategies > 0 then
table.insert( vProc, Proc)
-- altrimenti errore (non ci sono strategie per lavorare la topologia riconosciuta)
else
EgtOutLog( ' Feature ' .. tostring( Proc.FeatureId) .. ' : NO available strategies')
end
-- altrimenti errore (serviva riconoscimento topologico, ma non è stato possibile farlo)
else
EgtOutLog( ' Feature ' .. tostring( Proc.FeatureId) .. ' : NO available strategies')
end
else
Proc.Flg = 0
table.insert( vProc, Proc)
EgtOutLog( ' Feature ' .. tostring( Proc.FeatureId) .. ' is empty (no geometry)')
end
end
end
ProcId = EgtGetNext( ProcId)
end
end
return vProc
end
-------------------------------------------------------------------------------------------------------------
local function AreDrillingsMirrored( Proc, ProcMirror, Part)
if Proc.Id == ProcMirror.Id then return false end
-- geometria ausiliaria foro principale
AuxId = EgtGetInfo( Proc.Id, 'AUXID', 'i')
if AuxId then AuxId = AuxId + Proc.Id end
if not AuxId or EgtGetType( AuxId ) ~= GDB_TY.CRV_ARC then return false end
-- geometria ausiliaria foro specchiato
local AuxIdMirror = EgtGetInfo( ProcMirror.Id, 'AUXID', 'i')
if AuxIdMirror then AuxIdMirror = AuxIdMirror + ProcMirror.Id end
if not AuxIdMirror or EgtGetType( AuxIdMirror ) ~= GDB_TY.CRV_ARC then return false end
-- dati del foro principale
local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB)
local ptBC = EgtGP( AuxId, GDB_RT.GLOB)
-- dati del foro specchiato
local vtExtrMirror = EgtCurveExtrusion( AuxIdMirror, GDB_RT.GLOB)
local ptBCMirror = EgtGP( AuxIdMirror, GDB_RT.GLOB)
-- direzione fori
local nDouble
if AreOppositeVectorApprox( vtExtr, vtExtrMirror) then
-- fori lungo Y
-- per macchine tipo PF il foro principale è sul lato back, per macchine tipo PF1250 è sul lato front
if ( BD.TWO_EQUAL_HEADS and AreSameVectorApprox( vtExtr, Y_AX())) or
( BD.DOWN_HEAD and AreOppositeVectorApprox( vtExtr, Y_AX())) then
nDouble = 2
-- fori lungo Z
elseif BD.DOWN_HEAD and AreSameVectorApprox( vtExtr, Z_AX()) then
nDouble = 3
else
return false
end
else
return false
end
-- centri allineati, equidistanti dalla mezzeria trave, non troppo vicini
local vtDisplacement = ptBC - ptBCMirror
local ptCenRaw = Part.RawBox:getCenter()
if nDouble == 2 then
local dYMinDistance = max( Proc.Box:getMin():getY(), ProcMirror.Box:getMin():getY()) - min( Proc.Box:getMax():getY(), ProcMirror.Box:getMax():getY())
if not ( abs( vtDisplacement:getX()) < 100 * GEO.EPS_SMALL and abs( vtDisplacement:getZ()) < 100 * GEO.EPS_SMALL and
( abs( ptBC:getY() - ptCenRaw:getY()) - abs( ptBCMirror:getY() - ptCenRaw:getY())) < 100 * GEO.EPS_SMALL and
dYMinDistance > MIRROR_DRILLINGS_MIN_DISTANCE + 10 * GEO.EPS_SMALL) then
return false
end
else
local dZMinDistance = max( Proc.Box:getMin():getZ(), ProcMirror.Box:getMin():getZ()) - min( Proc.Box:getMax():getZ(), ProcMirror.Box:getMax():getZ())
if not ( abs( vtDisplacement:getX()) < 100 * GEO.EPS_SMALL and abs( vtDisplacement:getY()) < 100 * GEO.EPS_SMALL and
( abs( ptBC:getZ() - ptCenRaw:getZ()) - abs( ptBCMirror:getZ() - ptCenRaw:getZ())) < 100 * GEO.EPS_SMALL and
dZMinDistance > MIRROR_DRILLINGS_MIN_DISTANCE + 10 * GEO.EPS_SMALL) then
return false
end
end
-- fori della stessa profondità
if abs( Proc.Len - ProcMirror.Len) > 10 * GEO.EPS_SMALL then
return false
end
return true
end
-------------------------------------------------------------------------------------------------------------
local function GetFeatureInfoAndDependency( vProcSingleRot, Part)
-- ciclo tutte le feature
for i = 1, #vProcSingleRot do
local Proc = vProcSingleRot[i]
-- controllo la feature con tutte le altre per recuperare le dipendenze
for j = 1, #vProcSingleRot do
-- non si controlla la feature con se stessa
if i ~= j then
local ProcB = vProcSingleRot[j]
-- verifico se feature tipo LapJoint è attraversata da almeno un foro
if ( Proc.Topology.Family == 'Pocket' or Proc.Topology.Family == 'Tunnel' or Proc.Topology.Family == 'Groove' or ID.IsMortise( Proc)) and
ID.IsDrilling( ProcB) and Overlaps( Proc.Box, ProcB.Box) then
Proc.PassedByHole = true
end
-- verifiche per specchiature
if BeamData.DOWN_HEAD or BeamData.TWO_EQUAL_HEADS then
-- forature
if BeamData.DOUBLE_HEAD_DRILLING and ID.IsDrilling( Proc) and ID.IsDrilling( ProcB) and not Proc.Mirror then
if AreDrillingsMirrored( Proc, ProcB, Part) then
Proc.Mirror = ProcB
end
end
end
end
end
end
return vProcSingleRot
end
-------------------------------------------------------------------------------------------------------------
local function RunStrategyLibraries( sStrategyId)
local StrategyConfigName = sStrategyId .. '\\' .. sStrategyId .. 'Config'
local StrategyConfigPath = BEAM.BASEDIR .. '\\Strategies\\' .. StrategyConfigName .. '.lua'
local StrategyScriptName = sStrategyId .. '\\' .. sStrategyId
local StrategyScriptPath = BEAM.BASEDIR .. '\\Strategies\\' .. StrategyScriptName .. '.lua'
local StrategyLib = {}
if EgtExistsFile( StrategyConfigPath) and EgtExistsFile( StrategyScriptPath) then
StrategyLib.Config = require( StrategyConfigName)
-- eseguo file script strategia
StrategyLib.Script = require( StrategyScriptName)
return StrategyLib
else
return {}
end
end
-------------------------------------------------------------------------------------------------------------
-- ritorna l'indice della strategia migliore, tra le due passate
local function GetIndexBestStrategyFromComparison( AvailableStrategies, nIndex1, nIndex2)
local dChosenIndex = 0
-- controllo indici
if nIndex1 == 0 and nIndex2 == 0 then
dChosenIndex = 0
elseif nIndex1 == 0 then
-- basta che sia applicabile
if AvailableStrategies[nIndex2].RatingResult and ( AvailableStrategies[nIndex2].RatingResult.Status == 'Completed' or AvailableStrategies[nIndex2].RatingResult.Status == 'Not-Completed') then
dChosenIndex = nIndex2
end
elseif nIndex2 == 0 then
-- basta che sia applicabile
if AvailableStrategies[nIndex1].RatingResult and ( AvailableStrategies[nIndex1].RatingResult.Status == 'Completed' or AvailableStrategies[nIndex1].RatingResult.Status == 'Not-Completed') then
dChosenIndex = nIndex1
end
elseif not AvailableStrategies[nIndex1].RatingResult or not AvailableStrategies[nIndex2].RatingResult then
dChosenIndex = 0
elseif ( AvailableStrategies[nIndex1].RatingResult.Status == 'Completed' and AvailableStrategies[nIndex2].RatingResult.Status ~= 'Completed') or
( AvailableStrategies[nIndex1].RatingResult.Status == 'Not-Completed' and AvailableStrategies[nIndex2].RatingResult.Status == 'Not-Applicable') then
dChosenIndex = nIndex1
elseif ( AvailableStrategies[nIndex2].RatingResult.Status == 'Completed' and AvailableStrategies[nIndex1].RatingResult.Status ~= 'Completed') or
( AvailableStrategies[nIndex2].RatingResult.Status == 'Not-Completed' and AvailableStrategies[nIndex1].RatingResult.Status == 'Not-Applicable') then
dChosenIndex = nIndex2
else
-- se le due strategie hanno stesso stato e sono entrambe applicabili (quindi entrambe complete o entrambe non-complete)
if AvailableStrategies[nIndex1].RatingResult.Status ~= 'Not-Applicable' and AvailableStrategies[nIndex2].RatingResult.Status ~= 'Not-Applicable' and
AvailableStrategies[nIndex1].RatingResult.Status == AvailableStrategies[nIndex2].RatingResult.Status then
local dCompositeRatingStrategy1 = AvailableStrategies[nIndex1].RatingResult.Rating + AvailableStrategies[nIndex1].RatingResult.CompletionIndex
local dCompositeRatingStrategy2 = AvailableStrategies[nIndex2].RatingResult.Rating + AvailableStrategies[nIndex2].RatingResult.CompletionIndex
-- si predilige strategia con rating composito più alto
if dCompositeRatingStrategy1 > dCompositeRatingStrategy2 then
dChosenIndex = nIndex1
elseif dCompositeRatingStrategy2 > dCompositeRatingStrategy1 then
dChosenIndex = nIndex2
-- altrimenti si prende la strategia con indice più basso
else
dChosenIndex = EgtIf( nIndex1 < nIndex2, nIndex1, nIndex2)
end
end
end
return dChosenIndex
end
-------------------------------------------------------------------------------------------------------------
-- funzione che processa tutte le feature sul pezzo e trova la miglior strategia di lavorazione tra quelle disponibili
local function GetBestStrategy( vProcSingleRot, Part)
-- per ogni feature
for i = 1, #vProcSingleRot do
-- processo tutte le feature attive
local Proc = vProcSingleRot[i]
if Proc.Flg ~= 0 then
-- controllo se ci sono strategie disponibili
if Proc.AvailableStrategies and #Proc.AvailableStrategies > 0 then
local nIndexBestStrategy = 0
-- ciclo tutte le strategie della feature
for nIndexCurrentStrategy = 1, #Proc.AvailableStrategies do
-- eseguo file config con i parametri di default
local CurrentStrategy = {}
CurrentStrategy = RunStrategyLibraries( Proc.AvailableStrategies[nIndexCurrentStrategy].StrategyId)
-- 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
Proc.AvailableStrategies[nIndexCurrentStrategy].RatingResult = CurrentStrategy.Script.Make( false, Proc, Part, Proc.AvailableStrategies[nIndexCurrentStrategy].Parameters)
-- scelgo la migliore strategia tra le due
nIndexBestStrategy = GetIndexBestStrategyFromComparison( Proc.AvailableStrategies, nIndexCurrentStrategy, nIndexBestStrategy)
-- se scelta strategia standard, esco subito alla prima che trovo completa
-- TODO serve paraemtro da Beam&Wall ( oppure da confirgurazione) !!!!!!!!
if BEAM.GetFirstCompletedStrategy and nIndexBestStrategy > 0 then
if Proc.AvailableStrategies[nIndexBestStrategy].RatingResult.Status == 'Complete' then
break
end
end
-- se non trovo i file della strategia, scrivo che non è più disponibile
else
Proc.AvailableStrategies[nIndexCurrentStrategy].RatingResult = {}
Proc.AvailableStrategies[nIndexCurrentStrategy].RatingResult.Info = 'Strategy not found'
end
end
-- salvo sulla proc la migliore strategia
if nIndexBestStrategy ~= 0 then
Proc.ChosenStrategy = Proc.AvailableStrategies[nIndexBestStrategy]
end
end
end
end
return vProcSingleRot
end
-------------------------------------------------------------------------------------------------------------
-- esegue le strategie migliori che ha precedentemente scelto
local function ExecPieceFeatures( vProc, Part)
-- applico le strategie scelte
for i = 1, #vProc do
-- processo tutte le feature attive applicando le lavorazioni
local Proc = vProc[i]
if Proc.Flg ~= 0 and Proc.ChosenStrategy then
-- carico file script strategia (non serve verificare presenza del file perchè già fatto durante scelta strategia)
local StrategyScriptName = '\\Strategies\\' .. Proc.ChosenStrategy.StrategyId .. '\\' .. Proc.ChosenStrategy.StrategyId
local StrategyScript = require( StrategyScriptName)
-- eseguo la strategia e si applicano le lavorazioni. Si passa la Proc e i parametri personalizzati
Proc = StrategyScript.Make( true, Proc, Part, Proc.ChosenStrategy.Parameters)
end
end
return vProc
end
-------------------------------------------------------------------------------------------------------------
local function PrintFeatures( vProc, Part)
EgtOutLog( ' RawBox=' .. tostring( Part.RawBox))
for i = 1, #vProc do
local Proc = vProc[i]
local sOut = string.format( ' Id=%3d Grp=%1d Prc=%3d TC=%2d/%d Flg=%2d Down=%s Side=%s Head=%s Tail=%s Fcse=%1d,%1d Diam=%.2f Fct=%2d Box=%s TopoName=%s',
Proc.Id, Proc.Grp, Proc.Prc, Proc.TaskId, Proc.CutId,
Proc.Flg, EgtIf( Proc.Down, 'T', 'F'), EgtIf( Proc.Side, 'T', 'F'),
EgtIf( Proc.Head, 'T', 'F'), EgtIf( Proc.Tail, 'T', EgtIf( Proc.AdvTail, 'A', 'F')),
Proc.Fcs, Proc.Fce, Proc.Diam, Proc.Fct, tostring( Proc.Box), Proc.Topology.Name or '')
-- info speciali per Block Haus Half Lap
if Proc.Prc == 37 then
local sSpec = string.format( ' N=%s Hd=%s', tostring( Proc.vtN or V_NULL()), EgtIf( Proc.HeadDir, 'T', 'F'))
sOut = sOut .. sSpec
end
EgtOutLog( sOut)
end
end
-------------------------------------------------------------------------------------------------------------
function BeamExec.ProcessFeatures()
-- ciclo sui pezzi
local nTotErr = 0
local Stats = {}
local nOrd = 1
local Part = {}
Part.IdRaw = EgtGetFirstRawPart()
while Part.IdRaw do
-- verifico che il grezzo contenga pezzi oppure sia abbastanza lungo da essere scaricato coi carrelli
local nPartId = EgtGetFirstPartInRawPart( Part.IdRaw)
Part.RawBox = EgtGetRawPartBBox( Part.IdRaw)
if not nPartId and Part.RawBox:getDimX() < BeamData.MinRaw then break end
-- per ogni rotazione, calcolo come lavorare le feature per decidere posizionamento iniziale e in che rotazione verranno lavorate le singole feature
local vProcRot = {}
-- lista contenente le feature da eseguire
local vProc = {}
-- TODO da rimuovere o lasciare solo per debug
if EgtGetDebugLevel() >= 3 then
EgtStartCounter()
end
-- TODO Il numero di rotazioni da calcolare deve dipendere dalle impostazionei del cliente. Per adesso si calcolano tutte e 4, ma può essere ottimizzato
for dRotIndex = 1, 4 do
-- recupero le feature di lavorazione della trave
table.insert( vProcRot, CollectFeatures( nPartId, Part))
-- recupero informazioni ausiliarie feature e dipendenze tra feature stesse
-- TODO le dipendenze cambiano in base alla rotazione del pezzo? probabilmente no
vProcRot[dRotIndex] = GetFeatureInfoAndDependency( vProcRot[dRotIndex], Part)
-- sceglie la strategia migliore tra quelle disponibili ( presenti nella tabella vProcRot[dRotIndex].AvailableStrategies)
vProcRot[dRotIndex] = GetBestStrategy( vProcRot[dRotIndex], Part)
-- ruoto il grezzo per calcolare la fattibilità delle lavorazioni nella prossima rotazione
-- vettore movimento grezzi per rotazione di 90deg ogni step
local dDeltaYZ = Part.RawBox:getDimY() - Part.RawBox:getDimZ()
local vtMove = Vector3d( 0, dDeltaYZ / 2 * EgtIf( BeamData.RIGHT_LOAD, -1, 1), dDeltaYZ / 2)
local bPreMove = ( dDeltaYZ < 0)
-- ruoto le travi della fase corrente
if bPreMove then
EgtMoveRawPart( Part.IdRaw, vtMove)
end
EgtRotateRawPart( Part.IdRaw, X_AX(), EgtIf( BeamData.RIGHT_LOAD, -90, 90))
if not bPreMove then
EgtMoveRawPart( Part.IdRaw, vtMove)
end
-- aggiorno info pezzo
Part.RawBox = EgtGetRawPartBBox( Part.IdRaw)
end
-- TODO da rimuovere o lasciare solo per debug
if EgtGetDebugLevel() >= 3 then
local time = EgtStopCounter()
end
-- TODO decidere come lavorare ogni feature in base alla matrice delle rotazioni
-- la matrice delle rotazioni deve già salvare sulla proc la strategia da utilizzare
-- Conviene salvarsi tutti i dati fino alla lavorazione e il ciclo di applicazione va ad applicare senza calcolare?
-- aggiungo la fase, se non è la prima
if nOrd == 1 then
EgtSetCurrPhase( 1)
else
BeamLib.AddPhaseWithRawParts( Part, BeamData.OriXR, BeamData.PosXR, 0)
end
local nPhase = EgtGetCurrPhase()
local nDispId = EgtGetPhaseDisposition( nPhase)
EgtSetInfo( nDispId, 'TYPE', EgtIf( nPartId, 'START', 'REST'))
EgtSetInfo( nDispId, 'ORD', nOrd)
EgtOutLog( ' *** Phase=' .. tostring( nPhase) .. ' Raw=' .. tostring( Part.IdRaw) .. ' Part=' .. tostring( nPartId) .. ' ***', 1)
-- debug
if EgtGetDebugLevel() >= 1 then
PrintFeatures( vProc, Part)
end
EgtOutLog( ' *** AddMachinings ***', 1)
-- TODO ordinare feature e decidere spezzoni
-- ordino le features
-- OrderFeatures( vProc, Part)
-- TODO da fare
-- esegue le strategie migliori che ha precedentemente scelto
ExecPieceFeatures( vProc, Part)
-- TODO riordinare lavorazioni ottimizzando cambio utensile/spezzone ecc..., mantenendo dipendenze definite prima
-- ordino le lavorazioni
-- OrderMachining( vProc, Part)
EgtOutLog( ' *** End AddMachinings ***', 1)
-- passo al grezzo successivo
nOrd = nOrd + 1
Part.IdRaw = EgtGetNextRawPart( Part.IdRaw)
end
return ( nTotErr == 0), Stats
end
-------------------------------------------------------------------------------------------------------------
return BeamExec