fb68dd28a0
- uniformata la restituzione dei risultati in caso di strategia non applicabile (FeatureLib.GetStrategyResultNotApplicable, a cui si può passare il messaggio da ritornare)
310 lines
13 KiB
Lua
310 lines
13 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 GetStrategyResult( Machinings, dFeatureVolume)
|
|
local Result = {}
|
|
|
|
local dCompletionPercentageNumerator = 0
|
|
local dCompletionPercentageDenominator = 0
|
|
local dQualityNumerator = 0
|
|
local dQualityDenominator = 0
|
|
local dTimeToMachine = 0
|
|
local nWeightsCount = 0
|
|
for i = 1, #Machinings do
|
|
local Machining = Machinings[i]
|
|
local dWeight = Machining.dResultWeight
|
|
if not dWeight 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( 'GetStrategyResult : inconsistent weights')
|
|
end
|
|
local dWeightedCompletionPercentage = Machining.dCompletionPercentage * dWeight
|
|
local dWeightedQuality = FeatureLib.GetFeatureQuality( TOOLS[Machining.nToolIndex].MachiningQuality) * dWeight
|
|
if not Machining.bIsApplicable then
|
|
dWeightedCompletionPercentage = 0
|
|
end
|
|
dCompletionPercentageNumerator = dCompletionPercentageNumerator + dWeightedCompletionPercentage
|
|
dCompletionPercentageDenominator = dCompletionPercentageDenominator + dWeight
|
|
dQualityNumerator = dQualityNumerator + dWeightedQuality
|
|
dQualityDenominator = dQualityDenominator + dWeight
|
|
dTimeToMachine = dTimeToMachine + ( Machining.dLengthToMachine / TOOLS[Machining.nToolIndex].Feeds.dFeed)
|
|
end
|
|
|
|
Result.dCompletionPercentage = dCompletionPercentageNumerator / dCompletionPercentageDenominator
|
|
if Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
|
Result.sStatus = 'Completed'
|
|
elseif Result.dCompletionPercentage > 10 * GEO.EPS_SMALL then
|
|
Result.sStatus = 'Not-Completed'
|
|
else
|
|
Result.sStatus = 'Not-Applicable'
|
|
end
|
|
Result.dMRR = dFeatureVolume / dTimeToMachine
|
|
Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
|
|
-- TODO arrontondare all'intero più vicino?
|
|
Result.nQuality = dQualityNumerator / dQualityDenominator
|
|
|
|
return Result
|
|
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,
|
|
dHorizontalStepSpan = 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
|
|
|
|
-- 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 = GetStrategyResult( CalculatedMachinings, dFeatureVolume)
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
|
|
-- 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
|
|
|
|
end
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
return BLADEKEEPWASTE |