-- BeamNestProcess.lua by Egalware s.r.l. 2026/05/11 -- Gestione nesting automatico travi anche oblique -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() EgtEnableDebug( true) -- Include ---------------------------------------------------------------------------------------------------------- -- inventario grezzi local RawInventory = { Stock = {}, ActiveBeams = {} } function RawInventory:GetNewBeam( dLength) local NewBeam = { dTotalLength = dLength, dResidual = dLength - NEST.STARTOFFSET, LastOffsetX = { 0, 0, 0, 0}, LastVtN = Vector3d( 1, 0, 0), dLastHeadRecess = 0, NestedParts = {} } return NewBeam end function RawInventory:BuildStock() if #LEN ~= #QTY then error( 'NestProcess: invalid stock data') end for i = 1, #LEN do self.Stock[#self.Stock + 1] = { dLength = LEN[i], nCount = QTY[i] } end return RawInventory end -- aggiunge una nuova barra attiva rimuovendo la corrispondente dalla lista stock disponibili function RawInventory:AddActiveBeam( nStockIndex) local CurrentStock = self.Stock[nStockIndex] -- se barra disponibile posso aggiungerla a quelle attive if CurrentStock and CurrentStock.nCount > 0 then -- update quantità a stock CurrentStock.nCount = CurrentStock.nCount - 1 -- aggiungo una nuova barra attiva local NewBeam = self:GetNewBeam( CurrentStock.dLength) table.insert( self.ActiveBeams, NewBeam) return NewBeam end return nil end ---------------------------------------------------------------------------------------------------------- -- PartTemplates (informazioni geometriche pezzi univoci) -- JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare) local PartTemplates = {} local JobPool = {} function PartTemplates:GetInfoFromPart( id, sStateWithSide) local OffsetX = {} local vtN local sInfo = EgtGetInfo( id, sStateWithSide) if not sInfo then return end local Info = EgtSplitString( sInfo, ';') OffsetX = EgtSplitString( Info[1], ',') vtN = VectorFromString( Info[2]) -- si convertono gli offset in numeri for i = 1, #OffsetX do OffsetX[i] = tonumber( OffsetX[i]) or 0 end return OffsetX, vtN end function PartTemplates:AddPart( id) self[id] = {} self[id].dLength = EgtGetInfo( id, 'L', 'd') self[id].States = {} self[id].dMaxGlobalTailRecess = 0 local States = { '1000', '0010', '1000_INV', '0010_INV' } for _, sState in ipairs(States) do local OffsetXHead, vtNHead = self:GetInfoFromPart( id, 'ALT' .. sState .. '_H') local OffsetXTail, vtNTail = self:GetInfoFromPart( id, 'ALT' .. sState .. '_T') if OffsetXHead or OffsetXTail then if not OffsetXHead then OffsetXHead = { 0, 0, 0, 0} vtNHead = Vector3d( 1, 0, 0) end if not OffsetXTail then OffsetXTail = { 0, 0, 0, 0} vtNTail = Vector3d( -1, 0, 0) end self[id].States[sState] = {} local State = self[id].States[sState] State.Head = { OffsetX = OffsetXHead, vtN = vtNHead } State.Tail = { OffsetX = OffsetXTail, vtN = vtNTail } -- overlap massimi in testa e in coda per questo pezzo local dMaxHeadRecess = 0 for i = 1, 4 do if State.Head.OffsetX[i] > dMaxHeadRecess + 10 * GEO.EPS_SMALL then dMaxHeadRecess = State.Head.OffsetX[i] end end State.dMaxHeadRecess = dMaxHeadRecess local dMaxTailRecess = 0 for i = 1, 4 do if abs( State.Tail.OffsetX[i]) > dMaxTailRecess + 10 * GEO.EPS_SMALL then dMaxTailRecess = abs( State.Tail.OffsetX[i]) end end State.dMaxTailRecess = dMaxTailRecess if dMaxTailRecess > self[id].dMaxGlobalTailRecess + 10 * GEO.EPS_SMALL then self[id].dMaxGlobalTailRecess = dMaxTailRecess end end end end -- creazione combinata (si cicla una sola volta) di entrambe le tabelle local function BuildPartTemplatesAndJobPool() for id, nCount in pairs( PART) do PartTemplates:AddPart( id) for _ = 1, nCount do table.insert( JobPool, { id = id, bNested = false}) end end return PartTemplates, JobPool end ---------------------------------------------------------------------------------------------------------- local function FindBestPartForBeam( Beam) end ---------------------------------------------------------------------------------------------------------- -- script principale -- costruzione lista grezzi a stock disponibili RawInventory:BuildStock() -- costruzione lista pezzi template con proprietà geometriche e lista pezzi fisici da nestare BuildPartTemplatesAndJobPool() -- loop principale: scorre le barre, sia già attive che a stock, e le riempie nel modo migliore possibile -- per ogni giro sceglie la soluzione con punteggio più alto while true do local BestMove local dHighestScore = -GEO.INFINITO -- 1 Si provano le barre già attive for i = 1, #RawInventory.ActiveBeams do local CurrentMove = FindBestPartForBeam( RawInventory.ActiveBeams[i]) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore BestMove = CurrentMove BestMove.nActiveBeamIndex = i end end -- 2 Si provano le barre ancora a stock for i = 1, #RawInventory.Stock do local VirtualBeam = RawInventory:GetNewBeam( RawInventory.Stock[i].dLength) if RawInventory.Stock[i].nCount > 0 then local CurrentMove = FindBestPartForBeam( VirtualBeam) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore BestMove = CurrentMove BestMove.nStockIndex = i end end end -- 3 Se BestMove trovata si aggiornano lista pezzi e barre if BestMove then CommitBestMove( BestMove) -- se non c'è più niente di compatibile si esce else break end end