From 69db74e30e6bffc38589084ee83d1ac692da02f2 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 8 May 2026 12:00:58 +0200 Subject: [PATCH 01/47] =?UTF-8?q?-=20in=20BeamExec.ProcessBeams=20modifich?= =?UTF-8?q?e=20per=20accettare=20grezzi=20compenetranti=20-=20in=20BeamExe?= =?UTF-8?q?c.GetFeatureInfoAndDependency=20si=20scelgono=20taglio=20di=20t?= =?UTF-8?q?esta=20e=20coda=20anche=20obliqui,=20quelli=20pi=C3=B9=20verso?= =?UTF-8?q?=20il=20centro=20della=20trave.=20Gli=20altri=20tagli=20si=20di?= =?UTF-8?q?sattivano=20-=20da=20completare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 156 ++++++++++++++++++++++++++++++++++------- LuaLibs/FeatureLib.lua | 4 +- 2 files changed, 131 insertions(+), 29 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index c5602fe..88e954c 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -409,40 +409,43 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b -- Inserimento dei pezzi con il loro grezzo local nCnt = 0 - local dLen = dRawL + local dResidualLength = dRawL local idPrevRaw, dPrevDelta - local dDeltaS = dOvmHead - local dDeltaSMin = 0 - local dDeltaE = BeamData.OVM_MID + local dStartOffset = dOvmHead + local dEndOffset = 0 -- TODO cosa fare di BD.OVM_MID? usarlo solo se non è nesting obliquo? 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 dPartLength = 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 + local dNextResidualLength = dResidualLength - EgtIf( i == 1, dStartOffset, 0) - dPartLength - dEndOffset + local bIsSectionOk = (( 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)) + if bIsSectionOk and ( dNextResidualLength + dEndOffset >= 0) then -- eventuale sovramateriale di testa if i > 1 then if PARTS[i].dPosX then - dDeltaS = max( PARTS[i].dPosX - ( dRawL - dLen), dDeltaSMin) + dStartOffset = PARTS[i].dPosX - ( dRawL - dResidualLength) + if dStartOffset < -GEO.EPS_SMALL then + dResidualLength = dResidualLength - dStartOffset + dStartOffset = 0 + end else - dDeltaS = max( dOvmMid - dDeltaE, 0) + dStartOffset = max( dOvmMid - dEndOffset, 0) end end -- dimensioni del grezzo - local dCrawLen = min( dPartLen + dDeltaS + dDeltaE, dLen) - local dDelta = dCrawLen - dPartLen - dDeltaS + local dCurrentRawLength = min( dPartLength + dStartOffset + dEndOffset, dResidualLength) + local dDelta = dCurrentRawLength - dPartLength - dStartOffset -- creo e posiziono il grezzo - PARTS[i].idRaw = EgtAddRawPart( Point3d(0,0,0), dCrawLen, dRawW, dRawH, BeamData.RAWCOL) + PARTS[i].idRaw = EgtAddRawPart( Point3d(0,0,0), dCurrentRawLength, dRawW, dRawH, BeamData.RAWCOL) EgtMoveToCornerRawPart( PARTS[i].idRaw, BeamData.ptOriXR, BeamData.dPosXR) - EgtMoveRawPart( PARTS[i].idRaw, Vector3d( dLen - dRawL, 0, 0)) + EgtMoveRawPart( PARTS[i].idRaw, Vector3d( dResidualLength - dRawL, 0, 0)) -- assegno ordine in lavorazione nCnt = nCnt + 1 EgtSetInfo( PARTS[i].idRaw, 'ORD', nCnt) @@ -454,14 +457,14 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b -- 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 dStartOffset > 0.09 then + EgtSetInfo( PARTS[i].idRaw, 'HOVM', dStartOffset) if idPrevRaw then - EgtSetInfo( idPrevRaw, 'BDST', dDeltaS + dPrevDelta) + EgtSetInfo( idPrevRaw, 'BDST', dStartOffset + dPrevDelta) end end - if dDeltaE > 0.09 then - EgtSetInfo( PARTS[i].idRaw, 'TOVM', dDeltaE) + if dEndOffset > 0.09 then + EgtSetInfo( PARTS[i].idRaw, 'TOVM', dEndOffset) end -- aggiungo faccia per taglio finale al pezzo BeamLib.AddPartEndFace( PARTS[i].id, PARTS[i].b3PartOriginal) @@ -479,13 +482,13 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b EgtMovePartInRawPart( PARTS[i].id, ( vtEccOri - vtEccRot)) end -- aggiorno la lunghezza residua della barra - dLen = dLen - dCrawLen + dResidualLength = dResidualLength - dCurrentRawLength -- aggiorno grezzo precedente idPrevRaw = PARTS[i].idRaw dPrevDelta = dDelta PARTS[i].bIsLastPart = ( i == #PARTS) PARTS[i].dDistanceToNextPiece = dDelta - PARTS[i].dRestLength = dLen + PARTS[i].dRestLength = dResidualLength PARTS[i].b3Raw = EgtGetRawPartBBox( PARTS[i].idRaw) PARTS[i].dLength = PARTS[i].b3Raw:getDimX() PARTS[i].dWidth = PARTS[i].b3Raw:getDimY() @@ -496,7 +499,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b PARTS[i].nIndexInParts = i PARTS[i].SplittingPoints = BeamLib.GetPartSplittingPoints( PARTS[i]) PARTS[i].NotClampableLength = { STD = { dHead = 0, dTail = 0}, SIDE = { dHead = 0, dTail = 0}, DOWN = { dHead = 0, dTail = 0}} - PARTS[i].dHeadOverMaterial = dDeltaS + PARTS[i].dHeadOverMaterial = dStartOffset PARTS[i].sBTLInfo = EgtGetInfo( PARTS[i].id, 'PROJ', 's') or nil PARTS[i].sAISetupConfig = EgtGetInfo( PARTS[i].id, 'AISETUP', 's') or @@ -512,7 +515,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b PARTS[i].idTempGroup = idTempGroup else - local sOut = 'Error: part L(' .. EgtNumToString( dPartLen, 1) .. ') too big for raw part L(' .. EgtNumToString( dLen - 0.1, 1) .. ')' + local sOut = 'Error: part L(' .. EgtNumToString( dPartLength, 1) .. ') too big for raw part L(' .. EgtNumToString( dResidualLength - 0.1, 1) .. ')' return false, sOut end -- se rimasto troppo poco grezzo, esco @@ -525,10 +528,10 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b -- 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) + if dResidualLength > 10 then + local idRaw = EgtAddRawPart( Point3d(0,0,0), dResidualLength, dRawW, dRawH, BeamData.RAWCOL) EgtMoveToCornerRawPart( idRaw, BeamData.ptOriXR, BeamData.dPosXR) - EgtMoveRawPart( idRaw, Vector3d( dLen - dRawL, 0, 0)) + EgtMoveRawPart( idRaw, Vector3d( dResidualLength - dRawL, 0, 0)) -- assegno ordine in lavorazione nCnt = nCnt + 1 EgtSetInfo( idRaw, 'ORD', nCnt) @@ -781,6 +784,12 @@ end ------------------------------------------------------------------------------------------------------------- local function GetFeatureInfoAndDependency( vProcSingleRot, Part) + -- gruppo per geometrie temporanee + local idTempGroup = BeamLib.GetTempGroup() + + local HeadProc = {} + local TailProc = {} + -- ciclo tutte le feature for i = 1, #vProcSingleRot do local Proc = vProcSingleRot[i] @@ -791,6 +800,86 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) local ProcB = vProcSingleRot[j] -- non si controlla la feature con se stessa o se feature disabilitata if i ~= j and ProcB.nFlg ~= 0 then + + local bAreBothTruncatingCuts = + ( ID.IsCut( Proc) or ID.IsHeadCut( Proc) or ID.IsTailCut( Proc)) and ( ID.IsCut( ProcB) or ID.IsHeadCut( ProcB) or ID.IsTailCut( ProcB)) + and ( FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part) and FeatureLib.IsFeatureCuttingEntireSection( ProcB.b3Box, Part)) + + -- sono entrambi tagli troncanti di testa o coda + if bAreBothTruncatingCuts then + -- testa + if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL and ProcB.Faces[1].vtN:getX() > GEO.EPS_SMALL then + -- il primo taglio è più verso il centro della trave + if ( Proc.b3Box:getMin():getX() < ProcB.b3Box:getMin():getX() - 10 * GEO.EPS_SMALL) then + HeadProc = Proc + local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) + local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) + EgtMove( idProcCopy, - 500 * GEO.EPS_SMALL * Proc.Faces[1].vtN, GDB_RT.GLOB) + EgtMove( idProcBCopy, 500 * GEO.EPS_SMALL * ProcB.Faces[1].vtN, GDB_RT.GLOB) + -- se i tagli non si intersecano, quello più esterno è da disattivare + if not EgtTestSurfaceSurface( idProcCopy, idProcBCopy, GEO.EPS_SMALL) then + if not Proc.SlaveProcIndexes then + Proc.SlaveProcIndexes = {} + end + table.insert( Proc.SlaveProcIndexes, j) + ProcB.nIndexMasterProc = i + ProcB.nFlg = 0 + end + -- il secondo taglio è più verso il centro della trave + elseif Proc.b3Box:getMin():getX() >= ProcB.b3Box:getMin():getX() - 10 * GEO.EPS_SMALL then + HeadProc = ProcB + local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) + local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) + EgtMove( idProcBCopy, - 500 * GEO.EPS_SMALL * ProcB.Faces[1].vtN, GDB_RT.GLOB) + EgtMove( idProcCopy, 500 * GEO.EPS_SMALL * Proc.Faces[1].vtN, GDB_RT.GLOB) + -- se i tagli non si intersecano, quello più esterno è da disattivare + if not EgtTestSurfaceSurface( idProcCopy, idProcBCopy, GEO.EPS_SMALL) then + if not ProcB.SlaveProcIndexes then + ProcB.SlaveProcIndexes = {} + end + table.insert( ProcB.SlaveProcIndexes, j) + Proc.nIndexMasterProc = i + Proc.nFlg = 0 + end + end + -- coda + elseif Proc.Faces[1].vtN:getX() <= GEO.EPS_SMALL and ProcB.Faces[1].vtN:getX() <= GEO.EPS_SMALL then + -- il primo taglio è più verso il centro della trave + if Proc.b3Box:getMax():getX() > ProcB.b3Box:getMax():getX() + 10 * GEO.EPS_SMALL then + TailProc = Proc + local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) + local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) + EgtMove( idProcCopy, - 500 * GEO.EPS_SMALL * Proc.Faces[1].vtN, GDB_RT.GLOB) + EgtMove( idProcBCopy, 500 * GEO.EPS_SMALL * ProcB.Faces[1].vtN, GDB_RT.GLOB) + -- se i tagli non si intersecano, quello più esterno è da disattivare + if not EgtTestSurfaceSurface( idProcCopy, idProcBCopy, GEO.EPS_SMALL) then + if not Proc.SlaveProcIndexes then + Proc.SlaveProcIndexes = {} + end + table.insert( Proc.SlaveProcIndexes, j) + ProcB.nIndexMasterProc = i + ProcB.nFlg = 0 + end + -- il secondo taglio è più verso il centro della trave + elseif Proc.b3Box:getMax():getX() >= ProcB.b3Box:getMax():getX() - 10 * GEO.EPS_SMALL then + TailProc = ProcB + local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) + local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) + EgtMove( idProcBCopy, - 500 * GEO.EPS_SMALL * ProcB.Faces[1].vtN, GDB_RT.GLOB) + EgtMove( idProcCopy, 500 * GEO.EPS_SMALL * Proc.Faces[1].vtN, GDB_RT.GLOB) + -- se i tagli non si intersecano, quello più esterno è da disattivare + if not EgtTestSurfaceSurface( idProcCopy, idProcBCopy, GEO.EPS_SMALL) then + if not ProcB.SlaveProcIndexes then + ProcB.SlaveProcIndexes = {} + end + table.insert( ProcB.SlaveProcIndexes, j) + Proc.nIndexMasterProc = i + Proc.nFlg = 0 + end + end + end + end + -- se entrambi tagli di testa, si tiene sempre il primo ( ma non quello aggiunto dall'automatismo) if ( ID.IsHeadCut( Proc) and not EgtGetInfo( Proc.id, 'HEAD_ADD_CUT', 'i')) and ID.IsHeadCut( ProcB) then if not Proc.SlaveProcIndexes then @@ -828,6 +917,16 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) end end end + + HeadProc.Topology = {} + TailProc.Topology = {} + HeadProc.Topology.sFamily = 'HeadCut' + HeadProc.Topology.sName = 'HeadCut' + TailProc.Topology.sFamily = 'TailCut' + TailProc.Topology.sName = 'TailCut' + HeadProc.AvailableStrategies = GetStrategies( HeadProc, Part.sAISetupConfig) + TailProc.AvailableStrategies = GetStrategies( TailProc, Part.sAISetupConfig) + return vProcSingleRot end @@ -983,6 +1082,9 @@ local function CalculateStrategies( vProcSingleRot, Part) Proc.AvailableStrategies[nIndexCurrentStrategy].Result.dTimeToMachine = 99 end + if not Proc.AvailableStrategies.dAllStrategiesTotalTime then + Proc.AvailableStrategies.dAllStrategiesTotalTime = 0 + end Proc.AvailableStrategies.dAllStrategiesTotalTime = Proc.AvailableStrategies.dAllStrategiesTotalTime + Proc.AvailableStrategies[nIndexCurrentStrategy].Result.dTimeToMachine -- se scelta strategia in modalità base o standard, esco subito alla prima che trovo completa if Part.GeneralParameters.GEN_sMachiningStrategy == 'FIRST_IN_LIST' and Proc.AvailableStrategies[nIndexCurrentStrategy].Result.sStatus == 'Complete' then diff --git a/LuaLibs/FeatureLib.lua b/LuaLibs/FeatureLib.lua index 8ce6945..7054d5e 100644 --- a/LuaLibs/FeatureLib.lua +++ b/LuaLibs/FeatureLib.lua @@ -43,7 +43,7 @@ end ------------------------------------------------------------------------------------------------------------- -- restituisce vero se la feature con box b3Proc taglia l'intera sezione della barra -local function IsFeatureCuttingEntireSection( b3Proc, Part) +function FeatureLib.IsFeatureCuttingEntireSection( b3Proc, Part) return ( b3Proc:getDimY() > ( Part.b3Part:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimZ() > ( Part.b3Part:getDimZ() - 500 * GEO.EPS_SMALL)) end @@ -198,7 +198,7 @@ function FeatureLib.ClassifyTopology( Proc, Part) if not Proc.AffectedFaces then Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part) end - local bIsFeatureCuttingEntireSection = IsFeatureCuttingEntireSection( Proc.b3Box, Part) + local bIsFeatureCuttingEntireSection = FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part) local bIsFeatureCuttingEntireLength = IsFeatureCuttingEntireLength( Proc.b3Box, Part) local bIsAnyDimensionLongAsPart = IsAnyDimensionLongAsPart( Proc, Part) local vAdj = Proc.AdjacencyMatrix From f6b2477f2bd7d21f47d7cc23c7dd37038dfff7cc Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 8 May 2026 12:29:46 +0200 Subject: [PATCH 02/47] - in BeamExec.GetFeatureInfoAndDependency correzione --- LuaLibs/BeamExec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 88e954c..2d783af 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -837,8 +837,8 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) if not ProcB.SlaveProcIndexes then ProcB.SlaveProcIndexes = {} end - table.insert( ProcB.SlaveProcIndexes, j) - Proc.nIndexMasterProc = i + table.insert( ProcB.SlaveProcIndexes, i) + Proc.nIndexMasterProc = j Proc.nFlg = 0 end end @@ -872,8 +872,8 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) if not ProcB.SlaveProcIndexes then ProcB.SlaveProcIndexes = {} end - table.insert( ProcB.SlaveProcIndexes, j) - Proc.nIndexMasterProc = i + table.insert( ProcB.SlaveProcIndexes, i) + Proc.nIndexMasterProc = j Proc.nFlg = 0 end end From 40580cdc69f65a3c0f1ceac43671c21d8616610f Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 11 May 2026 12:42:34 +0200 Subject: [PATCH 03/47] - NestProcess attuale rinominata Old per test nesting obliqui, con NestProcess ripulita --- NestProcess.lua | 476 +------------------------------------------- NestProcessOld.lua | 477 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 480 insertions(+), 473 deletions(-) create mode 100644 NestProcessOld.lua diff --git a/NestProcess.lua b/NestProcess.lua index aaace66..49a325f 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -1,477 +1,7 @@ --- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15 --- Gestione nesting automatico travi --- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati. --- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione. --- 2023/01/15 Piccole correzioni. +-- BeamNestProcess.lua by Egalware s.r.l. 2026/05/11 +-- Gestione nesting automatico travi anche oblique -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() -EgtEnableDebug( false) - --- Per test ---NEST = {} ---NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl' ---NEST.MACHINE = 'Essetre-90480019_MW' ---NEST.FLAG = 3 - -local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1] -EgtOutLog( sLog) - --- flag per abilitare statistiche in log -local bLogStat = false - --- Cancello file di log specifico -local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt') -EgtEraseFile( sLogFile) - --- Funzioni per scrittura su file di log specifico -local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId) - local hFile = io.open( sLogFile, 'a') - hFile:write( 'ERR=' .. tostring( nErr) .. '\n') - hFile:write( sMsg .. '\n') - hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n') - hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n') - hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n') - hFile:close() -end - -local function WriteTimeToLogFile( dTime) - local hFile = io.open( sLogFile, 'a') - hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n') - hFile:close() -end - --- Funzione per gestire visualizzazione dopo errore -local function PostErrView( nErr, sMsg) - if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then - EgtSetView( SCE_VD.ISO_SW, false) - EgtZoom( SCE_ZM.ALL) - EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS') - end -end - --- Funzione per gestire visualizzazione dopo warning -local function PostWarnView( nWarn, sMsg) - if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then - EgtSetView( SCE_VD.ISO_SW, false) - EgtZoom( SCE_ZM.ALL) - EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS') - end -end - --- Funzione per aggiornare dati ausiliari -local function UpdateAuxData( sAuxFile) - local bModif = false - -- Se definito LOAD90, aggiorno - local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile) - if sLoad90 ~= '' then - local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL - EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90) - bModif = true - end - return bModif -end - -local function PartsToFill( Parts) - local nToFill = 0 - for i = 1, #Parts do - if Parts[i].Cnt > 0 then - nToFill = nToFill + Parts[i].Cnt - end - end - return nToFill -end - -local function ExecMaximumFilling( Raw, Parts) - -- Inizializzo maximum filler - EgtMaxFillerStart() - -- Inserisco i pezzi - for i = 1, #Parts do - EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1) - end - -- Eseguo l'ottimizzazione - EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType) - -- Recupero i risultati - local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults() - local OneRes = {} - for i = 0, nDiffParts - 1 do - local nPartId, nCount = EgtMaxFillerGetOneResult( i) - table.insert( OneRes, { Id=nPartId, Count=nCount}) - end - --return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes} - return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes} -end - --- Funzione per trovare nome MachGroup -local function NewMachGroupName() - local nMachGroupId = EgtGetFirstMachGroup() - if not nMachGroupId then return 1 end - local nMaxMachGroup = 0 - while nMachGroupId do - sMachGroupName = EgtGetMachGroupName(nMachGroupId) - local nMachGroupName = tonumber(sMachGroupName) - if nMachGroupName > nMaxMachGroup then - nMaxMachGroup = nMachGroupName - end - nMachGroupId = EgtGetNextMachGroup(nMachGroupId) - end - return nMaxMachGroup + 1 -end - -local function TotRawCount(Raws) - local nTotRaws = 0 - for RawIndex = 1, #Raws do - nTotRaws = nTotRaws + Raws[RawIndex].Count - end - return nTotRaws -end - -local function TotPartLen(Parts) - local nTotPartLen = 0 - for PartIndex = 1, #Parts do - nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt) - end - return nTotPartLen -end - --- Imposto direttorio libreria specializzata per Travi -EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua') - --- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi -EgtSetCurrMachine( NEST.MACHINE) -local sMachDir = EgtGetCurrMachineDir() -if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then - NEST.ERR = 12 - NEST.MSG = 'Error not configured for beam machine : ' .. sMachine - WriteErrToLogFile( NEST.ERR, NEST.MSG) - PostErrView( NEST.ERR, NEST.MSG) - return -end - --- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie -EgtRemoveBaseMachineDirFromPackagePath() -EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua') - --- Inizializzo contatori errori e avvisi -local nErrCnt = 0 -local nWarnCnt = 0 - --- Grezzi -local Raws = {} --- creo tabella dei grezzi -for nIndex, nLen in pairs( LEN) do - Raws[tonumber(nIndex)] = {LenToFill = nLen, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1} -end -for nIndex, nQty in pairs( QTY) do - Raws[tonumber(nIndex)].Count = nQty -end --- cerco il grezzo con la lunghezza maggiore, epurata dello start gap -local maxRawLenToFillNoStartGap = 0 -for RawIndex = 1, #Raws do - if Raws[RawIndex].Count > 0 then - maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap) - end -end - --- Pezzi -local Parts = {} --- ciclo su pezzi per aggiungerli al nesting -local dTotLen = 0 -for nPartId, nCount in pairs( PART) do - -- recupero lunghezza pezzo - local Len = EgtGetInfo( nPartId, "L", 'd') - local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0) - -- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione - if Len < maxRawLenToFillNoStartGap then - for nCntIndex = 1 , nCount do - table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1}) - dTotLen = dTotLen + Len - end - end -end - --- lunghezza totale pezzi -local dTotPartLen = TotPartLen( Parts) --- calcolo media delle barre necessarie -local NeededRawsForType = {} -for RawIndex = 1, #Raws do - NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count) -end -local RawQtySum = 0 -for NeededRawIndex = 1, #NeededRawsForType do - RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex] -end -local MediumRawQty = ceil( RawQtySum / #NeededRawsForType) -if MediumRawQty > 1 then - MediumRawQty = MediumRawQty - 1 -end - --- lista dei risultati -local ResultList = {} -local BestResult = nil -local BestResultIndex = nil --- riordino lista pezzi per lunghezza -table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end) - -local function NestSolutionByIndex( Index) - - -- creo copia lista raw - local TempRaws = {} - for TempRawIndex = 1, #Raws do - table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count}) - end - - -- recupero pezzi corti - local ShortList = {} - local LongList = {} - - for PartIndex = 1, #Parts do - if PartIndex <= Index then - table.insert( ShortList, Parts[PartIndex]) - else - table.insert( LongList, Parts[PartIndex]) - end - Parts[PartIndex].Cnt = 1 - end - -- numero di pezzi piccoli per barra - local ShortCount = Index - local ShortForRaw = floor( ShortCount / MediumRawQty) - local ExtraShortForRaw = 0 - if MediumRawQty > 0 then - ExtraShortForRaw = fmod( ShortCount, MediumRawQty) - end - -- creo lista pezzi corti singoli - local SingleShortList = {} - for ShortIndex = 1, #ShortList do - for ShortCount = 1, ShortList[ShortIndex].Cnt do - table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1}) - end - end - -- li divido per le barre previste - local RawsShortList = {} - local RawIndex = 0 - local ShortRawIndex = 0 - for ShortIndex = 1, #SingleShortList do - if ShortRawIndex > 0 then - table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex]) - ShortRawIndex = ShortRawIndex - 1 - else - table.insert( RawsShortList, {SingleShortList[ShortIndex]}) - RawIndex = RawIndex + 1 - ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1 - end - end - - -- Ciclo fino ad esaurimento pezzi o barre - local dTotPartInRawLen = 0 - local nRawTot = 0 - local dRawTotLen = 0 - local dTime = 0 - local nCycle = 1 - local CurrResult = {} - while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do - - -- creo lista con pezzi lunghi e pezzi corti di questo Cycle - local PartsToNest = {} - for PartIndex = 1, #LongList do - table.insert( PartsToNest, LongList[PartIndex]) - end - for CycleIndex = 1, #RawsShortList do - if CycleIndex <= nCycle then - for PartIndex = 1, #RawsShortList[CycleIndex] do - table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex]) - end - end - end - - -- se non ci sono pezzi da nestare, esco - if PartsToFill( PartsToNest) <= 0 then - break - end - -- Eseguo ottimizzazione per ogni lunghezza di barra - local Results = {} - for RawIndex = 1, #TempRaws do - if TempRaws[RawIndex].Count > 0 then - Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest) - else - Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0} - end - end - -- verifico quale e' quella con meno scarto - local nMinWasteRawIndex = GDB_ID.NULL - local dMinWaste = 100000 - for ResultIndex = 1, #Results do - if Results[ResultIndex] then - local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill - if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then - dMinWaste = dWaste - nMinWasteRawIndex = ResultIndex - end - end - end - -- verifico se ci sono pezzi - if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then - -- riporto barra e pezzi nel risultato corrente - local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}} - local CurrX = TempRaws[nMinWasteRawIndex].StartGap - local nInfoIndex = 1 - for i = 1, Results[nMinWasteRawIndex].DiffParts do - local PartIndex = Results[nMinWasteRawIndex].Data[i].Id - local PartId = PartsToNest[PartIndex].Id - local dLen = PartsToNest[PartIndex].Len - for j = 1, Results[nMinWasteRawIndex].Data[i].Count do - -- creo pezzo copia - CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX} - table.insert( CurrBar.Parts, CurrPart) - CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap - nInfoIndex = nInfoIndex + 1 - end - end - table.insert( CurrResult, CurrBar) - dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill) - nRawTot = nRawTot + 1 - dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill - -- Aggiorno per prossima iterazione - TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1 - for i = 1, Results[nMinWasteRawIndex].DiffParts do - local PartId = Results[nMinWasteRawIndex].Data[i].Id - PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count - end - else - -- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili - break - end - nCycle = nCycle + 1 - end - -- riporto risultato in lista - ResultList[Index] = dTotPartInRawLen - if not BestResult or not BestResultIndex or - ( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then - BestResult = CurrResult - BestResult.RawTotLen = dRawTotLen - BestResultIndex = Index - end -end - -local CycleCount = 0 - -local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1) -if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end -local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1) -if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end -local TargetRatio = 0.98 -local dTargetRatioLen = TargetRatio * dTotLen -if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end -local CurrTime = 0 - -local function NestSolutionFromSP( StartingPoint, OscillationStep) - -- ciclo sulle possibilita' da un punto di origine con uno step fisso - local CurrResultIndex = StartingPoint - NestSolutionByIndex( StartingPoint) - if OscillationStep == 0 then return end - local CycleIndex = 1 - local nOutOfBoundary = 0 - while nOutOfBoundary ~= 3 do - CurrTime = EgtStopCounter() / 1000 - if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end - if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end - -- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia - if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then - if bLogStat then EgtOutLog('Brake') end - break - end - local bCurrOutOfBoundary = false - if CurrResultIndex < 0 then - bCurrOutOfBoundary = true - if nOutOfBoundary == 2 then - nOutOfBoundary = 3 - else - nOutOfBoundary = 1 - end - end - if CurrResultIndex > #Parts then - bCurrOutOfBoundary = true - if nOutOfBoundary == 1 then - nOutOfBoundary = 3 - else - nOutOfBoundary = 2 - end - end - if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then - NestSolutionByIndex( CurrResultIndex) - if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end - if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end - CycleCount = CycleCount + 1 - end - CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep ) - CycleIndex = CycleIndex + 1 - end -end - --- lancio calcolo -EgtStartCounter() -local StartingResult = floor( #Parts * 0.3) -if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end ---local Step = floor( #Parts / 10) * floor( log10( #Parts)) -local nDividendo = pow( 10, floor( log10( #Parts)) - 1) -nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10) -local Step = floor( #Parts / nDividendo) * floor( log10( #Parts)) -if bLogStat then EgtOutLog('Step: ' .. Step ) end -NestSolutionFromSP( StartingResult, Step) -if Step > 1 then - NestSolutionFromSP( StartingResult, 1) -end - --- creo gruppi di lavorazione per risultato -for MachGroupIndex = 1, #BestResult do - local CurrMachGroup = BestResult[ MachGroupIndex] - -- creo gruppo di lavorazione - local MachGroupName = NewMachGroupName() - nMachGroup = EgtAddMachGroup( MachGroupName) - EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen) - EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL) - EgtSetInfo( nMachGroup, "AUTONEST", 1) - -- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione - EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID) - EgtSetInfo( nMachGroup, "PATTID", nMachGroup) - -- Disegno i pezzi - for i = 1, #CurrMachGroup.Parts do - local CurrPart = CurrMachGroup.Parts[ i] - -- creo pezzo copia - local nPartDuploId = EgtDuploNew( CurrPart.PartId) - EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX) - end -end - --- creo grezzi per ogni gruppo di lavorazione -local nRawCnt = 0 -local nRawTot = ResultList[BestResultIndex] -_G.BEAM = {} -BEAM.FILE = NEST.FILE -BEAM.MACHINE = NEST.MACHINE -BEAM.FLAG = 6 -- CREATE_PANEL -BEAM.BASEDIR = NEST.BASEDIR -nMachGroup = EgtGetFirstMachGroup() -while nMachGroup do - local nNextMachGroup = EgtGetNextMachGroup( nMachGroup) - EgtSetCurrMachGroup( nMachGroup) - if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then - EgtRemoveInfo( nMachGroup, "AUTONEST") - EgtSetInfo( nMachGroup, "UPDATEUI", 1) - local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua") - if not bOk then - EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')') - end - nRawCnt = nRawCnt + 1 - -- aggiorno interfaccia - EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0) - end - nMachGroup = nNextMachGroup -end - -EgtResetCurrMachGroup() - -NEST.ERR = 0 - -EgtOutLog( ' +++ BeamNestProcess completed') +EgtEnableDebug( false) \ No newline at end of file diff --git a/NestProcessOld.lua b/NestProcessOld.lua new file mode 100644 index 0000000..aaace66 --- /dev/null +++ b/NestProcessOld.lua @@ -0,0 +1,477 @@ +-- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15 +-- Gestione nesting automatico travi +-- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati. +-- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione. +-- 2023/01/15 Piccole correzioni. + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Per test +--NEST = {} +--NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl' +--NEST.MACHINE = 'Essetre-90480019_MW' +--NEST.FLAG = 3 + +local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1] +EgtOutLog( sLog) + +-- flag per abilitare statistiche in log +local bLogStat = false + +-- Cancello file di log specifico +local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt') +EgtEraseFile( sLogFile) + +-- Funzioni per scrittura su file di log specifico +local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId) + local hFile = io.open( sLogFile, 'a') + hFile:write( 'ERR=' .. tostring( nErr) .. '\n') + hFile:write( sMsg .. '\n') + hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n') + hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n') + hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n') + hFile:close() +end + +local function WriteTimeToLogFile( dTime) + local hFile = io.open( sLogFile, 'a') + hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n') + hFile:close() +end + +-- Funzione per gestire visualizzazione dopo errore +local function PostErrView( nErr, sMsg) + if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then + EgtSetView( SCE_VD.ISO_SW, false) + EgtZoom( SCE_ZM.ALL) + EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS') + end +end + +-- Funzione per gestire visualizzazione dopo warning +local function PostWarnView( nWarn, sMsg) + if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then + EgtSetView( SCE_VD.ISO_SW, false) + EgtZoom( SCE_ZM.ALL) + EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS') + end +end + +-- Funzione per aggiornare dati ausiliari +local function UpdateAuxData( sAuxFile) + local bModif = false + -- Se definito LOAD90, aggiorno + local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile) + if sLoad90 ~= '' then + local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL + EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90) + bModif = true + end + return bModif +end + +local function PartsToFill( Parts) + local nToFill = 0 + for i = 1, #Parts do + if Parts[i].Cnt > 0 then + nToFill = nToFill + Parts[i].Cnt + end + end + return nToFill +end + +local function ExecMaximumFilling( Raw, Parts) + -- Inizializzo maximum filler + EgtMaxFillerStart() + -- Inserisco i pezzi + for i = 1, #Parts do + EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1) + end + -- Eseguo l'ottimizzazione + EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType) + -- Recupero i risultati + local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults() + local OneRes = {} + for i = 0, nDiffParts - 1 do + local nPartId, nCount = EgtMaxFillerGetOneResult( i) + table.insert( OneRes, { Id=nPartId, Count=nCount}) + end + --return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes} + return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes} +end + +-- Funzione per trovare nome MachGroup +local function NewMachGroupName() + local nMachGroupId = EgtGetFirstMachGroup() + if not nMachGroupId then return 1 end + local nMaxMachGroup = 0 + while nMachGroupId do + sMachGroupName = EgtGetMachGroupName(nMachGroupId) + local nMachGroupName = tonumber(sMachGroupName) + if nMachGroupName > nMaxMachGroup then + nMaxMachGroup = nMachGroupName + end + nMachGroupId = EgtGetNextMachGroup(nMachGroupId) + end + return nMaxMachGroup + 1 +end + +local function TotRawCount(Raws) + local nTotRaws = 0 + for RawIndex = 1, #Raws do + nTotRaws = nTotRaws + Raws[RawIndex].Count + end + return nTotRaws +end + +local function TotPartLen(Parts) + local nTotPartLen = 0 + for PartIndex = 1, #Parts do + nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt) + end + return nTotPartLen +end + +-- Imposto direttorio libreria specializzata per Travi +EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua') + +-- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi +EgtSetCurrMachine( NEST.MACHINE) +local sMachDir = EgtGetCurrMachineDir() +if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then + NEST.ERR = 12 + NEST.MSG = 'Error not configured for beam machine : ' .. sMachine + WriteErrToLogFile( NEST.ERR, NEST.MSG) + PostErrView( NEST.ERR, NEST.MSG) + return +end + +-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie +EgtRemoveBaseMachineDirFromPackagePath() +EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua') + +-- Inizializzo contatori errori e avvisi +local nErrCnt = 0 +local nWarnCnt = 0 + +-- Grezzi +local Raws = {} +-- creo tabella dei grezzi +for nIndex, nLen in pairs( LEN) do + Raws[tonumber(nIndex)] = {LenToFill = nLen, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1} +end +for nIndex, nQty in pairs( QTY) do + Raws[tonumber(nIndex)].Count = nQty +end +-- cerco il grezzo con la lunghezza maggiore, epurata dello start gap +local maxRawLenToFillNoStartGap = 0 +for RawIndex = 1, #Raws do + if Raws[RawIndex].Count > 0 then + maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap) + end +end + +-- Pezzi +local Parts = {} +-- ciclo su pezzi per aggiungerli al nesting +local dTotLen = 0 +for nPartId, nCount in pairs( PART) do + -- recupero lunghezza pezzo + local Len = EgtGetInfo( nPartId, "L", 'd') + local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0) + -- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione + if Len < maxRawLenToFillNoStartGap then + for nCntIndex = 1 , nCount do + table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1}) + dTotLen = dTotLen + Len + end + end +end + +-- lunghezza totale pezzi +local dTotPartLen = TotPartLen( Parts) +-- calcolo media delle barre necessarie +local NeededRawsForType = {} +for RawIndex = 1, #Raws do + NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count) +end +local RawQtySum = 0 +for NeededRawIndex = 1, #NeededRawsForType do + RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex] +end +local MediumRawQty = ceil( RawQtySum / #NeededRawsForType) +if MediumRawQty > 1 then + MediumRawQty = MediumRawQty - 1 +end + +-- lista dei risultati +local ResultList = {} +local BestResult = nil +local BestResultIndex = nil +-- riordino lista pezzi per lunghezza +table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end) + +local function NestSolutionByIndex( Index) + + -- creo copia lista raw + local TempRaws = {} + for TempRawIndex = 1, #Raws do + table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count}) + end + + -- recupero pezzi corti + local ShortList = {} + local LongList = {} + + for PartIndex = 1, #Parts do + if PartIndex <= Index then + table.insert( ShortList, Parts[PartIndex]) + else + table.insert( LongList, Parts[PartIndex]) + end + Parts[PartIndex].Cnt = 1 + end + -- numero di pezzi piccoli per barra + local ShortCount = Index + local ShortForRaw = floor( ShortCount / MediumRawQty) + local ExtraShortForRaw = 0 + if MediumRawQty > 0 then + ExtraShortForRaw = fmod( ShortCount, MediumRawQty) + end + -- creo lista pezzi corti singoli + local SingleShortList = {} + for ShortIndex = 1, #ShortList do + for ShortCount = 1, ShortList[ShortIndex].Cnt do + table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1}) + end + end + -- li divido per le barre previste + local RawsShortList = {} + local RawIndex = 0 + local ShortRawIndex = 0 + for ShortIndex = 1, #SingleShortList do + if ShortRawIndex > 0 then + table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex]) + ShortRawIndex = ShortRawIndex - 1 + else + table.insert( RawsShortList, {SingleShortList[ShortIndex]}) + RawIndex = RawIndex + 1 + ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1 + end + end + + -- Ciclo fino ad esaurimento pezzi o barre + local dTotPartInRawLen = 0 + local nRawTot = 0 + local dRawTotLen = 0 + local dTime = 0 + local nCycle = 1 + local CurrResult = {} + while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do + + -- creo lista con pezzi lunghi e pezzi corti di questo Cycle + local PartsToNest = {} + for PartIndex = 1, #LongList do + table.insert( PartsToNest, LongList[PartIndex]) + end + for CycleIndex = 1, #RawsShortList do + if CycleIndex <= nCycle then + for PartIndex = 1, #RawsShortList[CycleIndex] do + table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex]) + end + end + end + + -- se non ci sono pezzi da nestare, esco + if PartsToFill( PartsToNest) <= 0 then + break + end + -- Eseguo ottimizzazione per ogni lunghezza di barra + local Results = {} + for RawIndex = 1, #TempRaws do + if TempRaws[RawIndex].Count > 0 then + Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest) + else + Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0} + end + end + -- verifico quale e' quella con meno scarto + local nMinWasteRawIndex = GDB_ID.NULL + local dMinWaste = 100000 + for ResultIndex = 1, #Results do + if Results[ResultIndex] then + local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill + if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then + dMinWaste = dWaste + nMinWasteRawIndex = ResultIndex + end + end + end + -- verifico se ci sono pezzi + if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then + -- riporto barra e pezzi nel risultato corrente + local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}} + local CurrX = TempRaws[nMinWasteRawIndex].StartGap + local nInfoIndex = 1 + for i = 1, Results[nMinWasteRawIndex].DiffParts do + local PartIndex = Results[nMinWasteRawIndex].Data[i].Id + local PartId = PartsToNest[PartIndex].Id + local dLen = PartsToNest[PartIndex].Len + for j = 1, Results[nMinWasteRawIndex].Data[i].Count do + -- creo pezzo copia + CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX} + table.insert( CurrBar.Parts, CurrPart) + CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap + nInfoIndex = nInfoIndex + 1 + end + end + table.insert( CurrResult, CurrBar) + dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill) + nRawTot = nRawTot + 1 + dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill + -- Aggiorno per prossima iterazione + TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1 + for i = 1, Results[nMinWasteRawIndex].DiffParts do + local PartId = Results[nMinWasteRawIndex].Data[i].Id + PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count + end + else + -- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili + break + end + nCycle = nCycle + 1 + end + -- riporto risultato in lista + ResultList[Index] = dTotPartInRawLen + if not BestResult or not BestResultIndex or + ( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then + BestResult = CurrResult + BestResult.RawTotLen = dRawTotLen + BestResultIndex = Index + end +end + +local CycleCount = 0 + +local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1) +if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end +local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1) +if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end +local TargetRatio = 0.98 +local dTargetRatioLen = TargetRatio * dTotLen +if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end +local CurrTime = 0 + +local function NestSolutionFromSP( StartingPoint, OscillationStep) + -- ciclo sulle possibilita' da un punto di origine con uno step fisso + local CurrResultIndex = StartingPoint + NestSolutionByIndex( StartingPoint) + if OscillationStep == 0 then return end + local CycleIndex = 1 + local nOutOfBoundary = 0 + while nOutOfBoundary ~= 3 do + CurrTime = EgtStopCounter() / 1000 + if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end + if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end + -- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia + if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then + if bLogStat then EgtOutLog('Brake') end + break + end + local bCurrOutOfBoundary = false + if CurrResultIndex < 0 then + bCurrOutOfBoundary = true + if nOutOfBoundary == 2 then + nOutOfBoundary = 3 + else + nOutOfBoundary = 1 + end + end + if CurrResultIndex > #Parts then + bCurrOutOfBoundary = true + if nOutOfBoundary == 1 then + nOutOfBoundary = 3 + else + nOutOfBoundary = 2 + end + end + if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then + NestSolutionByIndex( CurrResultIndex) + if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end + if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end + CycleCount = CycleCount + 1 + end + CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep ) + CycleIndex = CycleIndex + 1 + end +end + +-- lancio calcolo +EgtStartCounter() +local StartingResult = floor( #Parts * 0.3) +if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end +--local Step = floor( #Parts / 10) * floor( log10( #Parts)) +local nDividendo = pow( 10, floor( log10( #Parts)) - 1) +nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10) +local Step = floor( #Parts / nDividendo) * floor( log10( #Parts)) +if bLogStat then EgtOutLog('Step: ' .. Step ) end +NestSolutionFromSP( StartingResult, Step) +if Step > 1 then + NestSolutionFromSP( StartingResult, 1) +end + +-- creo gruppi di lavorazione per risultato +for MachGroupIndex = 1, #BestResult do + local CurrMachGroup = BestResult[ MachGroupIndex] + -- creo gruppo di lavorazione + local MachGroupName = NewMachGroupName() + nMachGroup = EgtAddMachGroup( MachGroupName) + EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen) + EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL) + EgtSetInfo( nMachGroup, "AUTONEST", 1) + -- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione + EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID) + EgtSetInfo( nMachGroup, "PATTID", nMachGroup) + -- Disegno i pezzi + for i = 1, #CurrMachGroup.Parts do + local CurrPart = CurrMachGroup.Parts[ i] + -- creo pezzo copia + local nPartDuploId = EgtDuploNew( CurrPart.PartId) + EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX) + end +end + +-- creo grezzi per ogni gruppo di lavorazione +local nRawCnt = 0 +local nRawTot = ResultList[BestResultIndex] +_G.BEAM = {} +BEAM.FILE = NEST.FILE +BEAM.MACHINE = NEST.MACHINE +BEAM.FLAG = 6 -- CREATE_PANEL +BEAM.BASEDIR = NEST.BASEDIR +nMachGroup = EgtGetFirstMachGroup() +while nMachGroup do + local nNextMachGroup = EgtGetNextMachGroup( nMachGroup) + EgtSetCurrMachGroup( nMachGroup) + if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then + EgtRemoveInfo( nMachGroup, "AUTONEST") + EgtSetInfo( nMachGroup, "UPDATEUI", 1) + local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua") + if not bOk then + EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')') + end + nRawCnt = nRawCnt + 1 + -- aggiorno interfaccia + EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0) + end + nMachGroup = nNextMachGroup +end + +EgtResetCurrMachGroup() + +NEST.ERR = 0 + +EgtOutLog( ' +++ BeamNestProcess completed') From 05a8d23f6a60d7fc8fd7cf6b4659025c6812fe79 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 12 May 2026 09:06:43 +0200 Subject: [PATCH 04/47] =?UTF-8?q?-=20in=20BeamExec.GetFeatureInfoAndDepend?= =?UTF-8?q?ency=20si=20calcolano=20i=20punti=20ai=20vertici=20dei=20tagli?= =?UTF-8?q?=20di=20testa=20e=20coda=20-=20in=20BeamLib=20aggiunta=20funzio?= =?UTF-8?q?ne=20GetSurfTmSortedVertices=20per=20restituire=20i=20punti=20a?= =?UTF-8?q?i=20vertici=20gi=C3=A0=20ordinati;=20da=20correggere=20perch?= =?UTF-8?q?=C3=A8=20i=20vertici=20non=20arrivano=20ordinati=20dalla=20funz?= =?UTF-8?q?ione=20EgtSurfTmGetAllVertInFacet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 4 ++- LuaLibs/BeamLib.lua | 68 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 2d783af..35df068 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -805,7 +805,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) ( ID.IsCut( Proc) or ID.IsHeadCut( Proc) or ID.IsTailCut( Proc)) and ( ID.IsCut( ProcB) or ID.IsHeadCut( ProcB) or ID.IsTailCut( ProcB)) and ( FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part) and FeatureLib.IsFeatureCuttingEntireSection( ProcB.b3Box, Part)) - -- sono entrambi tagli troncanti di testa o coda + -- si trovano i veri tagli di testa e coda e si disattivano gli altri, se necessario if bAreBothTruncatingCuts then -- testa if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL and ProcB.Faces[1].vtN:getX() > GEO.EPS_SMALL then @@ -926,6 +926,8 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) TailProc.Topology.sName = 'TailCut' HeadProc.AvailableStrategies = GetStrategies( HeadProc, Part.sAISetupConfig) TailProc.AvailableStrategies = GetStrategies( TailProc, Part.sAISetupConfig) + local PtSortedHead = BeamLib.GetSurfTmSortedVertices( HeadProc.id) + local PtSortedTail = BeamLib.GetSurfTmSortedVertices( TailProc.id) return vProcSingleRot end diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index ab8d022..47aaddf 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -512,10 +512,76 @@ function BeamLib.GetDirectionFromSCC( nSCC) elseif nSCC == MCH_SCC.ADIR_ZM then vtSCC = -Z_AX() end - + return vtSCC end +------------------------------------------------------------------------------------------------------------- +-- Funzione che restituisce una tabella con i punti ai vertici di una trimesh (se almeno 3), in globale +-- ordinati partendo da quello ai valori minimi degli assi e i successivi secondo rotazione attorno a X+ +function BeamLib.GetSurfTmSortedVertices( idSurfTm) + -- se più di una faccia si esce subito + if not ( EgtSurfTmFacetCount( idSurfTm) == 1) then + return + end + + local VerticesIndex = EgtSurfTmGetAllVertInFacet( idSurfTm, 0) + local nVerticesCount = #VerticesIndex + + -- Una faccia deve avere almeno 3 vertici + if nVerticesCount < 3 then + return + end + + local Vertices = {} + local nFirstVertex + + -- 1. Popolamento tabella Vertices e ricerca del vertice di partenza + local dMinYZ = GEO.INFINITO + for i = 1, nVerticesCount do + Vertices[i] = {} + Vertices[i].ptVertex = EgtSurfTmGetVertex( idSurfTm, VerticesIndex[i], GDB_RT.GLOB) + + -- Circular indexing 1 based + Vertices[i].nNextIndex = (i % nVerticesCount) + 1 + Vertices[i].nPrevIndex = ((i - 2 + nVerticesCount) % nVerticesCount) + 1 + + -- il primo punto è quello con il totale di coordinate Y e Z più basso + if( ( Vertices[i].ptVertex:getY() + Vertices[i].ptVertex:getZ()) < dMinYZ) then + nFirstVertex = i + dMinYZ = Vertices[i].ptVertex:getY() + Vertices[i].ptVertex:getZ() + end + end + + -- se non trova il punto con Y+Z minima c'è qualcosa che non va: si esce + if not nFirstVertex then + return + end + + local vtN = EgtSurfTmFacetNormVersor( idSurfTm, 0, GDB_ID.ROOT) + local PtVerticesSorted = {} + + -- 2. Ordinamento in base alla normale X + table.insert( PtVerticesSorted, Vertices[nFirstVertex].ptVertex) + + local nCurrentIndex = nFirstVertex + -- Faccia verso destra (avanti nell'indice della mesh) + if vtN:getX() > GEO.EPS_SMALL then + for _ = 1, nVerticesCount - 1 do + nCurrentIndex = Vertices[nCurrentIndex].nNextIndex + table.insert( PtVerticesSorted, Vertices[nCurrentIndex].ptVertex) + end + -- Faccia verso sinistra (indietro nell'indice della mesh) + else + for _ = 1, nVerticesCount - 1 do + nCurrentIndex = Vertices[nCurrentIndex].nPrevIndex + table.insert( PtVerticesSorted, Vertices[nCurrentIndex].ptVertex) + end + end + + return PtVerticesSorted +end + ------------------------------------------------------------------------------------------------------------- -- Funzione per determinare se la faccia ha lati molto corti (trascurabili) ed è quindi approssimabile ad una 3 facce function BeamLib.Is3EdgesApprox( Proc, idFace, nAddGrpId) From 983609397ec74cb8516d884ac2beda8220c6d31b Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 12 May 2026 10:45:26 +0200 Subject: [PATCH 05/47] - in BeamLib funzione GetSurfTmSortedVertices diventa GetSortedVertices e si passa la Proc direttamente - in BeamLib aggiunta funzione GetAdjacentIndices per la ricerca degli indici precedente e successivo con circular indexing --- LuaLibs/BeamExec.lua | 4 +- LuaLibs/BeamLib.lua | 101 ++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 56 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 35df068..5ed30ce 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -926,8 +926,8 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) TailProc.Topology.sName = 'TailCut' HeadProc.AvailableStrategies = GetStrategies( HeadProc, Part.sAISetupConfig) TailProc.AvailableStrategies = GetStrategies( TailProc, Part.sAISetupConfig) - local PtSortedHead = BeamLib.GetSurfTmSortedVertices( HeadProc.id) - local PtSortedTail = BeamLib.GetSurfTmSortedVertices( TailProc.id) + local PtSortedHead = BeamLib.GetSortedVertices( HeadProc) + local PtSortedTail = BeamLib.GetSortedVertices( TailProc) return vProcSingleRot end diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 47aaddf..99c03a8 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -517,71 +517,64 @@ function BeamLib.GetDirectionFromSCC( nSCC) end ------------------------------------------------------------------------------------------------------------- --- Funzione che restituisce una tabella con i punti ai vertici di una trimesh (se almeno 3), in globale --- ordinati partendo da quello ai valori minimi degli assi e i successivi secondo rotazione attorno a X+ -function BeamLib.GetSurfTmSortedVertices( idSurfTm) - -- se più di una faccia si esce subito - if not ( EgtSurfTmFacetCount( idSurfTm) == 1) then - return - end - - local VerticesIndex = EgtSurfTmGetAllVertInFacet( idSurfTm, 0) - local nVerticesCount = #VerticesIndex - - -- Una faccia deve avere almeno 3 vertici - if nVerticesCount < 3 then - return - end - - local Vertices = {} - local nFirstVertex - - -- 1. Popolamento tabella Vertices e ricerca del vertice di partenza - local dMinYZ = GEO.INFINITO - for i = 1, nVerticesCount do - Vertices[i] = {} - Vertices[i].ptVertex = EgtSurfTmGetVertex( idSurfTm, VerticesIndex[i], GDB_RT.GLOB) - - -- Circular indexing 1 based - Vertices[i].nNextIndex = (i % nVerticesCount) + 1 - Vertices[i].nPrevIndex = ((i - 2 + nVerticesCount) % nVerticesCount) + 1 - - -- il primo punto è quello con il totale di coordinate Y e Z più basso - if( ( Vertices[i].ptVertex:getY() + Vertices[i].ptVertex:getZ()) < dMinYZ) then - nFirstVertex = i - dMinYZ = Vertices[i].ptVertex:getY() + Vertices[i].ptVertex:getZ() - end - end - - -- se non trova il punto con Y+Z minima c'è qualcosa che non va: si esce - if not nFirstVertex then - return - end - - local vtN = EgtSurfTmFacetNormVersor( idSurfTm, 0, GDB_ID.ROOT) +-- Funzione che restituisce una tabella con i punti ai vertici della tabella, in globale +-- ordinati partendo da quello ai valori minimi degli assi e i successivi secondo rotazione destrorsa X+; +-- solo per Proc a 1 faccia +function BeamLib.GetSortedVertices( Proc) local PtVerticesSorted = {} - -- 2. Ordinamento in base alla normale X - table.insert( PtVerticesSorted, Vertices[nFirstVertex].ptVertex) + -- se più di una faccia si esce subito + if Proc.nFct > 1 then + return + end - local nCurrentIndex = nFirstVertex - -- Faccia verso destra (avanti nell'indice della mesh) - if vtN:getX() > GEO.EPS_SMALL then - for _ = 1, nVerticesCount - 1 do - nCurrentIndex = Vertices[nCurrentIndex].nNextIndex - table.insert( PtVerticesSorted, Vertices[nCurrentIndex].ptVertex) + local PtVertices = {} + local nFirstIndex + local dMinYZ = GEO.INFINITO + for i = 1, #Proc.Faces[1].Edges do + local Edge = Proc.Faces[1].Edges[i] + table.insert( PtVertices, Edge.ptStart) + if ( Edge.ptStart:getY() + Edge.ptStart:getZ() < dMinYZ) then + nFirstIndex = i + dMinYZ = Edge.ptStart:getY() + Edge.ptStart:getZ() end - -- Faccia verso sinistra (indietro nell'indice della mesh) + end + + table.insert( PtVerticesSorted, PtVertices[nFirstIndex]) + local nCurrentIndex = nFirstIndex + -- faccia che guarda verso X+, ordine ok + if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL then + for _ = 1, #PtVertices - 1 do + _, nCurrentIndex = BeamLib.GetAdjacentIndices( nCurrentIndex, #PtVertices) + table.insert( PtVerticesSorted, PtVertices[nCurrentIndex]) + end + -- faccia che guarda verso X-, ordine da invertire else - for _ = 1, nVerticesCount - 1 do - nCurrentIndex = Vertices[nCurrentIndex].nPrevIndex - table.insert( PtVerticesSorted, Vertices[nCurrentIndex].ptVertex) + for _ = 1, #PtVertices - 1 do + nCurrentIndex = BeamLib.GetAdjacentIndices( nCurrentIndex, #PtVertices) + table.insert( PtVerticesSorted, PtVertices[nCurrentIndex]) end end return PtVerticesSorted end +------------------------------------------------------------------------------------------------------------- +-- restituisce il precedente e prossimo indice 1-based, tenendo conto del massimo indice +function BeamLib.GetAdjacentIndices( nCurrentIndex, nMaxIndex) + local nPreviousIndex, nNextIndex + + if ( nCurrentIndex < 1) or ( nCurrentIndex > nMaxIndex) then + return + end + + -- circular indexing 1-based + nPreviousIndex = ((nCurrentIndex - 2 + nMaxIndex) % nMaxIndex) + 1 + nNextIndex = (nCurrentIndex % nMaxIndex) + 1 + + return nPreviousIndex, nNextIndex +end + ------------------------------------------------------------------------------------------------------------- -- Funzione per determinare se la faccia ha lati molto corti (trascurabili) ed è quindi approssimabile ad una 3 facce function BeamLib.Is3EdgesApprox( Proc, idFace, nAddGrpId) From 0274096f5799244375a4ca92b0c3d74346958c21 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 12 May 2026 11:59:26 +0200 Subject: [PATCH 06/47] - in BeamExec.GetFeatureInfoAndDependency si salvano le info necessarie per nesting (offset X dei vertici dei tagli rispetto al box, normali delle facce) --- LuaLibs/BeamExec.lua | 20 ++++++++++++++++++++ LuaLibs/BeamLib.lua | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 5ed30ce..72e6ac8 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -926,8 +926,28 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) TailProc.Topology.sName = 'TailCut' HeadProc.AvailableStrategies = GetStrategies( HeadProc, Part.sAISetupConfig) TailProc.AvailableStrategies = GetStrategies( TailProc, Part.sAISetupConfig) + -- per nesting, si settano come info gli offset X degli estremi dei tagli local PtSortedHead = BeamLib.GetSortedVertices( HeadProc) local PtSortedTail = BeamLib.GetSortedVertices( TailProc) + if PtSortedHead then + local HeadVertexOffsetX = {} + for i = 1, #PtSortedHead do + table.insert( HeadVertexOffsetX, Part.b3Part:getMax():getX() - PtSortedHead[i]:getX()) + end + local sInfo = table.concat( HeadVertexOffsetX, ',') + EgtSetInfo( Part.id, 'HEADOFFSETX', sInfo) + end + if PtSortedTail then + local TailVertexOffsetX = {} + for i = 1, #PtSortedHead do + table.insert( TailVertexOffsetX, Part.b3Part:getMin():getX() - PtSortedTail[i]:getX()) + end + local sInfo = table.concat( TailVertexOffsetX, ',') + EgtSetInfo( Part.id, 'TAILOFFSETX', sInfo) + end + -- per nesting, si settano come info le normali delle facce di taglio + EgtSetInfo( Part.id, 'HEADVTN', tostring( HeadProc.Faces[1].vtN)) + EgtSetInfo( Part.id, 'TAILVTN', tostring( TailProc.Faces[1].vtN)) return vProcSingleRot end diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 99c03a8..b9f7033 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -517,7 +517,7 @@ function BeamLib.GetDirectionFromSCC( nSCC) end ------------------------------------------------------------------------------------------------------------- --- Funzione che restituisce una tabella con i punti ai vertici della tabella, in globale +-- Restituisce una tabella con i punti ai vertici della faccia, in globale -- ordinati partendo da quello ai valori minimi degli assi e i successivi secondo rotazione destrorsa X+; -- solo per Proc a 1 faccia function BeamLib.GetSortedVertices( Proc) From fc47bca0f1fee150632d366cd850776ca011d8cc Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 11:47:25 +0200 Subject: [PATCH 07/47] - in NestProcess prime modifiche per nesting obliquo (da completare) - in BeamExec test BEAM.INFONGEPART per scrittura note pezzo in nge tramite Aedifica - in BeamLib aggiunta funzione RotateTableFromIndex per reindicizzare una tabella passata --- LuaLibs/BeamExec.lua | 12 ++++++ LuaLibs/BeamLib.lua | 12 ++++++ NestProcess.lua | 91 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 72e6ac8..7f53c01 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -2446,6 +2446,18 @@ function BeamExec.ProcessAlternatives( PARTS) end + + + + -- TEST + BEAM.INFONGEPART = 'TEST=666,999,666,999' + -- TEST + + + + + + -- si cancella eventuale mach group creato per le alternative EgtRemoveMachGroup( nTempMachGroupName) diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index b9f7033..d9fe22a 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -889,6 +889,18 @@ function BeamLib.CalculateStringBinaryFormat( dNumber, CharNumber) return NumberString end +------------------------------------------------------------------------------------------------------------- +-- reindicizza una tabella passata ripartendo dall'indice nStartIndex e mantenendo l'ordine +function BeamLib.RotateTableFromIndex( Table, nStartIndex) + local RotatedTable = {} + + for i = 1, #Table do + RotatedTable[#RotatedTable + 1] = Table[((RotatedTable + i - 2) % #Table) + 1] + end + + return RotatedTable +end + ------------------------------------------------------------------------------------------------------------- --- copia una tabella lua in modo ricorsivo, ossia mantiene indipendenti anche tutte le sottotabelle --- ATTENZIONE: in caso di modifiche vanno gestiti anche i tipi custom; sarebbe meglio metterla nel LuaLibs diff --git a/NestProcess.lua b/NestProcess.lua index 49a325f..1a8a075 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -4,4 +4,93 @@ -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() -EgtEnableDebug( false) \ No newline at end of file +EgtEnableDebug( true) + +-- Include +local BeamLib = require( 'BeamLib') + +---------------------------------------------------------------------------------------------------------- +-- stati che definiscono rotazione / inversione della parte +local STATE = { + STD = 1, -- Standard + ROT180 = 2, -- Rotazione 180deg attorno a X+ + INV = 3, -- Inversione (rotazione 180deg attorno a Z+) + INV_ROT180 = 4 -- Inversione + rotazione +} + +---------------------------------------------------------------------------------------------------------- +-- inventario grezzi +local RawInventory = { + Stock = {}, + ActiveBeams = {} +} + +function RawInventory:BuildStock() + if #LEN ~= #QTY then + error( 'NestProcess: invalid stock data') + end + + for i = 1, #LEN do + self.Stock[#self.Stock + 1] = { + Length = LEN[i], + Count = QTY[i] + } + end + + return RawInventory +end + +function RawInventory:AddActiveBeam() + -- TODO da fare +end + +---------------------------------------------------------------------------------------------------------- +-- PartTemplates (informazioni geometriche pezzi univoci) e JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare) +local PartTemplates = {} +local JobPool = {} + +function PartTemplates:AddPart( id) + PartTemplates[id] = {} + PartTemplates[id].dLength = EgtGetInfo( id, 'L', 'd') + -- TODO qua gli stati abilitati dovranno arrivare dalle alternatives + local VerticesHead = EgtSplitString( EgtGetInfo( id, 'HEADOFFSETX', 'd')) + local vtNHead = Vector3d( EgtSplitString( EgtGetInfo( id, 'HEADVTN', 'd'))) + local VerticesTail = EgtSplitString( EgtGetInfo( id, 'TAILOFFSETX', 'd')) + local vtNTail = Vector3d( EgtSplitString( EgtGetInfo( id, 'TAILVTN', 'd'))) + PartTemplates[id].States = { + [STATE.STD] = { + Head = { Vertices = VerticesHead, vtN = vtNHead}, + Tail = { Vertices = VerticesTail, vtN = vtNTail} + }, + [STATE.ROT180] = { + Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead}, + Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead} + }, + [STATE.INV] = { + Head = { Vertices = VerticesTail, vtN = vtNTail}, + Tail = { Vertices = VerticesHead, vtN = vtNHead} + }, + [STATE.INV_ROT180] = { + Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead}, + Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead} + } + } +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) + end + + return PartTemplates, JobPool +end + + + + + + + +RawInventory:BuildStock() +BuildPartTemplatesAndJobPool() \ No newline at end of file From b048e2ebe2d149629c876b089d74043d97e4d7a5 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 11:58:28 +0200 Subject: [PATCH 08/47] - in BeamLib.GetSortedVertices piccola correzione --- LuaLibs/BeamLib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index d9fe22a..23c470f 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -524,7 +524,7 @@ function BeamLib.GetSortedVertices( Proc) local PtVerticesSorted = {} -- se più di una faccia si esce subito - if Proc.nFct > 1 then + if not ( Proc.nFct) or ( Proc.nFct > 1) then return end From f6d6043c0eb34354f3bafe4565e5a9f42d11d874 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 12:40:45 +0200 Subject: [PATCH 09/47] - piccole modifiche per test nesting --- LuaLibs/BeamExec.lua | 2 +- LuaLibs/BeamLib.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 7f53c01..ee152da 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -2450,7 +2450,7 @@ function BeamExec.ProcessAlternatives( PARTS) -- TEST - BEAM.INFONGEPART = 'TEST=666,999,666,999' + BEAM.INFONGEPART = { 'TEST=666,999,666,999', 'TEST2=44444444444', 'TEST3=sksksk'} -- TEST diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 23c470f..d9fe22a 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -524,7 +524,7 @@ function BeamLib.GetSortedVertices( Proc) local PtVerticesSorted = {} -- se più di una faccia si esce subito - if not ( Proc.nFct) or ( Proc.nFct > 1) then + if Proc.nFct > 1 then return end From 1e861807231ddbb249b3f2114c58bca13223badb Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 16:00:20 +0200 Subject: [PATCH 10/47] - in BeamExec si scrivono HeadcutInfo e TailcutInfo nel PARTS che serviranno per nesting; da completare output alternative --- LuaLibs/BeamExec.lua | 64 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index ee152da..077c296 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -251,6 +251,27 @@ function BeamExec.GetStrategiesFromJSONinBD( sAISetupConfigName) end end +------------------------------------------------------------------------------------------------------------- +local function GetRotationName( nRotIndex, nInvertIndex) + local sRotation = '' + + if nRotIndex == 1 then + sRotation = '0' + elseif nRotIndex == 2 then + sRotation = '90' + elseif nRotIndex == 3 then + sRotation = '180' + elseif nRotIndex == 4 then + sRotation = '270' + end + + if nInvertIndex > 1 then + sRotation = sRotation .. 'INV' + end + + return sRotation +end + -- TODO prevedere parametri per preferire carico del pezzo verticale oppure orizzontale? ------------------------------------------------------------------------------------------------------------- -- funzione che controlla validità delle combinazioni proposte @@ -927,29 +948,27 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) HeadProc.AvailableStrategies = GetStrategies( HeadProc, Part.sAISetupConfig) TailProc.AvailableStrategies = GetStrategies( TailProc, Part.sAISetupConfig) -- per nesting, si settano come info gli offset X degli estremi dei tagli + local HeadcutInfo = {} local PtSortedHead = BeamLib.GetSortedVertices( HeadProc) - local PtSortedTail = BeamLib.GetSortedVertices( TailProc) if PtSortedHead then - local HeadVertexOffsetX = {} + HeadcutInfo.OffsetX = {} for i = 1, #PtSortedHead do - table.insert( HeadVertexOffsetX, Part.b3Part:getMax():getX() - PtSortedHead[i]:getX()) + table.insert( HeadcutInfo.OffsetX, Part.b3Part:getMax():getX() - PtSortedHead[i]:getX()) end - local sInfo = table.concat( HeadVertexOffsetX, ',') - EgtSetInfo( Part.id, 'HEADOFFSETX', sInfo) end + local TailcutInfo = {} + local PtSortedTail = BeamLib.GetSortedVertices( TailProc) if PtSortedTail then - local TailVertexOffsetX = {} + TailcutInfo.OffsetX = {} for i = 1, #PtSortedHead do - table.insert( TailVertexOffsetX, Part.b3Part:getMin():getX() - PtSortedTail[i]:getX()) + table.insert( TailcutInfo.OffsetX, Part.b3Part:getMin():getX() - PtSortedTail[i]:getX()) end - local sInfo = table.concat( TailVertexOffsetX, ',') - EgtSetInfo( Part.id, 'TAILOFFSETX', sInfo) end -- per nesting, si settano come info le normali delle facce di taglio - EgtSetInfo( Part.id, 'HEADVTN', tostring( HeadProc.Faces[1].vtN)) - EgtSetInfo( Part.id, 'TAILVTN', tostring( TailProc.Faces[1].vtN)) + HeadcutInfo.vtN = HeadProc.Faces[1].vtN + TailcutInfo.vtN = TailProc.Faces[1].vtN - return vProcSingleRot + return vProcSingleRot, HeadcutInfo, TailcutInfo end ------------------------------------------------------------------------------------------------------------- @@ -1368,12 +1387,15 @@ function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- se è prerotazione, oltre al ciclo normale, si devono verificare anche invertiti local bCalcInverted = bIsFlipRot and PARTS[nPart].GeneralParameters.GEN_bAllowPieceInversion local nCycles = EgtIf( bCalcInverted, 2, 1) + PARTS[nPart].HeadcutInfo = {} + PARTS[nPart].TailcutInfo = {} -- per ogni inversione for nInvertIndex = 1, nCycles do -- per ogni rotazione for nRotIndex = 1, 4 do local nOffsetIndex = EgtIf( nInvertIndex == 2, 4, 0) local nIndex = nRotIndex + nOffsetIndex + local HeadcutInfo, TailcutInfo -- si calcolano le feature solo se la rotazione può essere presa in considerazione if PARTS[nPart].CombinationList.Rotations[nRotIndex] == 1 then -- recupero le feature di lavorazione della trave @@ -1381,11 +1403,24 @@ function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- recupero informazioni ausiliarie feature e dipendenze tra feature stesse -- TODO le dipendenze cambiano in base alla rotazione del pezzo? probabilmente no - vProcRot[nIndex] = GetFeatureInfoAndDependency( vProcRot[nIndex], PARTS[nPart]) + vProcRot[nIndex], HeadcutInfo, TailcutInfo = GetFeatureInfoAndDependency( vProcRot[nIndex], PARTS[nPart]) else -- inserisco una tabella vuota table.insert( vProcRot, {}) end + local sRotation = GetRotationName( nRotIndex, nInvertIndex) + if HeadcutInfo then + PARTS[nPart].HeadcutInfo[sRotation] = { + OffsetX = HeadcutInfo.OffsetX, + vtN = HeadcutInfo.vtN + } + end + if TailcutInfo then + PARTS[nPart].TailcutInfo[sRotation] = { + OffsetX = TailcutInfo.OffsetX, + vtN = TailcutInfo.vtN + } + end -- rotazione pezzo di 90° per volta BeamLib.RotateRawPart( PARTS[nPart], 1) -- aggiorno info pezzo @@ -2451,6 +2486,9 @@ function BeamExec.ProcessAlternatives( PARTS) -- TEST BEAM.INFONGEPART = { 'TEST=666,999,666,999', 'TEST2=44444444444', 'TEST3=sksksk'} + + -- local sHeadVtN = ( tostring( HeadProc.Faces[1].vtN)):gsub("^%(", ""):gsub("%)$", "") + -- local sTailVtN = ( tostring( TailProc.Faces[1].vtN)):gsub("^%(", ""):gsub("%)$", "") -- TEST From 4a99f2bdf624ca03c3edc9e09e067e22de1d4a45 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 16:28:04 +0200 Subject: [PATCH 11/47] - in BeamExec.GetProcessings per HeadcutInfo e TailcutInfo si usano gli indici di rotazione canonici (1,2,3,4 per std e 5,6,7,8 per invertiti) --- LuaLibs/BeamExec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 077c296..eff1648 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1394,6 +1394,7 @@ function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- per ogni rotazione for nRotIndex = 1, 4 do local nOffsetIndex = EgtIf( nInvertIndex == 2, 4, 0) + -- le rotazioni sono 1,2,3,4 (0, 90, 180, 270) e 5,6,7,8 (le stesse invertite) local nIndex = nRotIndex + nOffsetIndex local HeadcutInfo, TailcutInfo -- si calcolano le feature solo se la rotazione può essere presa in considerazione @@ -1408,15 +1409,14 @@ function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- inserisco una tabella vuota table.insert( vProcRot, {}) end - local sRotation = GetRotationName( nRotIndex, nInvertIndex) if HeadcutInfo then - PARTS[nPart].HeadcutInfo[sRotation] = { + PARTS[nPart].HeadcutInfo[nIndex] = { OffsetX = HeadcutInfo.OffsetX, vtN = HeadcutInfo.vtN } end if TailcutInfo then - PARTS[nPart].TailcutInfo[sRotation] = { + PARTS[nPart].TailcutInfo[nIndex] = { OffsetX = TailcutInfo.OffsetX, vtN = TailcutInfo.vtN } From b8299df2471bfe622947fce6d7d93dfb63293573 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 13 May 2026 18:42:01 +0200 Subject: [PATCH 12/47] - in BeamExec.ProcessAlternatives si passano correttamente le info a interfaccia da scrivere sul pezzo - in BeamLib aggiunta funzione ConvertBitIndexToRotationIndex per convertire da BitIndex a RotationIndex --- LuaLibs/BeamExec.lua | 46 ++++++++++++++++++-------------------------- LuaLibs/BeamLib.lua | 25 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index eff1648..bc1b157 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -2121,8 +2121,8 @@ end function BeamExec.ProcessAlternatives( PARTS) -- inizializzazione variabili globali per interfaccia - BEAM.ALTERNATIVESNEST2D = '' - BEAM.ALTERNATIVES = '' + local Alternatives = {} + local AlternativesNest2D = {} -- ciclo sui pezzi local BestCombination = {} @@ -2451,23 +2451,14 @@ function BeamExec.ProcessAlternatives( PARTS) local bApplOk, _, _ = EgtApplyAllMachinings() -- se non ci sono errori, soluzione alternativa valida: scrittura variabili globali per interfaccia if bApplOk then - local Alternatives = {} local sBitIndexCombinationWithInvert = BestCombination.sBitIndexCombination .. EgtIf( BestCombination.bPartInCombiIsInverted, '_INV', '') if TotalCombiToTest[z].bIsNesting2D then - if BEAM.ALTERNATIVESNEST2D and BEAM.ALTERNATIVESNEST2D ~= "" then - table.insert( Alternatives, BEAM.ALTERNATIVESNEST2D) - end - table.insert( Alternatives, sBitIndexCombinationWithInvert) - BEAM.ALTERNATIVESNEST2D = table.concat( Alternatives, ', ') + table.insert( AlternativesNest2D, sBitIndexCombinationWithInvert) else - if BEAM.ALTERNATIVES and BEAM.ALTERNATIVES ~= "" then - table.insert( Alternatives, BEAM.ALTERNATIVES) - end table.insert( Alternatives, sBitIndexCombinationWithInvert) - BEAM.ALTERNATIVES = table.concat( Alternatives, ', ') end end - -- se ultima combinazione, si esce e non si riporta in posizione inizale. Verrà infatti cancellata + -- se ultima combinazione, si esce e non si riporta in posizione iniziale. Verrà infatti cancellata if z == #TotalCombiToTest then break end -- si riporta pezzo in posizione iniziale @@ -2481,21 +2472,22 @@ function BeamExec.ProcessAlternatives( PARTS) end + -- passaggio info a interfaccia da scrivere sul pezzo + BEAM.INFONGEPART = {} + for i = 1, #AlternativesNest2D do + local sRotation = BeamLib.ConvertBitIndexToRotationIndex( AlternativesNest2D[i]) + if PARTS[nPart].HeadcutInfo then + local sOffsetX = table.concat( PARTS[nPart].HeadcutInfo[sRotation].OffsetX, ',') + local sVtN = ( tostring( PARTS[nPart].HeadcutInfo[sRotation].vtN)):gsub("^%(", ""):gsub("%)$", "") + table.insert( BEAM.INFONGEPART, 'ALT' .. AlternativesNest2D[i].. '_H' .. '=' .. sOffsetX .. ';' .. sVtN ) + end + if PARTS[nPart].TailcutInfo then + local sOffsetX = table.concat( PARTS[nPart].TailcutInfo[sRotation].OffsetX, ',') + local sVtN = ( tostring( PARTS[nPart].TailcutInfo[sRotation].vtN)):gsub("^%(", ""):gsub("%)$", "") + table.insert( BEAM.INFONGEPART, 'ALT' .. AlternativesNest2D[i] .. '_T' .. '=' .. sOffsetX .. ';' .. sVtN) + end + end - - - -- TEST - BEAM.INFONGEPART = { 'TEST=666,999,666,999', 'TEST2=44444444444', 'TEST3=sksksk'} - - -- local sHeadVtN = ( tostring( HeadProc.Faces[1].vtN)):gsub("^%(", ""):gsub("%)$", "") - -- local sTailVtN = ( tostring( TailProc.Faces[1].vtN)):gsub("^%(", ""):gsub("%)$", "") - -- TEST - - - - - - -- si cancella eventuale mach group creato per le alternative EgtRemoveMachGroup( nTempMachGroupName) diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index d9fe22a..7bfeb80 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -889,6 +889,31 @@ function BeamLib.CalculateStringBinaryFormat( dNumber, CharNumber) return NumberString end +------------------------------------------------------------------------------------------------------------- +function BeamLib.ConvertBitIndexToRotationIndex( sBitIndexCombination) + local nRotationIndex + + if sBitIndexCombination == '1000' then + return 1 + elseif sBitIndexCombination == '0100' then + return 2 + elseif sBitIndexCombination == '0010' then + return 3 + elseif sBitIndexCombination == '0001' then + return 4 + elseif sBitIndexCombination == '1000_INV' then + return 5 + elseif sBitIndexCombination == '0100_INV' then + return 6 + elseif sBitIndexCombination == '0010_INV' then + return 7 + elseif sBitIndexCombination == '0001_INV' then + return 8 + end + + return nRotationIndex +end + ------------------------------------------------------------------------------------------------------------- -- reindicizza una tabella passata ripartendo dall'indice nStartIndex e mantenendo l'ordine function BeamLib.RotateTableFromIndex( Table, nStartIndex) From 0497877abbe9845a2e8201f33893060b143f6e10 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 14 May 2026 15:39:29 +0200 Subject: [PATCH 13/47] - in NestProcess ora si compilano correttamente le tabelle di grezzi e pezzi da nestare, in preparazione al neting --- NestProcess.lua | 158 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 45 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 1a8a075..743780a 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -7,16 +7,6 @@ _ENV = EgtProtectGlobal() EgtEnableDebug( true) -- Include -local BeamLib = require( 'BeamLib') - ----------------------------------------------------------------------------------------------------------- --- stati che definiscono rotazione / inversione della parte -local STATE = { - STD = 1, -- Standard - ROT180 = 2, -- Rotazione 180deg attorno a X+ - INV = 3, -- Inversione (rotazione 180deg attorno a Z+) - INV_ROT180 = 4 -- Inversione + rotazione -} ---------------------------------------------------------------------------------------------------------- -- inventario grezzi @@ -32,16 +22,38 @@ function RawInventory:BuildStock() for i = 1, #LEN do self.Stock[#self.Stock + 1] = { - Length = LEN[i], - Count = QTY[i] + dLength = LEN[i], + nCount = QTY[i] } end return RawInventory end -function RawInventory:AddActiveBeam() - -- TODO da fare +-- aggiunge una nuova barra attiva rimuovendo il 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 = { + dTotalLength = CurrentStock.dLength, + dResidual = CurrentStock.dLength, + LastOffsetX = { 0, 0, 0, 0}, + LastVtN = Vector3d( 1, 0, 0), + NestedParts = {} + } + + table.insert( self.ActiveBeams, NewBeam) + return NewBeam + end + + return nil end ---------------------------------------------------------------------------------------------------------- @@ -49,48 +61,104 @@ end 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) - PartTemplates[id] = {} - PartTemplates[id].dLength = EgtGetInfo( id, 'L', 'd') - -- TODO qua gli stati abilitati dovranno arrivare dalle alternatives - local VerticesHead = EgtSplitString( EgtGetInfo( id, 'HEADOFFSETX', 'd')) - local vtNHead = Vector3d( EgtSplitString( EgtGetInfo( id, 'HEADVTN', 'd'))) - local VerticesTail = EgtSplitString( EgtGetInfo( id, 'TAILOFFSETX', 'd')) - local vtNTail = Vector3d( EgtSplitString( EgtGetInfo( id, 'TAILVTN', 'd'))) - PartTemplates[id].States = { - [STATE.STD] = { - Head = { Vertices = VerticesHead, vtN = vtNHead}, - Tail = { Vertices = VerticesTail, vtN = vtNTail} - }, - [STATE.ROT180] = { - Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead}, - Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead} - }, - [STATE.INV] = { - Head = { Vertices = VerticesTail, vtN = vtNTail}, - Tail = { Vertices = VerticesHead, vtN = vtNHead} - }, - [STATE.INV_ROT180] = { - Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead}, - Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead} - } - } + self[id] = {} + self[id].dLength = EgtGetInfo( id, 'L', 'd') + self[id].States = {} + + 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 + } + 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 +---------------------------------------------------------------------------------------------------------- +-- script principale - - - - - +-- costruzione lista grezzi a stock disponibili RawInventory:BuildStock() -BuildPartTemplatesAndJobPool() \ No newline at end of file + +-- costruzione lista pezzi template con proprietà geometriche e lista pezzi fisici da nestare +BuildPartTemplatesAndJobPool() + +-- loop principale: scorre le barre, si già attive che a stock, e le riempie nel modo migliore possibile +while true do + local BestMove + local HighestScore = GEO.INFINITO + + -- 1 Si provano le barre già attive + + + -- 2 Si provano le barre ancora a stock + for i = 1, #RawInventory.Stock do + if RawInventory.Stock[i].nCount > 0 then + + end + end + + + -- 3 Procedi con nesting + + + + +end \ No newline at end of file From f90dd95880036c53318eacc5c9d6ca6bb89be7d1 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 14 May 2026 16:44:12 +0200 Subject: [PATCH 14/47] - in NestProcess creato il loop di base dello script. Mancano funzioni accessorie --- NestProcess.lua | 59 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 743780a..b69a184 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -15,6 +15,19 @@ local RawInventory = { ActiveBeams = {} } +function RawInventory:GetNewBeam( dLength) + + local NewBeam = { + dTotalLength = dLength, + dResidual = dLength, + LastOffsetX = { 0, 0, 0, 0}, + LastVtN = Vector3d( 1, 0, 0), + NestedParts = {} + } + + return NewBeam +end + function RawInventory:BuildStock() if #LEN ~= #QTY then error( 'NestProcess: invalid stock data') @@ -41,13 +54,7 @@ function RawInventory:AddActiveBeam( nStockIndex) CurrentStock.nCount = CurrentStock.nCount - 1 -- aggiungo una nuova barra attiva - local NewBeam = { - dTotalLength = CurrentStock.dLength, - dResidual = CurrentStock.dLength, - LastOffsetX = { 0, 0, 0, 0}, - LastVtN = Vector3d( 1, 0, 0), - NestedParts = {} - } + local NewBeam = self:GetNewBeam( CurrentStock.dLength) table.insert( self.ActiveBeams, NewBeam) return NewBeam @@ -140,25 +147,39 @@ RawInventory:BuildStock() -- costruzione lista pezzi template con proprietà geometriche e lista pezzi fisici da nestare BuildPartTemplatesAndJobPool() --- loop principale: scorre le barre, si già attive che a stock, e le riempie nel modo migliore possibile +-- 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 HighestScore = GEO.INFINITO + local dHighestScore = -GEO.INFINITO -- 1 Si provano le barre già attive - - - -- 2 Si provano le barre ancora a stock - for i = 1, #RawInventory.Stock do - if RawInventory.Stock[i].nCount > 0 then - + for i = 1, #RawInventory.ActiveBeams do + local CurrentMove = FindBestPartForBeam( RawInventory.ActiveBeams[i], JobPool) + 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, JobPool) + if CurrentMove and CurrentMove.dScore > dHighestScore then + dHighestScore = CurrentMove.dScore + BestMove = CurrentMove + BestMove.nStockIndex = i + end + end + end -- 3 Procedi con nesting - - - - + if BestMove then + CommitBestMove() + else + break + end end \ No newline at end of file From f27000b7bca5d6d41ed7e6c5ace02968542cd577 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 15 May 2026 10:10:25 +0200 Subject: [PATCH 15/47] - in NestProcess.PartTemplates:AddPart si salvano i MaxHeadRecess testa e coda; creata funzione FindBestPartForBeam, da completare --- NestProcess.lua | 53 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index b69a184..03b82c6 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -16,12 +16,12 @@ local RawInventory = { } function RawInventory:GetNewBeam( dLength) - local NewBeam = { dTotalLength = dLength, - dResidual = dLength, + dResidual = dLength - NEST.STARTOFFSET, LastOffsetX = { 0, 0, 0, 0}, LastVtN = Vector3d( 1, 0, 0), + dLastHeadRecess = 0, NestedParts = {} } @@ -43,13 +43,12 @@ function RawInventory:BuildStock() return RawInventory end --- aggiunge una nuova barra attiva rimuovendo il corrispondente dalla lista stock disponibili +-- 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 @@ -64,7 +63,8 @@ function RawInventory:AddActiveBeam( nStockIndex) end ---------------------------------------------------------------------------------------------------------- --- PartTemplates (informazioni geometriche pezzi univoci) e JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare) +-- PartTemplates (informazioni geometriche pezzi univoci) +-- JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare) local PartTemplates = {} local JobPool = {} @@ -80,7 +80,7 @@ function PartTemplates:GetInfoFromPart( id, sStateWithSide) 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 @@ -93,6 +93,7 @@ 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' } @@ -122,6 +123,26 @@ function PartTemplates:AddPart( id) 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 @@ -136,6 +157,13 @@ local function BuildPartTemplatesAndJobPool() end return PartTemplates, JobPool +end + +---------------------------------------------------------------------------------------------------------- +local function FindBestPartForBeam( Beam) + + + end ---------------------------------------------------------------------------------------------------------- @@ -152,10 +180,10 @@ BuildPartTemplatesAndJobPool() 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], JobPool) + local CurrentMove = FindBestPartForBeam( RawInventory.ActiveBeams[i]) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore BestMove = CurrentMove @@ -167,7 +195,7 @@ while true do 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, JobPool) + local CurrentMove = FindBestPartForBeam( VirtualBeam) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore BestMove = CurrentMove @@ -176,9 +204,10 @@ while true do end end - -- 3 Procedi con nesting + -- 3 Se BestMove trovata si aggiornano lista pezzi e barre if BestMove then - CommitBestMove() + CommitBestMove( BestMove) + -- se non c'è più niente di compatibile si esce else break end From 5e503762e5c734eb65a804f6905606b2fbee90fa Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 15 May 2026 10:26:30 +0200 Subject: [PATCH 16/47] - in NestProcess agiunto sorting della JobPool --- NestProcess.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/NestProcess.lua b/NestProcess.lua index 03b82c6..611780e 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -147,6 +147,25 @@ function PartTemplates:AddPart( id) end end +-- ordinamento JobPool per lunghezza decrescente dei pezzi +function JobPool:Sort() + local function SortByLengthDescending( Part1, Part2) + local dLength1 = PartTemplates[Part1.id].dLength + local dLength2 = PartTemplates[Part2.id].dLength + + if dLength1 > dLength2 + 10 * GEO.EPS_SMALL then + return true + elseif dLength2 > dLength1 + 10 * GEO.EPS_SMALL then + return false + end + + -- tie breaker + return Part1.id < Part2.id + end + + table.sort( self, SortByLengthDescending) +end + -- creazione combinata (si cicla una sola volta) di entrambe le tabelle local function BuildPartTemplatesAndJobPool() for id, nCount in pairs( PART) do @@ -175,6 +194,9 @@ RawInventory:BuildStock() -- costruzione lista pezzi template con proprietà geometriche e lista pezzi fisici da nestare BuildPartTemplatesAndJobPool() +-- ordinamento pezzi per lunghezza decrescente +JobPool:Sort() + -- 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 From cad57b2fd592fb0d19aa7de4aab6a321d399a881 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 15 May 2026 10:37:58 +0200 Subject: [PATCH 17/47] - in NestProcess piccole correzioni --- NestProcess.lua | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 611780e..03a8797 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -81,7 +81,6 @@ function PartTemplates:GetInfoFromPart( id, sStateWithSide) 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 @@ -188,13 +187,9 @@ end ---------------------------------------------------------------------------------------------------------- -- script principale --- costruzione lista grezzi a stock disponibili +-- preparazione tabelle lista grezzi (RawInventory), lista pezzi univoci (PartTemplates) e lista singoli pezzi da nestare (JobPool) RawInventory:BuildStock() - --- costruzione lista pezzi template con proprietà geometriche e lista pezzi fisici da nestare BuildPartTemplatesAndJobPool() - --- ordinamento pezzi per lunghezza decrescente JobPool:Sort() -- loop principale: scorre le barre, sia già attive che a stock, e le riempie nel modo migliore possibile @@ -215,8 +210,8 @@ while true do -- 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 VirtualBeam = RawInventory:GetNewBeam( RawInventory.Stock[i].dLength) local CurrentMove = FindBestPartForBeam( VirtualBeam) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore From b77e79d0d0b5009cc987c29a690f0ef37077e125 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 15 May 2026 18:33:15 +0200 Subject: [PATCH 18/47] - in NestProcess loop completo, alcune migliorie possibili per prestazioni; manca la parte che effettivamente crea i MachGroup --- NestProcess.lua | 241 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 6 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 03a8797..1e47e87 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -7,6 +7,33 @@ _ENV = EgtProtectGlobal() EgtEnableDebug( true) -- Include +local BeamData = require( 'BeamDataNew') + + +---------------------------------------------------------------------------------------------------------- +-- Parametri di configurazione Nesting +local CONFIG = { + -- Strategia di ricerca + NUM_LONGEST_CANDIDATES = 3, + + -- Punteggi + BONUS_PERFECT_FIT = 500, -- Se lo scarto è quasi zero (es: < 5mm) + BONUS_SHARED_CUT = 100, -- Se le inclinazioni combaciano perfettamente + PENALTY_TOO_SHORT = 1000, -- Se lo scarto è troppo piccolo per essere utile ma non zero + PENALTY_BAD_FIT_END_PHASE = 1000, -- Se siamo alla fine (>80%) e si utilizza un pezzo corto con fit mediocre + + -- Macchina + MIN_USABLE_REMNANT = BeamData.MINRAW_S, -- Sotto questa misura lo scarto è considerato "sfrido" + MAX_REMNANT_PERFECT_FIT = 20, + BLADE_THICKNESS = 5.4 -- TODO questo deve arrivare da interfaccia o da automatismo!!!!! +} + +---------------------------------------------------------------------------------------------------------- +-- variabili per tutto il modulo +local dMaxJobLength = 0 +local dMaxFillerLength = 0 +local dGlobalProgress = 0 +local t_insert = table.insert -- si mette via il riferimento locale per evitare continui lookup ---------------------------------------------------------------------------------------------------------- -- inventario grezzi @@ -18,9 +45,10 @@ local RawInventory = { function RawInventory:GetNewBeam( dLength) local NewBeam = { dTotalLength = dLength, - dResidual = dLength - NEST.STARTOFFSET, + dResidualLength = dLength - ( NEST.STARTOFFSET or 0), LastOffsetX = { 0, 0, 0, 0}, LastVtN = Vector3d( 1, 0, 0), + vtNXabs = 1, dLastHeadRecess = 0, NestedParts = {} } @@ -55,7 +83,7 @@ function RawInventory:AddActiveBeam( nStockIndex) -- aggiungo una nuova barra attiva local NewBeam = self:GetNewBeam( CurrentStock.dLength) - table.insert( self.ActiveBeams, NewBeam) + t_insert( self.ActiveBeams, NewBeam) return NewBeam end @@ -94,6 +122,11 @@ function PartTemplates:AddPart( id) self[id].States = {} self[id].dMaxGlobalTailRecess = 0 + -- si tiene via la lunghezza del pezzo massimo + if self[id].dLength > dMaxJobLength + 10 * GEO.EPS_SMALL then + dMaxJobLength = self[id].dLength + end + local States = { '1000', '0010', '1000_INV', '0010_INV' } for _, sState in ipairs(States) do @@ -116,11 +149,13 @@ function PartTemplates:AddPart( id) State.Head = { OffsetX = OffsetXHead, - vtN = vtNHead + vtN = vtNHead, + vtNXabs = abs( vtN:getX()) } State.Tail = { OffsetX = OffsetXTail, - vtN = vtNTail + vtN = vtNTail, + vtNXabs = abs( vtN:getX()) } -- overlap massimi in testa e in coda per questo pezzo @@ -170,7 +205,7 @@ local function BuildPartTemplatesAndJobPool() for id, nCount in pairs( PART) do PartTemplates:AddPart( id) for _ = 1, nCount do - table.insert( JobPool, { id = id, bNested = false}) + t_insert( JobPool, { id = id, bNested = false}) end end @@ -178,10 +213,185 @@ local function BuildPartTemplatesAndJobPool() end ---------------------------------------------------------------------------------------------------------- +-- calcolo singola Move, ossia combinazione barra-pezzo-stato, con relativo punteggio +local function CalculateMove( Beam, dPartLength, sState, State) + local Move = {} + + -- calcolo overlap pezzi (riduzione di lunghezza occupata) + local dSafeOverlap = GEO.INFINITO + for i = 1, 4 do + local dCornerDistance = Beam.LastOffsetX[i] - State.Tail.OffsetX[i] + if dCornerDistance < dSafeOverlap then + dSafeOverlap = dCornerDistance + end + end + + -- il massimo overlap va ridotto dello spessore lama + local dProjectedBlade = CONFIG.BLADE_THICKNESS / min( Beam.vtNXabs, State.Tail.vtNXabs) + dSafeOverlap = dSafeOverlap - dProjectedBlade + + -- lunghezza barra rimasta (se negativo non ci sta) + local dFutureResidualLength = Beam.dResidualLength + dSafeOverlap - dPartLength + if dFutureResidualLength < -10 * GEO.EPS_SMALL then + return nil + end + + -- Calcolo punteggio + -- All'inizio (Ratio=1) si dà vantaggio ai pezzi più lunghi. Alla fine (Ratio=0) si dà vantaggio ai best fit. + local dNormalizedLength = dPartLength / dMaxJobLength + local dEfficiency = dPartLength / ( dPartLength + dFutureResidualLength) + local dLengthScore = dNormalizedLength * ( 1 - GlobalProgress) * 1000 + local dEfficiencyScore = dEfficiency * GlobalProgress * 1000 + + local dScore = dLengthScore + dEfficiencyScore + + -- Bonus Perfect Fit + if dFutureResidualLength < CONFIG.MAX_REMNANT_PERFECT_FIT then + dScore = dScore + CONFIG.BONUS_PERFECT_FIT + + -- Penalità Sliver (si evitano sfridi non riutilizzabili) + elseif dFutureResidualLength < CONFIG.MIN_USABLE_REMNANT then + dScore = dScore - CONFIG.PENALTY_TOO_SHORT + end + + -- Bonus Shared Cut: se le normali sono opposte, si risparmia un taglio/posizionamento + if AreOppositeVectorApprox( Beam.LastVtN, State.Tail.vtN) then + dScore = dScore + CONFIG.BONUS_SHARED_CUT + end + + -- Protezione finale pezzi corti: se siamo alla fine e il pezzo è corto, penalizziamo se non è un fit quasi perfetto + if ( dGlobalProgress >= 0.8) and ( dPartLength < dMaxFillerLength) and ( dFutureResidualLength > CONFIG.MAX_REMNANT_PERFECT_FIT) then + dScore = dScore - CONFIG.PENALTY_BAD_FIT_END_PHASE + end + + Move = { + sState = sState, + dScore = dScore, + dSafeOverlap = dSafeOverlap, + dFutureResidualLength = dFutureResidualLength + } + return Move +end + +---------------------------------------------------------------------------------------------------------- +-- trova i migliori pezzi da inserire nella trave (N pezzi più lunghi e 2 pezzi di lunghezza più adeguata al restante della barra) e i migliori stati in cui metterli local function FindBestPartForBeam( Beam) + local nLongestParts = 0 + local Candidates = {} + local BestFitJob1 = { Job = nil, dGap = GEO.INFINITO } + local BestFitJob2 = { Job = nil, dGap = GEO.INFINITO } + -- 1 Scelta candidati -- + for i = 1, #JobPool do + local Job = JobPool[i] + if not Job.bNested then + local PartTemplate = PartTemplates[Job.id] + local dGap = Beam.dResidualLength + Beam.dLastHeadRecess + PartTemplate.dMaxGlobalTailRecess - PartTemplate.dLength + + if dGap > - 10 * GEO.EPS_SMALL then + + -- JobPool è già ordinata: i primi N pezzi che entrano sono i più lunghi + if nLongestParts < CONFIG.NUM_LONGEST_CANDIDATES then + t_insert( Candidates, Job) + nLongestParts = nLongestParts + 1 + end + + -- si cercano i due pezzi con il best fit nella barra restante + if dGap < BestFitJob1.dGap then + -- il bestfit1 è il nuovo bestfit 2 + BestFitJob2.Job = BestFitJob1.Job + BestFitJob2.dGap = BestFitJob1.dGap + -- la job corrente è la nuova bestfit1 + BestFitJob1.dGap = dGap + BestFitJob1.Job = Job + elseif dGap < BestFitJob2.dGap then + BestFitJob2.Job = Job + BestFitJob2.dGap = dGap + end + end + end + end + + -- i pezzi bestfit si aggiungono solo se non corrispondono a pezzi già inseriti + local function AddIfUnique( JobToAdd) + if not JobToAdd then return end + for i = 1, #Candidates do + if Candidates[i] == JobToAdd then return end + end + t_insert( Candidates, JobToAdd) + end + AddIfUnique( BestFitJob1.Job) + AddIfUnique( BestFitJob2.Job) + + -- 2 Scelta miglior candidato -- + local dHighestScore = -GEO.INFINITO + local BestMove + for i = 1, #Candidates do + local Candidate = Candidates[i] + local Template = PartTemplates[Candidate.id] + local dPartLength = Template.dLength + local dHighestCandidateScore = -GEO.INFINITO + local BestCandidateMove + + -- si trova la Move migliore del singolo candidato (a CalculateMove si passano gli argomenti precalcolati per evitare di rallentare il calcolo) + for sState, State in pairs( Template.States) do + local Move = CalculateMove( Beam, dPartLength, sState, State) + if Move and Move.dScore > dHighestCandidateScore + 10 * GEO.EPS_SMALL then + BestCandidateMove = Move + dHighestCandidateScore = Move.dScore + BestCandidateMove.Job = Candidate + end + end + + -- si trova la Move migliore in assoluto + if dHighestCandidateScore > dHighestScore + 10 * GEO.EPS_SMALL then + BestMove = BestCandidateMove + dHighestScore = dHighestCandidateScore + end + end + + return BestMove +end + +---------------------------------------------------------------------------------------------------------- +-- Esegue la mossa scelta: aggiorna lo stato della trave e segna il pezzo come nestato +local function CommitBestMove( BestMove) + local Beam + + -- recupero o creazione della barra + if BestMove.nActiveBeamIndex then + Beam = RawInventory.ActiveBeams[BestMove.nActiveBeamIndex] + elseif BestMove.nStockIndex then + Beam = RawInventory:AddActiveBeam(BestMove.nStockIndex) + end + + if not Beam then return end + + -- recupero dati pezzo e stato + local Job = BestMove.Job + local Template = PartTemplates[Job.id] + local State = Template.States[BestMove.sState] + + -- update geometria barra + -- la nuova faccia della barra è ora la testa (Head) del pezzo appena inserito + Beam.dResidualLength = BestMove.dFutureResidualLength + Beam.LastOffsetX = State.Head.OffsetX + Beam.LastVtN = State.Head.vtN + Beam.vtNXabs = abs( State.Head.vtN:getX()) + Beam.dLastHeadRecess = State.dMaxHeadRecess + + -- registrazione pezzo + t_insert( Beam.NestedParts, { + id = Job.id, + sState = BestMove.sState, + dSafeOverlap = BestMove.dSafeOverlap, + dLength = Template.dLength + }) + + -- chiusura job + Job.bNested = true end ---------------------------------------------------------------------------------------------------------- @@ -192,12 +402,29 @@ RawInventory:BuildStock() BuildPartTemplatesAndJobPool() JobPool:Sort() +-- calcolo lunghezza massima pezzi "filler" +local nTotalParts = #JobPool +local nFillerIndex = floor( nTotalParts * 0.8) + 1 +if nFillerIndex > nTotalParts then nFillerIndex = nTotalParts end +dMaxFillerLength = PartTemplates[JobPool[nFillerIndex].id].dLength +dMaxFillerLength = EgtClamp( dMaxFillerLength, ( BeamData.MINRAW_S + BeamData.MINRAW_L) / 2, BeamData.LEN_SHORT_PART) + -- 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 +local nDoneParts = 0 +local VirtualBeam = RawInventory:GetNewBeam( 0) while true do local BestMove local dHighestScore = -GEO.INFINITO + -- progresso calcolo + if nTotalParts > 0 then + dGlobalProgress = nDoneParts / nTotalParts + -- se non ci sono pezzi il calcolo è già finito + else + dGlobalProgress = 1 + end + -- 1 Si provano le barre già attive for i = 1, #RawInventory.ActiveBeams do local CurrentMove = FindBestPartForBeam( RawInventory.ActiveBeams[i]) @@ -211,7 +438,8 @@ while true do -- 2 Si provano le barre ancora a stock for i = 1, #RawInventory.Stock do if RawInventory.Stock[i].nCount > 0 then - local VirtualBeam = RawInventory:GetNewBeam( RawInventory.Stock[i].dLength) + VirtualBeam.dTotalLength = RawInventory.Stock[i].dLength + VirtualBeam.dResidualLength = RawInventory.Stock[i].dLength - ( NEST.STARTOFFSET or 0) local CurrentMove = FindBestPartForBeam( VirtualBeam) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore @@ -224,6 +452,7 @@ while true do -- 3 Se BestMove trovata si aggiornano lista pezzi e barre if BestMove then CommitBestMove( BestMove) + nDoneParts = nDoneParts + 1 -- se non c'è più niente di compatibile si esce else break From a66054a6c8de396033275852d3577753450798e0 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 10:16:20 +0200 Subject: [PATCH 19/47] =?UTF-8?q?-=20in=20NestProcess=20correzioni=20e=20m?= =?UTF-8?q?odifiche=20per=20migliorare=20l'efficienza.=20Sembra=20funziona?= =?UTF-8?q?re,=20da=20verificare=20bont=C3=A0=20nesting.=20Manca=20creazio?= =?UTF-8?q?ne=20MachGroup=20veri=20e=20propri?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NestProcess.lua | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 1e47e87..b10e195 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -150,12 +150,12 @@ function PartTemplates:AddPart( id) State.Head = { OffsetX = OffsetXHead, vtN = vtNHead, - vtNXabs = abs( vtN:getX()) + vtNXabs = abs( vtNHead:getX()) } State.Tail = { OffsetX = OffsetXTail, vtN = vtNTail, - vtNXabs = abs( vtN:getX()) + vtNXabs = abs( vtNTail:getX()) } -- overlap massimi in testa e in coda per questo pezzo @@ -240,8 +240,8 @@ local function CalculateMove( Beam, dPartLength, sState, State) -- All'inizio (Ratio=1) si dà vantaggio ai pezzi più lunghi. Alla fine (Ratio=0) si dà vantaggio ai best fit. local dNormalizedLength = dPartLength / dMaxJobLength local dEfficiency = dPartLength / ( dPartLength + dFutureResidualLength) - local dLengthScore = dNormalizedLength * ( 1 - GlobalProgress) * 1000 - local dEfficiencyScore = dEfficiency * GlobalProgress * 1000 + local dLengthScore = dNormalizedLength * ( 1 - dGlobalProgress) * 1000 + local dEfficiencyScore = dEfficiency * dGlobalProgress * 1000 local dScore = dLengthScore + dEfficiencyScore @@ -278,6 +278,7 @@ end local function FindBestPartForBeam( Beam) local nLongestParts = 0 local Candidates = {} + local JobsAlreadyInCandidates = {} local BestFitJob1 = { Job = nil, dGap = GEO.INFINITO } local BestFitJob2 = { Job = nil, dGap = GEO.INFINITO } @@ -295,6 +296,7 @@ local function FindBestPartForBeam( Beam) -- JobPool è già ordinata: i primi N pezzi che entrano sono i più lunghi if nLongestParts < CONFIG.NUM_LONGEST_CANDIDATES then t_insert( Candidates, Job) + JobsAlreadyInCandidates[Job] = true nLongestParts = nLongestParts + 1 end @@ -315,15 +317,15 @@ local function FindBestPartForBeam( Beam) end -- i pezzi bestfit si aggiungono solo se non corrispondono a pezzi già inseriti - local function AddIfUnique( JobToAdd) - if not JobToAdd then return end - for i = 1, #Candidates do - if Candidates[i] == JobToAdd then return end - end - t_insert( Candidates, JobToAdd) + if BestFitJob1.Job and not JobsAlreadyInCandidates[BestFitJob1.Job] then + table.insert( Candidates, BestFitJob1.Job) + JobsAlreadyInCandidates[BestFitJob1.Job] = true + end + + if BestFitJob2.Job and not JobsAlreadyInCandidates[BestFitJob2.Job] then + table.insert( Candidates, BestFitJob2.Job) + JobsAlreadyInCandidates[BestFitJob2.Job] = true end - AddIfUnique( BestFitJob1.Job) - AddIfUnique( BestFitJob2.Job) -- 2 Scelta miglior candidato -- local dHighestScore = -GEO.INFINITO @@ -364,7 +366,7 @@ local function CommitBestMove( BestMove) if BestMove.nActiveBeamIndex then Beam = RawInventory.ActiveBeams[BestMove.nActiveBeamIndex] elseif BestMove.nStockIndex then - Beam = RawInventory:AddActiveBeam(BestMove.nStockIndex) + Beam = RawInventory:AddActiveBeam( BestMove.nStockIndex) end if not Beam then return end @@ -455,6 +457,7 @@ while true do nDoneParts = nDoneParts + 1 -- se non c'è più niente di compatibile si esce else + local a break end end \ No newline at end of file From 1cde1c94d9129f23301192d0649c7a05f58f2cad Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 11:32:15 +0200 Subject: [PATCH 20/47] =?UTF-8?q?-=20in=20NestProcess=20aggiunta=20PrintDi?= =?UTF-8?q?agnosticReport=20per=20stimare=20la=20bont=C3=A0=20del=20nestin?= =?UTF-8?q?g;=20in=20CalculateMove=20modificato=20calcolo=20efficienza=20n?= =?UTF-8?q?el=20caso=20di=20barra=20nuova;=20correzioni=20minori?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NestProcess.lua | 85 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index b10e195..c104c90 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -19,7 +19,7 @@ local CONFIG = { -- Punteggi BONUS_PERFECT_FIT = 500, -- Se lo scarto è quasi zero (es: < 5mm) BONUS_SHARED_CUT = 100, -- Se le inclinazioni combaciano perfettamente - PENALTY_TOO_SHORT = 1000, -- Se lo scarto è troppo piccolo per essere utile ma non zero + PENALTY_TOO_SHORT = 100, -- Se lo scarto è troppo piccolo per essere utile ma non zero PENALTY_BAD_FIT_END_PHASE = 1000, -- Se siamo alla fine (>80%) e si utilizza un pezzo corto con fit mediocre -- Macchina @@ -34,6 +34,7 @@ local dMaxJobLength = 0 local dMaxFillerLength = 0 local dGlobalProgress = 0 local t_insert = table.insert -- si mette via il riferimento locale per evitare continui lookup +local JobPool = {} ---------------------------------------------------------------------------------------------------------- -- inventario grezzi @@ -90,11 +91,64 @@ function RawInventory:AddActiveBeam( nStockIndex) return nil end +-- auditor della bontà del nesting calcolato. Scrive nel log i risultati. +function RawInventory:PrintDiagnosticReport() + local nBeamsUsed = #self.ActiveBeams + local dTotalStockLength = 0 + local dTotalPartLength = 0 + local dTotalScrap = 0 + local dTotalUsableRemnants = 0 + + for i = 1, nBeamsUsed do + local Beam = self.ActiveBeams[i] + dTotalStockLength = dTotalStockLength + Beam.dTotalLength + + -- Classificazione del residuo rimasto in fondo alla barra + if Beam.dResidualLength >= CONFIG.MIN_USABLE_REMNANT then + dTotalUsableRemnants = dTotalUsableRemnants + Beam.dResidualLength + else + dTotalScrap = dTotalScrap + Beam.dResidualLength + end + + -- Somma delle lunghezze dei pezzi reali inseriti + for j = 1, #Beam.NestedParts do + local Part = Beam.NestedParts[j] + dTotalPartLength = dTotalPartLength + Part.dLength + end + end + + -- Calcolo efficienze percentuali con protezione per divisione per zero + local dGrossEfficiency = 0 + if dTotalStockLength > 0 then + dGrossEfficiency = (dTotalPartLength / dTotalStockLength) * 100 + end + + local dNetEfficiency = 0 + local dNetDenominator = dTotalStockLength - dTotalUsableRemnants + if dNetDenominator > 0 then + dNetEfficiency = (dTotalPartLength / dNetDenominator) * 100 + end + + -- Stampa tramite il sistema di logging proprietario EgtLog + EgtOutLog("==========================================================") + EgtOutLog(" EGALWARE NESTING ENGINE DIAGNOSTIC ") + EgtOutLog("==========================================================") + EgtOutLog(string.format("Total Parts Nested : %d", #JobPool)) + EgtOutLog(string.format("Total Bars Used : %d", nBeamsUsed)) + EgtOutLog(string.format("Total Material Cut : %.2f mm", dTotalPartLength)) + EgtOutLog("----------------------------------------------------------") + EgtOutLog(string.format("Gross Yield (Rendimento): %.2f%%", dGrossEfficiency)) + EgtOutLog(string.format("Net Yield (Riutilizzato): %.2f%%", dNetEfficiency)) + EgtOutLog("----------------------------------------------------------") + EgtOutLog(string.format("Total Usable Remnants : %.2f mm (Safe for Clamps)", dTotalUsableRemnants)) + EgtOutLog(string.format("Total Pure Scrap (Sfrido): %.2f mm (Trash Zone)", dTotalScrap)) + EgtOutLog("==========================================================") +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 = {} @@ -238,8 +292,21 @@ local function CalculateMove( Beam, dPartLength, sState, State) -- Calcolo punteggio -- All'inizio (Ratio=1) si dà vantaggio ai pezzi più lunghi. Alla fine (Ratio=0) si dà vantaggio ai best fit. + local dEfficiency + -- barra nuova, si valuta l'efficienza prospettica + if #Beam.NestedParts == 0 then + -- È una barra vergine dallo stock! Valutiamo la sua efficienza PROSPETTICA + -- Quanti pezzi di questa lunghezza ci starebbero al massimo? + local nMaxPieces = math.floor(Beam.dResidualLength / dPartLength) + if nMaxPieces == 0 then nMaxPieces = 1 end + + local dUltimateUsed = nMaxPieces * dPartLength + dEfficiency = dUltimateUsed / Beam.dTotalLength + -- barra avviata: efficienza reale + else + dEfficiency = dPartLength / ( dPartLength + dFutureResidualLength) + end local dNormalizedLength = dPartLength / dMaxJobLength - local dEfficiency = dPartLength / ( dPartLength + dFutureResidualLength) local dLengthScore = dNormalizedLength * ( 1 - dGlobalProgress) * 1000 local dEfficiencyScore = dEfficiency * dGlobalProgress * 1000 @@ -437,11 +504,16 @@ while true do end end - -- 2 Si provano le barre ancora a stock + -- 2 Si provano le barre ancora a stock (VirtualBeam si resetta invece di crearne una nuova per velocizzare il calcolo) for i = 1, #RawInventory.Stock do if RawInventory.Stock[i].nCount > 0 then VirtualBeam.dTotalLength = RawInventory.Stock[i].dLength VirtualBeam.dResidualLength = RawInventory.Stock[i].dLength - ( NEST.STARTOFFSET or 0) + VirtualBeam.LastOffsetX = { 0, 0, 0, 0} + VirtualBeam.LastVtN = Vector3d( 1, 0, 0) + VirtualBeam.vtNXabs = 1 + VirtualBeam.dLastHeadRecess = 0 + VirtualBeam.NestedParts = {} local CurrentMove = FindBestPartForBeam( VirtualBeam) if CurrentMove and CurrentMove.dScore > dHighestScore then dHighestScore = CurrentMove.dScore @@ -457,7 +529,8 @@ while true do nDoneParts = nDoneParts + 1 -- se non c'è più niente di compatibile si esce else - local a break end -end \ No newline at end of file +end + +RawInventory:PrintDiagnosticReport() \ No newline at end of file From a404bf2f9e9f98221d3dbd5d2f93c5cf49731fa1 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 12:03:46 +0200 Subject: [PATCH 21/47] =?UTF-8?q?-=20in=20NestProcess=20si=20provano=20bar?= =?UTF-8?q?re=20nuove=20solo=20se=20non=20si=20trovano=20soluzioni=20con?= =?UTF-8?q?=20quelle=20gi=C3=A0=20attive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NestProcess.lua | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index c104c90..178cd7a 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -4,7 +4,7 @@ -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() -EgtEnableDebug( true) +EgtEnableDebug( false) -- Include local BeamData = require( 'BeamDataNew') @@ -504,21 +504,24 @@ while true do end end - -- 2 Si provano le barre ancora a stock (VirtualBeam si resetta invece di crearne una nuova per velocizzare il calcolo) - for i = 1, #RawInventory.Stock do - if RawInventory.Stock[i].nCount > 0 then - VirtualBeam.dTotalLength = RawInventory.Stock[i].dLength - VirtualBeam.dResidualLength = RawInventory.Stock[i].dLength - ( NEST.STARTOFFSET or 0) - VirtualBeam.LastOffsetX = { 0, 0, 0, 0} - VirtualBeam.LastVtN = Vector3d( 1, 0, 0) - VirtualBeam.vtNXabs = 1 - VirtualBeam.dLastHeadRecess = 0 - VirtualBeam.NestedParts = {} - local CurrentMove = FindBestPartForBeam( VirtualBeam) - if CurrentMove and CurrentMove.dScore > dHighestScore then - dHighestScore = CurrentMove.dScore - BestMove = CurrentMove - BestMove.nStockIndex = i + -- 2 Si provano le barre ancora a stock SOLO SE NON TROVATA SOLUZIONE CON BARRE ATTIVE + -- VirtualBeam si resetta invece di crearne una nuova per velocizzare il calcolo + if not BestMove then + for i = 1, #RawInventory.Stock do + if RawInventory.Stock[i].nCount > 0 then + VirtualBeam.dTotalLength = RawInventory.Stock[i].dLength + VirtualBeam.dResidualLength = RawInventory.Stock[i].dLength - ( NEST.STARTOFFSET or 0) + VirtualBeam.LastOffsetX = { 0, 0, 0, 0} + VirtualBeam.LastVtN = Vector3d( 1, 0, 0) + VirtualBeam.vtNXabs = 1 + VirtualBeam.dLastHeadRecess = 0 + VirtualBeam.NestedParts = {} + local CurrentMove = FindBestPartForBeam( VirtualBeam) + if CurrentMove and CurrentMove.dScore > dHighestScore then + dHighestScore = CurrentMove.dScore + BestMove = CurrentMove + BestMove.nStockIndex = i + end end end end From d59039eae0f6876671c8532976d786a84f2c7000 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 12:28:36 +0200 Subject: [PATCH 22/47] - in NestProcess correzioni in PrintDiagnosticReport --- NestProcess.lua | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 178cd7a..91df45c 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -99,10 +99,19 @@ function RawInventory:PrintDiagnosticReport() local dTotalScrap = 0 local dTotalUsableRemnants = 0 + -- si contano i pezzi davvero nestati + local nActualNestedParts = 0 + for i = 1, #JobPool do + if JobPool[i].bNested then + nActualNestedParts = nActualNestedParts + 1 + end + end + local nUnnestedParts = #JobPool - nActualNestedParts + for i = 1, nBeamsUsed do local Beam = self.ActiveBeams[i] dTotalStockLength = dTotalStockLength + Beam.dTotalLength - + -- Classificazione del residuo rimasto in fondo alla barra if Beam.dResidualLength >= CONFIG.MIN_USABLE_REMNANT then dTotalUsableRemnants = dTotalUsableRemnants + Beam.dResidualLength @@ -133,7 +142,16 @@ function RawInventory:PrintDiagnosticReport() EgtOutLog("==========================================================") EgtOutLog(" EGALWARE NESTING ENGINE DIAGNOSTIC ") EgtOutLog("==========================================================") - EgtOutLog(string.format("Total Parts Nested : %d", #JobPool)) + EgtOutLog(string.format("Total Parts Demanded : %d", #JobPool)) + EgtOutLog(string.format("Parts Successfully Nested: %d", nActualNestedParts)) + + -- Se ci sono pezzi rimasti fuori, spariamo un alert visibile nel log + if nUnnestedParts > 0 then + EgtOutLog(string.format("WARNING: Unnested Parts : %d <<<<<< MATERIAL SHORTAGE!", nUnnestedParts)) + else + EgtOutLog("All Parts Nested : YES (Commessa completata)") + end + EgtOutLog(string.format("Total Bars Used : %d", nBeamsUsed)) EgtOutLog(string.format("Total Material Cut : %.2f mm", dTotalPartLength)) EgtOutLog("----------------------------------------------------------") From 965c6e8f9e7750b5a9547cfa07ff1f828c03064a Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 12:40:06 +0200 Subject: [PATCH 23/47] - in NestProcess aggiunta MIN_FILLER_LIMITin CONFIG per pulizia codice --- NestProcess.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 91df45c..2cbbe43 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -25,7 +25,8 @@ local CONFIG = { -- Macchina MIN_USABLE_REMNANT = BeamData.MINRAW_S, -- Sotto questa misura lo scarto è considerato "sfrido" MAX_REMNANT_PERFECT_FIT = 20, - BLADE_THICKNESS = 5.4 -- TODO questo deve arrivare da interfaccia o da automatismo!!!!! + BLADE_THICKNESS = 5.4, -- TODO questo deve arrivare da interfaccia o da automatismo!!!!! + MIN_FILLER_LIMIT = ( BeamData.MINRAW_S + BeamData.MINRAW_L) / 2 } ---------------------------------------------------------------------------------------------------------- @@ -494,7 +495,7 @@ local nTotalParts = #JobPool local nFillerIndex = floor( nTotalParts * 0.8) + 1 if nFillerIndex > nTotalParts then nFillerIndex = nTotalParts end dMaxFillerLength = PartTemplates[JobPool[nFillerIndex].id].dLength -dMaxFillerLength = EgtClamp( dMaxFillerLength, ( BeamData.MINRAW_S + BeamData.MINRAW_L) / 2, BeamData.LEN_SHORT_PART) +dMaxFillerLength = EgtClamp( dMaxFillerLength, CONFIG.MIN_FILLER_LIMIT, BeamData.LEN_SHORT_PART) -- 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 From e5f1abc47d1c1b6bc4bd260db46603e49af55e30 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 14:45:57 +0200 Subject: [PATCH 24/47] - in NestProcess aggiunto lo spostamento delle travi verso la testa della trave (vedere se poi integrare in creazione MachGroup) --- NestProcess.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/NestProcess.lua b/NestProcess.lua index 2cbbe43..47228ca 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -475,7 +475,8 @@ local function CommitBestMove( BestMove) id = Job.id, sState = BestMove.sState, dSafeOverlap = BestMove.dSafeOverlap, - dLength = Template.dLength + dLength = Template.dLength, + dPosX = BestMove.dFutureResidualLength }) -- chiusura job @@ -555,4 +556,17 @@ while true do end end +-- Spostamento travi verso la testa della barra +-- TODO vedere se integrabile in creazione MachGroup +for i = 1, #RawInventory.ActiveBeams do + local Beam = RawInventory.ActiveBeams[i] + local dOffset = NEST.STARTOFFSET or 0 + + for j = 1, #Beam.NestedParts do + local Part = Beam.NestedParts[j] + + Part.dPosX = Part.dPosX - Beam.dResidualLength + dOffset + end +end + RawInventory:PrintDiagnosticReport() \ No newline at end of file From b79617fbe4d292ed7a297ac231d50f5b161b4d6b Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 15:53:18 +0200 Subject: [PATCH 25/47] - in NestProcess primo abbozzo della creazione MachGroup --- NestProcess.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 47228ca..f2bc7be 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -556,16 +556,28 @@ while true do end end --- Spostamento travi verso la testa della barra --- TODO vedere se integrabile in creazione MachGroup +-- creazione MachGroup e Duplo for i = 1, #RawInventory.ActiveBeams do - local Beam = RawInventory.ActiveBeams[i] local dOffset = NEST.STARTOFFSET or 0 + local Beam = RawInventory.ActiveBeams[i] - for j = 1, #Beam.NestedParts do + -- creazione MachGroup + local sMachGroup = EgtGetMachGroupNewName( i) + local idMachGroup = EgtAddMachGroup( sMachGroup) + + -- assegnazione info + EgtSetInfo( idMachGroup, "BARLEN", Beam.dTotalLength) + EgtSetInfo( idMachGroup, "MATERIAL", NEST.MATERIAL) + EgtSetInfo( idMachGroup, "AUTONEST", 1) + EgtSetInfo( idMachGroup, "PRODID", NEST.PRODID) + EgtSetInfo( idMachGroup, "PATTID", idMachGroup) + + -- Spostamento pezzi verso la testa della barra e aggiunta duplo + for j = 1, Beam.NestedParts do local Part = Beam.NestedParts[j] - Part.dPosX = Part.dPosX - Beam.dResidualLength + dOffset + local idDuplo = EgtDuploNew( Part.id) + EgtSetInfo( idMachGroup, "PART" .. j, idDuplo .. "," .. Part.dPosX) end end From 974d1abb413530b8ae397568682da7a71524568d Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 16:40:58 +0200 Subject: [PATCH 26/47] - in NestProcess correzione bug --- NestProcess.lua | 71 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index f2bc7be..81b18a4 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -9,6 +9,24 @@ EgtEnableDebug( false) -- Include local BeamData = require( 'BeamDataNew') +-- Imposto direttorio libreria specializzata per Travi +EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua') + +-- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi +EgtSetCurrMachine( NEST.MACHINE) +local sMachDir = EgtGetCurrMachineDir() +if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then + NEST.ERR = 12 + NEST.MSG = 'Error : machine' .. sMachine .. 'note configured for Beam' + WriteErrToLogFile( NEST.ERR, NEST.MSG) + PostErrView( NEST.ERR, NEST.MSG) + return +end + +-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie +EgtRemoveBaseMachineDirFromPackagePath() +EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua') + ---------------------------------------------------------------------------------------------------------- -- Parametri di configurazione Nesting @@ -323,7 +341,7 @@ local function CalculateMove( Beam, dPartLength, sState, State) dEfficiency = dUltimateUsed / Beam.dTotalLength -- barra avviata: efficienza reale else - dEfficiency = dPartLength / ( dPartLength + dFutureResidualLength) + dEfficiency = dPartLength / ( dPartLength - dSafeOverlap) end local dNormalizedLength = dPartLength / dMaxJobLength local dLengthScore = dNormalizedLength * ( 1 - dGlobalProgress) * 1000 @@ -558,7 +576,7 @@ end -- creazione MachGroup e Duplo for i = 1, #RawInventory.ActiveBeams do - local dOffset = NEST.STARTOFFSET or 0 + local dStartOffset = NEST.STARTOFFSET or 0 local Beam = RawInventory.ActiveBeams[i] -- creazione MachGroup @@ -573,12 +591,55 @@ for i = 1, #RawInventory.ActiveBeams do EgtSetInfo( idMachGroup, "PATTID", idMachGroup) -- Spostamento pezzi verso la testa della barra e aggiunta duplo - for j = 1, Beam.NestedParts do + local nIndex = 1 + for j = #Beam.NestedParts, 1, -1 do local Part = Beam.NestedParts[j] - Part.dPosX = Part.dPosX - Beam.dResidualLength + dOffset + + -- spostamento verso la testa della barra + local dPosX = Part.dPosX - Beam.dResidualLength + dStartOffset + + -- copia del pezzo (aggiunta duplo) local idDuplo = EgtDuploNew( Part.id) - EgtSetInfo( idMachGroup, "PART" .. j, idDuplo .. "," .. Part.dPosX) + + -- assegnazione info + EgtSetInfo( idMachGroup, "PART" .. nIndex, idDuplo .. "," .. dPosX) + + nIndex = nIndex + 1 end end +-- creazione grezzi per ogni MachGroup (si chiama la BatchProcess in modalità creazione barra) +local nRawCounter = 0 +local nTotalRaws = #RawInventory.ActiveBeams + +-- variabili per BatchProcess +_G.BEAM = {} +BEAM.FILE = NEST.FILE +BEAM.MACHINE = NEST.MACHINE +BEAM.FLAG = 6 -- CREATE_PANEL +BEAM.BASEDIR = NEST.BASEDIR + +-- per ogni MachGroup si chiama la BatchProcess pe creare il grezzo +local idMachGroup = EgtGetFirstMachGroup() +while idMachGroup do + local nNextMachGroup = EgtGetNextMachGroup( idMachGroup) + EgtSetCurrMachGroup( idMachGroup) + if EgtGetInfo( idMachGroup, "AUTONEST",'i') == 1 then + EgtRemoveInfo( idMachGroup, "AUTONEST") + EgtSetInfo( idMachGroup, "UPDATEUI", 1) + local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua") + if not bOk then + EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')') + end + nRawCounter = nRawCounter + 1 + -- aggiorno interfaccia + EgtProcessEvents( 200 + ( nRawCounter / nTotalRaws * 100), 0) + end + idMachGroup = nNextMachGroup +end + +EgtResetCurrMachGroup() +NEST.ERR = 0 + +-- calcolo bontà soluzione RawInventory:PrintDiagnosticReport() \ No newline at end of file From b7dbc7422c60ab2852c2dd32a78464ca7558e3a6 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 17:26:05 +0200 Subject: [PATCH 27/47] - in BeamExec.ProcessAlternatives si passa all'interfaccia da scrivere anche la posizione iniziale del pezzo --- LuaLibs/BeamExec.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index bc1b157..519c76e 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -2474,6 +2474,7 @@ function BeamExec.ProcessAlternatives( PARTS) -- passaggio info a interfaccia da scrivere sul pezzo BEAM.INFONGEPART = {} + table.insert( BEAM.INFONGEPART, 'INITIALPOSITION=' .. PARTS[nPart].nInitialPosition) for i = 1, #AlternativesNest2D do local sRotation = BeamLib.ConvertBitIndexToRotationIndex( AlternativesNest2D[i]) if PARTS[nPart].HeadcutInfo then From 08397ae1027a8b59e1ef25f303229763cb24111f Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 18 May 2026 18:28:57 +0200 Subject: [PATCH 28/47] - in NestProcess aggiunte eventuali rotazioni/inversioni duplo nella barra --- NestProcess.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/NestProcess.lua b/NestProcess.lua index 81b18a4..ef7b856 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -8,6 +8,7 @@ EgtEnableDebug( false) -- Include local BeamData = require( 'BeamDataNew') +local BeamLib = require( 'BeamLib') -- Imposto direttorio libreria specializzata per Travi EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua') @@ -594,12 +595,25 @@ for i = 1, #RawInventory.ActiveBeams do local nIndex = 1 for j = #Beam.NestedParts, 1, -1 do local Part = Beam.NestedParts[j] + local nInitialPosition = EgtGetInfo( Part.id, 'INITIALPOSITION', 'i') -- spostamento verso la testa della barra local dPosX = Part.dPosX - Beam.dResidualLength + dStartOffset -- copia del pezzo (aggiunta duplo) local idDuplo = EgtDuploNew( Part.id) + local Duplo = { id = idDuplo, idRaw = EgtGetRawPartFromPart( idDuplo)} + + -- eventuale inversione + if EgtEndsWith( Part.sState, 'INV') then + BeamLib.InvertRawPart( Duplo, 2) + end + + -- eventuale rotazione + if ( EgtStartsWith( Part.sState, '0010') and nInitialPosition == 1) + or ( EgtStartsWith( Part.sState, '1000') and nInitialPosition == 3) then + BeamLib.RotateRawPart( Duplo, 2) + end -- assegnazione info EgtSetInfo( idMachGroup, "PART" .. nIndex, idDuplo .. "," .. dPosX) From 608f8da033187b0c6ddd2525a09511ad441d8365 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 19 May 2026 09:50:58 +0200 Subject: [PATCH 29/47] - in NestProcess si fanno correttamente inversioni e rotazioni --- NestProcess.lua | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index ef7b856..0320427 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -160,7 +160,7 @@ function RawInventory:PrintDiagnosticReport() -- Stampa tramite il sistema di logging proprietario EgtLog EgtOutLog("==========================================================") - EgtOutLog(" EGALWARE NESTING ENGINE DIAGNOSTIC ") + EgtOutLog(" NESTING RESULT ") EgtOutLog("==========================================================") EgtOutLog(string.format("Total Parts Demanded : %d", #JobPool)) EgtOutLog(string.format("Parts Successfully Nested: %d", nActualNestedParts)) @@ -173,13 +173,13 @@ function RawInventory:PrintDiagnosticReport() end EgtOutLog(string.format("Total Bars Used : %d", nBeamsUsed)) - EgtOutLog(string.format("Total Material Cut : %.2f mm", dTotalPartLength)) + EgtOutLog(string.format("Total Material Cut : %.2f m", dTotalPartLength / 1000)) EgtOutLog("----------------------------------------------------------") EgtOutLog(string.format("Gross Yield (Rendimento): %.2f%%", dGrossEfficiency)) EgtOutLog(string.format("Net Yield (Riutilizzato): %.2f%%", dNetEfficiency)) EgtOutLog("----------------------------------------------------------") - EgtOutLog(string.format("Total Usable Remnants : %.2f mm (Safe for Clamps)", dTotalUsableRemnants)) - EgtOutLog(string.format("Total Pure Scrap (Sfrido): %.2f mm (Trash Zone)", dTotalScrap)) + EgtOutLog(string.format("Total Usable Remnants : %.2f m (Safe for Clamps)", dTotalUsableRemnants / 1000)) + EgtOutLog(string.format("Total Pure Scrap (Sfrido): %.2f m (Trash Zone)", dTotalScrap / 1000)) EgtOutLog("==========================================================") end @@ -544,7 +544,7 @@ while true do end -- 2 Si provano le barre ancora a stock SOLO SE NON TROVATA SOLUZIONE CON BARRE ATTIVE - -- VirtualBeam si resetta invece di crearne una nuova per velocizzare il calcolo + -- Per velocizzare il calcolo, VirtualBeam si resetta invece di crearne una nuova ogni volta if not BestMove then for i = 1, #RawInventory.Stock do if RawInventory.Stock[i].nCount > 0 then @@ -602,17 +602,22 @@ for i = 1, #RawInventory.ActiveBeams do -- copia del pezzo (aggiunta duplo) local idDuplo = EgtDuploNew( Part.id) - local Duplo = { id = idDuplo, idRaw = EgtGetRawPartFromPart( idDuplo)} - - -- eventuale inversione - if EgtEndsWith( Part.sState, 'INV') then - BeamLib.InvertRawPart( Duplo, 2) - end -- eventuale rotazione if ( EgtStartsWith( Part.sState, '0010') and nInitialPosition == 1) or ( EgtStartsWith( Part.sState, '1000') and nInitialPosition == 3) then - BeamLib.RotateRawPart( Duplo, 2) + local idSurfTmBoxDuplo = EgtGetFirstNameInGroup( idDuplo, "Box") + local b3Duplo = EgtGetBBoxGlob( idSurfTmBoxDuplo, GDB_BB.STANDARD) + EgtRotate( idDuplo, b3Duplo:getCenter(), X_AX(), 180, GDB_RT.GLOB) + EgtSetInfo( idDuplo, 'ROT', 180) + end + + -- eventuale inversione + if EgtEndsWith( Part.sState, 'INV') then + local idSurfTmBoxDuplo = EgtGetFirstNameInGroup( idDuplo, "Box") + local b3Duplo = EgtGetBBoxGlob( idSurfTmBoxDuplo, GDB_BB.STANDARD) + EgtRotate( idDuplo, b3Duplo:getCenter(), Z_AX(), 180, GDB_RT.GLOB) + EgtSetInfo( idDuplo, 'FLIP', 180) end -- assegnazione info From 3ba456f72f6bfad9a99bc328c4fc2fb8d1f0e5ce Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 19 May 2026 12:47:21 +0200 Subject: [PATCH 30/47] - in BeamLib e correlate modificata AddPhaseWithRawParts per funzionare con overlap dei pezzi per nesting obliquo --- LuaLibs/BeamExec.lua | 26 +++++++++++++------------- LuaLibs/BeamLib.lua | 21 +++++++++++++++++---- LuaLibs/MachiningLib.lua | 4 ++-- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 519c76e..55a4ce2 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1824,7 +1824,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) nPhase = nPhase} table.insert( DB_MACH_APPLIED, MachExtraInfo) else - BeamLib.AddPhaseWithRawParts( PARTS[nPart].idRaw, BeamData.ptOriXR, BeamData.dPosXR, 0) + BeamLib.AddPhaseWithRawParts( PARTS, nPart, 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. @@ -1982,7 +1982,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) nCurrPosition = nRotation EgtSetInfo( idDisp, 'ROT', -2) - bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'DOWN') + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'DOWN') bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot bProcess = bProcess or bTryToReProcess end @@ -1991,7 +1991,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) 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)) + BeamLib.AddPhaseWithRawParts( PARTS, nPart, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) nPhase = EgtGetCurrPhase() idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'ORD', nOrd) @@ -2010,14 +2010,14 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) nCurrPosition = nRotation EgtSetInfo( idDisp, 'ROT', -1) - bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'SIDE') + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'SIDE') bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot bProcess = bProcess or bTryToReProcess 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)) + BeamLib.AddPhaseWithRawParts( PARTS, nPart, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) nPhase = EgtGetCurrPhase() idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'ORD', nOrd) @@ -2036,7 +2036,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) BeamLib.RotateRawPart( PARTS[nPart], nInitialPosition - 1) -- aggiunta lavorazioni in ultima fase - _, _, _, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'STD') + _, _, _, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'STD') bProcess = bProcess or bTryToReProcess -- se bisogna riprocessare, si annulla tutto @@ -2076,7 +2076,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) -- ===== 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) + BeamLib.AddPhaseWithRawParts( PARTS, #PARTS, BeamData.ptOriXR, BeamData.dPosXR, 0) local nPhase = EgtGetCurrPhase() local idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'TYPE', 'REST') @@ -2352,7 +2352,7 @@ function BeamExec.ProcessAlternatives( PARTS) BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) nCurrPosition = nRotation EgtSetInfo( idDisp, 'ROT', -2) - bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'DOWN') + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'DOWN') bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot bProcess = bProcess or bTryToReProcess end @@ -2361,7 +2361,7 @@ function BeamExec.ProcessAlternatives( PARTS) 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)) + BeamLib.AddPhaseWithRawParts( PARTS, nPart, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) nPhase = EgtGetCurrPhase() idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'ORD', nOrd) @@ -2380,14 +2380,14 @@ function BeamExec.ProcessAlternatives( PARTS) BeamLib.RotateRawPart( PARTS[nPart], nRotation - nCurrPosition) nCurrPosition = nRotation EgtSetInfo( idDisp, 'ROT', -1) - bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'SIDE') + bAreAllMachiningApplyOk, sErr, bSplitExecutedOnRot, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'SIDE') bSplitAlreadyExecuted = bSplitAlreadyExecuted or bSplitExecutedOnRot bProcess = bProcess or bTryToReProcess 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)) + BeamLib.AddPhaseWithRawParts( PARTS, nPart, BeamData.ptOriXR, BeamData.dPosXR, EgtIf( bSplitAlreadyExecuted, BeamData.RAW_OFFSET, 0)) nPhase = EgtGetCurrPhase() idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'ORD', nOrd) @@ -2406,7 +2406,7 @@ function BeamExec.ProcessAlternatives( PARTS) BeamLib.RotateRawPart( PARTS[nPart], nInitialPosition - 1) -- aggiunta lavorazioni in ultima fase - _, _, _, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS[nPart], 'STD') + _, _, _, bTryToReProcess = MachiningLib.AddOperations( MACHININGS, PARTS, PARTS[nPart], 'STD') bProcess = bProcess or bTryToReProcess -- se bisogna riprocessare, si annulla tutto @@ -2440,7 +2440,7 @@ function BeamExec.ProcessAlternatives( PARTS) -- ===== 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) + BeamLib.AddPhaseWithRawParts( PARTS, #PARTS, BeamData.ptOriXR, BeamData.dPosXR, 0) local nPhase = EgtGetCurrPhase() local idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'TYPE', 'REST') diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 7bfeb80..b23b596 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -161,17 +161,30 @@ function BeamLib.GetPartSplittingPoints( Part) end ------------------------------------------------------------------------------------------------------------- -function BeamLib.AddPhaseWithRawParts( idRaw, OriXR, PosXR, dDeltaSucc) +function BeamLib.AddPhaseWithRawParts( PARTS, nPartIndex, OriXR, PosXR, dDeltaSucc) + local Part = PARTS[nPartIndex] local nPhase = EgtAddPhase() -- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola EgtSetTableAreaOffset( 2000, 2000, 2000, 2000) - local dRawMove = 0 + local dRawMove = dDeltaSucc + local bFirstRaw = true + local idRaw = Part.idRaw while idRaw do + local dPosX = 0 + for i = 1, #PARTS do + local CurrentPart = PARTS[i] + if CurrentPart.idRaw == idRaw then + dPosX = CurrentPart.dPosX + end + end + if bFirstRaw then + bFirstRaw = false + else + dRawMove = dDeltaSucc + dPosX + end EgtKeepRawPart( idRaw) EgtMoveToCornerRawPart( idRaw, OriXR, PosXR) EgtMoveRawPart( idRaw, Vector3d( - dRawMove, 0, 0)) - if dRawMove == 0 then dRawMove = dRawMove + dDeltaSucc end - dRawMove = dRawMove + EgtGetRawPartBBox( idRaw):getDimX() idRaw = EgtGetNextRawPart( idRaw) end -- salvo info nuova fase aggiunta diff --git a/LuaLibs/MachiningLib.lua b/LuaLibs/MachiningLib.lua index a02e068..4c3fd64 100644 --- a/LuaLibs/MachiningLib.lua +++ b/LuaLibs/MachiningLib.lua @@ -1184,7 +1184,7 @@ end ------------------------------------------------------------------------------------------------------------- -- funzione per aggiungere una nuova lavorazione -function MachiningLib.AddOperations( MACHININGS, Part, sRotation) +function MachiningLib.AddOperations( MACHININGS, PARTS, Part, sRotation) local nErr local sErr = '' local bAreAllMachiningApplyOk = true @@ -1452,7 +1452,7 @@ function MachiningLib.AddOperations( MACHININGS, Part, sRotation) bSplitExecuted = true MACHININGS.Info.bSplitExecuted = true - BeamLib.AddPhaseWithRawParts( Part.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET) + BeamLib.AddPhaseWithRawParts( PARTS, Part.nIndexInParts, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET) -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( Part.idRaw) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BeamData.dMinRaw then From 10592ac612121ce71bc9f5c0d0def2dc98a8b27c Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 19 May 2026 14:29:16 +0200 Subject: [PATCH 31/47] - in BeamLib.AddPhaseWithRawParts correzioni, ma ancora non funziona correttamente --- LuaLibs/BeamLib.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index b23b596..29ba6c1 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -162,23 +162,27 @@ end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPhaseWithRawParts( PARTS, nPartIndex, OriXR, PosXR, dDeltaSucc) - local Part = PARTS[nPartIndex] local nPhase = EgtAddPhase() + local Part = PARTS[nPartIndex] -- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola EgtSetTableAreaOffset( 2000, 2000, 2000, 2000) - local dRawMove = dDeltaSucc - local bFirstRaw = true + local dRawMove = 0 + local bIsFirstRaw = true local idRaw = Part.idRaw while idRaw do - local dPosX = 0 + local dPosX for i = 1, #PARTS do local CurrentPart = PARTS[i] if CurrentPart.idRaw == idRaw then dPosX = CurrentPart.dPosX + break + end + if i == #PARTS then + dPosX = PARTS[i].dPosX + PARTS[i].b3Raw:getDimX() end end - if bFirstRaw then - bFirstRaw = false + if bIsFirstRaw then + bIsFirstRaw = false else dRawMove = dDeltaSucc + dPosX end From 72e3b7dc8f4fbb97d85016742467beb9611fc562 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 19 May 2026 15:53:53 +0200 Subject: [PATCH 32/47] - in BeamLib.AddPhaseWithRawParts correzioni --- LuaLibs/BeamLib.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index 29ba6c1..b30624d 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -169,12 +169,16 @@ function BeamLib.AddPhaseWithRawParts( PARTS, nPartIndex, OriXR, PosXR, dDeltaSu local dRawMove = 0 local bIsFirstRaw = true local idRaw = Part.idRaw + local dPosXFirst = 0 while idRaw do local dPosX for i = 1, #PARTS do local CurrentPart = PARTS[i] if CurrentPart.idRaw == idRaw then dPosX = CurrentPart.dPosX + if bIsFirstRaw then + dPosXFirst = dPosX + end break end if i == #PARTS then @@ -184,7 +188,7 @@ function BeamLib.AddPhaseWithRawParts( PARTS, nPartIndex, OriXR, PosXR, dDeltaSu if bIsFirstRaw then bIsFirstRaw = false else - dRawMove = dDeltaSucc + dPosX + dRawMove = dDeltaSucc + dPosX - dPosXFirst end EgtKeepRawPart( idRaw) EgtMoveToCornerRawPart( idRaw, OriXR, PosXR) From a773e0156afd2f92d9178e8d51eef7ca26de200e Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Tue, 19 May 2026 17:03:21 +0200 Subject: [PATCH 33/47] - in BeamLib.AddPhaseWithRawParts e correlati correzioni in caso di scarico ultimo grezzo --- LuaLibs/BeamExec.lua | 4 ++-- LuaLibs/BeamLib.lua | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 55a4ce2..0b7effa 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -2076,7 +2076,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) -- ===== finiti i pezzi, si scarica il restante ===== local idRestPart = EgtGetNextRawPart( PARTS[#PARTS].idRaw) if idRestPart and EgtGetRawPartBBox( idRestPart):getDimX() >= BeamData.dMinRaw then - BeamLib.AddPhaseWithRawParts( PARTS, #PARTS, BeamData.ptOriXR, BeamData.dPosXR, 0) + BeamLib.AddPhaseWithRawParts( PARTS, #PARTS + 1, BeamData.ptOriXR, BeamData.dPosXR, 0) local nPhase = EgtGetCurrPhase() local idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'TYPE', 'REST') @@ -2440,7 +2440,7 @@ function BeamExec.ProcessAlternatives( PARTS) -- ===== finiti i pezzi, si scarica il restante ===== local idRestPart = EgtGetNextRawPart( PARTS[#PARTS].idRaw) if idRestPart and EgtGetRawPartBBox( idRestPart):getDimX() >= BeamData.dMinRaw then - BeamLib.AddPhaseWithRawParts( PARTS, #PARTS, BeamData.ptOriXR, BeamData.dPosXR, 0) + BeamLib.AddPhaseWithRawParts( PARTS, #PARTS + 1, BeamData.ptOriXR, BeamData.dPosXR, 0) local nPhase = EgtGetCurrPhase() local idDisp = EgtGetPhaseDisposition( nPhase) EgtSetInfo( idDisp, 'TYPE', 'REST') diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index b30624d..ce9841b 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -163,12 +163,19 @@ end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPhaseWithRawParts( PARTS, nPartIndex, OriXR, PosXR, dDeltaSucc) local nPhase = EgtAddPhase() - local Part = PARTS[nPartIndex] + local Part + local idRaw + -- se l'indice è oltre significa che è l'ultimo grezzo senza pezzi + if nPartIndex > #PARTS then + idRaw = EgtGetNextRawPart( PARTS[#PARTS].idRaw) + else + Part = PARTS[nPartIndex] + idRaw = Part.idRaw + end -- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola EgtSetTableAreaOffset( 2000, 2000, 2000, 2000) local dRawMove = 0 local bIsFirstRaw = true - local idRaw = Part.idRaw local dPosXFirst = 0 while idRaw do local dPosX From 5e5f3d08c407e3104b0214fb5e61d32f9fba7661 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 20 May 2026 14:42:59 +0200 Subject: [PATCH 34/47] =?UTF-8?q?-=20in=20BeamExec=20se=20non=20=C3=A8=20s?= =?UTF-8?q?tato=20trovato=20nessun=20taglio=20di=20testa=20o=20di=20coda?= =?UTF-8?q?=20si=20usa=20quello=20settato=20in=20precedenza?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 0b7effa..ee9123e 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -808,12 +808,19 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) -- gruppo per geometrie temporanee local idTempGroup = BeamLib.GetTempGroup() - local HeadProc = {} - local TailProc = {} + local HeadProcOriginal + local TailProcOriginal + local HeadProc + local TailProc -- ciclo tutte le feature for i = 1, #vProcSingleRot do local Proc = vProcSingleRot[i] + if Proc.Topology.sName == 'HeadCut' then + HeadProcOriginal = Proc + elseif Proc.Topology.sName == 'TailCut' then + TailProcOriginal = Proc + end -- se feature abilitata alla lavorazione if Proc.nFlg ~= 0 then -- controllo la feature con tutte le altre per recuperare le dipendenze @@ -939,6 +946,12 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) end end + if not HeadProc then + HeadProc = HeadProcOriginal + end + if not TailProc then + TailProc = TailProcOriginal + end HeadProc.Topology = {} TailProc.Topology = {} HeadProc.Topology.sFamily = 'HeadCut' From 630d28bf5be482dff1eba0a16412a2ebd06d7ad4 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 20 May 2026 16:00:15 +0200 Subject: [PATCH 35/47] =?UTF-8?q?-=20in=20BeamExec=20se=20un=20taglio=20?= =?UTF-8?q?=C3=A8=20diventato=20Headcut=20o=20Tailcut=20viene=20comunque?= =?UTF-8?q?=20considerato=20nel=20punteggio=20delle=20combinazioni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index ee9123e..4ee799a 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -818,8 +818,10 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) local Proc = vProcSingleRot[i] if Proc.Topology.sName == 'HeadCut' then HeadProcOriginal = Proc + HeadProcOriginal.bIsOriginalHeadcut = true elseif Proc.Topology.sName == 'TailCut' then TailProcOriginal = Proc + TailProcOriginal.bIsOriginalTailcut = true end -- se feature abilitata alla lavorazione if Proc.nFlg ~= 0 then @@ -1663,13 +1665,15 @@ local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bRePro for nProc = 1, #ProcessingsOnPart.Rotation[1] do -- Si controlla sempre la rotazione 1 perchè la dipendenza di una feature da un'altra non dipende dalla rotazione -- 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]) + local ProcOnFirstRotation = ProcessingsOnPart.Rotation[1][nProc] + if ProcOnFirstRotation.nFlg == 0 and ProcOnFirstRotation.nIndexMasterProc then + ProcOnFirstRotation.nIndexRotation = nUnloadPos + table.insert( SingleCombination.Rot0, ProcOnFirstRotation) SingleCombination.nComplete = SingleCombination.nComplete + 1 else local nOffsetIndex = EgtIf( SingleCombination.bPartInCombiIsInverted, 4, 0) - if not ID.IsHeadCut( ProcessingsOnPart.Rotation[1][nProc]) and not ID.IsTailCut( ProcessingsOnPart.Rotation[1][nProc]) then + if not ( ( ID.IsHeadCut( ProcOnFirstRotation) and ProcOnFirstRotation.bIsOriginalHeadcut) + or ( ID.IsTailCut( ProcOnFirstRotation) and ProcOnFirstRotation.bIsOriginalTailcut)) then -- ciclo sulle rotazioni local nNextRot = nUnloadPos local ResultsList = {} @@ -1724,12 +1728,11 @@ local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bRePro table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc]) SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1 end - else - if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then - SingleCombination.nIndexHeadCutInVProc = nProc - elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then - SingleCombination.nIndexTailCutInVProc = nProc - end + end + if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexHeadCutInVProc = nProc + elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexTailCutInVProc = nProc end end end From 3fcca044ed3dd8573b644a22e50181d2de49c28a Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 20 May 2026 16:14:54 +0200 Subject: [PATCH 36/47] - in BeamExec si ritornano stati per l'interfaccia anche per tagli che sono diventati Headcut e TailCut --- LuaLibs/BeamExec.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 4ee799a..13b1397 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1350,7 +1350,11 @@ local function CalculateMachinings( vProc, Part, nInitialRotation) 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) + local _, Result = StrategyScript.Make( true, Proc, Part, Proc.ChosenStrategy) + -- per i tagli di testa e coda, che non hanno girato nel CalculateStrategies, si devono settare i risultati + if ID.IsHeadCut( Proc) or ID.IsTailCut( Proc) then + Proc.ChosenStrategy.Result = Result + end -- se tutte le strategie disponibili non sono applicabili else local nOffsetIndex = EgtIf( Part.bPartInCombiIsInverted, 4, 0) From 27475763a203dfa834f8b632a48acbb3edd6274a Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 21 May 2026 09:29:55 +0200 Subject: [PATCH 37/47] =?UTF-8?q?-=20in=20BeamExec=20correzioni=20per=20il?= =?UTF-8?q?=20caso=20di=20taglio=20standard=20che=20diventa=20taglio=20di?= =?UTF-8?q?=20testa=20-=20in=20MachiningLib.FindBlade=20e=20relativi=20non?= =?UTF-8?q?=20si=20testa=20pi=C3=B9=20la=20normale=20della=20faccia=20in?= =?UTF-8?q?=20caso=20di=20informazioni=20lato=20mancanti=20(portava=20erro?= =?UTF-8?q?neamente=20a=20non=20trovare=20la=20lama=20nei=20casi=20solo=20?= =?UTF-8?q?downUp)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 71 +++++++++++++++++++---------------- LuaLibs/MachiningLib.lua | 9 ----- StrategyLibs/BLADETOWASTE.lua | 2 +- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 13b1397..baa1ea7 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1703,40 +1703,47 @@ local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bRePro 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, PartInfo) - 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.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + Data.dTimeToMachine - SingleCombination.dTotalQuality = SingleCombination.dTotalQuality + Data.dQuality - SingleCombination.dTotalCompletionIndex = SingleCombination.dTotalCompletionIndex + Data.dCompletionIndex - 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 + -- se la feature può essere lavorata in almeno una rotazione e non è un taglio di testa o coda + if ID.IsHeadCut( ProcOnFirstRotation) then + SingleCombination.nIndexHeadCutInVProc = nProc + elseif ID.IsTailCut( ProcOnFirstRotation) then + SingleCombination.nIndexTailCutInVProc = nProc else - ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nIndexRotation = nUnloadPos - ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nFlg = 0 - table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc]) - SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1 + if #ResultsList > 0 then + local Proc, Data = GetProcBestMachRotationFromList( ResultsList, PartInfo) + 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.dTotalTimeToMachine = SingleCombination.dTotalTimeToMachine + Data.dTimeToMachine + SingleCombination.dTotalQuality = SingleCombination.dTotalQuality + Data.dQuality + SingleCombination.dTotalCompletionIndex = SingleCombination.dTotalCompletionIndex + Data.dCompletionIndex + 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[nUnloadPos+nOffsetIndex][nProc].nIndexRotation = nUnloadPos + ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc].nFlg = 0 + table.insert( SingleCombination.Rot0, ProcessingsOnPart.Rotation[nUnloadPos+nOffsetIndex][nProc]) + SingleCombination.nNotExecute = SingleCombination.nNotExecute + 1 + end + end + else + if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexHeadCutInVProc = nProc + elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then + SingleCombination.nIndexTailCutInVProc = nProc end - end - if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then - SingleCombination.nIndexHeadCutInVProc = nProc - elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then - SingleCombination.nIndexTailCutInVProc = nProc end end end diff --git a/LuaLibs/MachiningLib.lua b/LuaLibs/MachiningLib.lua index 4c3fd64..0428f65 100644 --- a/LuaLibs/MachiningLib.lua +++ b/LuaLibs/MachiningLib.lua @@ -607,9 +607,6 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters) local ToolInfo = {} -- parametri obbligatori - if type( ToolSearchParameters.FaceToMachine) ~= 'table' then - error( 'FindBlade : missing face info') - end if type( ToolSearchParameters.bAllowTopHead) ~= 'boolean' then error( 'FindBlade : missing top head info') end @@ -675,12 +672,6 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters) if not bIsBladeOk then bIsToolCompatible = false end - - -- se si ha solo la faccia si può verificare se questa è orientata correttamente - elseif FaceToMachine then - if MachiningLib.IsFaceZOutOfRange( FaceToMachine.vtN, TOOLS[i]) then - bIsToolCompatible = false - end end end diff --git a/StrategyLibs/BLADETOWASTE.lua b/StrategyLibs/BLADETOWASTE.lua index 750d6d3..287444b 100644 --- a/StrategyLibs/BLADETOWASTE.lua +++ b/StrategyLibs/BLADETOWASTE.lua @@ -977,7 +977,7 @@ local function CutWithDicing( Proc, Part, OptionalParameters) -- scelta lama da sopra o da sotto local sChosenBladeType = '' if not nToolIndex then - nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, Face1) + nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part) end -- se non trovata lama la lavorazione non è fattibile From 6649842c70b6f1bb228b71eafb7392d4383583d4 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 21 May 2026 10:49:28 +0200 Subject: [PATCH 38/47] - in NestProcess modifiche per nestare pezzi senza alternative --- NestProcess.lua | 119 ++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/NestProcess.lua b/NestProcess.lua index 0320427..a6fa8f0 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -188,7 +188,7 @@ end -- JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare) local PartTemplates = {} -function PartTemplates:GetInfoFromPart( id, sStateWithSide) +function PartTemplates:GetStateInfoFromPart( id, sStateWithSide) local OffsetX = {} local vtN @@ -219,58 +219,84 @@ function PartTemplates:AddPart( id) dMaxJobLength = self[id].dLength end - local States = { '1000', '0010', '1000_INV', '0010_INV' } + -- info eventuali rotazioni / inversioni custom e forzature manuali + local bIsManualFlipRot = ( ( EgtGetInfo( id, 'MANUALROT', 'i') or 0) == 1) or ( ( EgtGetInfo( id, 'MANUALFLIP', 'i') or 0) == 1) - 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 not bIsManualFlipRot then - if OffsetXHead or OffsetXTail then + local States = { '1000', '0010', '1000_INV', '0010_INV' } - 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 + for _, sState in ipairs(States) do + local OffsetXHead, vtNHead = self:GetStateInfoFromPart( id, 'ALT' .. sState .. '_H') + local OffsetXTail, vtNTail = self:GetStateInfoFromPart( id, 'ALT' .. sState .. '_T') - self[id].States[sState] = {} - local State = self[id].States[sState] + if OffsetXHead or OffsetXTail then - State.Head = { - OffsetX = OffsetXHead, - vtN = vtNHead, - vtNXabs = abs( vtNHead:getX()) - } - State.Tail = { - OffsetX = OffsetXTail, - vtN = vtNTail, - vtNXabs = abs( vtNTail:getX()) - } - - -- 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] + if not OffsetXHead then + OffsetXHead = { 0, 0, 0, 0} + vtNHead = Vector3d( 1, 0, 0) 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]) + 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, + vtNXabs = abs( vtNHead:getX()) + } + State.Tail = { + OffsetX = OffsetXTail, + vtN = vtNTail, + vtNXabs = abs( vtNTail:getX()) + } + + -- 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 - State.dMaxTailRecess = dMaxTailRecess - if dMaxTailRecess > self[id].dMaxGlobalTailRecess + 10 * GEO.EPS_SMALL then - self[id].dMaxGlobalTailRecess = dMaxTailRecess end end end + + -- se nessuna alternativa stato fisso + if not next( self[id].States) then + + self[id].States['FIXED'] = {} + local State = self[id].States['FIXED'] + + State.Head = { + OffsetX = { 0, 0, 0, 0}, + vtN = Vector3d( 1, 0, 0), + vtNXabs = 1 + } + State.Tail = { + OffsetX = { 0, 0, 0, 0}, + vtN = Vector3d( -1, 0, 0), + vtNXabs = 1 + } + State.dMaxHeadRecess = 0 + State.dMaxTailRecess = 0 + end end -- ordinamento JobPool per lunghezza decrescente dei pezzi @@ -318,8 +344,11 @@ local function CalculateMove( Beam, dPartLength, sState, State) end end - -- il massimo overlap va ridotto dello spessore lama - local dProjectedBlade = CONFIG.BLADE_THICKNESS / min( Beam.vtNXabs, State.Tail.vtNXabs) + -- Il massimo overlap va ridotto dello spessore lama solo se ci sono già altri pezzi sulla barra + local dProjectedBlade = 0 + if #Beam.NestedParts > 0 then + dProjectedBlade = CONFIG.BLADE_THICKNESS / min( Beam.vtNXabs, State.Tail.vtNXabs) + end dSafeOverlap = dSafeOverlap - dProjectedBlade -- lunghezza barra rimasta (se negativo non ci sta) From 5c7751aebd9999c2ee386101d39b6d37ec3c3645 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 21 May 2026 15:02:23 +0200 Subject: [PATCH 39/47] - in BeamLib aggiunta GetNewMachGroupName per avere il prossimo numero MachGroup intero libero - in NestProcess i nomi MachGroup sono sempre interi; si mantiene sempre un BEAM_SAFETY_BUFFER nel riempimento delle barre - in BeamExec.GetCombinationListFromMatrix corretti indici taglio di testa e coda --- LuaLibs/BeamExec.lua | 4 ++-- LuaLibs/BeamLib.lua | 18 ++++++++++++++++++ NestProcess.lua | 9 ++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index baa1ea7..2a1ce8c 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1704,9 +1704,9 @@ local function GetCombinationListFromMatrix( ProcessingsOnPart, PartInfo, bRePro end -- se la feature può essere lavorata in almeno una rotazione e non è un taglio di testa o coda - if ID.IsHeadCut( ProcOnFirstRotation) then + if ID.IsHeadCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then SingleCombination.nIndexHeadCutInVProc = nProc - elseif ID.IsTailCut( ProcOnFirstRotation) then + elseif ID.IsTailCut( ProcessingsOnPart.Rotation[1+nOffsetIndex][nProc]) then SingleCombination.nIndexTailCutInVProc = nProc else if #ResultsList > 0 then diff --git a/LuaLibs/BeamLib.lua b/LuaLibs/BeamLib.lua index ce9841b..7bdce43 100644 --- a/LuaLibs/BeamLib.lua +++ b/LuaLibs/BeamLib.lua @@ -423,6 +423,24 @@ function BeamLib.GetAddGroup( PartId) return AddGrpId, sMchGrp end +------------------------------------------------------------------------------------------------------------- +-- Funzione prossimo nome MachGroup libero (numero intero) +function BeamLib.GetNewMachGroupName() + local idMachGroup = EgtGetFirstMachGroup() + if not idMachGroup then return 1 end + local nMaxMachGroup = 0 + while idMachGroup do + local sMachGroupName = EgtGetMachGroupName( idMachGroup) + local nMachGroupName = tonumber( sMachGroupName) + if nMachGroupName > nMaxMachGroup then + nMaxMachGroup = nMachGroupName + end + idMachGroup = EgtGetNextMachGroup( idMachGroup) + end + + return nMaxMachGroup + 1 +end + ------------------------------------------------------------------------------------------------------------- -- restituisce le facce della parte interessate dalla feature Proc -- TODO da spostare in FeatureLib??? diff --git a/NestProcess.lua b/NestProcess.lua index a6fa8f0..82a429f 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -45,7 +45,10 @@ local CONFIG = { MIN_USABLE_REMNANT = BeamData.MINRAW_S, -- Sotto questa misura lo scarto è considerato "sfrido" MAX_REMNANT_PERFECT_FIT = 20, BLADE_THICKNESS = 5.4, -- TODO questo deve arrivare da interfaccia o da automatismo!!!!! - MIN_FILLER_LIMIT = ( BeamData.MINRAW_S + BeamData.MINRAW_L) / 2 + MIN_FILLER_LIMIT = ( BeamData.MINRAW_S + BeamData.MINRAW_L) / 2, + + -- Tolleranze + BEAM_SAFETY_BUFFER = 5 -- Buffer di sicurezza riempimento barra per evitare problemi nei solidi EgtCam5 } ---------------------------------------------------------------------------------------------------------- @@ -353,7 +356,7 @@ local function CalculateMove( Beam, dPartLength, sState, State) -- lunghezza barra rimasta (se negativo non ci sta) local dFutureResidualLength = Beam.dResidualLength + dSafeOverlap - dPartLength - if dFutureResidualLength < -10 * GEO.EPS_SMALL then + if dFutureResidualLength < CONFIG.BEAM_SAFETY_BUFFER - 10 * GEO.EPS_SMALL then return nil end @@ -610,7 +613,7 @@ for i = 1, #RawInventory.ActiveBeams do local Beam = RawInventory.ActiveBeams[i] -- creazione MachGroup - local sMachGroup = EgtGetMachGroupNewName( i) + local sMachGroup = BeamLib.GetNewMachGroupName() local idMachGroup = EgtAddMachGroup( sMachGroup) -- assegnazione info From eacabb5af7c73798ad9d28ec2eb82f6211bd0fde Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 21 May 2026 18:53:02 +0200 Subject: [PATCH 40/47] - in BeamExec.ProcessBeams correzioni. Sembra funzionare correttamente in tutti i casi --- LuaLibs/BeamExec.lua | 302 +++++++++++++++++++++---------------------- 1 file changed, 145 insertions(+), 157 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 2a1ce8c..79ad799 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -377,191 +377,179 @@ function BeamExec.GetAvailableCombinations( PartInfo, bIsFlipRot) end ------------------------------------------------------------------------------------------------------------- --- *** funzioni posizionamento pezzi all'interno della barra *** +-- *** Funzioni posizionamento pezzi all'interno della barra*** ------------------------------------------------------------------------------------------------------------- -function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, bCreateMachGroup, bIsFlipRot) - -- gruppo per geometrie temporanee - local idTempGroup = BeamLib.GetTempGroup() +function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, bCreateMachGroup, bIsFlipRot ) + -- 1. Inizializzazione e Default + local idTempGroup = BeamLib.GetTempGroup( ) - -- 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) + 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) + dOvmMid = ( dOvmMid or 5.4 ) + dOvmHead = ( dOvmHead or 0 ) + BeamExec.CalcMinUnloadableRaw( dRawW, dRawH ) - -- 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 + -- 2. Gestione Gruppo di Lavoro + if ( bCreateMachGroup == nil ) then bCreateMachGroup = true end + if ( bCreateMachGroup ) then + local sMgName = EgtGetMachGroupNewName( 'Mach_1' ) + local idNewMg = EgtAddMachGroup( sMgName ) + if ( not idNewMg ) then + return false, 'Errore creazione gruppo di lavoro' 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) + -- 3. Configurazione Tavola Macchina + EgtSetTable( 'Tab' ) + local nMGrpId = EgtGetCurrMachGroup( ) + if ( not EgtGetInfo( nMGrpId, 'BARLEN', 'd' ) ) 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) + local b3Tab = EgtGetTableArea( ) + 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() + EgtImportSetup( ) - -- Inserimento dei pezzi con il loro grezzo + -- 4. Ciclo di Inserimento Pezzi local nCnt = 0 - local dResidualLength = dRawL - local idPrevRaw, dPrevDelta - local dStartOffset = dOvmHead - local dEndOffset = 0 -- TODO cosa fare di BD.OVM_MID? usarlo solo se non è nesting obliquo? + local dMaxX = 0 + local idPrevRaw = nil + local dNextStartOffset = dOvmHead -- Il primo pezzo applica il sormonto iniziale a destra (testa) + 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 dPartLength = PARTS[i].b3PartOriginal:getDimX() - local dPartWidth = PARTS[i].b3PartOriginal:getDimY() - local dPartHeight = PARTS[i].b3PartOriginal:getDimZ() - local dNextResidualLength = dResidualLength - EgtIf( i == 1, dStartOffset, 0) - dPartLength - dEndOffset - local bIsSectionOk = (( 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)) - if bIsSectionOk and ( dNextResidualLength + dEndOffset >= 0) then - -- eventuale sovramateriale di testa - if i > 1 then - if PARTS[i].dPosX then - dStartOffset = PARTS[i].dPosX - ( dRawL - dResidualLength) - if dStartOffset < -GEO.EPS_SMALL then - dResidualLength = dResidualLength - dStartOffset - dStartOffset = 0 - end - else - dStartOffset = max( dOvmMid - dEndOffset, 0) - end - end - -- dimensioni del grezzo - local dCurrentRawLength = min( dPartLength + dStartOffset + dEndOffset, dResidualLength) - local dDelta = dCurrentRawLength - dPartLength - dStartOffset - -- creo e posiziono il grezzo - PARTS[i].idRaw = EgtAddRawPart( Point3d(0,0,0), dCurrentRawLength, dRawW, dRawH, BeamData.RAWCOL) + local CurrentPart = PARTS[i] + local b3BoxExact = EgtGetBBoxGlob( CurrentPart.id or GDB_ID.NULL, GDB_BB.EXACT ) + + if ( b3BoxExact:isEmpty( ) or CurrentPart.b3PartOriginal:isEmpty( ) ) then break end - EgtMoveToCornerRawPart( PARTS[i].idRaw, BeamData.ptOriXR, BeamData.dPosXR) - EgtMoveRawPart( PARTS[i].idRaw, Vector3d( dResidualLength - dRawL, 0, 0)) - -- assegno ordine in lavorazione + local dPartLen = CurrentPart.b3PartOriginal:getDimX( ) + local dPartWidth = CurrentPart.b3PartOriginal:getDimY( ) + local dPartHeight = CurrentPart.b3PartOriginal:getDimZ( ) + + local dStartOffset = dNextStartOffset + local dEndOffset = dOvmMid + + -- LOGICA LOOK-AHEAD: Analisi del gap reale per la ripartizione specchiata + if ( i < #PARTS ) then + local dTotalGap = PARTS[i + 1].dPosX - CurrentPart.dPosX - dPartLen + if ( dTotalGap > dOvmMid ) then + dEndOffset = dOvmMid -- Max 5.4mm sulla coda (lato sinistro del grezzo) + dNextStartOffset = dTotalGap - dOvmMid -- Il residuo sulla testa del prossimo (lato destro) + else + -- Gestione automatica sotto-soglia o compenetrazione geometrica (Nesting Obliquo) + dEndOffset = dTotalGap + dNextStartOffset = 0 + end + end + + -- MATEMATICA CORRETTA PER X CAD INVERTITA: + -- Il grezzo idRaw si estende verso destra. Spostando il pezzo internamente di dEndOffset (dDelta), + -- lasciamo dEndOffset a sinistra (coda) e matematicamente dStartOffset a destra (testa). + local dCrawLen = dPartLen + dStartOffset + dEndOffset + local dDelta = dEndOffset + local dStartPos = CurrentPart.dPosX - dStartOffset + + local bIsSectionOk = ( ( 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 ) ) + + if ( bIsSectionOk and ( dStartPos + dCrawLen <= dRawL + GEO.EPS_SMALL ) ) then + + -- 5. Creazione e Posizionamento del Contenitore RawPart + CurrentPart.idRaw = EgtAddRawPart( Point3d( 0, 0, 0 ), dCrawLen, dRawW, dRawH, BeamData.RAWCOL ) + EgtMoveToCornerRawPart( CurrentPart.idRaw, BeamData.ptOriXR, BeamData.dPosXR ) + EgtMoveRawPart( CurrentPart.idRaw, Vector3d( -dStartPos, 0, 0 ) ) + + -- 6. Configurazione Geometrie Pezzo 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 + EgtSetInfo( CurrentPart.idRaw, 'ORD', nCnt ) + + if ( not BeamLib.CreateOrEmptyAddGroup( CurrentPart.id ) ) then + return false, 'Error creating Additional Group in Part ' .. tostring( CurrentPart.id ) end - -- aggiungo faccia per taglio iniziale al pezzo - BeamLib.AddPartStartFace( PARTS[i].id, PARTS[i].b3PartOriginal) - -- se sovramateriale di testa, lo notifico - if dStartOffset > 0.09 then - EgtSetInfo( PARTS[i].idRaw, 'HOVM', dStartOffset) - if idPrevRaw then - EgtSetInfo( idPrevRaw, 'BDST', dStartOffset + dPrevDelta) - end - end - if dEndOffset > 0.09 then - EgtSetInfo( PARTS[i].idRaw, 'TOVM', dEndOffset) - 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 - dResidualLength = dResidualLength - dCurrentRawLength - -- aggiorno grezzo precedente - idPrevRaw = PARTS[i].idRaw - dPrevDelta = dDelta - PARTS[i].bIsLastPart = ( i == #PARTS) - PARTS[i].dDistanceToNextPiece = dDelta - PARTS[i].dRestLength = dResidualLength - 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].idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PARTS[i].id, 'Box') or GDB_ID.NULL) - PARTS[i].b3Part = EgtGetBBoxGlob( PARTS[i].idBoxTm, GDB_BB.STANDARD) - PARTS[i].nIndexInParts = i - PARTS[i].SplittingPoints = BeamLib.GetPartSplittingPoints( PARTS[i]) - PARTS[i].NotClampableLength = { STD = { dHead = 0, dTail = 0}, SIDE = { dHead = 0, dTail = 0}, DOWN = { dHead = 0, dTail = 0}} - PARTS[i].dHeadOverMaterial = dStartOffset - PARTS[i].sBTLInfo = EgtGetInfo( PARTS[i].id, 'PROJ', 's') or nil + + BeamLib.AddPartStartFace( CurrentPart.id, CurrentPart.b3PartOriginal ) + BeamLib.AddPartEndFace( CurrentPart.id, CurrentPart.b3PartOriginal ) - PARTS[i].sAISetupConfig = EgtGetInfo( PARTS[i].id, 'AISETUP', 's') or - ( GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo] and GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo].sAISetupConfig) or -- i parametri BTL potrebbero non esistere - GENERAL_PARAMETERS.PROJECT.sAISetupConfig or nil + -- Inserimento con dDelta (lascia lo spazio vuoto a sinistra e spinge il pezzo a destra) + EgtDeselectPartObjs( CurrentPart.id ) + local ptPos = b3BoxExact:getMin( ) - CurrentPart.b3PartOriginal:getMin( ) + Vector3d( dDelta, ( dRawW - dPartWidth ) / 2, ( dRawH - dPartHeight ) / 2 ) + EgtAddPartToRawPart( CurrentPart.id, ptPos, CurrentPart.idRaw ) - -- si carica configurazione lavorazioni - TIMER:startElapsed('Json') - BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig) - PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON) - TIMER:stopElapsed('Json') - PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bIsFlipRot) - PARTS[i].idTempGroup = idTempGroup + -- Rotazione sezione se necessaria + if ( abs( dPartWidth - dRawW ) > 100 * GEO.EPS_SMALL ) then + EgtRotatePartInRawPart( CurrentPart.id, X_AX( ), 90 ) + local vtEccOri = CurrentPart.b3PartOriginal:getCenter( ) - b3BoxExact:getCenter( ) + local vtEccRot = Vector3d( vtEccOri ) + vtEccRot:rotate( X_AX( ), 90 ) + EgtMovePartInRawPart( CurrentPart.id, ( vtEccOri - vtEccRot ) ) + end + -- 7. Popolamento Metadati della Tabella CurrentPart + CurrentPart.bIsLastPart = ( i == #PARTS ) + CurrentPart.dDistanceToNextPiece = dEndOffset + CurrentPart.b3Raw = EgtGetRawPartBBox( CurrentPart.idRaw ) + CurrentPart.dLength = CurrentPart.b3Raw:getDimX( ) + CurrentPart.dWidth = CurrentPart.b3Raw:getDimY( ) + CurrentPart.dHeight = CurrentPart.b3Raw:getDimZ( ) + CurrentPart.bSquareSection = abs( CurrentPart.dWidth - CurrentPart.dHeight ) < 100 * GEO.EPS_SMALL + + CurrentPart.idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( CurrentPart.id, 'Box' ) or GDB_ID.NULL ) + CurrentPart.b3Part = EgtGetBBoxGlob( CurrentPart.idBoxTm, GDB_BB.STANDARD ) + CurrentPart.nIndexInParts = i + CurrentPart.SplittingPoints = BeamLib.GetPartSplittingPoints( CurrentPart ) + CurrentPart.NotClampableLength = { STD = { dHead = 0, dTail = 0 }, SIDE = { dHead = 0, dTail = 0 }, DOWN = { dHead = 0, dTail = 0 } } + CurrentPart.dHeadOverMaterial = dStartOffset + CurrentPart.sBTLInfo = EgtGetInfo( CurrentPart.id, 'PROJ', 's' ) or nil + CurrentPart.idTempGroup = idTempGroup + + -- Notifiche al Post-Processor basate sulla nuova scomposizione + if ( dStartOffset > 0.09 ) then EgtSetInfo( CurrentPart.idRaw, 'HOVM', dStartOffset ) end + if ( dEndOffset > 0.09 ) then EgtSetInfo( CurrentPart.idRaw, 'TOVM', dEndOffset ) end + if ( idPrevRaw ) then EgtSetInfo( idPrevRaw, 'BDST', dStartOffset ) end + + -- Caricamento Strategie JSON + CurrentPart.sAISetupConfig = EgtGetInfo( CurrentPart.id, 'AISETUP', 's' ) or + ( GENERAL_PARAMETERS.BTL[CurrentPart.sBTLInfo] and GENERAL_PARAMETERS.BTL[CurrentPart.sBTLInfo].sAISetupConfig ) or + GENERAL_PARAMETERS.PROJECT.sAISetupConfig or nil + + TIMER:startElapsed( 'Json' ) + BeamExec.GetStrategiesFromJSONinBD( CurrentPart.sAISetupConfig ) + CurrentPart.GeneralParameters = BeamLib.GetPieceGeneralParameters( CurrentPart, GENERAL_PARAMETERS_JSON ) + TIMER:stopElapsed( 'Json' ) + + CurrentPart.CombinationList = BeamExec.GetAvailableCombinations( CurrentPart, bIsFlipRot ) + + -- Avanzamento calcolato sulla coordinata reale di fine RawPart (estremità sinistra sulla barra) + dMaxX = max( dMaxX, dStartPos + dCrawLen ) + CurrentPart.dRestLength = dRawL - dMaxX + idPrevRaw = CurrentPart.idRaw else - local sOut = 'Error: part L(' .. EgtNumToString( dPartLength, 1) .. ') too big for raw part L(' .. EgtNumToString( dResidualLength - 0.1, 1) .. ')' + local sOut = 'Error: part L(' .. EgtNumToString( dPartLen, 1 ) .. ') too big for remaining bar space' 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 dResidualLength > 10 then - local idRaw = EgtAddRawPart( Point3d(0,0,0), dResidualLength, dRawW, dRawH, BeamData.RAWCOL) - EgtMoveToCornerRawPart( idRaw, BeamData.ptOriXR, BeamData.dPosXR) - EgtMoveRawPart( idRaw, Vector3d( dResidualLength - dRawL, 0, 0)) - -- assegno ordine in lavorazione + -- 8. Chiusura Barra e Gestione Avanzo (Rest Material) + if ( idPrevRaw ) then EgtSetInfo( idPrevRaw, 'BDST', 10000 ) end + + local dRemaining = dRawL - dMaxX + if ( dRemaining > 10 ) then + local idRawRest = EgtAddRawPart( Point3d( 0, 0, 0 ), dRemaining, dRawW, dRawH, BeamData.RAWCOL ) + EgtMoveToCornerRawPart( idRawRest, BeamData.ptOriXR, BeamData.dPosXR ) + EgtMoveRawPart( idRawRest, Vector3d( -dMaxX, 0, 0 ) ) nCnt = nCnt + 1 - EgtSetInfo( idRaw, 'ORD', nCnt) - -- aggiorno distanza dell'ultimo pezzo dall'eventuale grezzo scaricabile - if EgtGetRawPartBBox( idRaw):getDimX() < BeamData.dMinRaw then + EgtSetInfo( idRawRest, 'ORD', nCnt ) + + if ( EgtGetRawPartBBox( idRawRest ):getDimX( ) < BeamData.dMinRaw ) then PARTS[#PARTS].dDistanceToNextPiece = 10000 end else - PARTS[#PARTS].dDistanceToNextPiece = 10000 + if ( #PARTS > 0 ) then PARTS[#PARTS].dDistanceToNextPiece = 10000 end end return true From 387eda8b4a64c5704f80e2df1a6edf7b10f8d981 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 8 Jun 2026 11:16:50 +0200 Subject: [PATCH 41/47] =?UTF-8?q?-=20in=20BeamExec=20corretta=20ProcessBea?= =?UTF-8?q?ms=20per=20i=20casi=20in=20cui=20dPosX=20non=20=C3=A8=20definit?= =?UTF-8?q?o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 38ca696..2d76427 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -436,8 +436,23 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b local dPartWidth = CurrentPart.b3PartOriginal:getDimY( ) local dPartHeight = CurrentPart.b3PartOriginal:getDimZ( ) + -- --- LOGICA ON-THE-FLY PER dPosX (PEZZO CORRENTE E SUCCESSIVO) --- + -- Se il pezzo corrente non ha coordinata, la calcoliamo come fallback standard + if ( not CurrentPart.dPosX) then + if ( i == 1) then + CurrentPart.dPosX = dOvmHead + else + CurrentPart.dPosX = PARTS[i - 1].dPosX + PARTS[i - 1].b3PartOriginal:getDimX( ) + dOvmMid + end + end + + -- Se il pezzo SUCCESSIVO non ha coordinata, la pre-calcoliamo per il look-ahead + if ( i < #PARTS and not PARTS[i + 1].dPosX) then + PARTS[i + 1].dPosX = CurrentPart.dPosX + dPartLen + dOvmMid + end + local dStartOffset = dNextStartOffset - local dEndOffset = dOvmMid + local dEndOffset = ( i == #PARTS ) and 0 or dOvmMid -- LOGICA LOOK-AHEAD: Analisi del gap reale per la ripartizione specchiata if ( i < #PARTS ) then From 19f35ccd6128fa5bf288cfa5643213de926e322f Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 8 Jun 2026 11:58:15 +0200 Subject: [PATCH 42/47] - in BeamExec.ProcessBeams modifiche minori --- LuaLibs/BeamExec.lua | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 2d76427..7e23604 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -436,8 +436,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b local dPartWidth = CurrentPart.b3PartOriginal:getDimY( ) local dPartHeight = CurrentPart.b3PartOriginal:getDimZ( ) - -- --- LOGICA ON-THE-FLY PER dPosX (PEZZO CORRENTE E SUCCESSIVO) --- - -- Se il pezzo corrente non ha coordinata, la calcoliamo come fallback standard + -- Se il pezzo corrente non ha coordinata, si calcola da OvmMid if ( not CurrentPart.dPosX) then if ( i == 1) then CurrentPart.dPosX = dOvmHead @@ -446,7 +445,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b end end - -- Se il pezzo SUCCESSIVO non ha coordinata, la pre-calcoliamo per il look-ahead + -- Se il pezzo SUCCESSIVO non ha coordinata, si calcola da OvmMid if ( i < #PARTS and not PARTS[i + 1].dPosX) then PARTS[i + 1].dPosX = CurrentPart.dPosX + dPartLen + dOvmMid end @@ -454,33 +453,30 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b local dStartOffset = dNextStartOffset local dEndOffset = ( i == #PARTS ) and 0 or dOvmMid - -- LOGICA LOOK-AHEAD: Analisi del gap reale per la ripartizione specchiata + -- Gap reale tra i pezzi (può essere negativo in caso di compenetrazione nesting obliqui) if ( i < #PARTS ) then local dTotalGap = PARTS[i + 1].dPosX - CurrentPart.dPosX - dPartLen if ( dTotalGap > dOvmMid ) then - dEndOffset = dOvmMid -- Max 5.4mm sulla coda (lato sinistro del grezzo) - dNextStartOffset = dTotalGap - dOvmMid -- Il residuo sulla testa del prossimo (lato destro) + dEndOffset = dOvmMid + dNextStartOffset = dTotalGap - dOvmMid else - -- Gestione automatica sotto-soglia o compenetrazione geometrica (Nesting Obliquo) + -- Gap minore dello spessore lama (compenetrazione per nesting obliqui) dEndOffset = dTotalGap dNextStartOffset = 0 end end - -- MATEMATICA CORRETTA PER X CAD INVERTITA: - -- Il grezzo idRaw si estende verso destra. Spostando il pezzo internamente di dEndOffset (dDelta), - -- lasciamo dEndOffset a sinistra (coda) e matematicamente dStartOffset a destra (testa). - local dCrawLen = dPartLen + dStartOffset + dEndOffset + local dCurrentRawLen = dPartLen + dStartOffset + dEndOffset local dDelta = dEndOffset local dStartPos = CurrentPart.dPosX - dStartOffset local bIsSectionOk = ( ( 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 ) ) - if ( bIsSectionOk and ( dStartPos + dCrawLen <= dRawL + GEO.EPS_SMALL ) ) then + if ( bIsSectionOk and ( dStartPos + dCurrentRawLen <= dRawL + GEO.EPS_SMALL ) ) then -- 5. Creazione e Posizionamento del Contenitore RawPart - CurrentPart.idRaw = EgtAddRawPart( Point3d( 0, 0, 0 ), dCrawLen, dRawW, dRawH, BeamData.RAWCOL ) + CurrentPart.idRaw = EgtAddRawPart( Point3d( 0, 0, 0 ), dCurrentRawLen, dRawW, dRawH, BeamData.RAWCOL ) EgtMoveToCornerRawPart( CurrentPart.idRaw, BeamData.ptOriXR, BeamData.dPosXR ) EgtMoveRawPart( CurrentPart.idRaw, Vector3d( -dStartPos, 0, 0 ) ) @@ -545,7 +541,7 @@ function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, b CurrentPart.CombinationList = BeamExec.GetAvailableCombinations( CurrentPart, bIsFlipRot ) -- Avanzamento calcolato sulla coordinata reale di fine RawPart (estremità sinistra sulla barra) - dMaxX = max( dMaxX, dStartPos + dCrawLen ) + dMaxX = max( dMaxX, dStartPos + dCurrentRawLen ) CurrentPart.dRestLength = dRawL - dMaxX idPrevRaw = CurrentPart.idRaw else From 8da693817df4e1ea98d090f5b111700a06f71ab5 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 8 Jun 2026 13:27:40 +0200 Subject: [PATCH 43/47] - in BeamExec.GetFeatureInfoAndDependency correzione importante --- LuaLibs/BeamExec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index 7e23604..a036b0c 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -860,7 +860,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) ProcB.nFlg = 0 end -- il secondo taglio è più verso il centro della trave - elseif Proc.b3Box:getMin():getX() >= ProcB.b3Box:getMin():getX() - 10 * GEO.EPS_SMALL then + else HeadProc = ProcB local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) @@ -895,7 +895,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) ProcB.nFlg = 0 end -- il secondo taglio è più verso il centro della trave - elseif Proc.b3Box:getMax():getX() >= ProcB.b3Box:getMax():getX() - 10 * GEO.EPS_SMALL then + else TailProc = ProcB local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) local idProcBCopy = EgtCopyGlob( ProcB.id, idTempGroup) @@ -979,7 +979,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) local PtSortedTail = BeamLib.GetSortedVertices( TailProc) if PtSortedTail then TailcutInfo.OffsetX = {} - for i = 1, #PtSortedHead do + for i = 1, #PtSortedTail do table.insert( TailcutInfo.OffsetX, Part.b3Part:getMin():getX() - PtSortedTail[i]:getX()) end end From beedbc71f1137f2eaecb64930c05018ae83dc68e Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Wed, 10 Jun 2026 09:20:37 +0200 Subject: [PATCH 44/47] - in BLADETOWASTE.CalculateDiceMachinings grezzo dinamico per evitare collisioni in presimulazione, da completare --- StrategyLibs/BLADETOWASTE.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/StrategyLibs/BLADETOWASTE.lua b/StrategyLibs/BLADETOWASTE.lua index 287444b..a44dae3 100644 --- a/StrategyLibs/BLADETOWASTE.lua +++ b/StrategyLibs/BLADETOWASTE.lua @@ -797,6 +797,10 @@ local function CalculateDiceMachinings( vCuts, Parameters) local bCannotSplitRestLength = Parameters.bCannotSplitRestLength local bReduceDiceDepth = Parameters.bReduceDiceDepth + -- trimesh con RestLength + local b3CheckCollision = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation) + local idCheckCollisionTm = EgtSurfTmBBox( Part.idTempGroup, b3CheckCollision, false, GDB_RT.GLOB) + -- eventuale inversione tagli ortogonali e aggiunta informazioni alla geometria local bAreOrthogonalCutsInverted = false for i = 1, #vCuts do @@ -877,6 +881,15 @@ local function CalculateDiceMachinings( vCuts, Parameters) bMoveAfterSplit = true end end + + -- aggiornamento grezzo dinamico + -- TODO + if ( i >= 3) and ( i % 2) > 0 then + local idMergedParallelCutsSurf = EgtSurfTmBySewing( nAddGrpId, vCuts[i], false) + idCheckCollisionTm = nil + + end + else EgtErase( nSurfToCut) bIsDicingOk = false @@ -936,6 +949,15 @@ local function CalculateDiceMachinings( vCuts, Parameters) if Cutting.sStage == 'AfterTail' then bMoveAfterSplit = true end + + -- aggiornamento grezzo dinamico + -- TODO + if ( i >= 3) and ( i % 2) > 0 then + local nAddGrpId = BeamLib.GetAddGroup( Part.id) + local idMergedParallelCutsSurf = EgtSurfTmBySewing( nAddGrpId, vCuts[i], false) + idCheckCollisionTm = nil + + end end end end From 4ff1405c8e1388bf8b0a7236b4abcf587581c9d4 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Thu, 11 Jun 2026 17:22:16 +0200 Subject: [PATCH 45/47] =?UTF-8?q?-=20ora=20i=20tagli=20di=20testa=20obliqu?= =?UTF-8?q?i=20e=20le=20informazioni=20per=20nesting=20obliquo=20sono=20sc?= =?UTF-8?q?ritte=20solo=20se=20il=20parametro=20GEN=5FbGetAlternativesNest?= =?UTF-8?q?ing2D=20=C3=A8=20attivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index a036b0c..a9497ef 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -840,7 +840,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) and ( FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part) and FeatureLib.IsFeatureCuttingEntireSection( ProcB.b3Box, Part)) -- si trovano i veri tagli di testa e coda e si disattivano gli altri, se necessario - if bAreBothTruncatingCuts then + if Part.GeneralParameters.GEN_bGetAlternativesNesting2D and bAreBothTruncatingCuts then -- testa if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL and ProcB.Faces[1].vtN:getX() > GEO.EPS_SMALL then -- il primo taglio è più verso il centro della trave @@ -952,6 +952,10 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) end end + if not Part.GeneralParameters.GEN_bGetAlternativesNesting2D then + return vProcSingleRot + end + if not HeadProc then HeadProc = HeadProcOriginal end From 08856faba283003ea5c633257a0fb478872ad689 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Fri, 12 Jun 2026 14:23:35 +0200 Subject: [PATCH 46/47] - in BeamExec.GetAvailableCombinations se FlipRot e Nesting2D si disattivano le combinazioni con rotazioni; i tagli di testa ottimizzati (inclinati) si usano solo se FlipRot e Nesing2D --- LuaLibs/BeamExec.lua | 36 +++++++++++++++++++++++++------ Strategies/GeneralParameters.json | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index a9497ef..ae877ee 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -341,6 +341,11 @@ function BeamExec.GetAvailableCombinations( PartInfo, bIsFlipRot) nCycles = 2 end + if bIsFlipRot and PartInfo.GeneralParameters.GEN_bGetAlternativesNesting2D then + BeamData.ROT90 = false + BeamData.ROT180 = false + end + -- verifico tutte le combinazioni che possono essere considerate for nInvertIndex = 1, nCycles do for nUnloadPos = 1, 4 do @@ -358,22 +363,31 @@ function BeamExec.GetAvailableCombinations( PartInfo, bIsFlipRot) Combination.bPartInCombiIsInverted = true end + -- counter numero totale di rotazioni della combinazione + Combination.nRotationCounter = 0 + -- se posizionamento iniziale attivo if string.sub( sBitIndexCombination, 1, 1) == '1' then CombinationList.Rotations[1] = 1 + Combination.nRotationCounter = Combination.nRotationCounter + 1 end -- se attiva rotazione 90 if string.sub( sBitIndexCombination, 2, 2) == '1' then CombinationList.Rotations[2] = 1 + Combination.nRotationCounter = Combination.nRotationCounter + 1 end -- se attiva rotazione 180 if string.sub( sBitIndexCombination, 3, 3) == '1' then CombinationList.Rotations[3] = 1 + Combination.nRotationCounter = Combination.nRotationCounter + 1 end -- se attiva rotazione 270 if string.sub( sBitIndexCombination, 4, 4) == '1' then CombinationList.Rotations[4] = 1 + Combination.nRotationCounter = Combination.nRotationCounter + 1 end + + Combination.nRotationCounter = Combination.nRotationCounter - 1 end end end @@ -808,7 +822,7 @@ local function AreDrillingsMirrored( Proc, ProcMirror, Part) end ------------------------------------------------------------------------------------------------------------- -local function GetFeatureInfoAndDependency( vProcSingleRot, Part) +local function GetFeatureInfoAndDependency( vProcSingleRot, Part, bIsFlipRot) -- gruppo per geometrie temporanee local idTempGroup = BeamLib.GetTempGroup() @@ -820,12 +834,10 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) -- ciclo tutte le feature for i = 1, #vProcSingleRot do local Proc = vProcSingleRot[i] - if Proc.Topology.sName == 'HeadCut' then + if not HeadProcOriginal and Proc.Topology.sName == 'HeadCut' then HeadProcOriginal = Proc - HeadProcOriginal.bIsOriginalHeadcut = true - elseif Proc.Topology.sName == 'TailCut' then + elseif not TailProcOriginal and Proc.Topology.sName == 'TailCut' then TailProcOriginal = Proc - TailProcOriginal.bIsOriginalTailcut = true end -- se feature abilitata alla lavorazione if Proc.nFlg ~= 0 then @@ -840,7 +852,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) and ( FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part) and FeatureLib.IsFeatureCuttingEntireSection( ProcB.b3Box, Part)) -- si trovano i veri tagli di testa e coda e si disattivano gli altri, se necessario - if Part.GeneralParameters.GEN_bGetAlternativesNesting2D and bAreBothTruncatingCuts then + if bIsFlipRot and Part.GeneralParameters.GEN_bGetAlternativesNesting2D and bAreBothTruncatingCuts then -- testa if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL and ProcB.Faces[1].vtN:getX() > GEO.EPS_SMALL then -- il primo taglio è più verso il centro della trave @@ -922,6 +934,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) table.insert( Proc.SlaveProcIndexes, j) ProcB.nIndexMasterProc = i ProcB.nFlg = 0 + HeadProcOriginal = Proc end -- se entrambi tagli di coda, si tiene sempre il primo ( ma non quello aggiunto dall'automatismo) if ( ID.IsTailCut( Proc) and not EgtGetInfo( Proc.id, 'HEAD_ADD_CUT', 'i')) and ID.IsTailCut( ProcB) then @@ -931,6 +944,7 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) table.insert( Proc.SlaveProcIndexes, j) ProcB.nIndexMasterProc = i ProcB.nFlg = 0 + TailProcOriginal = Proc 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 @@ -956,12 +970,20 @@ local function GetFeatureInfoAndDependency( vProcSingleRot, Part) return vProcSingleRot end + -- si tiene via il riferimento alla Proc Head/Tail originale in caso si dovesse rimpiazzare + HeadProcOriginal.bIsOriginalHeadcut = true + TailProcOriginal.bIsOriginalTailcut = true if not HeadProc then HeadProc = HeadProcOriginal + else + HeadProc.HeadProcOriginal = HeadProcOriginal end if not TailProc then TailProc = TailProcOriginal + else + TailProc.TailProcOriginal = TailProcOriginal end + HeadProc.Topology = {} TailProc.Topology = {} HeadProc.Topology.sFamily = 'HeadCut' @@ -1431,7 +1453,7 @@ function BeamExec.GetProcessings( PARTS, bIsFlipRot) -- recupero informazioni ausiliarie feature e dipendenze tra feature stesse -- TODO le dipendenze cambiano in base alla rotazione del pezzo? probabilmente no - vProcRot[nIndex], HeadcutInfo, TailcutInfo = GetFeatureInfoAndDependency( vProcRot[nIndex], PARTS[nPart]) + vProcRot[nIndex], HeadcutInfo, TailcutInfo = GetFeatureInfoAndDependency( vProcRot[nIndex], PARTS[nPart], bIsFlipRot) else -- inserisco una tabella vuota table.insert( vProcRot, {}) diff --git a/Strategies/GeneralParameters.json b/Strategies/GeneralParameters.json index 69eabef..dd2a2df 100644 --- a/Strategies/GeneralParameters.json +++ b/Strategies/GeneralParameters.json @@ -46,7 +46,7 @@ "sName": "GEN_bGetAlternativesNesting2D", "sNameNge": "GET_ALTERNATIVES_NEST2D", "sValue": "false", - "sDescriptionShort": "Enable material optimization function in nesting", + "sDescriptionShort": "Enable material optimization function in nesting (part rotation disabled)", "sDescriptionLong": "", "sType": "b", "sMessageId": " ", From ab6380c1c582dcebf793b50833adea83f43c9fd0 Mon Sep 17 00:00:00 2001 From: "luca.mazzoleni" Date: Mon, 15 Jun 2026 12:23:10 +0200 Subject: [PATCH 47/47] =?UTF-8?q?-=20in=20STR0011=20e=2013=20aggiunto=20SC?= =?UTF-8?q?C=20-=20in=20BeamExec=20il=20clamp=20del=20MaxReprocess=20?= =?UTF-8?q?=C3=A8=20portato=20a=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LuaLibs/BeamExec.lua | 2 +- Strategies/Standard/STR0011/STR0011.lua | 23 +++++++++++++++++++++++ Strategies/Standard/STR0013/STR0013.lua | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index ae877ee..a7d02ce 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1840,7 +1840,7 @@ function BeamExec.ProcessMachinings( PARTS, bIsFlipRot) -- ricerca strategia di lavorazione per ogni pezzo e applicazione lavorazioni for nPart = 1, #PARTS do local nCycles = 1 - local nMaxReProcessCycles = EgtClamp( PARTS[nPart].GeneralParameters.GEN_nMaxReProcessCycles, 1, 3) + local nMaxReProcessCycles = EgtClamp( PARTS[nPart].GeneralParameters.GEN_nMaxReProcessCycles, 1, 5) -- la parte di applicazione lavorazioni può essere lanciata più volte in caso della presenza di errori local bProcess = true diff --git a/Strategies/Standard/STR0011/STR0011.lua b/Strategies/Standard/STR0011/STR0011.lua index 666be25..407bf2b 100644 --- a/Strategies/Standard/STR0011/STR0011.lua +++ b/Strategies/Standard/STR0011/STR0011.lua @@ -16,6 +16,27 @@ local Strategy = {} -- TODO Da fare completamente gestione foratura doppia con 2 teste +------------------------------------------------------------------------------------------------------------- +local function GetSCC( vtMachiningDirection) + -- TODO implementare SCC come per FacesBySaw + local nSCC = MCH_SCC.NONE + if vtMachiningDirection:getZ() < -0.9 then + nSCC = MCH_SCC.ADIR_ZM + elseif vtMachiningDirection:getZ() > 0.9 then + nSCC = MCH_SCC.ADIR_ZP + elseif vtMachiningDirection:getY() < -0.707 then + nSCC = MCH_SCC.ADIR_YM + elseif vtMachiningDirection:getY() > 0.707 then + nSCC = MCH_SCC.ADIR_YP + elseif vtMachiningDirection:getX() < -0.707 then + nSCC = MCH_SCC.ADIR_XM + elseif vtMachiningDirection:getX() > 0.707 then + nSCC = MCH_SCC.ADIR_XP + end + + return nSCC +end + ------------------------------------------------------------------------------------------------------------- local function GetDrillingStrategy( Proc, Part) local ToolSearchParameters = {} @@ -39,6 +60,7 @@ local function GetDrillingStrategy( Proc, Part) Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion Drilling.dStep = TOOLS[Drilling.nToolIndex].dStep + Drilling.nSCC = GetSCC( -Drilling.vtToolDirection) end -- TODO se utensile 2 che si torverà è il gemello da usare nelle lavorazioni in doppio, allora gestire di conseguenza l'applicazione delle lavorazioni in doppio @@ -61,6 +83,7 @@ local function GetDrillingStrategy( Proc, Part) Drilling2.bInvert = true Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion Drilling2.dStep = TOOLS[Drilling2.nToolIndex].dStep + Drilling2.nSCC = GetSCC( -Drilling2.vtToolDirection) end end diff --git a/Strategies/Standard/STR0013/STR0013.lua b/Strategies/Standard/STR0013/STR0013.lua index 00c55bf..5d67f1e 100644 --- a/Strategies/Standard/STR0013/STR0013.lua +++ b/Strategies/Standard/STR0013/STR0013.lua @@ -14,6 +14,27 @@ local FeatureLib = require( 'FeatureLib') local STR0013 = {} local Strategy = {} +------------------------------------------------------------------------------------------------------------- +local function GetSCC( vtMachiningDirection) + -- TODO implementare SCC come per FacesBySaw + local nSCC = MCH_SCC.NONE + if vtMachiningDirection:getZ() < -0.9 then + nSCC = MCH_SCC.ADIR_ZM + elseif vtMachiningDirection:getZ() > 0.9 then + nSCC = MCH_SCC.ADIR_ZP + elseif vtMachiningDirection:getY() < -0.707 then + nSCC = MCH_SCC.ADIR_YM + elseif vtMachiningDirection:getY() > 0.707 then + nSCC = MCH_SCC.ADIR_YP + elseif vtMachiningDirection:getX() < -0.707 then + nSCC = MCH_SCC.ADIR_XM + elseif vtMachiningDirection:getX() > 0.707 then + nSCC = MCH_SCC.ADIR_XP + end + + return nSCC +end + ------------------------------------------------------------------------------------------------------------- local function GetDrillingWithMillStrategy( Proc, Part) local ToolSearchParameters = {} @@ -172,6 +193,7 @@ function STR0013.Make( bAddMachining, Proc, Part, CustomParameters) MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING) MachiningToAdd = BeamLib.MergeTables( MachiningToAdd, Strategy.Machinings[j]) MachiningToAdd.Steps.dStep = TOOLS[nIndexTool].dStep / 3 + MachiningToAdd.nSCC = GetSCC( -MachiningToAdd.vtToolDirection) -- se diametro foro più grande della fresa, ma non oltre il doppio del diametro, si fa contornatura a spirale elseif Proc.FeatureInfo.dDrillDiam < ( TOOLS[nIndexTool].dDiameter * 0.75) * 2 or Strategy.Parameters.bOnlyContouring then MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.MILLING) @@ -184,6 +206,7 @@ function STR0013.Make( bAddMachining, Proc, Part, CustomParameters) MachiningToAdd.LeadOut.dTangentDistance = 0.5 MachiningToAdd.LeadOut.dPerpDistance = 0.5 MachiningToAdd.LeadOut.dElevation = Proc.FeatureInfo.dDrillLen + MachiningToAdd.nSCC = GetSCC( -MachiningToAdd.vtToolDirection) -- se diametro foro più grande del doppio del diametro fresa, si fa svuotatura else MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING) @@ -194,6 +217,7 @@ function STR0013.Make( bAddMachining, Proc, Part, CustomParameters) MachiningToAdd.LeadIn.nType = MCH_POCK_LI.HELIX MachiningToAdd.LeadIn.dTangentDistance = TOOLS[nIndexTool].dDiameter / 2 MachiningToAdd.LeadIn.dElevation = MachiningToAdd.Steps.dStep / 2 + MachiningToAdd.nSCC = GetSCC( -MachiningToAdd.vtToolDirection) end MachiningToAdd.nToolIndex = nIndexTool