-- BLADEKEEPWASTE.lua by Egalware s.r.l. 2025/03/17 -- Libreria di supporto a strategie con funzioni comune a strategie diverse. -- Tabella per definizione modulo local BLADEKEEPWASTE = {} -- Include require( 'EgtBase') -- Carico i dati globali local FeatureLib = require( 'FeatureLib') local FaceData = require( 'FaceData') local MachiningLib = require( 'MachiningLib') -- strategie di base local FaceByBlade = require('FACEBYBLADE') local FaceByMill = require('FACEBYMILL') -- tabella per definizione modulo local Machinings = {} ------------------------------------------------------------------------------------------------------------- local function CompareEdges( EdgeA, EdgeB) -- prima i lati orientati lungo X if abs( EdgeA.vtN:getX()) < abs( EdgeB.vtN:getX()) - 10 * GEO.EPS_SMALL then return true elseif abs( EdgeA.vtN:getX()) > abs( EdgeB.vtN:getX()) + 10 * GEO.EPS_SMALL then return false -- se stessa X si preferiscono i lati più lunghi (nel caso di 5 lati è quello non spezzato) else if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then return true elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then return false -- se stessa lunghezza si preferiscono i lati più in basso -- TODO qui dipenderà dalla lama scelta else if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then return false -- se stessa Z si preferiscono i lati verso il fronte della trave else if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 10 * GEO.EPS_SMALL then return false else return false end end end end end local function SortMachiningsBySegment( MachiningA, MachiningB) if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then return false elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then return true -- se segmento uguale, si guarda la priorità else if MachiningA.nInternalSortingPriority > MachiningB.nInternalSortingPriority then return false elseif MachiningB.nInternalSortingPriority > MachiningA.nInternalSortingPriority then return true -- se priorità uguale, si minimizzano i cambi di lato else local bIsOddSegment = ( MachiningA.nFeatureSegment % 2 ~= 0) if MachiningA.vtToolDirection:getY() < MachiningB.vtToolDirection:getY() - 10 * GEO.EPS_SMALL then if bIsOddSegment then return true else return false end elseif MachiningA.vtToolDirection:getY() > MachiningB.vtToolDirection:getY() + 10 * GEO.EPS_SMALL then if bIsOddSegment then return false else return true end else return false end end end end function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters) -- TODO verificare funzionamento con lama da sotto -- attenzione perchè se l'inclinazione della faccia la fa finire oltre lo spigolo questo riduce il massimo (come calcolare????) -- il FindBlade dovrà restituire di utilizzare sempre la lama sopra se l'angolo lo permette, ma avendo un'altezza massima (da macchina) oltre cui il DownUp non sarà fattibile (evita collisioni tra asse e pezzo) local Result = {} Machinings = {} local CreatedMachinings = {} local Cutting1 = {} local Cutting2 = {} -- controlli preventivi if Proc.nFct > 3 then error( 'BladeKeepWaste : max 3 faces supported') elseif Proc.nFct == 2 then if Proc.AdjacencyMatrix[1][2] > 10 * GEO.EPS_SMALL or Proc.AdjacencyMatrix[1][2] < -91 then error( 'BladeKeepWaste : angle between faces must be concave and >= 90deg') end elseif Proc.nFct == 3 then if Proc.AdjacencyMatrix[1][2] > 10 * GEO.EPS_SMALL or Proc.AdjacencyMatrix[1][2] < -91 then error( 'BladeKeepWaste : angle between faces must be concave and >= 90deg') end if Proc.AdjacencyMatrix[1][3] > 10 * GEO.EPS_SMALL or Proc.AdjacencyMatrix[1][3] < -91 then error( 'BladeKeepWaste : angle between faces must be concave and >= 90deg') end if Proc.AdjacencyMatrix[2][3] > 10 * GEO.EPS_SMALL or Proc.AdjacencyMatrix[2][3] < -91 then error( 'BladeKeepWaste : angle between faces must be concave and >= 90deg') end end -- parametri opzionali e default if not OptionalParameters then OptionalParameters = {} end local nToolIndex = OptionalParameters.nToolIndex local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000 local bFinishWithMill if OptionalParameters.bFinishWithMill == nil then bFinishWithMill = true else bFinishWithMill = OptionalParameters.bFinishWithMill end local dMillingOffsetFromSide = OptionalParameters.dMillingOffsetFromSide or 1 -- si trovano le facce da lavorare local BottomFace = {} local LongFaces = {} if Proc.nFct == 1 then BottomFace = Proc.Faces[1] else if not Proc.MainFaces then Proc.MainFaces = FaceData.GetMainFaces( Proc, Part) end BottomFace = Proc.MainFaces.BottomFaces[1] LongFaces = Proc.MainFaces.LongFaces end -- si trova il lato da lavorare local EdgeToMachine = {} local EdgesSorted = {} for i = 1, #BottomFace.Edges do table.insert( EdgesSorted, BottomFace.Edges[i]) end table.sort( EdgesSorted, CompareEdges) EdgeToMachine = EdgesSorted[1] local dDepthToMachine = EdgeToMachine.dElevation / 2 - OptionalParameters.dStripWidth / 2 -- eventuali punti di spezzatura local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part) local bIsSplitFeature = false if #FeatureSplittingPoints > 0 then bIsSplitFeature = true end -- calcolo lavorazioni -- taglio eventuali facce di chiusura for i = 1, #LongFaces do local Cutting = {} local OptionalParametersFaceByBlade = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex} Cutting = FaceByBlade.Make( Proc, Part, Proc.MainFaces.LongFaces[i], Proc.MainFaces.LongFaces[i].MainEdges.BottomEdge, OptionalParametersFaceByBlade) Cutting.nInternalSortingPriority = 1 table.insert( CreatedMachinings, Cutting) end -- faccia di fondo -- primo lato local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex} Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade) Cutting1.nInternalSortingPriority = 3 table.insert( CreatedMachinings, Cutting1) -- secondo lato OptionalParametersFaceByBlade.bOppositeToolDirection = true Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade) Cutting2.nInternalSortingPriority = 3 table.insert( CreatedMachinings, Cutting2) -- eventuale pulitura raggio lama if bFinishWithMill then for i = 1, #LongFaces do local dDepthToMachineMill = BottomFace.MainEdges.LongEdges[i].dElevation - dMillingOffsetFromSide local dBladeMarkLength = max( Cutting1.dBladeMarkLength, Cutting2.dBladeMarkLength) local OptionalParametersFaceByMill = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, dHorizontalStepSpan = dBladeMarkLength, dDepthToMachine = dDepthToMachineMill } local Milling = FaceByMill.Make( Proc, Part, BottomFace, BottomFace.MainEdges.LongEdges[i], OptionalParametersFaceByMill) Milling.nInternalSortingPriority = 2 table.insert( CreatedMachinings, Milling) end end -- lavorazioni raggruppate in unica lista for i = 1, #CreatedMachinings do if CreatedMachinings[i].bIsApplicable then table.insert( Machinings, CreatedMachinings[i]) end end -- aggiunta eventuali lavorazioni splittate if bIsSplitFeature then Machinings = MachiningLib.GetSplitMachinings( Machinings, FeatureSplittingPoints, Part) end -- ordinamento table.sort( Machinings, SortMachiningsBySegment) -- calcolo parametri per la stima della velocità di asportazione -- TODO non è corretto: come si stima la velocità di asportazione con il codolo? è come se avesse rimosso tutto il volume feature nel tempo di percorrenza if Cutting1.bIsApplicable or Cutting2.bIsApplicable then MRRParameters1 = { dStep = TOOLS[Cutting1.nToolIndex].dThickness, dSideStep = min( TOOLS[Cutting1.nToolIndex].dSideStep, dDepthToMachine), dFeed = TOOLS[Cutting1.nToolIndex].Feeds.dFeed} MRRParameters2 = { dStep = TOOLS[Cutting2.nToolIndex].dThickness, dSideStep = min( TOOLS[Cutting2.nToolIndex].dSideStep, dDepthToMachine), dFeed = TOOLS[Cutting2.nToolIndex].Feeds.dFeed} local dMRRBlade1 = MachiningLib.GetToolMRR( MRRParameters1) local dMRRBlade2 = MachiningLib.GetToolMRR( MRRParameters2) Result.dMRR = ( dMRRBlade1 + dMRRBlade2) / 2 Result.dCompletionPercentage = 0.5 * Cutting1.dCompletionPercentage + 0.5 * Cutting2.dCompletionPercentage if Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then Result.sStatus = 'Completed' else Result.sStatus = 'Not-Completed' end Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage) Result.nQuality = FeatureLib.GetFeatureQuality( 'Blade') else Result.dMRR = 0 Result.dCompletionPercentage = 0 Result.sStatus = 'Not-Applicable' Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage) Result.nQuality = FeatureLib.GetFeatureQuality( 'Blade') end return Machinings, Result end ------------------------------------------------------------------------------------------------------------- return BLADEKEEPWASTE