Files
databeamnew/StrategyLibs/BLADEKEEPWASTE.lua
T

276 lines
11 KiB
Lua

-- 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')
-- tabelle per definizione modulo
-------------------------------------------------------------------------------------------------------------
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
local function GetStrategyCompletionPercentage( Machinings)
local dCompletionPercentage = 0
local dCompletionPercentageNumerator = 0
local dCompletionPercentageDenominator = 0
local nWeightsCount = 0
for i = 1, #Machinings do
local Machining = Machinings[i]
local dWeight = Machining.dResultWeight
if not dWeight or ( dWeight < 10 * GEO.EPS_SMALL) then
dWeight = 1
else
nWeightsCount = nWeightsCount + 1
end
-- il peso deve essere settato in tutte le lavorazioni o in nessuna
if ( nWeightsCount == 0) or ( nWeightsCount ~= i) then
error( 'GetWeightedCompletionPercentage : inconsistent weights')
end
local dWeightedCompletionPercentage = Machining.dCompletionPercentage / 100 * dWeight
if Machining.bIsApplicable then
dCompletionPercentageNumerator = dCompletionPercentageNumerator + dWeightedCompletionPercentage
end
dCompletionPercentageDenominator = dCompletionPercentageDenominator + dWeight
end
dCompletionPercentage = min( 100 * dCompletionPercentageNumerator / dCompletionPercentageDenominator, 100)
return dCompletionPercentage
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 = {}
local Machinings = {}
local CalculatedMachinings = {}
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
-- volume della feature
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
-- 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 della faccia di fondo da lavorare
local BottomEdgeToMachine = {}
local BottomEdgesSorted = {}
for i = 1, #BottomFace.Edges do
table.insert( BottomEdgesSorted, BottomFace.Edges[i])
end
table.sort( BottomEdgesSorted, CompareEdges)
BottomEdgeToMachine = BottomEdgesSorted[1]
-- 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, LongFaces[i], LongFaces[i].MainEdges.BottomEdge, OptionalParametersFaceByBlade)
Cutting.nInternalSortingPriority = 1
Cutting.dResultWeight = 0.15
table.insert( CalculatedMachinings, Cutting)
end
-- taglio con codolo faccia di fondo
local dDepthToMachine = BottomEdgeToMachine.dElevation / 2 - OptionalParameters.dStripWidth / 2
local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex}
-- primo lato
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade)
Cutting1.nInternalSortingPriority = 3
Cutting1.dResultWeight = 0.3
table.insert( CalculatedMachinings, Cutting1)
-- secondo lato
OptionalParametersFaceByBlade.bOppositeToolDirection = true
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade)
Cutting2.nInternalSortingPriority = 3
Cutting2.dResultWeight = 0.3
table.insert( CalculatedMachinings, Cutting2)
-- fresatura eventuali facce di chiusura
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,
dRadialStepSpan = dBladeMarkLength, dDepthToMachine = dDepthToMachineMill
}
local Milling = FaceByMill.Make( Proc, Part, BottomFace, BottomFace.MainEdges.LongEdges[i], OptionalParametersFaceByMill)
Milling.nInternalSortingPriority = 2
Milling.dResultWeight = 0.05
table.insert( CalculatedMachinings, Milling)
end
end
-- lavorazioni da applicare spostate in lista finale
for i = 1, #CalculatedMachinings do
if CalculatedMachinings[i].bIsApplicable then
table.insert( Machinings, CalculatedMachinings[i])
end
end
-- calcolo completamento, serve la lista di lavorazioni che comprende le non applicabili
Result.dCompletionPercentage = GetStrategyCompletionPercentage( CalculatedMachinings)
Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
-- aggiunta eventuali lavorazioni splittate
if bIsSplitFeature then
Machinings = MachiningLib.GetSplitMachinings( Machinings, FeatureSplittingPoints, Part)
end
-- ordinamento
table.sort( Machinings, SortMachiningsBySegment)
-- calcolo risultati
if Cutting1.bIsApplicable or Cutting2.bIsApplicable then
Result.nQuality = FeatureLib.GetStrategyQuality( Machinings)
local dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
Result.dMRR = ( dFeatureVolume / dTimeToMachine) / pow( 10, 6)
if Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
Result.sStatus = 'Completed'
else
Result.sStatus = 'Not-Completed'
end
else
Result = FeatureLib.GetStrategyResultNotApplicable()
end
return Machinings, Result
end
-------------------------------------------------------------------------------------------------------------
return BLADEKEEPWASTE