e0d1a2905d
- in BeamExec lettura JSON modifiche per allineamento con interfaccia. Il nome del JSON al momento si legge da BeamData ma andrà modificato
1767 lines
86 KiB
Lua
1767 lines
86 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 FeatureLib = require( 'FeatureLib')
|
|
local FaceData = require( 'FaceData')
|
|
local MachiningLib = require( 'MachiningLib')
|
|
local Logs = require( 'Logs')
|
|
|
|
|
|
EgtOutLog( ' BeamExec started', 1)
|
|
EgtMdbSetGeneralParam( MCH_GP.MAXDEPTHSAFE, BeamData.COLL_SIC)
|
|
EgtMdbSave()
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** variabili globali ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
TOOLS = {} -- tabella contenente tutti gli utensili
|
|
STRATEGIES = nil -- tabella contenente le strategie disponibili per ogni feature
|
|
STRATEGIES_CONFIG = {} -- tabella contenente i parametri di default delle strategie disponibili
|
|
MACHININGS = {} -- tabella contenente le lavorazioni da applicare
|
|
MACHININGS.Info = {}
|
|
PROCESSINGS = {} -- tabella contenente tutte le informazioni di ogni feature, processate per ogni rotazione
|
|
RESULT = {} -- tabella contenente il risultato, feature per feature, dell'applicazione della strategia scelta e il resoconto dell'analisi fatta
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** 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.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 BeamExec.GetToolsFromDB()
|
|
-- 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
|
|
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)
|
|
Tool.sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD)
|
|
Tool.SetupInfo = {}
|
|
Tool.SetupInfo = BeamData.GetSetupInfo( Tool.sHead)
|
|
if not Tool.SetupInfo.GetMinNzDownUp then
|
|
Tool.SetupInfo.GetMinNzDownUp = BeamLib.GetMinNzDownUpDefault
|
|
end
|
|
if not Tool.SetupInfo.GetMinNz then
|
|
Tool.SetupInfo.GetMinNz = BeamLib.GetMinNzDefault
|
|
end
|
|
if not Tool.SetupInfo.GetMaxNz then
|
|
Tool.SetupInfo.GetMaxNz = BeamLib.GetMaxNzDefault
|
|
end
|
|
if not Tool.SetupInfo.dMaxMatDecrease then
|
|
Tool.SetupInfo.dMaxMatDecrease = 0
|
|
end
|
|
-- TODO sostituire la qualità numerica con una stringa??
|
|
Tool.nQuality = 1
|
|
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', 'd')
|
|
Tool.bIsProfiledTool = not EgtTdbIsCurrToolStandardDraw()
|
|
|
|
-- 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.sType == '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', 'd') 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', 'd') or ( Tool.dMaxMaterial / 3) -- se non settato nell'utensile, considero un terzo del tagliente
|
|
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP', 'd') or floor( Tool.dDiameter / 3) -- se non settato nell'utensile, considero un terzo del diametro
|
|
Tool.bIsPen = abs( Tool.dSpeed) < 5
|
|
Tool.dPerformanceIndex = ( Tool.dDiameter * Tool.dMaxMaterial) / Tool.dLength
|
|
Tool.nQuality = 4
|
|
-- recupero parametri propri delle lame
|
|
elseif sToolFamily == 'SAWBLADE' then
|
|
Tool.bIsUsedForLongCut = EgtGetValInNotes( Tool.sUserNotes, 'LONGCUT') == 1 or false -- false come valore di default
|
|
Tool.dStep = EgtGetValInNotes( Tool.sUserNotes, 'STEP', 'd') or Tool.dThickness -- se non settato nell'utensile, considero lo spessore lama
|
|
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP', 'd') or Tool.dMaxMaterial -- se non settato nell'utensile, considero un quarto del diametro
|
|
Tool.dPerformanceIndex = 1 / ( Tool.dDiameter * Tool.dLength)
|
|
Tool.nQuality = 5
|
|
-- 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', 'd') or floor( Tool.dMaxMaterial / 3) -- se non settato nell'utensile, considero un terzo della lunghezza
|
|
Tool.dSideStep = EgtGetValInNotes( Tool.sUserNotes, 'SIDESTEP', 'd') 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
|
|
Tool.dPerformanceIndex = 1 / Tool.dLength
|
|
Tool.nQuality = 2
|
|
end
|
|
-- drillbit
|
|
else
|
|
Tool.dPerformanceIndex = Tool.dDiameter / Tool.dLength
|
|
Tool.nQuality = 4
|
|
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
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
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\\AISetup\\' .. 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 FeatureList = {}
|
|
FeatureList = ImportFileJSON( sFile)
|
|
|
|
-- metto la tabella letta nella lista globale STRATEGIES
|
|
STRATEGIES = {}
|
|
STRATEGIES.FeatureList = FeatureList
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che controlla validità delle combinazioni proposte
|
|
local function IsCombinationAvailable( sCombination, nUnloadPos, bSquareSection)
|
|
-- se non utilizzo BEAMWALL, forzo comportamento BASIC
|
|
if not BEAM.BeamWall or not BEAM.Rotation then
|
|
BEAM.Rotation = {}
|
|
BEAM.Rotation.Basic = true
|
|
end
|
|
|
|
--------------------------------------------------------------------------
|
|
-- TODO scelta combinazione forzato DA RIMUOVERE!! Serve modifica al BEAM.
|
|
BEAM.BeamWall = true
|
|
BEAM.Rotation = {}
|
|
BEAM.Rotation.bBasic = false
|
|
BEAM.Rotation.bNoRotation = false
|
|
BEAM.Rotation.bAdvanced = true
|
|
--------------------------------------------------------------------------
|
|
|
|
-- BASIC : posizione di scarico come posizionamento iniziale
|
|
if not BEAM.BeamWall or BEAM.Rotation.bBasic then
|
|
local ExtraRotation = nUnloadPos + 3
|
|
if nUnloadPos ~= 1 then
|
|
return false
|
|
elseif string.sub( sCombination, nUnloadPos, nUnloadPos) == '1' and string.sub( sCombination, ExtraRotation, ExtraRotation) == '0' then
|
|
if not BeamData.ROT90 and string.sub( sCombination, nUnloadPos+1, nUnloadPos+1) == '1' then
|
|
return false
|
|
elseif not BeamData.ROT180 and string.sub( sCombination, nUnloadPos+2, nUnloadPos+2) == '1' then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
else
|
|
return false
|
|
end
|
|
-- NO ROTATION : solo posizione di partenza
|
|
elseif BEAM.Rotation.bNoRotation then
|
|
if sCombination == '1000' and nUnloadPos == 1 then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
-- ADVANCED : come BASIC ma ammesse anche le prerotazioni (posizione di scarico può essere diversa da posizione iniziale)
|
|
elseif BEAM.Rotation.bAdvanced then
|
|
local nRotation90 = EgtIf( nUnloadPos + 1 > 4, nUnloadPos + 1 - 4, nUnloadPos + 1)
|
|
local nRotation180 = EgtIf( nUnloadPos + 2 > 4, nUnloadPos + 2 - 4, nUnloadPos + 2)
|
|
local nExtraRotation = EgtIf( nUnloadPos + 3 > 4, nUnloadPos + 3 - 4, nUnloadPos + 3)
|
|
|
|
if not bSquareSection and ( nUnloadPos == 2 or nUnloadPos == 4) then
|
|
return false
|
|
else
|
|
if string.sub( sCombination, nUnloadPos, nUnloadPos) ~= '1' or string.sub( sCombination, nExtraRotation, nExtraRotation) == '1' then
|
|
return false
|
|
else
|
|
if not BeamData.ROT90 and string.sub( sCombination, nRotation90, nRotation90) == '1' then
|
|
return false
|
|
elseif not BeamData.ROT180 and string.sub( sCombination, nRotation180, nRotation180) == '1' then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function BeamExec.GetAvailableCombinations( PartInfo)
|
|
local CombinationList = {}
|
|
CombinationList.Rotations = {0, 0, 0, 0} -- indice rotazione attiva, per calcolo collect feature
|
|
|
|
-- verifico tutte le combinazioni che possono essere considerate
|
|
for nUnloadPos = 1, 4 do
|
|
for i = 1, BeamLib.BinaryToDecimal( 1111) do
|
|
local nBitIndexCombination = BeamLib.DecimalToBinary( i)
|
|
local sBitIndexCombination = BeamLib.CalculateStringBinaryFormat( nBitIndexCombination, 4)
|
|
-- si calcolano le combinazioni all'inizio, ottimizzando calcolo della collect solo nelle rotazioni che possono essere considerate
|
|
if IsCombinationAvailable( sBitIndexCombination, nUnloadPos, PartInfo.bSquareSection) then
|
|
local Combination = {}
|
|
Combination.sBitIndexCombination = sBitIndexCombination
|
|
Combination.nUnloadPos = nUnloadPos
|
|
table.insert( CombinationList, Combination)
|
|
|
|
-- se posizionamento iniziale attivo
|
|
if string.sub( sBitIndexCombination, 1, 1) == '1' then
|
|
CombinationList.Rotations[1] = 1
|
|
end
|
|
-- se attiva rotazione 90
|
|
if string.sub( sBitIndexCombination, 2, 2) == '1' then
|
|
CombinationList.Rotations[2] = 1
|
|
end
|
|
-- se attiva rotazione 180
|
|
if string.sub( sBitIndexCombination, 3, 3) == '1' then
|
|
CombinationList.Rotations[3] = 1
|
|
end
|
|
-- se attiva rotazione 270
|
|
if string.sub( sBitIndexCombination, 4, 4) == '1' then
|
|
CombinationList.Rotations[4] = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return CombinationList
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** funzioni posizionamento pezzi all'interno della barra ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, bCreateMachGroup)
|
|
-- 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 (di default va creato)
|
|
if bCreateMachGroup == nil then
|
|
bCreateMachGroup = true
|
|
end
|
|
if bCreateMachGroup then
|
|
local sMgName = EgtGetMachGroupNewName( 'Mach_1')
|
|
local idNewMg = EgtAddMachGroup( sMgName)
|
|
if not idNewMg 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.ptOriXR = Point3d( b3Tab:getDimX(), dPosY, 0)
|
|
BeamData.dPosXR = EgtIf( BeamData.RIGHT_LOAD, MCH_CR.BR, MCH_CR.TR)
|
|
|
|
-- Impostazione dell'attrezzaggio di default
|
|
EgtImportSetup()
|
|
|
|
-- Inserimento dei pezzi con il loro grezzo
|
|
local nCnt = 0
|
|
local dLen = dRawL
|
|
local idPrevRaw, dPrevDelta
|
|
local dDeltaS = dOvmHead
|
|
local dDeltaSMin = 0
|
|
local dDeltaE = BeamData.OVM_MID
|
|
for i = 1, #PARTS do
|
|
-- dati del pezzo
|
|
local b3BoxExact = EgtGetBBoxGlob( PARTS[i].id or GDB_ID.NULL, GDB_BB.EXACT)
|
|
if b3BoxExact:isEmpty() or PARTS[i].b3PartOriginal:isEmpty() then break end
|
|
EgtOutLog( 'PartSez=' .. EgtNumToString( b3BoxExact:getDimY(), 1) .. 'x' .. EgtNumToString( b3BoxExact:getDimZ(), 1), 3)
|
|
-- se sezione compatibile e lunghezza disponibile sufficiente
|
|
local dPartLen = PARTS[i].b3PartOriginal:getDimX()
|
|
local dPartWidth = PARTS[i].b3PartOriginal:getDimY()
|
|
local dPartHeight = PARTS[i].b3PartOriginal:getDimZ()
|
|
local dNextLen = dLen - EgtIf( i == 1, dDeltaS, 0) - dPartLen - dDeltaE
|
|
if (( abs( dPartWidth - dRawW) < 100 * GEO.EPS_SMALL and abs( dPartHeight - dRawH) < 100 * GEO.EPS_SMALL) or
|
|
( abs( dPartHeight - dRawW) < 100 * GEO.EPS_SMALL and abs( dPartWidth - dRawH) < 100 * GEO.EPS_SMALL)) and
|
|
dNextLen + dDeltaE >= 0 then
|
|
-- eventuale sovramateriale di testa
|
|
if i > 1 then
|
|
if PARTS[i].dPosX then
|
|
dDeltaS = max( PARTS[i].dPosX - ( dRawL - dLen), dDeltaSMin)
|
|
else
|
|
dDeltaS = max( dOvmMid - dDeltaE, 0)
|
|
end
|
|
end
|
|
-- dimensioni del grezzo
|
|
local dCrawLen = min( dPartLen + dDeltaS + dDeltaE, dLen)
|
|
local dDelta = dCrawLen - dPartLen - dDeltaS
|
|
-- creo e posiziono il grezzo
|
|
PARTS[i].idRaw = EgtAddRawPart( Point3d(0,0,0), dCrawLen, dRawW, dRawH, BeamData.RAWCOL)
|
|
|
|
EgtMoveToCornerRawPart( PARTS[i].idRaw, BeamData.ptOriXR, BeamData.dPosXR)
|
|
EgtMoveRawPart( PARTS[i].idRaw, Vector3d( dLen - dRawL, 0, 0))
|
|
-- assegno ordine in lavorazione
|
|
nCnt = nCnt + 1
|
|
EgtSetInfo( PARTS[i].idRaw, 'ORD', nCnt)
|
|
-- creo o pulisco gruppo geometrie aggiuntive
|
|
if not BeamLib.CreateOrEmptyAddGroup( PARTS[i].id) then
|
|
local sOut = 'Error creating Additional Group in Part ' .. tostring( PARTS[i].id)
|
|
return false, sOut
|
|
end
|
|
-- aggiungo faccia per taglio iniziale al pezzo
|
|
BeamLib.AddPartStartFace( PARTS[i].id, PARTS[i].b3PartOriginal)
|
|
-- se sovramateriale di testa, lo notifico
|
|
if dDeltaS > 0.09 then
|
|
EgtSetInfo( PARTS[i].idRaw, 'HOVM', dDeltaS)
|
|
if idPrevRaw then
|
|
EgtSetInfo( idPrevRaw, 'BDST', dDeltaS + dPrevDelta)
|
|
end
|
|
end
|
|
if dDeltaE > 0.09 then
|
|
EgtSetInfo( PARTS[i].idRaw, 'TOVM', dDeltaE)
|
|
end
|
|
-- aggiungo faccia per taglio finale al pezzo
|
|
BeamLib.AddPartEndFace( PARTS[i].id, PARTS[i].b3PartOriginal)
|
|
-- inserisco il pezzo nel grezzo
|
|
EgtDeselectPartObjs( PARTS[i].id)
|
|
local ptPos = b3BoxExact:getMin() - PARTS[i].b3PartOriginal:getMin() + Vector3d( dDelta, ( dRawW - dPartWidth) / 2, ( dRawH - dPartHeight) / 2)
|
|
EgtAddPartToRawPart( PARTS[i].id, ptPos, PARTS[i].idRaw)
|
|
if abs( dPartWidth - dRawW) > 100 * GEO.EPS_SMALL then
|
|
-- rotazione attorno a centro geometria complessiva del pezzo
|
|
EgtRotatePartInRawPart( PARTS[i].id, X_AX(), 90)
|
|
-- correggo per eccentricità solido rispetto a geometria complessiva del pezzo
|
|
local vtEccOri = PARTS[i].b3PartOriginal:getCenter() - b3BoxExact:getCenter()
|
|
local vtEccRot = Vector3d( vtEccOri)
|
|
vtEccRot:rotate( X_AX(), 90)
|
|
EgtMovePartInRawPart( PARTS[i].id, ( vtEccOri - vtEccRot))
|
|
end
|
|
-- aggiorno la lunghezza residua della barra
|
|
dLen = dLen - dCrawLen
|
|
-- aggiorno grezzo precedente
|
|
idPrevRaw = PARTS[i].idRaw
|
|
dPrevDelta = dDelta
|
|
PARTS[i].bIsLastPart = ( i == #PARTS)
|
|
PARTS[i].dDistanceToNextPiece = dDelta
|
|
PARTS[i].dRestLength = dLen
|
|
PARTS[i].b3Raw = EgtGetRawPartBBox( PARTS[i].idRaw)
|
|
PARTS[i].dLength = PARTS[i].b3Raw:getDimX()
|
|
PARTS[i].dWidth = PARTS[i].b3Raw:getDimY()
|
|
PARTS[i].dHeight = PARTS[i].b3Raw:getDimZ()
|
|
PARTS[i].bSquareSection = abs( PARTS[i].dWidth - PARTS[i].dHeight) < 100 * GEO.EPS_SMALL
|
|
PARTS[i].b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[i].id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
PARTS[i].nIndexInParts = i
|
|
PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i])
|
|
PARTS[i].SplittingPoints = BeamLib.GetPartSplittingPoints( PARTS[i])
|
|
else
|
|
local sOut = 'Error: part L(' .. EgtNumToString( dPartLen, 1) .. ') too big for raw part L(' .. EgtNumToString( dLen - 0.1, 1) .. ')'
|
|
return false, sOut
|
|
end
|
|
-- se rimasto troppo poco grezzo, esco
|
|
--if Len < BeamData.MinRaw then break end
|
|
DeltaS = 0
|
|
end
|
|
if idPrevRaw then
|
|
EgtSetInfo( idPrevRaw, 'BDST', 10000)
|
|
end
|
|
|
|
-- Se rimasto materiale aggiungo grezzo dell'avanzo
|
|
-- TODO valutare se ridurre la dLen minima perchè crea discrepanze tra lunghezza inserita e VMill
|
|
if dLen > 10 then
|
|
local idRaw = EgtAddRawPart( Point3d(0,0,0), dLen, dRawW, dRawH, BeamData.RAWCOL)
|
|
EgtMoveToCornerRawPart( idRaw, BeamData.ptOriXR, BeamData.dPosXR)
|
|
EgtMoveRawPart( idRaw, Vector3d( dLen - dRawL, 0, 0))
|
|
-- assegno ordine in lavorazione
|
|
nCnt = nCnt + 1
|
|
EgtSetInfo( idRaw, 'ORD', nCnt)
|
|
-- aggiorno distanza dell'ultimo pezzo dall'eventuale grezzo scaricabile
|
|
if EgtGetRawPartBBox( idRaw):getDimX() < BeamData.dMinRaw then
|
|
PARTS[#PARTS].dDistanceToNextPiece = 10000
|
|
end
|
|
else
|
|
PARTS[#PARTS].dDistanceToNextPiece = 10000
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
|
|
-- TODO convertire in GetMinUnloadableRaw che viene richiamata all'inizio delle funzioni che necessitano di dMinRaw
|
|
if BeamData.GetMinUnloadableRaw then
|
|
BeamData.dMinRaw = BeamData.GetMinUnloadableRaw( dRawW, dRawH)
|
|
else
|
|
local H_S = 200
|
|
local H_L = 400
|
|
-- Determinazione minimo grezzo scaricabile
|
|
if dRawH <= H_S then
|
|
BeamData.dMinRaw = BeamData.MINRAW_S
|
|
elseif dRawH <= H_L then
|
|
local Coeff = ( dRawH - H_S) / ( H_L - H_S)
|
|
BeamData.dMinRaw = ( 1 - Coeff) * BeamData.MINRAW_S + Coeff * BeamData.MINRAW_L
|
|
else
|
|
BeamData.dMinRaw = BeamData.MINRAW_L
|
|
end
|
|
-- lettura minimo pezzo pinzabile
|
|
BeamData.dMinClampRaw = BeamData.LEN_VERY_SHORT_PART or 400
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- *** Inserimento delle lavorazioni nelle travi ***
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
local function GetStrategiesFromGlobalList( Proc)
|
|
-- cerco tra le feature
|
|
for i = 1, #STRATEGIES.FeatureList do
|
|
-- se trovo la feature
|
|
if Proc.nPrc == STRATEGIES.FeatureList[i].nPrc and Proc.nGrp == STRATEGIES.FeatureList[i].nGrp then
|
|
-- cerco tra le topologie
|
|
for j = 1, #STRATEGIES.FeatureList[i].TopologyList do
|
|
-- se trovo la topologia
|
|
if Proc.Topology.sName == STRATEGIES.FeatureList[i].TopologyList[j].sName then
|
|
-- ritorno le strategie disponibili per la feature che sto analizzando
|
|
return STRATEGIES.FeatureList[i].TopologyList[j].StrategyList
|
|
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.FeatureList > 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
|
|
-- si prepara tabella strategia. In questa fase si salva solo id strategia e il fatto che è stata forzata. I parametri forzati vengono letti all'esecuzioen della strategia
|
|
local StrategyToProc = {}
|
|
local ParamList = {}
|
|
ParamList.bForcedStrategy = true
|
|
ParamList.sStrategyId = sStrategyId
|
|
|
|
-- ritorno la lista strategia con parametri
|
|
table.insert( StrategyToProc, ParamList)
|
|
return StrategyToProc
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function CollectFeatures( Part)
|
|
-- recupero le feature
|
|
local nProcCount = 0
|
|
local vProc = {}
|
|
local LayerId = {}
|
|
LayerId[1] = BeamLib.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 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.idPart = Part.id
|
|
Proc.idRaw = Part.idRaw
|
|
Proc.nIndexPartInParts = Part.nIndexInParts
|
|
Proc.id = ProcId
|
|
-- id della feature btl ( se non presente info, si prende id dell'entità geometrica)
|
|
Proc.idFeature = EgtGetInfo( Proc.id, 'PRID', 's') or Proc.id
|
|
Proc.nGrp = nGrp
|
|
Proc.nPrc = nPrc
|
|
Proc.nFlg = 1
|
|
Proc.nFct = EgtSurfTmFacetCount( ProcId) or 0
|
|
Proc.idCut = EgtGetInfo( EgtGetParent( EgtGetParent( ProcId)), 'CUTID', 'i') or 0
|
|
Proc.idTask = EgtGetInfo( ProcId, 'TASKID', 'i') or 0
|
|
Proc.b3Box = EgtGetBBoxGlob( ProcId, GDB_BB.STANDARD)
|
|
EgtOutLog( '------Feature ' .. Proc.idFeature .. '------')
|
|
-- se esiste la geometria
|
|
if Proc.b3Box and not Proc.b3Box:isEmpty() then
|
|
-- informazioni facce e topologia
|
|
Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part)
|
|
-- calcolo topologia solo se necessario, altrimenti si sfruttano le informazioni della feature BTL
|
|
Proc.Topology = {}
|
|
local bIsFeatureReadyForProcessing = false
|
|
if FeatureLib.NeedTopologyFeature( Proc) then
|
|
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
|
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
|
Proc.Topology = FeatureLib.ClassifyTopology( Proc, Part)
|
|
-- se topologia feature riconosciuta, oppure da non calcolare perchè il riconoscimento topologico è basato sulla feature stessa
|
|
if Proc.Topology.sName ~= 'NOT_IMPLEMENTED' then
|
|
Proc.MainFaces = FaceData.GetMainFaces( Proc, Part)
|
|
bIsFeatureReadyForProcessing = true
|
|
end
|
|
else
|
|
Proc = FeatureLib.GetAdditionalInfo( Proc, Part)
|
|
Proc.Topology = FeatureLib.GetTopologyFromFeature( Proc, Part)
|
|
bIsFeatureReadyForProcessing = true
|
|
end
|
|
-- se la feature è stata compresa
|
|
if bIsFeatureReadyForProcessing then
|
|
-- 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
|
|
nProcCount = nProcCount + 1
|
|
Proc.nIndexInVProc = nProcCount
|
|
table.insert( vProc, Proc)
|
|
-- altrimenti errore (non ci sono strategie per lavorare la topologia riconosciuta)
|
|
else
|
|
Proc.nFlg = 0
|
|
nProcCount = nProcCount + 1
|
|
Proc.nIndexInVProc = nProcCount
|
|
table.insert( vProc, Proc)
|
|
EgtOutLog( ' Feature ' .. tostring( Proc.idFeature) .. ' : NO available strategies')
|
|
end
|
|
-- calcolo riduzione lunghezza pinzabile testa/coda
|
|
Proc.NotClampableLength = FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part)
|
|
-- si verifica se la feature, lavorata in questa fase, compromette lettura misura laser
|
|
Proc.bHindersLaserMeasure = FeatureLib.CalculateFeatureHindersLaserMeasure( Proc, Part)
|
|
-- altrimenti errore (serviva riconoscimento topologico, ma non è stato possibile farlo)
|
|
else
|
|
Proc.nFlg = 0
|
|
nProcCount = nProcCount + 1
|
|
Proc.nIndexInVProc = nProcCount
|
|
table.insert( vProc, Proc)
|
|
EgtOutLog( ' Feature ' .. tostring( Proc.idFeature) .. ' : NO available strategies')
|
|
end
|
|
else
|
|
Proc.nFlg = 0
|
|
nProcCount = nProcCount + 1
|
|
Proc.nIndexInVProc = nProcCount
|
|
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 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 ( BeamData.TWO_EQUAL_HEADS and AreSameVectorApprox( vtExtr, Y_AX())) or
|
|
( BeamData.DOWN_HEAD and AreOppositeVectorApprox( vtExtr, Y_AX())) then
|
|
nDouble = 2
|
|
-- fori lungo Z
|
|
elseif BeamData.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.b3Raw:getCenter()
|
|
if nDouble == 2 then
|
|
local dYMinDistance = max( Proc.b3Box:getMin():getY(), ProcMirror.b3Box:getMin():getY()) - min( Proc.b3Box:getMax():getY(), ProcMirror.b3Box: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.b3Box:getMin():getZ(), ProcMirror.b3Box:getMin():getZ()) - min( Proc.b3Box:getMax():getZ(), ProcMirror.b3Box: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.dLen - ProcMirror.dLen) > 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]
|
|
-- se feature abilitata alla lavorazione
|
|
if Proc.nFlg ~= 0 then
|
|
-- controllo la feature con tutte le altre per recuperare le dipendenze
|
|
for j = 1, #vProcSingleRot do
|
|
local ProcB = vProcSingleRot[j]
|
|
-- non si controlla la feature con se stessa o se feature disabilitata
|
|
if i ~= j and ProcB.nFlg ~= 0 then
|
|
-- TODO problemi di riferimenti a elementi della stessa tabella... spariscono le SubstitutedProc
|
|
-- verifico se il taglio può essere saltato perchè è nella stessa posizione del taglio di testa
|
|
if Proc.nPrc == 340 and ProcB.Topology.sFamily == 'Cut' and
|
|
AreSameVectorApprox( ProcB.Faces[1].vtN, X_AX()) and abs( ProcB.Faces[1].ptCenter:getX() - Part.b3Part:getMax():getX()) < 10 * GEO.EPS_SMALL then
|
|
if not Proc.SlaveProcIndexes then
|
|
Proc.SlaveProcIndexes = {}
|
|
end
|
|
table.insert( Proc.SlaveProcIndexes, j)
|
|
ProcB.nIndexMasterProc = i
|
|
ProcB.nFlg = 0
|
|
end
|
|
-- verifico se il taglio può essere saltato perchè è nella stessa posizione del taglio di coda
|
|
if Proc.nPrc == 350 and ProcB.Topology.sFamily == 'Cut' and
|
|
AreSameVectorApprox( ProcB.Faces[1].vtN, -X_AX()) and abs( ProcB.Faces[1].ptCenter:getX() - Part.b3Part:getMin():getX()) < 10 * GEO.EPS_SMALL then
|
|
if not Proc.SlaveProcIndexes then
|
|
Proc.SlaveProcIndexes = {}
|
|
end
|
|
table.insert( Proc.SlaveProcIndexes, j)
|
|
ProcB.nIndexMasterProc = i
|
|
ProcB.nFlg = 0
|
|
end
|
|
-- verifico se feature tipo LapJoint è attraversata da almeno un foro
|
|
if ( Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Tunnel' or Proc.Topology.sFamily == 'Groove' or ID.IsMortise( Proc)) and
|
|
ID.IsDrilling( ProcB) and Overlaps( Proc.b3Box, ProcB.b3Box) then
|
|
Proc.bPassedByHole = 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
|
|
end
|
|
return vProcSingleRot
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- caricamento librerie strategie (standard o speciali) se presenti nella Proc come strategie disponibili per questo Processing
|
|
local function RunStrategyLibraries( sStrategyId)
|
|
-- file script
|
|
local StrategyScriptName = sStrategyId .. '\\' .. sStrategyId
|
|
local StrategyScriptPathStandard = BEAM.BASEDIR .. '\\Strategies\\Standard\\' .. StrategyScriptName .. '.lua'
|
|
local StrategyScriptPathSpecial = BEAM.BASEDIR .. '\\Strategies\\Special\\' .. StrategyScriptName .. '.lua'
|
|
-- file config
|
|
local StrategyConfigName = sStrategyId .. '\\' .. sStrategyId .. '.json'
|
|
local StrategyConfigPathStandard = BEAM.BASEDIR .. '\\Strategies\\Standard\\' .. StrategyConfigName
|
|
local StrategyConfigPathSpecial = BEAM.BASEDIR .. '\\Strategies\\Special\\' .. StrategyConfigName
|
|
|
|
local StrategyLib = {}
|
|
if ( EgtExistsFile( StrategyConfigPathStandard) and EgtExistsFile( StrategyScriptPathStandard)) or
|
|
( EgtExistsFile( StrategyConfigPathSpecial) and EgtExistsFile( StrategyScriptPathSpecial)) then
|
|
-- caricamento script strategia come libreria
|
|
StrategyLib.Script = require( StrategyScriptName)
|
|
-- se config strategia non ancora caricato, importo il JSON
|
|
if not STRATEGIES_CONFIG[sStrategyId] then
|
|
if EgtExistsFile( StrategyConfigPathStandard) then
|
|
STRATEGIES_CONFIG[sStrategyId] = ImportFileJSON( StrategyConfigPathStandard)
|
|
else
|
|
STRATEGIES_CONFIG[sStrategyId] = ImportFileJSON( StrategyConfigPathSpecial)
|
|
end
|
|
end
|
|
StrategyLib.Config = STRATEGIES_CONFIG[sStrategyId]
|
|
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 == nIndex2 then
|
|
dChosenIndex = nIndex1
|
|
elseif nIndex1 == 0 then
|
|
-- basta che sia applicabile
|
|
if AvailableStrategies[nIndex2].Result and ( AvailableStrategies[nIndex2].Result.sStatus == 'Completed' or AvailableStrategies[nIndex2].Result.sStatus == 'Not-Completed') then
|
|
dChosenIndex = nIndex2
|
|
end
|
|
elseif nIndex2 == 0 then
|
|
-- basta che sia applicabile
|
|
if AvailableStrategies[nIndex1].Result and ( AvailableStrategies[nIndex1].Result.sStatus == 'Completed' or AvailableStrategies[nIndex1].Result.sStatus == 'Not-Completed') then
|
|
dChosenIndex = nIndex1
|
|
end
|
|
elseif not AvailableStrategies[nIndex1].Result or not AvailableStrategies[nIndex2].Result then
|
|
dChosenIndex = 0
|
|
elseif ( AvailableStrategies[nIndex1].Result.sStatus == 'Completed' and AvailableStrategies[nIndex2].Result.sStatus ~= 'Completed') or
|
|
( AvailableStrategies[nIndex1].Result.sStatus == 'Not-Completed' and AvailableStrategies[nIndex2].Result.sStatus == 'Not-Applicable') then
|
|
dChosenIndex = nIndex1
|
|
elseif ( AvailableStrategies[nIndex2].Result.sStatus == 'Completed' and AvailableStrategies[nIndex1].Result.sStatus ~= 'Completed') or
|
|
( AvailableStrategies[nIndex2].Result.sStatus == 'Not-Completed' and AvailableStrategies[nIndex1].Result.sStatus == '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].Result.sStatus ~= 'Not-Applicable' and AvailableStrategies[nIndex2].Result.sStatus ~= 'Not-Applicable' and
|
|
AvailableStrategies[nIndex1].Result.sStatus == AvailableStrategies[nIndex2].Result.sStatus then
|
|
local dCompositeRatingStrategy1 = AvailableStrategies[nIndex1].Result.dCompositeRating
|
|
local dCompositeRatingStrategy2 = AvailableStrategies[nIndex2].Result.dCompositeRating
|
|
-- 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 trova la strategia migliore tra quelle disponibili
|
|
local function GetBestStrategy( vProcSingleRot)
|
|
for i = 1, #vProcSingleRot do
|
|
-- processo tutte le feature attive
|
|
local Proc = vProcSingleRot[i]
|
|
if Proc.nFlg ~= 0 then
|
|
local nIndexBestStrategy = 0
|
|
-- controllo se ci sono strategie disponibili
|
|
if Proc.AvailableStrategies and #Proc.AvailableStrategies > 0 then
|
|
-- ciclo tutte le strategie della feature
|
|
for nIndexCurrentStrategy = 1, #Proc.AvailableStrategies do
|
|
-- scelgo la migliore strategia tra le due
|
|
nIndexBestStrategy = GetIndexBestStrategyFromComparison( Proc.AvailableStrategies, nIndexCurrentStrategy, nIndexBestStrategy)
|
|
-- salvo sulla proc la migliore strategia
|
|
end
|
|
if nIndexBestStrategy ~= 0 then
|
|
Proc.ChosenStrategy = Proc.AvailableStrategies[nIndexBestStrategy]
|
|
Proc.nIndexBestStrategy = nIndexBestStrategy
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return vProcSingleRot
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che processa tutte le feature del pezzo
|
|
local function CalculateStrategies( vProcSingleRot, Part)
|
|
-- per ogni feature
|
|
for i = 1, #vProcSingleRot do
|
|
-- processo tutte le feature attive
|
|
local Proc = vProcSingleRot[i]
|
|
if Proc.nFlg ~= 0 then
|
|
-- controllo se ci sono strategie disponibili
|
|
if Proc.AvailableStrategies and #Proc.AvailableStrategies > 0 then
|
|
-- 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].sStrategyId)
|
|
-- TODO in caso di ulteriore ciclo dovuto a errori imprevisti, controllare se questa strategia è quella che ha dato errore e disabilitarla senza calcolare nulla
|
|
-- controllo che le librerie siano state effettivamente caricate
|
|
if CurrentStrategy.Config and CurrentStrategy.Script then
|
|
-- eseguo la strategia solo come calcolo fattibilità e voto. Non si applicano le lavorazioni. Si passa la Proc e i parametri personalizzati
|
|
_, Proc.AvailableStrategies[nIndexCurrentStrategy].Result = CurrentStrategy.Script.Make( false, Proc, Part, Proc.AvailableStrategies[nIndexCurrentStrategy])
|
|
|
|
Proc.AvailableStrategies[nIndexCurrentStrategy].Result = FeatureLib.CalculateCompositeRating( Proc.AvailableStrategies[nIndexCurrentStrategy].Result)
|
|
-- se scelta strategia in modalità base o standard, esco subito alla prima che trovo completa
|
|
-- TODO serve parametro da Beam&Wall ( oppure da confirgurazione) !!!!!!!!
|
|
if BEAM.GetFirstCompletedStrategy and Proc.AvailableStrategies[nIndexCurrentStrategy].Result.sStatus == 'Complete' then
|
|
break
|
|
end
|
|
|
|
-- se non trovo i file della strategia (Script e Config), scrivo che non è più disponibile
|
|
else
|
|
Proc.AvailableStrategies[nIndexCurrentStrategy].Result = {}
|
|
Proc.AvailableStrategies[nIndexCurrentStrategy].Result.sInfo = 'Strategy not found'
|
|
Proc.AvailableStrategies[nIndexCurrentStrategy].Result.sStatus = 'Not-Applicable'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return vProcSingleRot
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- Ordina le feature in base a fase di lavorazione
|
|
-- 1) Head : ( intestatura)
|
|
-- 2) Standard : ( lavorazioni standard che non impattano sulla coda)
|
|
-- 3) AdvanceTail : ( lavorazioni che richiedono taglio di separazione, ma che devono essere fatte prima perchè il taglio di separazione farebbe cadere il pezzo)
|
|
-- 4) Split : ( taglio di separazione)
|
|
-- 5) Tail : ( lavorazioni di coda, fatte dopo il taglio di separazione)
|
|
local function OrderFeatures( vProc)
|
|
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 B2.nFlg ~= 0 and B1.nFlg == 0 then
|
|
return false
|
|
-- se entrambi disabilitati seguo l'Id
|
|
elseif B1.nFlg == 0 and B2.nFlg == 0 then
|
|
return ( B1.id < B2.id)
|
|
-- se in rotazioni diverse, si mette in ordine di rotazioni
|
|
elseif B1.nRot ~= B2.nRot then
|
|
return ( B1.nRot < B2.nRot)
|
|
-- se primo è taglio di testa, va prima degli altri casi
|
|
elseif B1.Head and ( B2.Standard or B2.AdvanceTail or B2.Split or B2.Tail) then
|
|
return true
|
|
-- se primo è taglio standard, va prima degli altri casi
|
|
elseif B1.Standard and ( B2.AdvanceTail or B2.Split or B2.Tail) then
|
|
return true
|
|
-- se primo è taglio di testa anticipata, va prima degli altri casi
|
|
elseif B1.AdvanceTail and ( B2.Split or B2.Tail) then
|
|
return true
|
|
-- se primo è taglio di separazione, va prima delle lavorazioni di coda
|
|
elseif B1.Split and B2.Tail then
|
|
return true
|
|
-- se da lavorare in stessa fase pezzo
|
|
elseif B1.Head == B2.Head or B1.Standard == B2.Standard or B1.AdvanceTail == B2.AdvanceTail or B1.Split == B2.Split or B1.Tail == B2.Tail then
|
|
-- confronto standard
|
|
if abs( B1.b3Box:getCenter():getX() - B2.b3Box:getCenter():getX()) > 0.4 * ( B1.b3Box:getDimX() + B2.b3Box:getDimX()) then
|
|
return B1.b3Box:getCenter():getX() > B2.b3Box:getCenter():getX()
|
|
elseif abs( B1.b3Box:getCenter():getY() - B2.b3Box:getCenter():getY()) > 0.2 * ( B1.b3Box:getDimY() + B2.b3Box:getDimY()) then
|
|
return B1.b3Box:getCenter():getY() > B2.b3Box:getCenter():getY()
|
|
elseif abs( B1.b3Box:getCenter():getZ() - B2.b3Box:getCenter():getZ()) > 0.1 * ( B1.b3Box:getDimZ() + B2.b3Box:getDimZ()) then
|
|
return B1.b3Box:getCenter():getZ() > B2.b3Box:getCenter():getZ()
|
|
end
|
|
-- 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 vProcToSort
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function AddFeatureResultToGlobalList( Proc, OptionalParameters)
|
|
local sStrategyId
|
|
local sStatus
|
|
local nCompletionIndex
|
|
local dCompositeRating
|
|
local sInfo
|
|
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local nRotation = OptionalParameters.nRotation or 1
|
|
|
|
if Proc.nIndexMasterProc then
|
|
sStrategyId = PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexMasterProc].ChosenStrategy.sStrategyId
|
|
sStatus = PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexMasterProc].ChosenStrategy.Result.sStatus
|
|
nCompletionIndex = PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexMasterProc].ChosenStrategy.Result.nCompletionIndex
|
|
dCompositeRating = PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexMasterProc].ChosenStrategy.Result.dCompositeRating
|
|
sInfo = PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexMasterProc].ChosenStrategy.Result.sInfo
|
|
elseif Proc.ChosenStrategy then
|
|
sStrategyId = Proc.ChosenStrategy.sStrategyId
|
|
sStatus = Proc.ChosenStrategy.Result.sStatus
|
|
nCompletionIndex = Proc.ChosenStrategy.Result.nCompletionIndex
|
|
dCompositeRating = Proc.ChosenStrategy.Result.dCompositeRating
|
|
sInfo = Proc.ChosenStrategy.Result.sInfo
|
|
end
|
|
|
|
RESULT[#RESULT+1] = {
|
|
sType = 'Feature',
|
|
id = Proc.id,
|
|
idFeature = Proc.idFeature,
|
|
idTask = Proc.idTask,
|
|
idCut = Proc.idCut,
|
|
nFlg = Proc.nFlg,
|
|
nRotation = nRotation,
|
|
idPart = Proc.idPart,
|
|
ChosenStrategy = {
|
|
sStrategyName = sStrategyId,
|
|
sStatus = sStatus,
|
|
nCompletionIndex = nCompletionIndex,
|
|
dCompositeRating = dCompositeRating,
|
|
sInfo = sInfo
|
|
}
|
|
}
|
|
-- scrivo le strategie disponibili solo se ne esistono
|
|
if Proc.AvailableStrategies then
|
|
RESULT[#RESULT].AvailableStrategies = BeamLib.TableCopyDeep( Proc.AvailableStrategies)
|
|
end
|
|
|
|
-- si segna nella Proc la sua posizione nel RESULT
|
|
Proc.nIndexInResult = #RESULT
|
|
|
|
return RESULT
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function AddApplyResultToGlobalList( nErr, idCut, sMsg)
|
|
RESULT[#RESULT+1] = {
|
|
sType = 'Part',
|
|
idCut = idCut,
|
|
idTask = 0,
|
|
nErr = nErr,
|
|
sMsg = sMsg
|
|
}
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- esegue le strategie migliori che ha precedentemente scelto
|
|
local function CalculateMachinings( vProc, Part, nInitialRotation)
|
|
local bAreAllApplyOk = true
|
|
local n0Rotation = nInitialRotation
|
|
local n90Rotation = nInitialRotation + 1
|
|
if n90Rotation > 4 then n90Rotation = n90Rotation - 4 end
|
|
local n180Rotation = nInitialRotation + 2
|
|
if n180Rotation > 4 then n180Rotation = n180Rotation - 4 end
|
|
local nCurrRotation = 1
|
|
-- applico le strategie scelte
|
|
for i = 1, #vProc do
|
|
-- processo tutte le feature attive applicando le lavorazioni
|
|
local Proc = vProc[i]
|
|
-- se la feature deve essere processata
|
|
if Proc.nFlg ~= 0 then
|
|
-- si sistemano i pezzi per le rotazioni
|
|
if Proc.bDown and nCurrRotation ~= n180Rotation then
|
|
BeamLib.RotateRawPart( Part, n180Rotation - nCurrRotation)
|
|
nCurrRotation = n180Rotation
|
|
elseif Proc.bSide and nCurrRotation ~= n90Rotation then
|
|
BeamLib.RotateRawPart( Part, n90Rotation - nCurrRotation)
|
|
nCurrRotation = n90Rotation
|
|
elseif nCurrRotation ~= n0Rotation and not( Proc.bSide) and not( Proc.bDown) then
|
|
BeamLib.RotateRawPart( Part, n0Rotation - nCurrRotation)
|
|
nCurrRotation = n0Rotation
|
|
end
|
|
-- aggiorno info pezzo
|
|
Part.b3Raw = EgtGetRawPartBBox( Part.idRaw)
|
|
Part.b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Part.id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
-- si applicano le strategie
|
|
if Proc.ChosenStrategy then
|
|
-- carico file script strategia (non serve verificare presenza del file perchè già fatto durante scelta strategia)
|
|
local StrategyScriptName = Proc.ChosenStrategy.sStrategyId .. '\\' .. Proc.ChosenStrategy.sStrategyId
|
|
local StrategyScript = require( StrategyScriptName)
|
|
-- eseguo la strategia e si applicano le lavorazioni. Si passa la Proc e i parametri personalizzati
|
|
_, _ = StrategyScript.Make( true, Proc, Part, Proc.ChosenStrategy)
|
|
-- se tutte le strategie disponibili non sono applicabili
|
|
else
|
|
-- se non esiste una strategia scelta (non dovrebbe mai succedere) cancello da lista generale
|
|
PROCESSINGS[Proc.nIndexPartInParts].Rotation[Proc.nIndexRotation][Proc.nIndexInVProc].ChosenStrategy = nil
|
|
|
|
-- TODO dare messaggio che la feature non 0è stata eseguita nonostante la presenza di strategie disponibili
|
|
|
|
end
|
|
end
|
|
-- scrivo risultato in tabella globale
|
|
AddFeatureResultToGlobalList( Proc, { nRotation = nCurrRotation})
|
|
end
|
|
|
|
-- ripristino pezzo in posizione originale
|
|
if nCurrRotation ~= 1 then
|
|
BeamLib.RotateRawPart( Part, 1 - nCurrRotation)
|
|
-- aggiorno info pezzo
|
|
Part.b3Raw = EgtGetRawPartBBox( Part.idRaw)
|
|
Part.b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Part.id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
end
|
|
return MACHININGS, bAreAllApplyOk
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function PrintFeatures( vProc, Part)
|
|
if vProc then
|
|
EgtOutLog( ' RawBox=' .. tostring( Part.b3Box))
|
|
for i = 1, #vProc do
|
|
local Proc = vProc[i]
|
|
local sOut = string.format( ' Id=%3d Grp=%1d Prc=%3d Flg=%2d Fct=%2d TopoName=%s',
|
|
Proc.id, Proc.nGrp, Proc.nPrc, Proc.nFlg, Proc.nFct, Proc.Topology.sName or '')
|
|
EgtOutLog( sOut)
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function BeamExec.GetProcessings( PARTS)
|
|
-- recupero tutti i processing di tutti i pezzi in tutte le rotazioni
|
|
-- TODO calcolo tempi da rimuovere o lasciare solo per debug
|
|
-- if EgtGetDebugLevel() >= 3 then
|
|
-- EgtStartCounter()
|
|
-- end
|
|
|
|
-- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola
|
|
EgtSetTableAreaOffset( 2000, 2000, 2000, 2000)
|
|
|
|
for nPart = 1, #PARTS do
|
|
if not PARTS[nPart].id and PARTS[nPart].b3Raw:getDimX() < BeamData.dMinRaw then break end
|
|
local vProcRot = {}
|
|
|
|
for dRotIndex = 1, 4 do
|
|
-- si calcolano le feature solo se la rotazione può essere presa in considerazione
|
|
if PARTS[nPart].CombinationList.Rotations[dRotIndex] == 1 then
|
|
-- recupero le feature di lavorazione della trave
|
|
table.insert( vProcRot, CollectFeatures( PARTS[nPart]))
|
|
|
|
-- 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], PARTS[nPart])
|
|
else
|
|
-- inserisco una tabella vuota
|
|
table.insert( vProcRot, {})
|
|
end
|
|
-- rotazione pezzo di 90° per volta
|
|
BeamLib.RotateRawPart( PARTS[nPart], 1)
|
|
-- aggiorno info pezzo
|
|
PARTS[nPart].b3Raw = EgtGetRawPartBBox( PARTS[nPart].idRaw)
|
|
PARTS[nPart].b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[nPart].id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
end
|
|
local Part = {}
|
|
Part.Rotation = vProcRot
|
|
-- recupero le feature di lavorazione della trave
|
|
table.insert( PROCESSINGS, Part)
|
|
end
|
|
-- TODO calcolo tempi da rimuovere o lasciare solo per debug
|
|
-- if EgtGetDebugLevel() >= 3 then
|
|
-- local timeGetProcessings = EgtStopCounter()
|
|
-- timeGetProcessings = timeGetProcessings + 0
|
|
-- EgtOutBox( timeGetProcessings, 'GetProcessings calculation time')
|
|
-- EgtStartCounter()
|
|
-- end
|
|
return PROCESSINGS
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che decide la migliore tra le combinazioni di rotazione disponibili
|
|
local function GetBestCombination( ListToCompare)
|
|
-- TODO da completare
|
|
local nIndexBestCombination = 1
|
|
if #ListToCompare == 1 then
|
|
nIndexBestCombination = 1
|
|
else
|
|
for ListIndex = 2, #ListToCompare do
|
|
local bBestComplete = ListToCompare[nIndexBestCombination].nNotComplete == 0 and ListToCompare[nIndexBestCombination].nNotExecute == 0
|
|
local bOtherComplete = ListToCompare[ListIndex].nNotComplete == 0 and ListToCompare[ListIndex].nNotExecute == 0
|
|
|
|
-- prediligo combinazione completa
|
|
if bBestComplete and not bOtherComplete then
|
|
; -- la migliore resta la stessa
|
|
elseif not bBestComplete and bOtherComplete then
|
|
nIndexBestCombination = ListIndex
|
|
-- altrimenti guardo il voto
|
|
else
|
|
-- si sceglie soluzione con più feature complete
|
|
if ListToCompare[ListIndex].nComplete > ListToCompare[nIndexBestCombination].nComplete then
|
|
nIndexBestCombination = ListIndex
|
|
-- se stesso voto
|
|
elseif ListToCompare[nIndexBestCombination].dTotalRating == ListToCompare[ListIndex].dTotalRating then
|
|
-- TODO il voto dovrebbe essere considerato già pesando le rotazioni, con un coefficiente o un peso fisso aggiuntivo
|
|
-- scelgo soluzione con meno rotazioni
|
|
if ListToCompare[nIndexBestCombination].nRotations > ListToCompare[ListIndex].nRotations then
|
|
nIndexBestCombination = ListIndex
|
|
-- se anche le rotazioni sono le stesse, prendo la soluzione con più lavorazioni alla fine
|
|
elseif #ListToCompare[nIndexBestCombination].Rot0 < #ListToCompare[ListIndex].Rot0 then
|
|
nIndexBestCombination = ListIndex
|
|
end
|
|
-- se voto diverso
|
|
else
|
|
-- scelgo soluzione con voto più alto
|
|
if ListToCompare[nIndexBestCombination].dTotalRating < ListToCompare[ListIndex].dTotalRating then
|
|
nIndexBestCombination = ListIndex
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ChosenCombination = ListToCompare[nIndexBestCombination]
|
|
return ChosenCombination
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che decide le combinazioni di rotazione per lavorare la trave
|
|
local function GetProcessingListFromCombination( BestCombination)
|
|
local vProc = {}
|
|
local ProcessingResult = {}
|
|
ProcessingResult.bSomeFeatureDown = false
|
|
ProcessingResult.bSomeFeatureSide = false
|
|
ProcessingResult.nInitialPosition = BestCombination.nIndexRotation
|
|
ProcessingResult.nIndexInCombinationList = BestCombination.nIndexInCombinationList
|
|
ProcessingResult.nIndexHeadCutInVProc = BestCombination.nIndexHeadCutInVProc
|
|
ProcessingResult.nIndexTailCutInVProc = BestCombination.nIndexTailCutInVProc
|
|
|
|
|
|
-- aggiungo processing da fare in fase ribaltata
|
|
if #BestCombination.Rot180 > 0 then
|
|
ProcessingResult.bSomeFeatureDown = true
|
|
for i = 1, #BestCombination.Rot180 do
|
|
BestCombination.Rot180[i].bDown = true
|
|
table.insert( vProc, BestCombination.Rot180[i])
|
|
end
|
|
end
|
|
|
|
-- aggiungo processing da fare in fase ruotata
|
|
if #BestCombination.Rot90 > 0 then
|
|
ProcessingResult.bSomeFeatureSide = true
|
|
for i = 1, #BestCombination.Rot90 do
|
|
BestCombination.Rot90[i].bSide = true
|
|
table.insert( vProc, BestCombination.Rot90[i])
|
|
end
|
|
end
|
|
|
|
-- aggiungo processing da fare in ultima fase
|
|
if #BestCombination.Rot0 > 0 then
|
|
for i = 1, #BestCombination.Rot0 do
|
|
table.insert( vProc, BestCombination.Rot0[i])
|
|
end
|
|
end
|
|
|
|
return vProc, ProcessingResult
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che ritorna la Proc nella rotazione scelta
|
|
local function GetProcBestMachRotationFromList( ListToCompare)
|
|
local Data = {}
|
|
local Proc = {}
|
|
local nIndexChosenProcInRot = 1
|
|
|
|
-- se ci sono almeno 2 possibili soluzioni, scelgo la posizione migliore di lavorazione
|
|
if #ListToCompare > 1 then
|
|
-- formatto lista strategie disponibili come se le aspetta la funzione di compare
|
|
local AvailableStrategiesInRot = {}
|
|
for i = 1, #ListToCompare do
|
|
table.insert( AvailableStrategiesInRot, ListToCompare[i][1].ChosenStrategy)
|
|
end
|
|
for nIndexCurrentStrategy = 1, #AvailableStrategiesInRot do
|
|
-- la scelta tra le differenti strategie tra le rotazioni utilizza gli stessi criteri della scelta strategie all'interno della feature stessa
|
|
nIndexChosenProcInRot = GetIndexBestStrategyFromComparison( AvailableStrategiesInRot, nIndexCurrentStrategy, nIndexChosenProcInRot)
|
|
end
|
|
-- altrimenti prendo la prima
|
|
else
|
|
nIndexChosenProcInRot = 1
|
|
end
|
|
|
|
Proc = ListToCompare[nIndexChosenProcInRot][1]
|
|
Data.nIndexRotation = ListToCompare[nIndexChosenProcInRot].nRotation
|
|
Data.dCompositeRating = ListToCompare[nIndexChosenProcInRot][1].ChosenStrategy.Result.dCompositeRating
|
|
Data.bComplete = ListToCompare[nIndexChosenProcInRot][1].ChosenStrategy.Result.sStatus == 'Completed'
|
|
Data.bNotComplete = ListToCompare[nIndexChosenProcInRot][1].ChosenStrategy.Result.sStatus == 'Not-Completed'
|
|
Data.bNotApplicable = ListToCompare[nIndexChosenProcInRot][1].ChosenStrategy.Result.sStatus == 'Not-Applicable'
|
|
return Proc, Data
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che calcola le combinazioni di rotazione per lavorare la trave e sceglie la migliore
|
|
local function GetBestResultFromCombinationsMatrix( ProcessingsOnPart, PartInfo)
|
|
local BestCombination = {}
|
|
local CombinationsList = {}
|
|
|
|
-- scrittura nel log della matrice delle rotazioni
|
|
if EgtGetDebugLevel() >= 3 then
|
|
Logs.WriteMatrixLog( ProcessingsOnPart, PartInfo)
|
|
end
|
|
|
|
-- per ogni posizione di scarico
|
|
for nUnloadPos = 1, 4 do
|
|
-- calcolo per tutte le combinazioni disponibili precedentemente verificate
|
|
for i = 1, #PartInfo.CombinationList do
|
|
-- controllo che la combinazione abbia ultima fase come quella calcolata in fase di definizione combinazioni
|
|
if PartInfo.CombinationList[i].nUnloadPos == nUnloadPos then
|
|
local bRot90, bRot180
|
|
local SingleCombination = {}
|
|
SingleCombination.nRotations = 0
|
|
SingleCombination.dTotalRating = 0
|
|
SingleCombination.nComplete = 0
|
|
SingleCombination.nNotComplete = 0
|
|
SingleCombination.nNotExecute = 0
|
|
SingleCombination.sBitIndexCombination = PartInfo.CombinationList[i].sBitIndexCombination
|
|
SingleCombination.nUnloadPos = nUnloadPos
|
|
-- creo liste dei proc suddivisi per rotazione
|
|
SingleCombination.Rot0 = {}
|
|
SingleCombination.Rot90 = {}
|
|
SingleCombination.Rot180 = {}
|
|
|
|
-- ciclo su tutte le feature, ad eccezione dei tagli testa/coda che dipendono dal risultato delle altre
|
|
-- tagli testa e coda vengono aggiunti sempre alla fine
|
|
for nProc = 1, #ProcessingsOnPart.Rotation[1] do
|
|
if ProcessingsOnPart.Rotation[1][nProc].nPrc ~= 340 and ProcessingsOnPart.Rotation[1][nProc].nPrc ~= 350 then
|
|
-- se feature disattivata perchè eseguita da master a lei associata dichiaro comunque eseguita
|
|
if ProcessingsOnPart.Rotation[1][nProc].nFlg == 0 and ProcessingsOnPart.Rotation[1][nProc].nIndexMasterProc then
|
|
ProcessingsOnPart.Rotation[1][nProc].nIndexRotation = nUnloadPos
|
|
table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[1][nProc])
|
|
SingleCombination.nComplete = SingleCombination.nComplete + 1
|
|
else
|
|
-- ciclo sulle rotazioni
|
|
local nNextRot = nUnloadPos
|
|
local ResultsList = {}
|
|
for nRotation = 1, 3 do
|
|
-- se rotazione abilitata da combinazione
|
|
if string.sub( PartInfo.CombinationList[i].sBitIndexCombination, nNextRot, nNextRot) == '1' then
|
|
-- se è ultima rotazione oppure se feature non impatta su misura laser, allora è valida e può essere effettivamente considerata
|
|
if nNextRot == nUnloadPos or not( ProcessingsOnPart.Rotation[nNextRot][nProc].bHindersLaserMeasure) then
|
|
-- controllo se è stata scelta una strategia
|
|
if ProcessingsOnPart.Rotation[nNextRot][nProc].ChosenStrategy then
|
|
local Proc = {}
|
|
Proc.nRotation = nNextRot
|
|
table.insert( Proc, ProcessingsOnPart.Rotation[nNextRot][nProc])
|
|
table.insert( ResultsList, Proc)
|
|
end
|
|
end
|
|
end
|
|
nNextRot = EgtIf( nNextRot + 1 > 4, nNextRot + 1 - 4, nNextRot + 1)
|
|
end
|
|
|
|
-- se la feature può essere lavorata in almeno una rotazione
|
|
if #ResultsList > 0 then
|
|
local Proc, Data = GetProcBestMachRotationFromList( ResultsList)
|
|
Proc.nIndexRotation = Data.nIndexRotation
|
|
-- inserisco la Proc nell'apposita lista
|
|
if Data.nIndexRotation == nUnloadPos then
|
|
table.insert( SingleCombination.Rot0, Proc)
|
|
elseif Data.nIndexRotation == nUnloadPos + 1 then
|
|
table.insert( SingleCombination.Rot90, Proc)
|
|
bRot90 = true
|
|
else
|
|
table.insert( SingleCombination.Rot180, Proc)
|
|
bRot180 = true
|
|
end
|
|
|
|
SingleCombination.dTotalRating = SingleCombination.dTotalRating + Data.dCompositeRating
|
|
SingleCombination.nComplete = SingleCombination.nComplete + EgtIf( Data.bComplete, 1, 0)
|
|
SingleCombination.nNotComplete = SingleCombination.nNotComplete + EgtIf( Data.bNotComplete, 1, 0)
|
|
SingleCombination.nNotExecute = SingleCombination.nNotExecute + EgtIf( Data.bNotApplicable, 1, 0)
|
|
SingleCombination.nIndexInCombinationList = i
|
|
SingleCombination.nIndexRotation = nUnloadPos
|
|
else
|
|
ProcessingsOnPart.Rotation[1][nProc].nIndexRotation = nUnloadPos
|
|
table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[1][nProc])
|
|
SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1
|
|
end
|
|
end
|
|
else
|
|
if ProcessingsOnPart.Rotation[1][nProc].nPrc == 340 then
|
|
SingleCombination.nIndexHeadCutInVProc = nProc
|
|
elseif ProcessingsOnPart.Rotation[1][nProc].nPrc == 350 then
|
|
SingleCombination.nIndexTailCutInVProc = nProc
|
|
end
|
|
end
|
|
end
|
|
-- aggiungo rotazioni
|
|
SingleCombination.nRotations = EgtIf( bRot90, 1, 0) + EgtIf( bRot180, 1, 0)
|
|
-- aggiungo la combinazione all'elenco delle combinazioni disponibili
|
|
table.insert( CombinationsList, SingleCombination)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ci deve essere almeno una combinazione, altrimenti errore
|
|
if #CombinationsList < 1 then
|
|
error( 'UNEXPECTED ERROR: NO combinations available')
|
|
end
|
|
BestCombination = GetBestCombination( CombinationsList)
|
|
|
|
-- scrittura nel log delle combinazioni possibili
|
|
if EgtGetDebugLevel() >= 3 then
|
|
Logs.WriteCombinationLog( CombinationsList, BestCombination)
|
|
end
|
|
|
|
local vFinalProc, BestCombinationResult = GetProcessingListFromCombination( BestCombination)
|
|
|
|
return vFinalProc, BestCombinationResult
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function BeamExec.ProcessMachinings( PARTS)
|
|
-- ciclo sui pezzi
|
|
local nTotErr = 0
|
|
local Stats = {}
|
|
local nOrd = 1
|
|
local ProcessCompleted = false
|
|
local nMaxLoops = 5
|
|
|
|
-- TODO da rimuovere o lasciare solo per debug
|
|
--if EgtGetDebugLevel() >= 3 then
|
|
-- EgtStartCounter()
|
|
--end
|
|
-- TODO da rimuovere o lasciare solo per debug
|
|
--if EgtGetDebugLevel() >= 3 then
|
|
-- local timeCollect = EgtStopCounter()
|
|
-- timeCollect = timeCollect + 0
|
|
-- EgtOutBox( timeCollect, 'Collect calculation time')
|
|
-- EgtStartCounter()
|
|
--end
|
|
-- TODO da rimuovere o lasciare solo per debug
|
|
--if EgtGetDebugLevel() >= 3 then
|
|
-- local timeMachining = EgtStopCounter()
|
|
-- timeMachining = timeMachining + 0
|
|
-- EgtOutBox( timeMachining, 'Machining calculation time')
|
|
--end
|
|
|
|
local nCurrLoop = 0
|
|
-- ciclo fino a che tutte le applicazioni delle lavorazioni sono corrette
|
|
while not ProcessCompleted do
|
|
-- aumento numero loop nel quale siamo
|
|
nCurrLoop = nCurrLoop + 1
|
|
-- ricerca strategia di lavorazione per ogni pezzo e applicazione lavorazioni
|
|
for nPart = 1, #PARTS do
|
|
-- si mette subito il pezzo nella fase
|
|
if nOrd == 1 then
|
|
EgtSetCurrPhase( 1)
|
|
else
|
|
BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, 0)
|
|
end
|
|
-- si sposta il pezzo nella posizione originale, di quando è stata fatta la collect. In questo modo tutti i dati calcolati nella collect restano validi.
|
|
-- Altrimenti bisognava ricalcolare tutto, aumentando tempo di calcolo.
|
|
local vtRawOffsetPos = PARTS[nPart].b3Raw:getMin() - EgtGetRawPartBBox( PARTS[nPart].idRaw):getMin()
|
|
local nRawId = PARTS[nPart].idRaw
|
|
while nRawId and abs( vtRawOffsetPos:len()) > 0 do
|
|
EgtKeepRawPart( nRawId)
|
|
EgtMoveRawPart( nRawId, vtRawOffsetPos)
|
|
nRawId = EgtGetNextRawPart( nRawId)
|
|
end
|
|
|
|
-- calcolo della migliore strategia per ogni rotazione del pezzo
|
|
for dRotIndex = 1, 4 do
|
|
-- calcola le strategie applicabili
|
|
PROCESSINGS[nPart].Rotation[dRotIndex] = CalculateStrategies( PROCESSINGS[nPart].Rotation[dRotIndex], PARTS[nPart])
|
|
-- tra le calcolate, sceglie la migliore
|
|
PROCESSINGS[nPart].Rotation[dRotIndex] = GetBestStrategy( PROCESSINGS[nPart].Rotation[dRotIndex])
|
|
-- rotazione pezzo di 90° per volta
|
|
BeamLib.RotateRawPart( PARTS[nPart], 1)
|
|
-- aggiorno info pezzo
|
|
PARTS[nPart].b3Raw = EgtGetRawPartBBox( PARTS[nPart].idRaw)
|
|
PARTS[nPart].b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[nPart].id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
|
end
|
|
|
|
-- scrittura nel log del risultato della scelta della strategia migliore tra quelle disponibili
|
|
if EgtGetDebugLevel() >= 3 then
|
|
Logs.WriteFeaturesLog( PROCESSINGS[nPart], PARTS[nPart])
|
|
end
|
|
|
|
local bIsCombinationMachinable = false
|
|
local vProc, MatrixResult
|
|
while not bIsCombinationMachinable do
|
|
bIsCombinationMachinable = true
|
|
local bAllStrategiesApplied = false
|
|
-- si calcola la combinazione di lavorazione migliore
|
|
vProc, MatrixResult = GetBestResultFromCombinationsMatrix( PROCESSINGS[nPart], PARTS[nPart])
|
|
|
|
-- debug
|
|
if EgtGetDebugLevel() >= 1 then
|
|
PrintFeatures( vProc, PARTS[nPart])
|
|
end
|
|
EgtOutLog( ' *** AddMachinings ***', 1)
|
|
|
|
-- se la posizione iniziale non è calcolata, significa che non ci sono feature da eseguire. Solo taglio testa/coda
|
|
if not MatrixResult.nInitialPosition then
|
|
MatrixResult.nInitialPosition = 1
|
|
MACHININGS.Info.nHeadCutRotation = 1
|
|
MACHININGS.Info.nSplitCutRotation = 1
|
|
-- anche se non ci sono feature da eseguire, bisogna comunque scrivrere i risultati
|
|
for nProc = 1, #vProc do
|
|
AddFeatureResultToGlobalList( vProc[nProc])
|
|
end
|
|
-- altrimenti si fanno tutti i calcoli
|
|
else
|
|
-- ordinamento di base delle feature
|
|
vProc = OrderFeatures( vProc)
|
|
|
|
-- esegue le strategie migliori che ha precedentemente scelto e salva le lavorazioni nella lista globale
|
|
bAllStrategiesApplied = false
|
|
MACHININGS, bAllStrategiesApplied = CalculateMachinings( vProc, PARTS[nPart], MatrixResult.nInitialPosition)
|
|
bIsCombinationMachinable = bAllStrategiesApplied
|
|
end
|
|
-- salvo sul PART la posizione di partenza che è stata scelta
|
|
PARTS[nPart].nInitialPosition = MatrixResult.nInitialPosition
|
|
|
|
-- aggiunge tagli testa e coda in fasi opportune
|
|
local nRotHeadCut = MatrixResult.nInitialPosition + MACHININGS.Info.nHeadCutRotation - 1
|
|
if nRotHeadCut > 4 then
|
|
nRotHeadCut = nRotHeadCut - 4
|
|
end
|
|
local nRotSplitCut = MatrixResult.nInitialPosition + MACHININGS.Info.nSplitCutRotation - 1
|
|
if nRotSplitCut > 4 then
|
|
nRotSplitCut = nRotSplitCut - 4
|
|
end
|
|
|
|
-- setto nella Proc l'indice rotazione nella quale deve essere lavorata
|
|
PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].nIndexRotation = nRotHeadCut
|
|
PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].nIndexRotation = nRotSplitCut
|
|
|
|
-- si imposta flag rotazione per taglio di testa
|
|
if MACHININGS.Info.nHeadCutRotation == 2 then
|
|
PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bSide = true
|
|
elseif MACHININGS.Info.nHeadCutRotation == 3 then
|
|
PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc].bDown = true
|
|
end
|
|
-- si imposta flag rotazione per taglio di coda
|
|
if MACHININGS.Info.nSplitCutRotation == 2 then
|
|
PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bSide = true
|
|
elseif MACHININGS.Info.nSplitCutRotation == 3 then
|
|
PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc].bDown = true
|
|
end
|
|
|
|
local vProcHeadTail = {}
|
|
table.insert( vProcHeadTail, PROCESSINGS[nPart].Rotation[nRotHeadCut][MatrixResult.nIndexHeadCutInVProc])
|
|
table.insert( vProcHeadTail, PROCESSINGS[nPart].Rotation[nRotSplitCut][MatrixResult.nIndexTailCutInVProc])
|
|
|
|
bAllStrategiesApplied = false
|
|
MACHININGS, bAllStrategiesApplied = CalculateMachinings( vProcHeadTail, PARTS[nPart], MatrixResult.nInitialPosition)
|
|
bIsCombinationMachinable = bIsCombinationMachinable and bAllStrategiesApplied
|
|
end
|
|
|
|
-- cancellazione entità create ma non usate
|
|
-- TODO funzione?
|
|
local idAddGroup = BeamLib.GetAddGroup( PARTS[nPart].id)
|
|
local idCurrentEntity = EgtGetFirstInGroup( idAddGroup or GDB_ID.NULL)
|
|
while idCurrentEntity do
|
|
if EgtGetLevel( idCurrentEntity) == GDB_LV.TEMP then
|
|
local idEntityToDelete = idCurrentEntity
|
|
idCurrentEntity = EgtGetNext( idCurrentEntity)
|
|
EgtErase( idEntityToDelete)
|
|
else
|
|
idCurrentEntity = EgtGetNext( idCurrentEntity)
|
|
end
|
|
end
|
|
|
|
-- ordinamento lavorazioni
|
|
-- TODO completare ordinamento. Mancano le dipendenze.
|
|
-- TODO la FinalizeSorting andrebbe rimossa e usato un sorting che non viola le dipendenze
|
|
MACHININGS = MachiningLib.PrepareMachiningsForSorting( PARTS[nPart])
|
|
MACHININGS = BeamLib.StableSort( MACHININGS, MachiningLib.CompareMachinings)
|
|
MACHININGS = MachiningLib.FinalizeSorting()
|
|
|
|
-- finiti i calcoli di applicazione delle lavorazioni, si riporta il pezzo nello zero della fase
|
|
nRawId = PARTS[nPart].idRaw
|
|
while nRawId and abs( vtRawOffsetPos:len()) > 0 do
|
|
EgtKeepRawPart( nRawId)
|
|
EgtMoveRawPart( nRawId, -vtRawOffsetPos)
|
|
nRawId = EgtGetNextRawPart( nRawId)
|
|
end
|
|
|
|
local bAreAllMachiningApplyOk
|
|
local sErr
|
|
local bSplitAlreadyExecuted = false
|
|
local bSplitExecutedOnRot = false
|
|
local nPhase = EgtGetCurrPhase()
|
|
local nDispId = EgtGetPhaseDisposition( nPhase)
|
|
EgtSetInfo( nDispId, 'TYPE', 'START')
|
|
EgtSetInfo( nDispId, 'ORD', nOrd)
|
|
EgtOutLog( ' *** Phase=' .. tostring( nPhase) .. ' Raw=' .. tostring( PARTS[nPart].idRaw) .. ' Part=' .. tostring( PARTS[nPart].id) .. ' ***', 1)
|
|
|
|
-- creazione effettiva delle lavorazioni
|
|
local nCurrPosition = 1
|
|
local nInitialPosition = MatrixResult.nInitialPosition
|
|
-- se c'è almeno una lavorazione in posizionamento con trave ribaltata
|
|
if MatrixResult.bSomeFeatureDown then
|
|
local nRotation = EgtIf( nInitialPosition + 2 > 4, nInitialPosition + 2 - 4, nInitialPosition + 2)
|
|
BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition)
|
|
nCurrPosition = nRotation
|
|
EgtSetInfo( nDispId, 'ROT', -2)
|
|
bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'DOWN')
|
|
bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot
|
|
end
|
|
|
|
-- se c'è almeno una lavorazione in posizionamento con trave ruotata
|
|
if MatrixResult.bSomeFeatureSide then
|
|
-- se ci sono state lavorazioni in rotazione precedente devo creare altra fase. Altrimenti già creata da prima
|
|
if MatrixResult.bSomeFeatureDown then
|
|
BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0))
|
|
nPhase = EgtGetCurrPhase()
|
|
nDispId = EgtGetPhaseDisposition( nPhase)
|
|
EgtSetInfo( nDispId, 'ORD', nOrd)
|
|
-- se c'è già stata seoparazione
|
|
if bSplitAlreadyExecuted then
|
|
EgtSetInfo( nDispId, 'TYPE', 'MID2')
|
|
else
|
|
EgtSetInfo( nDispId, 'TYPE', 'MID')
|
|
end
|
|
end
|
|
local nRotation = EgtIf( nInitialPosition + 1 > 4, nInitialPosition + 1 - 4, nInitialPosition + 1)
|
|
BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition)
|
|
nCurrPosition = nRotation
|
|
EgtSetInfo( nDispId, 'ROT', -1)
|
|
bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'SIDE')
|
|
bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot
|
|
end
|
|
|
|
-- se ci sono state lavorazioni in rotazione precedente devo creare altra fase. Altrimenti già creata da prima
|
|
if MatrixResult.bSomeFeatureDown or MatrixResult.bSomeFeatureSide then
|
|
BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0))
|
|
nPhase = EgtGetCurrPhase()
|
|
nDispId = EgtGetPhaseDisposition( nPhase)
|
|
EgtSetInfo( nDispId, 'ORD', nOrd)
|
|
-- se c'è già stata seoparazione
|
|
if bSplitAlreadyExecuted then
|
|
EgtSetInfo( nDispId, 'TYPE', 'END2')
|
|
else
|
|
EgtSetInfo( nDispId, 'TYPE', 'MID')
|
|
end
|
|
end
|
|
|
|
BeamLib.RotateRawPart( PARTS[nPart], nInitialPosition - 1)
|
|
|
|
-- aggiunta lavorazioni in ultima fase
|
|
MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'STD')
|
|
|
|
EgtOutLog( ' *** End AddMachinings ***', 1)
|
|
-- azzero lavorazioni per pezzo successivo
|
|
MACHININGS = {}
|
|
MACHININGS.Info = {}
|
|
-- indice pezzo successivo
|
|
nOrd = nOrd + 1
|
|
end
|
|
|
|
-- ===== finiti i pezzi, si scarica il restante =====
|
|
local idRestPart = EgtGetNextRawPart( PARTS[#PARTS].idRaw)
|
|
if idRestPart and EgtGetRawPartBBox( idRestPart):getDimX() >= BeamData.dMinRaw then
|
|
BeamLib.AddPhaseWithRawParts( idRestPart, BeamData.ptOriXR, BeamData.dPosXR, 0)
|
|
local nPhase = EgtGetCurrPhase()
|
|
local nDispId = EgtGetPhaseDisposition( nPhase)
|
|
EgtSetInfo( nDispId, 'TYPE', 'REST')
|
|
EgtSetInfo( nDispId, 'ORD', nOrd)
|
|
end
|
|
|
|
-- Aggiornamento finale di tutto
|
|
EgtSetCurrPhase( 1)
|
|
local bApplOk, sApplErrors, sApplWarns = EgtApplyAllMachinings()
|
|
-- TODO a cosa serve questo ricalcolo? Con nuovo sistema si può eliminare?
|
|
-- eventuale ricalcolo per macchine tipo PF (ma tengo warning del primo calcolo)
|
|
if EgtExistsInfo( EgtGetCurrMachGroup(), 'RECALC') then
|
|
EgtOutLog( ' **** RECALC ****')
|
|
bApplOk, sApplErrors, _ = EgtApplyAllMachinings()
|
|
EgtRemoveInfo( EgtGetCurrMachGroup(), 'RECALC')
|
|
end
|
|
-- TODO qui restituire errori in modo migliore, come per feature
|
|
-- TODO in caso di lavorazioni di coda saltate, l'informazione va restituita anche sulle singole feature
|
|
if not bApplOk then
|
|
nTotErr = nTotErr + 1
|
|
AddApplyResultToGlobalList( 1, 0, sApplErrors)
|
|
elseif sApplWarns and #sApplWarns > 0 then
|
|
local vLine = EgtSplitString( sApplWarns, '\r\n')
|
|
for i = 1, #vLine do
|
|
local nPos = vLine[i]:find( '(WRN', 1, true)
|
|
if nPos then
|
|
local sData = vLine[i]:sub( nPos + 1, -2)
|
|
local vVal = EgtSplitString( sData, ',')
|
|
local nWarn = EgtGetVal( vVal[1] or '', 'WRN', 'i')
|
|
local nCutId = EgtGetVal( vVal[2] or '', 'CUTID', 'i')
|
|
if nWarn and nCutId then
|
|
AddApplyResultToGlobalList( -nWarn, nCutId, vLine[i])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- TODO per il momento non si cicla mai una seconda volta. Controllare anche parametro modalità scelta strategia
|
|
-- Gestione da fare completamente. La strategia che ha generato una lavorazione con errore deve essere annullata
|
|
-- si può salvare una lista delle strategie da non utilizzare e, nella CalculateStrategy, settare quella specifica strategia come non valida
|
|
-- si fa un reset del MACH e poi si ritorna a inizio ciclo e si rifà tutto
|
|
-- se i cicli superano il massimo si esce (nell'ultimo ciclo possibile si potrebbe escludere la feature e basta, anche se avesse altre strategie da provare)
|
|
if true or nCurrLoop > nMaxLoops then
|
|
ProcessCompleted = true
|
|
end
|
|
end
|
|
|
|
return ( nTotErr == 0), RESULT
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
return BeamExec
|