-- 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') 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 -- TODO se ci sono strategie, posso caricare qui le varie librerie delle strategie. Oppure farlo quando si lanciano 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 local StrategyData = require( sStrategyID .. '\\' .. sStrategyID .. 'Config.lua') -- se ID strategia letto in NGE è differente da quello letto nella strategia, esco subito if StrategyData.StrategyID ~= sStrategyID then return nil end -- cerco e aggiorno i parametri come sono settati nel processing for i = 1, #StrategyData 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, b3Raw) -- 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 local nCutId = EgtGetInfo( EgtGetParent( EgtGetParent( ProcId)), 'CUTID', 'i') or 0 local nTaskId = EgtGetInfo( ProcId, 'TASKID', 'i') or 0 -- leggo se ci sono feature collegate local nAddAdjId = EgtGetInfo( ProcId, 'ADJID', 'i') local nAddMainId = EgtGetInfo( ProcId, 'MAINID', 'i') 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 = nCutId Proc.TaskId = nTaskId -- se ci sono feature collegate ne scrivo il riferimento nella Proc -- TODO AdjId e MainId servono a qualcosa??? if nAddAdjId then Proc.AdjId = Proc.Id + nAddAdjId elseif nAddMainId then Proc.MainId = Proc.Id + nAddMainId end 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.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc) Proc.Faces = FaceData.GetFacesInfo( Proc) Proc.Topology = FeatureData.GetTopology( Proc, b3Raw) -- 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.Strategies = vForcedStrategy -- altrimenti cerco tra le strategie disponibili else Proc.Strategies = GetStrategies( Proc) end -- se ci sono strategie disponibili, aggiungo a lista delle feature da lavorare if Proc.Strategies and #Proc.Strategies > 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 GetFeatureInfoAndDependency( vProc, b3Raw) -- ciclo tutte le feature for i = 1, #vProc do local Proc = vProc[i] -- controllo la feature con tutte le altre per recuperare le dipendenze for j = 1, #vProc do -- non si controlla la feature con se stessa if i ~= j then local ProcB = vProc[j] -- 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, b3Raw) then Proc.Mirror = ProcB end end end end end end end ------------------------------------------------------------------------------------------------------------- function BeamExec.ProcessFeatures() -- ciclo sui pezzi local nTotErr = 0 local Stats = {} local nOrd = 1 local nRawId = EgtGetFirstRawPart() while nRawId do -- verifico che il grezzo contenga pezzi oppure sia abbastanza lungo da essere scaricato coi carrelli local nPartId = EgtGetFirstPartInRawPart( nRawId) if not nPartId and EgtGetRawPartBBox( nRawId):getDimX() < BeamData.MinRaw then break end -- aggiungo la fase, se non è la prima if nOrd == 1 then EgtSetCurrPhase( 1) else BeamLib.AddPhaseWithRawParts( nRawId, 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( nRawId) .. ' Part=' .. tostring( nPartId) .. ' ***', 1) -- ingombro del grezzo local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero le feature di lavorazione della trave local vProc = CollectFeatures( nPartId, b3Raw) -- recupero informazioni ausiliarie feature e dipendenze tra feature stesse GetFeatureInfoAndDependency( vProc, b3Raw) -- TODO ordinare feature e decidere spezzoni -- TODO applicare lavorazioni in base a strategie disponibili (prima applicabile o EgalwareIA in base a parametro) -- TODO riordinare lavorazioni ottimizzando cambio utensile/spezzone ecc..., mantenendo dipendenze definite prima EgtOutLog( ' *** End AddMachinings ***', 1) -- passo al grezzo successivo nOrd = nOrd + 1 nRawId = EgtGetNextRawPart( nRawId) end return ( nTotErr == 0), Stats end ------------------------------------------------------------------------------------------------------------- return BeamExec