diff --git a/LuaLibs/BeamExec.lua b/LuaLibs/BeamExec.lua index b15c420..770065f 100644 --- a/LuaLibs/BeamExec.lua +++ b/LuaLibs/BeamExec.lua @@ -1,4 +1,4 @@ --- BeamExec.lua by Egaltech s.r.l. 2022/12/23 +-- BeamExec.lua by Egaltech s.r.l. 2022/12/28 -- Libreria esecuzione lavorazioni per Travi -- 2019/07/11 Aggiunta gestione stato rotazione di feature per TS3. -- 2019/09/04 Corretto controllo feature di testa e coda con sovramateriale di testa elevato. @@ -38,6 +38,7 @@ -- 2022/09/28 I fori vengono sempre fatti prima delle tacche. -- 2022/09/29 Aggiunta la ricerca di feature specchiate, al momento solo per DtMortise, con le relative funzioni. -- 2022/12/23 Corrette rotazioni 90 deg per macchine con carico da destra. +-- 2022/12/28 Implementata gestione forature e code di rondine in doppio. -- Tabella per definizione modulo @@ -954,8 +955,8 @@ local function ClassifyFeatures( vProc, b3Raw, Stats) table.Insert ( vMachineBeforeIntersectingDrillingsId, Proc.Id) end - -- se senza geometria (già disabilitato - if Proc.Flg == 0 then + -- se senza geometria (già disabilitato) + if Proc.Flg == 0 and not Proc.Double then bOk = false -- se intestatura elseif Hcut.Identify( Proc) then @@ -1370,103 +1371,203 @@ local function MoveDrillsOnTenon( vProc) end end -------------------------------------------------------------------------------------------------------------- --- Estrazione parametri P da lavorazioni di tipo DtMortise -local function GetPParametersDtMortise( Proc) - local vPParameters = { - { 'P01', 'd'}, - { 'P02', 'd'}, - { 'P03', 'd'}, - { 'P04', 'i'}, - { 'P05', 'i'}, - { 'P06', 'd'}, - { 'P07', 'd'}, - { 'P09', 'd'}, - { 'P10', 'd'}, - { 'P11', 'd'}, - { 'P12', 'd'}, - { 'P13', 'd'}, - { 'P14', 'd'}, - { 'P15', 'd'} - } - for i = 1, #vPParameters do - vPParameter = vPParameters[i] - vPParameter[3] = EgtGetInfo( Proc.Id, vPParameter[1], vPParameter[2]) - end - return vPParameters -end - ------------------------------------------------------------------------------------------------------------- -- Controlla se la feature ProcMirror è la specchiata di Proc, per feature di tipo DtMortise -local function CheckMirrorDtMortise( Proc, ProcMirror, dHBeam) +local function CheckMirrorDtMortise( Proc, ProcMirror, b3Raw, AuxId) + + -- recupero i dati geometrici della curva Proc + local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) + local ptBC = EgtGP( AuxId, GDB_RT.GLOB) + local rfDtMrt = EgtSurfTmFacetMinAreaRectangle( Proc.Id, 0, GDB_RT.GLOB) + local b3DtMrt = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, rfDtMrt) + -- determino l'asse della curva Proc + local vtAx = EgtEV( AuxId, GDB_RT.GLOB) - EgtSV( AuxId, GDB_RT.GLOB) + + -- recupero e verifico l'entità curva ProcMirror + local AuxIdMirror = EgtGetInfo( ProcMirror.Id, 'AUXID', 'i') + if AuxIdMirror then AuxIdMirror = AuxIdMirror + ProcMirror.Id end + if not AuxIdMirror or ( EgtGetType( AuxIdMirror) & GDB_FY.GEO_CURVE) == 0 then + return false + end + -- recupero i dati geometrici della curva ProcMirror + local vtExtrMirror = EgtCurveExtrusion( AuxIdMirror, GDB_RT.GLOB) + local ptBCMirror = EgtGP( AuxIdMirror, GDB_RT.GLOB) + local b3DtMrtMirror = EgtGetBBoxRef( ProcMirror.Id, GDB_BB.STANDARD, rfDtMrt) + -- determino l'asse della curva ProcMirror + local vtAxMirror = EgtEV( AuxIdMirror, GDB_RT.GLOB) - EgtSV( AuxIdMirror, GDB_RT.GLOB) + + -- verifico se le mortase sono specchiate local bIsMirror = true - local vPParametersProc = GetPParametersDtMortise( Proc) - local vPParametersMirror = GetPParametersDtMortise( ProcMirror) - local nP02, nP06 = 2, 6 - -- controllo che i parametri P delle due feature, tranne P02 e P06, siano uguali - for i = 1, #vPParametersProc do - local vPParameterProc = vPParametersProc[i] - local vPParameterMirror = vPParametersMirror[i] - if vPParameterProc[1] ~= 'P02' and vPParameterProc[1] ~= 'P06'then - bIsMirror = ( abs( vPParameterProc[3] - vPParameterMirror[3]) < 100 * GEO.EPS_SMALL) - if bIsMirror == false then break end - elseif vPParameterProc[1] == 'P02' then - nP02 = i - elseif vPParameterProc[1] == 'P06' then - nP06 = i - end - end - -- se gli altri parametri P sono uguali, verifico che P02 e P06 siano compatibili con feature specchiate - if bIsMirror == true then - bIsMirror = ( ( vPParametersProc[nP02][3] == 0 and abs( vPParametersMirror[nP02][3] - dHBeam) < 100 * GEO.EPS_SMALL) and - ( vPParametersProc[nP06][3] == 90 and vPParametersMirror[nP06][3] == -90)) or - ( ( vPParametersMirror[nP02][3] == 0 and abs( vPParametersProc[nP02][3] - dHBeam) < 100 * GEO.EPS_SMALL) and - ( vPParametersMirror[nP06][3] == 90 and vPParametersProc[nP06][3] == -90)) + local vtDisplacement = ptBC - ptBCMirror + local ptCenRaw = b3Raw:getCenter() + -- controllo che il centro delle due mortase sia allineato e che queste siano equidistanti dalla mezzeria della trave + if AreSameOrOppositeVectorApprox( vtExtr, Y_AX()) then + bIsMirror = abs( vtDisplacement:getX()) < 500 * GEO.EPS_SMALL and abs( vtDisplacement:getZ()) < 500 * GEO.EPS_SMALL and + ( abs( ptBC:getY() - ptCenRaw:getY()) - abs( ptBCMirror:getY() - ptCenRaw:getY())) < 500 * GEO.EPS_SMALL + elseif AreSameOrOppositeVectorApprox( vtExtr, Z_AX()) then + bIsMirror = abs( vtDisplacement:getX()) < 500 * GEO.EPS_SMALL and abs( vtDisplacement:getY()) < 500 * GEO.EPS_SMALL and + ( abs( ptBC:getZ() - ptCenRaw:getZ()) - abs( ptBCMirror:getZ() - ptCenRaw:getZ())) < 500 * GEO.EPS_SMALL end + -- controllo che le dimensioni dei due box siano le stesse + bIsMirror = bIsMirror and abs( b3DtMrt:getDimX() - b3DtMrtMirror:getDimX()) < 500 * GEO.EPS_SMALL and + abs( b3DtMrt:getDimY() - b3DtMrtMirror:getDimY()) < 500 * GEO.EPS_SMALL and + abs( b3DtMrt:getDimZ() - b3DtMrtMirror:getDimZ()) < 500 * GEO.EPS_SMALL + -- controllo che l'asse delle due mortase sia allineato + bIsMirror = bIsMirror and AreSameVectorApprox( vtAx, vtAxMirror) + return bIsMirror end ------------------------------------------------------------------------------------------------------------- --- Cerca se esiste una feature specchiata di Proc e nel caso ne restituisce la posizione in vProc -local function FindMirrorFeature( vProc, Proc, sFeatureType, dHBeam) - local nProcMirror - -- se mortasa a coda di rondine - if sFeatureType == 'DtMortise' then - Proc.Side = EgtGetInfo( Proc.Id, 'SIDE', 'i') - for i = 1, #vProc do - local ProcMirror = vProc[i] - if DtMortise.SideIdentify(ProcMirror) then - ProcMirror.Side = EgtGetInfo( ProcMirror.Id, 'SIDE', 'i') - if ( Proc.Side == 1 and ProcMirror.Side == 3) or ( Proc.Side == 3 and ProcMirror.Side == 1) or - ( Proc.Side == 2 and ProcMirror.Side == 4) or ( Proc.Side == 4 and ProcMirror.Side == 2) then - local bIsMirror = CheckMirrorDtMortise( Proc, ProcMirror, dHBeam) - if bIsMirror then nProcMirror = i end +-- Verifica se Proc (mortasa a coda di rondine) è lavorabile in doppio e nel caso ne imposta i dati. +local function VerifyDtMortiseMirrored( Proc, vProc, b3Raw) + -- verifico se con tasca + local bPocket = ( EgtGetInfo( Proc.Id, 'P05', 'i') == 1) + if bPocket then + return + end + -- recupero e verifico l'entità curva ausiliaria + local AuxId = EgtGetInfo( Proc.Id, 'AUXID', 'i') + if AuxId then AuxId = AuxId + Proc.Id end + if not AuxId or ( EgtGetType( AuxId) & GDB_FY.GEO_CURVE) == 0 then + return + end + local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) + -- recupero il raggio minimo della mortasa + local dMinRad = 1000 + local nSt, nEnd = EgtCurveDomain( AuxId) + for i = nSt, nEnd - 1 do + local dRad = EgtCurveCompoRadius( AuxId, i) + if dRad > 0 and dRad < dMinRad then + dMinRad = dRad + end + end + -- recupero lavorazione adatta + local dMaxDiam = 2 * dMinRad + local sMilling = ML.FindMilling( 'DtMortise', nil, nil, dMaxDiam, nil, true, false, true) + if not sMilling or not EgtMdbSetCurrMachining( sMilling) then + return + end + -- recupero il suo utensile + if not EgtTdbSetCurrTool( EgtMdbGetCurrMachiningParam( MCH_MP.TOOL) or '') then + return + end + -- recupero eventuale utensile in doppio e suo diametro + local sToolDoubleName = EgtTdbGetCurrToolValInNotes( MCH_TP.USERNOTES, 'DOUBLE', 's') + if not sToolDoubleName or not EgtTdbSetCurrTool( sToolDoubleName) or not EgtTdbGetCurrToolParam( MCH_TP.ACTIVE) then + return + end + local dToolDoubleDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM, 'd') + -- verifico se possibile in doppio (diametro utensile e direzione feaure) + if dToolDoubleDiam < dMaxDiam + GEO.EPS_SMALL and ( AreSameOrOppositeVectorApprox( vtExtr, Y_AX()) or AreSameVectorApprox( vtExtr, Z_AX())) then + for i = 1, #vProc do + local ProcMirror = vProc[i] + if DtMortise.SideIdentify( ProcMirror) and ProcMirror.Id ~= Proc.Id and ProcMirror.Flg ~= 0 then + if CheckMirrorDtMortise( Proc, ProcMirror, b3Raw, AuxId) then + if ( not BD.DOWN_HEAD and AreSameVectorApprox( vtExtr, Y_AX())) or + ( BD.DOWN_HEAD and AreOppositeVectorApprox( vtExtr, Y_AX())) then + Proc.Double = 2 + Proc.MirrorId = ProcMirror.Id + Proc.MirrorCurId = ProcMirror.CutId + Proc.MirrorTaskId = ProcMirror.TaskId + ProcMirror.Flg = 0 + ProcMirror.Double = 0 + elseif BD.DOWN_HEAD and AreSameVectorApprox( vtExtr, Z_AX()) then + Proc.Double = 3 + Proc.MirrorId = ProcMirror.Id + Proc.MirrorCurId = ProcMirror.CutId + Proc.MirrorTaskId = ProcMirror.TaskId + ProcMirror.Flg = 0 + ProcMirror.Double = 0 end + break end end + end end - -- se foratura (da implementare) - return nProcMirror end ------------------------------------------------------------------------------------------------------------- --- Cerca in vProc la presenza di feature specchiate. Se le trova scrive in Proc e nelle info l'Id della specchiata. -local function SetMirroredFeatures( vProc, dHBeam) +-- Disabilita la foratura dall'altra parte dello stesso foro +local function DisableOtherDrilling( Proc, vProc) + local ProcMirror + for i = 1, #vProc do + if vProc[i].Id == Proc.Id and not vProc[i].Double then + ProcMirror = vProc[i] + break + end + end + if ProcMirror then + ProcMirror.Flg = 0 + ProcMirror.Double = 0 + end +end + +------------------------------------------------------------------------------------------------------------- +-- Verifica se Proc (foratura) è lavorabile in doppio e nel caso ne restituisce la direzione di specchiatura. +local function VerifyDrillMirrored( Proc, vProc, b3Raw) + -- recupero e verifico l'entità foro + local AuxId = EgtGetInfo( Proc.Id, 'AUXID', 'i') + if AuxId then AuxId = AuxId + Proc.Id end + if not AuxId or EgtGetType( AuxId) ~= GDB_TY.CRV_ARC then + return + end + -- recupero direzione e dimensioni del foro + local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) + local dDiam = 2 * EgtArcRadius( AuxId) + local dLen = abs( EgtCurveThickness( AuxId)) + local dMachiningDepth = dLen / 2 + BD.DRILL_OVERLAP + -- recupero lavorazione adatta + local sDrilling, sType, dMaxDepth = ML.FindDrilling( dDiam, dMachiningDepth, true, false, true) + if not sDrilling then + sDrilling, sType, dMaxDepth = ML.FindDrilling( dDiam, 0, true, false, true) + dMachiningDepth = dMaxDepth or dMachiningDepth + end + if not sDrilling or sType ~= 'Drill' or not EgtMdbSetCurrMachining( sDrilling) then + return + end + -- recupero il suo utensile + if not EgtTdbSetCurrTool( EgtMdbGetCurrMachiningParam( MCH_MP.TOOL) or '') then + return + end + -- recupero eventuale utensile in doppio, suo diametro e massima lavorazione + local sToolDoubleName = EgtTdbGetCurrToolValInNotes( MCH_TP.USERNOTES, 'DOUBLE', 's') + if not sToolDoubleName or not EgtTdbSetCurrTool( sToolDoubleName) or not EgtTdbGetCurrToolParam( MCH_TP.ACTIVE) then + return + end + local dToolDoubleDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM, 'd') + local dToolDoubleMaxDepth = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) + -- verifico se in doppio + dMachiningDepth = min( dMachiningDepth, dToolDoubleMaxDepth) + if abs( Proc.Flg) == 2 and dToolDoubleDiam < dDiam + 10 * GEO.EPS_SMALL and dToolDoubleDiam > dDiam - BD.DRILL_TOL - 10 * GEO.EPS_SMALL then + if Proc.Fce ~= 0 then + if Proc.Flg == -2 then vtExtr = -vtExtr end + if ( not BD.DOWN_HEAD and AreSameVectorApprox( vtExtr, Y_AX())) or + ( BD.DOWN_HEAD and AreOppositeVectorApprox( vtExtr, Y_AX())) then + Proc.Double = 2 + Proc.MachDepthDouble = dMachiningDepth + DisableOtherDrilling( Proc, vProc) + elseif BD.DOWN_HEAD and AreSameVectorApprox( vtExtr, Z_AX()) then + Proc.Double = 3 + Proc.MachDepthDouble = dMachiningDepth + DisableOtherDrilling( Proc, vProc) + end + end + end +end + +------------------------------------------------------------------------------------------------------------- +-- Cerca in vProc la presenza di feature da lavorare in doppio. Se le trova scrive in Proc la direzione di specchiatura e l'utensile da utilizzare. +local function SetMirroredFeatures( vProc, b3Raw) for i = 1, #vProc do local Proc = vProc[i] - local sFeatureType - if DtMortise.SideIdentify(Proc) then - sFeatureType = 'DtMortise' - elseif Drill.Identify(Proc) then - sFeatureType = 'Drill' - end - if ( sFeatureType == 'DtMortise' or sFeatureType == 'Drill') and not Proc.MirrorId then - local nProcMirror = FindMirrorFeature( vProc, Proc, sFeatureType, dHBeam) - if nProcMirror then - Proc.MirrorId = vProc[nProcMirror].Id - vProc[nProcMirror].MirrorId = Proc.Id - EgtSetInfo( Proc.Id, 'MIRRORID', vProc[nProcMirror].Id) - EgtSetInfo( vProc[nProcMirror].Id, 'MIRRORID', Proc.Id) + if Proc.Flg ~= 0 then + -- Proc.Double -> 0: nessuna specchiatura, 1: specchiatura X, 2: specchiatura Y, 3: specchiatura Z + -- Proc.MirrorId -> Id della feature mirrorata + if DtMortise.SideIdentify( Proc) and BD.DOUBLE_HEAD_DOVETAIL then + VerifyDtMortiseMirrored( Proc, vProc, b3Raw) + elseif Drill.Identify( Proc) and BD.DOUBLE_HEAD_DRILLING then + VerifyDrillMirrored( Proc, vProc, b3Raw) end end end @@ -1567,9 +1668,8 @@ function BeamExec.ProcessFeatures() SetDrillingsToMachineAfterHeadOrTailCut( vProc, vMachineBeforeIntersectingDrillings) end -- verifica presenza di feature specchiate per eventuali lavorazioni simultanee - local bConcurrentDoubleHead = BD.DOUBLE_HEAD_MIRRORED_FEATURES and ( BD.TWO_EQUAL_HEADS or BD.TWO_UP_DOWN_HEADS) - if bConcurrentDoubleHead then - SetMirroredFeatures( vProc, EgtGetRawPartBBox( nRawId):getDimZ()) + if BD.TWO_EQUAL_HEADS or BD.DOWN_HEAD then + SetMirroredFeatures( vProc, b3Raw) end -- le ordino lungo X OrderFeatures( vProc, b3Raw) @@ -1614,6 +1714,9 @@ function BeamExec.ProcessFeatures() table.insert( Stats, {Err=-1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) else table.insert( Stats, {Err=0, Msg='', Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) + if Proc.Double == 2 or Proc.Double == 3 then + table.insert( Stats, {Err=0, Msg='', Rot=-2, CutId=Proc.MirrorCurId, TaskId=Proc.MirrorTaskId}) + end end -- se è taglio di separazione, verifico se ha già aggiunto una nuova fase oppure se è da creare if nNewPhase > 0 then @@ -1679,11 +1782,14 @@ function BeamExec.ProcessFeatures() local bOk, sMsg, nNewPhase = AddFeatureMachining( Proc, nPhase, nRawId, nPartId, dCurrOvmH, false, b3Raw, nOrd, sDownOrSideOrStd, bPreMove, vtMove, dCurrOvmT) if not bOk then nTotErr = nTotErr + 1 - table.insert( Stats, {Err=1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) + table.insert( Stats, {Err=1, Msg=sMsg, Rot=-1, CutId=Proc.CutId, TaskId=Proc.TaskId}) elseif sMsg and #sMsg > 0 then - table.insert( Stats, {Err=-1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) + table.insert( Stats, {Err=-1, Msg=sMsg, Rot=-1, CutId=Proc.CutId, TaskId=Proc.TaskId}) else - table.insert( Stats, {Err=0, Msg='', Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) + table.insert( Stats, {Err=0, Msg='', Rot=-1, CutId=Proc.CutId, TaskId=Proc.TaskId}) + if Proc.Double == 2 or Proc.Double == 3 then + table.insert( Stats, {Err=0, Msg='', Rot=-1, CutId=Proc.MirrorCurId, TaskId=Proc.MirrorTaskId}) + end end if bOk then nSideMchOk = nSideMchOk + 1 end -- se era taglio di separazione, aggiungo nuova fase @@ -1742,6 +1848,9 @@ function BeamExec.ProcessFeatures() table.insert( Stats, {Err=-1, Msg=sMsg, Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) else table.insert( Stats, {Err=0, Msg='', Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) + if Proc.Double == 2 or Proc.Double == 3 then + table.insert( Stats, {Err=0, Msg='', Rot=0, CutId=Proc.MirrorCurId, TaskId=Proc.MirrorTaskId}) + end end -- se era taglio di separazione, aggiungo nuova fase if nNewPhase > 0 then diff --git a/LuaLibs/MachiningLib.lua b/LuaLibs/MachiningLib.lua index b51dd6b..8f10250 100644 --- a/LuaLibs/MachiningLib.lua +++ b/LuaLibs/MachiningLib.lua @@ -4,6 +4,7 @@ -- 2022/07/27 Aggiunta la gestione del tipo di foratura "AngleDrill" per fori molto inclinati -- 2022/11/02 Modificata scelta utensile ottimizzata. Ora se c'è un utensile più grande disponibile si dà preferenza a quello. -- 2022/11/25 Per FindMilling implementata la possibilità di escludere la testa H3 dalla ricerca utensile. +-- 2022/12/28 Per FindMilling e FindDrilling possibilità di escludere la testa H2 dalla ricerca utensile. -- Tabella per definizione modulo local MachiningLib = {} @@ -224,7 +225,7 @@ function ReturnParams( MachiningType, MachiningName, sType, ToolParams) end --------------------------------------------------------------------- -local function FindMachining( MachiningType, sType, Params, bTopHead, bDownHead, bExcludeH3) +local function FindMachining( MachiningType, sType, Params, bTopHead, bDownHead, bExcludeH2, bExcludeH3) if bTopHead == nil and bDownHead == nil then bTopHead = true bDownHead = false @@ -233,6 +234,12 @@ local function FindMachining( MachiningType, sType, Params, bTopHead, bDownHead, elseif bDownHead == nil then bDownHead = not bTopHead end + if bExcludeH2 == nil then + bExcludeH2 = false + end + if bExcludeH3 == nil then + bExcludeH3 = false + end SetCurrMachineHeadType() -- verifico se testa attiva va bene local sH1Mach = '' @@ -276,7 +283,7 @@ local function FindMachining( MachiningType, sType, Params, bTopHead, bDownHead, end -- recupero dati utensile local bToolActive, sToolName, bH2, bFixed, bH3 = SetCurrMachiningAndTool( Machining.Name) - if Machining.On and sMachiningType == sType and bToolActive and ( not bH3 or bH3 == not bExcludeH3) then + if Machining.On and sMachiningType == sType and bToolActive and ( not bH2 or bH2 == not bExcludeH2) and ( not bH3 or bH3 == not bExcludeH3) then local bOk, ToolParams = VerifyTool( MachiningType, sType, Params, bH2) if bOk then if MachineHeadUse == ONE_HEAD then @@ -367,8 +374,8 @@ function MachiningLib.FindCutting( sType, bTopHead, bDownHead) end --------------------------------------------------------------------- -function MachiningLib.FindDrilling( dDiam, dDepth, bTopHead, bDownHead) - local MachiningName, MachiningType, Param1, Param2, Param3, Param4, Param5 = FindMachining( MCH_MY.DRILLING, 'Drill', { Diam = dDiam, Depth = dDepth}, bTopHead, bDownHead) +function MachiningLib.FindDrilling( dDiam, dDepth, bTopHead, bDownHead, bExcludeH2) + local MachiningName, MachiningType, Param1, Param2, Param3, Param4, Param5 = FindMachining( MCH_MY.DRILLING, 'Drill', { Diam = dDiam, Depth = dDepth}, bTopHead, bDownHead, bExcludeH2) if not MachiningName or MachiningName == '' then MachiningName, MachiningType, Param1, Param2, Param3, Param4, Param5 = FindMachining( MCH_MY.DRILLING, 'Pocket', { Diam = dDiam, Depth = dDepth}, bTopHead, bDownHead) end @@ -386,8 +393,8 @@ function MachiningLib.FindAngleDrilling( dDiam, dDepth, bTopHead, bDownHead) end --------------------------------------------------------------------- -function MachiningLib.FindMilling( sType, dDepth, sTuuidMstr, dMaxDiam, dMaxTotLen, bTopHead, bDownHead, bExcludeH3) - return FindMachining( MCH_MY.MILLING, sType, { Depth = dDepth, TuuidMstr = sTuuidMstr, MaxDiam = dMaxDiam, MaxTotLen = dMaxTotLen}, bTopHead, bDownHead, bExcludeH3) +function MachiningLib.FindMilling( sType, dDepth, sTuuidMstr, dMaxDiam, dMaxTotLen, bTopHead, bDownHead, bExcludeH2, bExcludeH3) + return FindMachining( MCH_MY.MILLING, sType, { Depth = dDepth, TuuidMstr = sTuuidMstr, MaxDiam = dMaxDiam, MaxTotLen = dMaxTotLen}, bTopHead, bDownHead, bExcludeH2, bExcludeH3) end --------------------------------------------------------------------- diff --git a/LuaLibs/ProcessDrill.lua b/LuaLibs/ProcessDrill.lua index d53f865..f3e18e9 100644 --- a/LuaLibs/ProcessDrill.lua +++ b/LuaLibs/ProcessDrill.lua @@ -15,6 +15,7 @@ -- 2022/08/18 Aggiunta gestione macchine con testa da sotto e punta disabilitata. -- 2022/10/25 Nella funzione Split aggiunto il controllo che le facce di ingresso e uscita siano differenti (potrebbe succedere per fori molto corti). Modifica importatore in futuro. -- 2022/11/23 Aggiunta la gestione dei fori con angolo < 30 gradi, per i quali si usa la testa della macchina per accorciare l'utile di lavoro. +-- 2022/12/28 Implementata gestione forature in doppio -- Tabella per definizione modulo local ProcessDrill = {} @@ -269,11 +270,17 @@ function ProcessDrill.Make( Proc, nPhase, nRawId, nPartId) -- abilitazione foratura da sotto local bDrillDown = ( bDownDrill and ( Proc.Down or vtExtr:getZ() < -0.1 or vtExtr:getZ() < 0.259)) local bDrillUp = ( bDownDrill and vtExtr:getZ() > -0.421) + local bExcludeH2 = false + if Proc.Double and Proc.Double > 0 then + bMillUp = true + bDrillDown = false + bExcludeH2 = true + end -- primo gruppo di controlli con lunghezza utensile pari a metà foro se passante -- recupero la lavorazione - local sDrilling, sType, dMaxDepth, dMaxToolLength, dToolDiam, dDiamTh, dToolFreeLen = ML.FindDrilling( dDiam, dCheckDepth, bDrillUp, bDrillDown) + local sDrilling, sType, dMaxDepth, dMaxToolLength, dToolDiam, dDiamTh, dToolFreeLen = ML.FindDrilling( dDiam, dCheckDepth, bDrillUp, bDrillDown, bExcludeH2) if not sDrilling and dCheckDepth then - sDrilling, sType, dMaxDepth, dMaxToolLength, dToolDiam, dDiamTh, dToolFreeLen = ML.FindDrilling( dDiam, 0, bDrillUp, bDrillDown) + sDrilling, sType, dMaxDepth, dMaxToolLength, dToolDiam, dDiamTh, dToolFreeLen = ML.FindDrilling( dDiam, 0, bDrillUp, bDrillDown, bExcludeH2) if sDrilling then dCheckDepth = nil end end if not sDrilling then @@ -393,7 +400,7 @@ function ProcessDrill.Make( Proc, nPhase, nRawId, nPartId) local dMaxElev local sMyWarn -- se c'è un taglio precedente di testa o coda in cui il foro "entra" devo ricalcolare i dati della foratura - if (( Proc.MachineAfterHeadCutId and vtExtr:getX() > 0) or ( Proc.MachineAfterTailCutId and vtExtr:getX() < 0)) then + if ( not Proc.Double or Proc.Double == 0) and(( Proc.MachineAfterHeadCutId and vtExtr:getX() > 0) or ( Proc.MachineAfterTailCutId and vtExtr:getX() < 0)) then local bIntersectionOk, _, vDistance = EgtLineSurfTmInters( ptCen, -vtExtr, Proc.MachineAfterHeadCutId or Proc.MachineAfterTailCutId, GDB_RT.GLOB) if bIntersectionOk then local dHoleToCutDistance = vDistance[1] @@ -463,6 +470,11 @@ function ProcessDrill.Make( Proc, nPhase, nRawId, nPartId) end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- imposto affondamento + if Proc.Double and Proc.Double > 0 and dDepth > Proc.MachDepthDouble + 10 * GEO.EPS_SMALL then + sMyWarn = 'Warning in double head drilling : depth (' .. EgtNumToString( dDepth, 1) .. ') reduced to (' .. EgtNumToString( Proc.MachDepthDouble, 1) .. ') to match H2 max tool depth' + dDepth = Proc.MachDepthDouble + dMaxElev = Proc.MachDepthDouble + end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- imposto il valore della distanza di sicurezza per l'attacco. Se il valore del db utensili è troppo basso lo alzo a 10. local dToolDbStartPos = EgtGetMachiningParam( MCH_MP.STARTPOS) @@ -470,20 +482,18 @@ function ProcessDrill.Make( Proc, nPhase, nRawId, nPartId) local dStartPos = max( dMinStartPos, dToolDbStartPos) EgtSetMachiningParam( MCH_MP.STARTPOS, dStartPos) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill - local sUserNotes = 'VMRS=0;' + local sUserNotes = EgtSetVal( 'VMRS', 0) -- aggiungo alle note massima elevazione (coincide con affondamento) if dMaxElev then - sUserNotes = sUserNotes .. 'MaxElev=' .. EgtNumToString( dMaxElev, 1) .. ';' + sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dMaxElev, 1)) end -- se foro passante, aggiungo questa qualifica alle note if ( sType == 'Drill' or sType == 'Drill_H2' or sType == 'AngleDrill') and bOpen then - sUserNotes = sUserNotes .. 'Open=1;' + sUserNotes = EgtSetValInNotes( sUserNotes, 'Open', 1) end -- se lavorazione in doppio - if EgtExistsInfo( Proc.Id, 'MAIN') then - sUserNotes = sUserNotes .. 'Double;' - elseif EgtExistsInfo( Proc.Id, 'DOU') then - sUserNotes = sUserNotes .. 'Main;' + if Proc.Double and Proc.Double > 0 then + sUserNotes = EgtSetValInNotes( sUserNotes, 'DOUBLE', Proc.Double) end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo diff --git a/LuaLibs/ProcessDtMortise.lua b/LuaLibs/ProcessDtMortise.lua index e7ebb09..a268f35 100644 --- a/LuaLibs/ProcessDtMortise.lua +++ b/LuaLibs/ProcessDtMortise.lua @@ -34,18 +34,18 @@ function ProcessDtMortise.Identify( Proc) (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 56)) end ---------------------------------------------------------------------- --- Riconoscimento della sola feature frontale -function ProcessDtMortise.FrontIdentify( Proc) - return (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 56) -end - --------------------------------------------------------------------- -- Riconoscimento della sola feature laterale function ProcessDtMortise.SideIdentify( Proc) return (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 55) end +--------------------------------------------------------------------- +-- Riconoscimento della sola feature frontale +function ProcessDtMortise.FrontIdentify( Proc) + return (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 56) +end + --------------------------------------------------------------------- -- Verifica se feature di coda function ProcessDtMortise.IsTailFeature( Proc, b3Raw) @@ -232,10 +232,16 @@ function ProcessDtMortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) elseif bMillAngTrasm then sMchExt = '_AT' end + local bExcludeH2 = false + if Proc.Double and Proc.Double > 0 then + bMillUp = true + bMillDown = false + bExcludeH2 = true + end -- recupero la lavorazione : prima ricerca per sola tipologia - local sMilling = ML.FindMilling( sMillType..sMchExt, nil, nil, nil, nil, bMillUp, bMillDown) + local sMilling = ML.FindMilling( sMillType..sMchExt, nil, nil, nil, nil, bMillUp, bMillDown, bExcludeH2) if not sMilling and bMillUp then - sMilling = ML.FindMilling( sMillType, nil, nil, nil, nil, bMillUp, bMillDown) + sMilling = ML.FindMilling( sMillType, nil, nil, nil, nil, bMillUp, bMillDown, bExcludeH2) end if not sMilling then local sErr = 'Milling not found in library : Error on DtMortise ' .. tostring( Proc.Id) @@ -243,9 +249,9 @@ function ProcessDtMortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) return false, sErr end -- recupero la lavorazione : seconda ricerca con tipologia e diametro massimo - sMilling = ML.FindMilling( sMillType..sMchExt, nil, nil, 2 * dMinRad, nil, bMillUp, bMillDown) + sMilling = ML.FindMilling( sMillType..sMchExt, nil, nil, 2 * dMinRad, nil, bMillUp, bMillDown, bExcludeH2) if not sMilling and bMillUp then - sMilling = ML.FindMilling( sMillType, nil, nil, 2 * dMinRad, nil, bMillUp, bMillDown) + sMilling = ML.FindMilling( sMillType, nil, nil, 2 * dMinRad, nil, bMillUp, bMillDown, bExcludeH2) sMchExt = '' end if not sMilling then @@ -414,6 +420,10 @@ function ProcessDtMortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) end -- dichiaro non si generano sfridi per VMill local sUserNotes = 'MaxElev='.. EgtNumToString( dAltMort, 1) .. '; VMRS=0;' + -- se lavorazione in doppio + if Proc.Double and Proc.Double > 0 then + sUserNotes = EgtSetValInNotes( sUserNotes, 'DOUBLE', Proc.Double) + end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then @@ -489,8 +499,12 @@ function ProcessDtMortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) if nSCC then EgtSetMachiningParam( MCH_MP.SCC, nSCC) end - -- dichiaro non si generano sfridi per VMill - local sUserNotes = 'MaxElev='.. EgtNumToString( dMaxMat - 0.1, 1) .. '; VMRS=0;' + -- dichiaro massima elevazione e assenza sfridi per VMill + local sUserNotes = EgtSetVal( 'MaxElev', EgtNumToString( dMaxMat - 0.1, 1)) .. ';' .. EgtSetVal( 'VMRS', 0) .. ';' + -- se lavorazione in doppio + if Proc.Double and Proc.Double > 0 then + sUserNotes = EgtSetValInNotes( sUserNotes, 'DOUBLE', Proc.Double) + end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then diff --git a/LuaLibs/ProcessLapJoint.lua b/LuaLibs/ProcessLapJoint.lua index fce8ff7..9938b98 100644 --- a/LuaLibs/ProcessLapJoint.lua +++ b/LuaLibs/ProcessLapJoint.lua @@ -57,6 +57,7 @@ -- 2022/09/27 Aggiunta gestione SCC per svuotature con TURN (solo dopo applicazione lavorazione). -- 2022/10/20 In MakeByChainOrSaw modificato check per trovare la faccia adiacente sul lato più lungo. -- 2022/12/12 Default 1000 per BD.MIN_LEN_LAMELLO. In MachineByMill migliorata ricerca utensile e gestione inversione in funzione del lato di lavoro. +-- 2022/12/16 Implementato parametro Q_SIDE_ROUGH_TOOL anche per L20 -- 2022/12/21 Sistemata gestione SideMillAsSaw. -- Tabella per definizione modulo @@ -141,6 +142,7 @@ local function AssignQIdent( Proc) Q_DEPTH_CHAMFER = 'Q01' -- d Q_USE_MILL = 'Q02' -- i Q_USE_ROUGH_TOOL = 'Q03' -- i + Q_SIDE_ROUGH_TOOL = 'Q04' -- i Q_BORE_ON_CORNER = 'Q06' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 25 then Q_BORE_ON_CORNER = 'Q01' -- i @@ -5003,7 +5005,7 @@ local function MakeMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead, bSinglePa if bSpecialMillOnSide then -- eseguo bOk, sWarn = MakeByMillAsSaw( Proc, nPhase, nRawId, nPartId, nFacInd, - rfFac, dH, dV, dFacElev, + rfFac, dH, dV, dFacElev, nBottomFace, nAddGrpId, b3Solid, dMaxDepthOnSide, sMillingOnSide, dToolDiamOnSide, dThickMillOnSide, bAllWithEndCap) if bOk then @@ -5583,7 +5585,7 @@ function ProcessLapJoint.Make( Proc, nPhase, nRawId, nPartId, dOvmHead) local nForceUseBladeOnNotContinueFace -- se ho attivo la lama e ho la feature 30, verifico i parametri Q propri della feature if bUseBlade then - if Proc.Prc == 30 then + if Proc.Prc == 30 or Proc.Prc == 20 then local nBladeAntisplint = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') or 0 local nUseRoughToolOnSide = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 nForceUseBladeOnNotContinueFace = EgtGetInfo( Proc.Id, Q_BLADE_ON_ALONG_FACE, 'i') or 0 diff --git a/LuaLibs/ProcessLongCut.lua b/LuaLibs/ProcessLongCut.lua index d01ffe9..82e7c90 100644 --- a/LuaLibs/ProcessLongCut.lua +++ b/LuaLibs/ProcessLongCut.lua @@ -863,7 +863,7 @@ function ProcessLongCut.Make( Proc, nPhase, nRawId, nPartId, bCustUseBlade, nCus local bDownHead = ( nSide == - 1) sMchType = EgtIf( bDownHead, 'Long2Cut_H2', 'Long2Cut') local bExcludeH3 = bLarghAsFace and abs( nSide) ~= 1 - local sMilling = ML.FindMilling( sMchType, dElev, nil, nil, nil, not bDownHead, bDownHead, bExcludeH3) + local sMilling = ML.FindMilling( sMchType, dElev, nil, nil, nil, not bDownHead, bDownHead, nil, bExcludeH3) if not sMilling then local sErr = 'Error : milling '..sMchType..' not found in library' EgtOutLog( sErr) diff --git a/NestProcess.lua b/NestProcess.lua index be7ea92..ace4f83 100644 --- a/NestProcess.lua +++ b/NestProcess.lua @@ -17,6 +17,9 @@ EgtEnableDebug( false) 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) @@ -87,9 +90,9 @@ local function ExecMaximumFilling( Raw, Parts) EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1) end -- Eseguo l'ottimizzazione - EgtStartCounter() + --EgtStartCounter() EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType) - local dTime = EgtStopCounter() + --local dTime = EgtStopCounter() -- Recupero i risultati local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults() local OneRes = {} @@ -97,7 +100,8 @@ local function ExecMaximumFilling( Raw, Parts) 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, Time=dTime, Data=OneRes} + return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes} end -- Funzione per trovare nome MachGroup @@ -155,7 +159,6 @@ local nErrCnt = 0 local nWarnCnt = 0 -- Grezzi --- lista dei grezzi local Raws = {} -- creo tabella dei grezzi for nIndex, nLen in pairs( LEN) do @@ -165,8 +168,6 @@ for nIndex, nQty in pairs( QTY) do Raws[tonumber(nIndex)].Count = nQty end ---local nTotRaws = Raws.Count - -- Pezzi local Parts = {} @@ -176,13 +177,17 @@ for RawIndex = 1, #Raws do maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap) end -- 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 - table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = nCount}) + for nCntIndex = 1 , nCount do + table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1}) + dTotLen = dTotLen + Len + end end end @@ -201,131 +206,247 @@ local MediumRawQty = ceil( RawQtySum / #NeededRawsForType) if MediumRawQty > 1 then MediumRawQty = MediumRawQty - 1 end --- recupero pezzi piu' corti di mille -local ShortList = {} -local LongList = {} -for PartIndex = 1, #Parts do - if Parts[PartIndex].Len <= 1000 then - table.insert( ShortList, Parts[PartIndex]) - else - table.insert( LongList, Parts[PartIndex]) + +-- 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 -end --- numero di pezzi piccoli per barra -local ShortCount = 0 -for ShortIndex = 1, #ShortList do - ShortCount = ShortCount + ShortList[ShortIndex].Cnt -end -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}) + + -- 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 -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 + -- 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} + 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 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 --- Ciclo fino ad esaurimento pezzi o barre -local nRawTot = 0 -local dTime = 0 -local nCycle = 1 -while TotRawCount( Raws) > 0 and PartsToFill( Parts) > 0 do +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 - -- creo lista pezzi con pezzi lunghi e pezzi corti di questo Cycle - local PartsToNest = {} - for PartIndex = 1, #LongList do - table.insert( PartsToNest, LongList[PartIndex]) +-- 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 - 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, #Raws do - if Raws[RawIndex].Count > 0 then - Results[RawIndex] = ExecMaximumFilling( Raws[RawIndex], PartsToNest) - else - Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000} - 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) * Raws[ResultIndex].LenToFill - if 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 - -- creo gruppo di lavorazione - local MachGroupName = NewMachGroupName() - nMachGroup = EgtAddMachGroup( MachGroupName) - EgtSetInfo( nMachGroup, "BARLEN", Raws[nMinWasteRawIndex].LenToFill) - 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 - local CurrX = Raws[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 - local nPartDuploId = EgtDuploNew( PartId) - EgtSetInfo( nMachGroup, "PART" .. nInfoIndex, nPartDuploId .. "," .. CurrX) - CurrX = CurrX + dLen + Raws[nMinWasteRawIndex].MidGap - nInfoIndex = nInfoIndex + 1 - end - end - nRawTot = nRawTot + 1 - -- Aggiorno per prossima iterazione - Raws[nMinWasteRawIndex].Count = Raws[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 - end - nCycle = nCycle + 1 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