1322 lines
57 KiB
Lua
1322 lines
57 KiB
Lua
-- BLADETOWASTE.lua by Egalware s.r.l. 2025/01/08
|
|
-- Libreria di supporto a strategie con funzioni comune a strategie diverse.
|
|
|
|
-- Tabella per definizione modulo
|
|
local BLADETOWASTE = {}
|
|
|
|
-- Include
|
|
require( 'EgtBase')
|
|
|
|
-- Carico i dati globali
|
|
local BeamData = require( 'BeamDataNew')
|
|
local BeamLib = require( 'BeamLib')
|
|
local FaceData = require( 'FaceData')
|
|
local FeatureLib = require( 'FeatureLib')
|
|
local MachiningLib = require( 'MachiningLib')
|
|
local DiceCut = require( 'DiceCut')
|
|
-- strategie di base
|
|
local FaceByBlade = require('FACEBYBLADE')
|
|
|
|
local FeatureInfo = {}
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function CompareEdgesTopHead( EdgeA, EdgeB)
|
|
-- prima i lati vicini all'orizzontale (30deg)
|
|
if ( abs( EdgeA.vtN:getZ()) < 0.5 + 10 * GEO.EPS_SMALL) and ( abs( EdgeB.vtN:getZ()) > 0.5 + 10 * GEO.EPS_SMALL) then
|
|
return true
|
|
elseif ( abs( EdgeA.vtN:getZ()) > 0.5 + 10 * GEO.EPS_SMALL) and ( abs( EdgeB.vtN:getZ()) < 0.5 + 10 * GEO.EPS_SMALL) then
|
|
return false
|
|
else
|
|
-- se entrambi entro i 30deg si preferiscono i lati a minore elevazione
|
|
if ( abs( EdgeA.vtN:getZ()) < 0.5 + 10 * GEO.EPS_SMALL) and ( abs( EdgeB.vtN:getZ()) < 0.5 + 10 * GEO.EPS_SMALL) then
|
|
if EdgeA.dElevation < EdgeB.dElevation - 5 then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 5 then
|
|
return false
|
|
-- se stessa elevazione si preferiscono i lati più lunghi
|
|
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
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
-- se entrambi oltre i 30deg si preferiscono i lati più vicini all'orizzontale
|
|
elseif ( abs( EdgeA.vtN:getZ()) > 0.5 + 10 * GEO.EPS_SMALL) and ( abs( EdgeB.vtN:getZ()) > 0.5 + 10 * GEO.EPS_SMALL) then
|
|
if abs( EdgeA.vtN:getZ()) < abs( EdgeB.vtN:getZ()) - 100 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif abs( EdgeA.vtN:getZ()) > abs( EdgeB.vtN:getZ()) + 100 * GEO.EPS_SMALL then
|
|
return false
|
|
-- se stessa Z si preferiscono i lati a minore elevazione
|
|
else
|
|
if EdgeA.dElevation < EdgeB.dElevation - 5 then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 5 then
|
|
return false
|
|
-- se stessa elevazione si preferiscono i lati più lunghi
|
|
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
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function CompareEdgesBottomHead( EdgeA, EdgeB)
|
|
-- prima i lati a minore elevazione (se entro 5 mm si considerano uguali)
|
|
if EdgeA.dElevation < EdgeB.dElevation - 5 then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 5 then
|
|
return false
|
|
-- se stessa elevazione si preferiscono i lati più in alto (testa sotto)
|
|
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
|
|
|
|
|
|
local function CompareEdgesTopHeadGuillotine( EdgeA, EdgeB)
|
|
-- prima il lato sotto
|
|
if ( EdgeA.vtN:getZ()) > 0.98 + 10 * GEO.EPS_SMALL and ( EdgeB.vtN:getZ()) < 0.98 + 10 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif ( EdgeA.vtN:getZ()) < 0.98 + 10 * GEO.EPS_SMALL and ( EdgeB.vtN:getZ()) > 0.98 + 10 * GEO.EPS_SMALL then
|
|
return false
|
|
else
|
|
-- se entrambi lati sotto, si sceglie quello a minor elevazione
|
|
if EdgeA.vtN:getZ() > 0.98 + 10 * GEO.EPS_SMALL and EdgeB.vtN:getZ() > 0.98 + 10 * GEO.EPS_SMALL then
|
|
if EdgeA.dElevation < EdgeB.dElevation - 10 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 10 * GEO.EPS_SMALL then
|
|
return false
|
|
else
|
|
return false
|
|
end
|
|
-- se entrambi non lati sotto, si sceglie quello con normale non oltre l'orizzontale
|
|
elseif ( EdgeA.vtN:getZ()) > -0.1 + 10 * GEO.EPS_SMALL and ( EdgeB.vtN:getZ()) < -0.1 + 10 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif ( EdgeA.vtN:getZ()) < -0.1 + 10 * GEO.EPS_SMALL and ( EdgeB.vtN:getZ()) > -0.1 + 10 * GEO.EPS_SMALL then
|
|
return false
|
|
else
|
|
-- se entrambi entro l'orizzontale, si sceglie quello a minor elevazione
|
|
if EdgeA.vtN:getZ() > -0.1 + 10 * GEO.EPS_SMALL and EdgeB.vtN:getZ() > -0.1 + 10 * GEO.EPS_SMALL then
|
|
if EdgeA.dElevation < EdgeB.dElevation - 10 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 10 * GEO.EPS_SMALL then
|
|
return false
|
|
else
|
|
return false
|
|
end
|
|
-- se entrambi oltre l'orizzontale, si sceglie quello più verso l'orizzontale
|
|
else
|
|
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 100 * GEO.EPS_SMALL then
|
|
return true
|
|
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 100 * GEO.EPS_SMALL then
|
|
return false
|
|
-- se stessa Z si preferiscono i lati a minore elevazione
|
|
else
|
|
if EdgeA.dElevation < EdgeB.dElevation - 5 then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation + 5 then
|
|
return false
|
|
-- se stessa elevazione si preferiscono i lati più lunghi
|
|
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
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- si cerca il lato più verticale
|
|
local function CompareEdgesVertical( EdgeA, EdgeB)
|
|
|
|
if abs( EdgeA.vtN:getZ()) < abs( EdgeB.vtN:getZ()) - 10 * GEO.EPS_SMALL then return true end
|
|
if abs( EdgeA.vtN:getZ()) > abs( EdgeB.vtN:getZ()) + 10 * GEO.EPS_SMALL then return false end
|
|
|
|
return false
|
|
end
|
|
|
|
|
|
-- si cerca il lato orizzontale più in basso
|
|
local function CompareEdgesHorizontalBottom( EdgeA, EdgeB)
|
|
|
|
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then return true end
|
|
if EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then return false end
|
|
|
|
return false
|
|
end
|
|
|
|
|
|
local function CompareEdgesNoPreference( EdgeA, EdgeB)
|
|
-- prima i lati a minore elevazione
|
|
if EdgeA.dElevation < EdgeB.dElevation then
|
|
return true
|
|
elseif EdgeA.dElevation > EdgeB.dElevation then
|
|
return false
|
|
-- se stessa elevazione si preferiscono i lati più in basso (testa sopra)
|
|
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
|
|
|
|
|
|
local function GetEdgeToMachine( Edges, sBladeType, OptionalParameters)
|
|
local EdgeToMachine = {}
|
|
|
|
-- parametri opzionali
|
|
OptionalParameters = OptionalParameters or {}
|
|
local bAllowFastCuts = OptionalParameters.bAllowFastCuts or false
|
|
local nIndex = OptionalParameters.nIndex or 1
|
|
|
|
local EdgesSorted = {}
|
|
for i = 1, #Edges do
|
|
table.insert( EdgesSorted, Edges[i])
|
|
end
|
|
|
|
if ( sBladeType == 'Top') then
|
|
if bAllowFastCuts then
|
|
table.sort( EdgesSorted, CompareEdgesNoPreference)
|
|
else
|
|
table.sort( EdgesSorted, CompareEdgesTopHead)
|
|
end
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
elseif sBladeType == 'Bottom' then
|
|
table.sort( EdgesSorted, CompareEdgesBottomHead)
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
elseif sBladeType == 'TopGuillotine' then
|
|
table.sort( EdgesSorted, CompareEdgesTopHeadGuillotine)
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
elseif sBladeType == 'HorizontalBottom' then
|
|
table.sort( EdgesSorted, CompareEdgesHorizontalBottom)
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
elseif sBladeType == 'Vertical' then
|
|
table.sort( EdgesSorted, CompareEdgesVertical)
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
-- TODO non testato; non si dovrebbe mai entrare in questo caso
|
|
else
|
|
table.sort( EdgesSorted, CompareEdgesNoPreference)
|
|
EdgeToMachine = EdgesSorted[nIndex]
|
|
end
|
|
|
|
return EdgeToMachine
|
|
end
|
|
|
|
|
|
local function GetBestBlade( Proc, Part, Face, OptionalParameters)
|
|
local nChosenToolIndex
|
|
local sChosenBladeType
|
|
local nToolIndexTop
|
|
local nToolIndexBottom
|
|
|
|
-- parametri opzionali e default
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local dMinNzTopBladeIfEqual = OptionalParameters.dMinNzTopBlade or sin(-5)
|
|
local dMaxNyTopBlade = OptionalParameters.dMaxNyTopBlade or sin(1)
|
|
local dShortPartLength = OptionalParameters.dShortPartLength or BeamData.LEN_SHORT_PART
|
|
local EdgeToMachineTop = OptionalParameters.EdgeToMachineTop
|
|
local EdgeToMachineBottom = OptionalParameters.EdgeToMachineBottom
|
|
local bIsDicing = OptionalParameters.bIsDicing
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength
|
|
-- TODO qui sarebbe meglio avere dExtra come OptionalParameter???
|
|
local dElevationTop = EdgeToMachineTop and EdgeToMachineTop.dElevation + BeamData.CUT_EXTRA or nil
|
|
local dElevationBottom = EdgeToMachineBottom and EdgeToMachineBottom.dElevation + BeamData.CUT_EXTRA or nil
|
|
|
|
-- se ho già l'utensile, devo solo discriminare se è lama sopra o sotto e verificare se ci arriva
|
|
if OptionalParameters.nToolIndex then
|
|
if TOOLS[OptionalParameters.nToolIndex].SetupInfo.HeadType.bTop then
|
|
if ( not dElevationTop) or ( TOOLS[OptionalParameters.nToolIndex].dMaxMaterial > dElevationTop - 10 * GEO.EPS_SMALL) then
|
|
nToolIndexTop = OptionalParameters.nToolIndex
|
|
end
|
|
elseif TOOLS[OptionalParameters.nToolIndex].SetupInfo.HeadType.bBottom then
|
|
if ( not dElevationBottom) or ( TOOLS[OptionalParameters.nToolIndex].dMaxMaterial > dElevationBottom - 10 * GEO.EPS_SMALL) then
|
|
nToolIndexBottom = OptionalParameters.nToolIndex
|
|
end
|
|
end
|
|
-- non ho l'utensile, devo cercarlo e scegliere il migliore tra testa sopra e sotto
|
|
else
|
|
local ToolInfo
|
|
-- ricerca lama testa sopra
|
|
ToolInfo = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = true,
|
|
bAllowBottomHead = false,
|
|
dElevation = dElevationTop,
|
|
FaceToMachine = Face,
|
|
EdgeToMachine = EdgeToMachineTop,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
if ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
nToolIndexTop = ToolInfo.nToolIndex
|
|
end
|
|
-- ricerca lama testa sotto
|
|
ToolInfo = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = false,
|
|
bAllowBottomHead = true,
|
|
dElevation = dElevationBottom,
|
|
FaceToMachine = Face,
|
|
EdgeToMachine = EdgeToMachineBottom,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
if ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
nToolIndexBottom = ToolInfo.nToolIndex
|
|
end
|
|
end
|
|
|
|
-- lama sopra e sotto
|
|
-- TODO rivedere con Engagement, MinNzTopBlade e MaxNyTopBlade sono obsoleti!!!!!!!!!!!!
|
|
if nToolIndexTop and nToolIndexBottom then
|
|
-- angolo minimo che determina la preferenza tra lama sopra e sotto
|
|
local dMinNzTopBlade
|
|
-- entrambe le lame senza aggregato o entrambe con aggregato
|
|
if TOOLS[nToolIndexTop].SetupInfo.bIsCSymmetrical == TOOLS[nToolIndexBottom].SetupInfo.bIsCSymmetrical then
|
|
dMinNzTopBlade = dMinNzTopBladeIfEqual
|
|
-- lama sopra con aggregato - preferenza testa sopra
|
|
elseif not TOOLS[nToolIndexTop].SetupInfo.bIsCSymmetrical then
|
|
dMinNzTopBlade = OptionalParameters.dMinNzTopBlade or TOOLS[nToolIndexTop].SetupInfo.GetMinNz( Face.vtN, TOOLS[nToolIndexTop]) / 2
|
|
-- lama sotto con aggregato - preferenza testa sotto
|
|
elseif not TOOLS[nToolIndexBottom].SetupInfo.bIsCSymmetrical then
|
|
dMinNzTopBlade = OptionalParameters.dMinNzTopBlade or TOOLS[nToolIndexBottom].SetupInfo.GetMaxNz( Face.vtN, TOOLS[nToolIndexBottom]) / 2
|
|
else
|
|
error( 'GetBestBlade : unknown blade type')
|
|
end
|
|
|
|
-- se la Z della faccia è sotto all'angolo minimo e inclinata in Y oppure il pezzo è corto, si preferisce la lama sotto
|
|
if Face.vtN:getZ() < dMinNzTopBlade - GEO.EPS_SMALL
|
|
and ( abs( Face.vtN:getY()) > dMaxNyTopBlade or Part.b3Raw:getDimX() < dShortPartLength - 10 * GEO.EPS_SMALL) then
|
|
nChosenToolIndex = nToolIndexBottom
|
|
else
|
|
nChosenToolIndex = nToolIndexTop
|
|
end
|
|
-- solo lama sopra
|
|
elseif nToolIndexTop then
|
|
nChosenToolIndex = nToolIndexTop
|
|
-- solo lama sotto
|
|
elseif nToolIndexBottom then
|
|
nChosenToolIndex = nToolIndexBottom
|
|
end
|
|
|
|
-- assegnazione tipo lama
|
|
if nChosenToolIndex == nToolIndexBottom then
|
|
sChosenBladeType = 'Bottom'
|
|
elseif nChosenToolIndex == nToolIndexTop then
|
|
sChosenBladeType = 'Top'
|
|
end
|
|
|
|
-- se non trovata alcuna lama ritorna nil
|
|
return nChosenToolIndex, sChosenBladeType
|
|
end
|
|
|
|
|
|
local function SetDiceFaceInfo( Proc, idDiceFace)
|
|
EgtSetName( idDiceFace, 'Face' .. tostring( Proc.idFeature or 'Add') .. '_Dice')
|
|
end
|
|
|
|
|
|
local function GetSingleCutStrategy( Proc, Part, OptionalParameters)
|
|
|
|
-- parametri opzionali
|
|
OptionalParameters = OptionalParameters or {}
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
local bReduceBladePath = OptionalParameters.bReduceBladePath or false
|
|
local bAllowFastCuts = OptionalParameters.bAllowFastCuts or false
|
|
local FaceToMachine = Proc.Faces[OptionalParameters.nFaceToMachineIndex or 1]
|
|
local bIsDicing = OptionalParameters.bIsDicing or false
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
|
-- lati da lavorare in base al tipo di lama
|
|
-- se non arrivano dall'esterno si cercano i migliori disponibili, dapprima ignorando il flag bAllowFastCuts
|
|
local EdgeToMachineList = OptionalParameters.EdgeToMachineList
|
|
or {
|
|
Top = GetEdgeToMachine( FaceToMachine.Edges, 'Top'),
|
|
Bottom = GetEdgeToMachine( FaceToMachine.Edges, 'Bottom'),
|
|
TopGuillotine = GetEdgeToMachine( FaceToMachine.Edges, 'TopGuillotine')
|
|
}
|
|
|
|
local sChosenBladeType
|
|
local bIsFastCut = false
|
|
|
|
local OptionalParametersGetBestBlade = {
|
|
EdgeToMachineTop = EdgeToMachineList.Top,
|
|
EdgeToMachineBottom = EdgeToMachineList.Bottom,
|
|
nToolIndex = nToolIndex,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
-- se nToolIndex è presente, GetBestBlade sceglierà solo il lato, altrimenti sceglierà lama e lato
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, FaceToMachine, OptionalParametersGetBestBlade)
|
|
|
|
-- se non è stato trovato un utensile e utensile e lati non arrivavano dall'esterno, si prova a cambiare lato (si prende il secondo della lista), sempre ignorando bAllowFastCuts
|
|
if not nToolIndex and not OptionalParameters.nToolIndex and not OptionalParameters.EdgeToMachineList then
|
|
EdgeToMachineList.Top = GetEdgeToMachine( FaceToMachine.Edges, 'Top', { nIndex = 2})
|
|
EdgeToMachineList.Bottom = GetEdgeToMachine( FaceToMachine.Edges, 'Bottom', { nIndex = 2})
|
|
OptionalParametersGetBestBlade.EdgeToMachineTop = EdgeToMachineList.Top
|
|
OptionalParametersGetBestBlade.EdgeToMachineBottom = EdgeToMachineList.Bottom
|
|
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, FaceToMachine, OptionalParametersGetBestBlade)
|
|
end
|
|
|
|
-- se ancora non è stato trovato un utensile e utensile e lati non arrivavano dall'esterno, se permesso, si prova a scegliere il primo lato a minor elevazione (bAllowFastCuts)
|
|
if bAllowFastCuts and not nToolIndex and not OptionalParameters.nToolIndex and not OptionalParameters.EdgeToMachineList then
|
|
EdgeToMachineList.Top = GetEdgeToMachine( FaceToMachine.Edges, 'Top', { bAllowFastCuts = true})
|
|
EdgeToMachineList.Bottom = GetEdgeToMachine( FaceToMachine.Edges, 'Bottom', { bAllowFastCuts = true})
|
|
OptionalParametersGetBestBlade.EdgeToMachineTop = EdgeToMachineList.Top
|
|
OptionalParametersGetBestBlade.EdgeToMachineBottom = EdgeToMachineList.Bottom
|
|
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, FaceToMachine, OptionalParametersGetBestBlade)
|
|
bIsFastCut = true
|
|
end
|
|
|
|
|
|
-- se ancora non è stato trovato un utensile e utensile e lati non arrivavano dall'esterno, se permesso, si prova a scegliere il secondo lato a minor elevazione (bAllowFastCuts)
|
|
if bAllowFastCuts and not nToolIndex and not OptionalParameters.nToolIndex and not OptionalParameters.EdgeToMachineList then
|
|
EdgeToMachineList.Top = GetEdgeToMachine( FaceToMachine.Edges, 'Top', { bAllowFastCuts = true, nIndex = 2})
|
|
EdgeToMachineList.Bottom = GetEdgeToMachine( FaceToMachine.Edges, 'Bottom', { bAllowFastCuts = true, nIndex = 2})
|
|
OptionalParametersGetBestBlade.EdgeToMachineTop = EdgeToMachineList.Top
|
|
OptionalParametersGetBestBlade.EdgeToMachineBottom = EdgeToMachineList.Bottom
|
|
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, FaceToMachine, OptionalParametersGetBestBlade)
|
|
bIsFastCut = true
|
|
end
|
|
|
|
-- se possibile, upgrade del taglio tipo 'Top' a taglio a ghigliottina. Si tenta anche se il taglio singolo non è riuscito.
|
|
if ( sChosenBladeType == 'Top' or not nToolIndex) and bReduceBladePath and FaceData.IsFaceRectangle( FaceToMachine) then
|
|
local nToolIndexGuillotine
|
|
|
|
-- ricerca lama migliore testa sopra
|
|
local ToolInfo = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = true,
|
|
bAllowBottomHead = false,
|
|
dElevation = EdgeToMachineList.TopGuillotine.dElevation,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = EdgeToMachineList.TopGuillotine,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
nToolIndexGuillotine = ToolInfo.nToolIndex
|
|
|
|
-- test fattibilità taglio a ghigliottina
|
|
if nToolIndexGuillotine then
|
|
local dRadialOffset = FaceByBlade.GetRadialOffsetForGuillotine( nToolIndexGuillotine, EdgeToMachineList.TopGuillotine.dLength)
|
|
|
|
if ( TOOLS[nToolIndexGuillotine].dMaxMaterial - EdgeToMachineList.TopGuillotine.dElevation - BeamData.CUT_SIC) > dRadialOffset + 10 * GEO.EPS_SMALL then
|
|
nToolIndex = nToolIndexGuillotine
|
|
sChosenBladeType = 'TopGuillotine'
|
|
end
|
|
end
|
|
end
|
|
|
|
-- se taglio su lati brutti si cambia il tipo
|
|
local sChosenBladeTypeOriginal = sChosenBladeType
|
|
if bIsFastCut then
|
|
sChosenBladeType = sChosenBladeType .. 'Fast'
|
|
end
|
|
|
|
return nToolIndex, EdgeToMachineList[sChosenBladeTypeOriginal], sChosenBladeType
|
|
end
|
|
|
|
|
|
local function GetDualSideCutStrategy( Proc, Part, OptionalParameters)
|
|
|
|
-- parametri opzionali
|
|
OptionalParameters = OptionalParameters or {}
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
local FaceToMachine = Proc.Faces[OptionalParameters.nFaceToMachineIndex or 1]
|
|
local bIsDicing = OptionalParameters.bIsDicing or false
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
|
|
|
local CuttingParametersList
|
|
local EdgeToMachine
|
|
|
|
-- se possibile, si prova il doppio taglio orizzontale con mix testa sopra/sotto (questa modalità si esclude se l'utensile arriva dall'esterno)
|
|
-- TODO valutare se farlo anche doppio orizzontale solo con testa sopra, se la lama ha la corsa per andare sotto!
|
|
EdgeToMachine = GetEdgeToMachine( FaceToMachine.Edges, 'HorizontalBottom')
|
|
if not nToolIndex and AreSameOrOppositeVectorApprox( EdgeToMachine.vtN, Z_AX()) then
|
|
|
|
-- inizialmente si prova a lavorare in mezzeria
|
|
local dDepthToMachineTop = EdgeToMachine.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
|
local dDepthToMachineBottom = dDepthToMachineTop
|
|
|
|
-- ricerca lama testa sopra
|
|
local ToolInfoTopBlade = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = true,
|
|
bAllowBottomHead = false,
|
|
dElevation = dDepthToMachineTop,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = EdgeToMachine,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
-- ricerca lama testa sotto
|
|
-- lavorando dalla direzione opposta si verifica come se si lavorasse il lato opposto
|
|
local ToolInfoBottomBlade = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = false,
|
|
bAllowBottomHead = true,
|
|
dElevation = dDepthToMachineBottom,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( FaceToMachine.Edges, -EdgeToMachine.vtN),
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
|
|
local bIsTopLimited = ToolInfoTopBlade.dResidualDepth > 10 * GEO.EPS_SMALL
|
|
local bIsBottomLimited = ToolInfoBottomBlade.dResidualDepth > 10 * GEO.EPS_SMALL
|
|
|
|
-- testa sopra limitante
|
|
if bIsTopLimited and not bIsBottomLimited then
|
|
-- ricalcolo profondità di lavoro
|
|
dDepthToMachineTop = TOOLS[ToolInfoTopBlade.nToolIndex].dMaxMaterial
|
|
dDepthToMachineBottom = EdgeToMachine.dElevation - dDepthToMachineTop + BeamData.CUT_EXTRA_MIN
|
|
-- ricerca lama sotto con la nuova depth
|
|
-- lavorando dalla direzione opposta si verifica come se si lavorasse il lato opposto
|
|
ToolInfoBottomBlade = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = false,
|
|
bAllowBottomHead = true,
|
|
dElevation = dDepthToMachineBottom,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( FaceToMachine.Edges, -EdgeToMachine.vtN),
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
bIsBottomLimited = ToolInfoBottomBlade.dResidualDepth > 10 * GEO.EPS_SMALL
|
|
|
|
-- testa sotto limitante
|
|
elseif bIsBottomLimited and not bIsTopLimited then
|
|
-- ricalcolo profondità di lavoro
|
|
dDepthToMachineBottom = TOOLS[ToolInfoBottomBlade.nToolIndex].dMaxMaterial
|
|
dDepthToMachineTop = EdgeToMachine.dElevation - dDepthToMachineBottom + BeamData.CUT_EXTRA_MIN
|
|
-- ricerca lama sopra con la nuova depth
|
|
ToolInfoTopBlade = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = true,
|
|
bAllowBottomHead = false,
|
|
dElevation = dDepthToMachineTop,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = EdgeToMachine,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
bIsTopLimited = ToolInfoTopBlade.dResidualDepth > 10 * GEO.EPS_SMALL
|
|
end
|
|
|
|
-- se almeno una delle due lame ci arriva si assegnano utensili e profondità da ritornare
|
|
if not ( bIsTopLimited and bIsBottomLimited) and ToolInfoTopBlade.nToolIndex and ToolInfoBottomBlade.nToolIndex then
|
|
CuttingParametersList = {
|
|
{
|
|
nToolIndex = ToolInfoBottomBlade.nToolIndex,
|
|
dDepthToMachine = dDepthToMachineBottom
|
|
},
|
|
{
|
|
nToolIndex = ToolInfoTopBlade.nToolIndex,
|
|
dDepthToMachine = dDepthToMachineTop
|
|
}
|
|
}
|
|
|
|
return CuttingParametersList, EdgeToMachine
|
|
end
|
|
end
|
|
|
|
-- arrivati qui si prova il taglio doppio verticale (taglio doppio orizzontale non si può fare oppure non ci arriva)
|
|
EdgeToMachine = GetEdgeToMachine( FaceToMachine.Edges, 'Vertical')
|
|
local dDepthToMachine = EdgeToMachine.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
|
|
|
-- ricerca lama testa sopra
|
|
local ToolInfo = MachiningLib.FindBlade( Proc, {
|
|
bAllowTopHead = true,
|
|
bAllowBottomHead = false,
|
|
dElevation = dDepthToMachine,
|
|
FaceToMachine = FaceToMachine,
|
|
EdgeToMachine = EdgeToMachine,
|
|
Part = Part,
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
})
|
|
|
|
-- se lama ci arriva si assegnano utensili e profondità da ritornare
|
|
if ToolInfo.nToolIndex and ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
|
|
-- lavorando dalla direzione opposta si verifica come se si lavorasse il lato opposto
|
|
local EdgeToMachineOpposite = BeamLib.FindEdgeBestOrientedAsDirection( FaceToMachine.Edges, -EdgeToMachine.vtN)
|
|
local BladeEngagementParameters = {
|
|
Face = FaceToMachine,
|
|
Edge = EdgeToMachineOpposite,
|
|
Part = Part,
|
|
Tool = TOOLS[ToolInfo.nToolIndex],
|
|
dDepthToMachine = dDepthToMachine
|
|
}
|
|
local BladeEngagementOptionalParameters = {
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
TIMER:startElapsed( 'GetBladeEngagement')
|
|
local bIsApplicableOpposite = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
|
TIMER:stopElapsed( 'GetBladeEngagement')
|
|
if not bIsApplicableOpposite then
|
|
return CuttingParametersList, EdgeToMachine
|
|
end
|
|
|
|
-- si deve decidere se fare per primo il taglio opposto oppure no
|
|
local bIsOppositeCutFirst = false
|
|
local vtTemp = EdgeToMachine.vtN ^ FaceToMachine.vtN
|
|
local bIsEdgeLeftSide = vtTemp:getZ() < 10 * GEO.EPS_SMALL
|
|
if ( TOOLS[ToolInfo.nToolIndex].bIsCCW and bIsEdgeLeftSide) or ( not TOOLS[ToolInfo.nToolIndex].bIsCCW and not bIsEdgeLeftSide) then
|
|
bIsOppositeCutFirst = true
|
|
end
|
|
|
|
CuttingParametersList = {
|
|
{
|
|
nToolIndex = ToolInfo.nToolIndex,
|
|
dDepthToMachine = dDepthToMachine
|
|
},
|
|
{
|
|
nToolIndex = ToolInfo.nToolIndex,
|
|
dDepthToMachine = dDepthToMachine
|
|
},
|
|
bIsOppositeCutFirst = bIsOppositeCutFirst
|
|
}
|
|
else
|
|
EdgeToMachine = nil
|
|
end
|
|
|
|
return CuttingParametersList, EdgeToMachine
|
|
end
|
|
|
|
|
|
local function CutWholeWaste( Proc, Part, OptionalParameters)
|
|
local Machinings = {}
|
|
local Cutting = nil
|
|
local CuttingDouble = nil
|
|
local Result = {}
|
|
local EdgeToMachine
|
|
local sChosenBladeType = ''
|
|
local dCompletionPercentage = 0
|
|
|
|
-- controlli preventivi
|
|
local bIsFeatureLong = FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
|
if bIsFeatureLong then
|
|
Result = FeatureLib.GetStrategyResultNotApplicable('Feature too long')
|
|
return Machinings, Result
|
|
end
|
|
|
|
-- parametri opzionali e default
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000
|
|
local bReduceBladePath = OptionalParameters.bReduceBladePath or false
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
|
|
|
-- si cerca di tagliare tutto da un lato
|
|
nToolIndex, EdgeToMachine, sChosenBladeType = GetSingleCutStrategy( Proc, Part, OptionalParameters)
|
|
|
|
-- se taglio da un lato ce la fa, si crea la lavorazione
|
|
if nToolIndex then
|
|
local OptionalParametersFaceByBlade = {
|
|
dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA,
|
|
nToolIndex = nToolIndex,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
if sChosenBladeType ~= 'TopGuillotine' then
|
|
OptionalParametersFaceByBlade.OppositeToolDirectionMode = 'Optimized'
|
|
end
|
|
|
|
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[1], EdgeToMachine, OptionalParametersFaceByBlade)
|
|
|
|
-- se taglio da un lato non ce la fa, si prova da due lati
|
|
elseif FaceData.IsFaceRectangle( Proc.Faces[1]) then
|
|
|
|
local CuttingParametersList
|
|
CuttingParametersList, EdgeToMachine = GetDualSideCutStrategy( Proc, Part, OptionalParameters)
|
|
|
|
if CuttingParametersList then
|
|
local OptionalParametersFaceByBlade = {
|
|
dDepthToMachine = CuttingParametersList[1].dDepthToMachine,
|
|
nToolIndex = CuttingParametersList[1].nToolIndex,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
OppositeToolDirectionMode = 'Enabled',
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
local OptionalParametersFaceByBladeDouble = {
|
|
dDepthToMachine = CuttingParametersList[2].dDepthToMachine,
|
|
nToolIndex = CuttingParametersList[2].nToolIndex,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
-- se necessario, si inverte l'ordine delle lavorazioni per avere il secondo taglio verso l'alto
|
|
if not CuttingParametersList.bIsOppositeCutFirst then
|
|
OptionalParametersFaceByBlade, OptionalParametersFaceByBladeDouble = OptionalParametersFaceByBladeDouble, OptionalParametersFaceByBlade
|
|
end
|
|
|
|
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[1], EdgeToMachine, OptionalParametersFaceByBlade)
|
|
CuttingDouble = FaceByBlade.Make( Proc, Part, Proc.Faces[1], EdgeToMachine, OptionalParametersFaceByBladeDouble)
|
|
end
|
|
end
|
|
|
|
-- se nessun taglio è riuscito si riprova il taglio singolo permettendo i lati a minor elevazione, abbassando la qualità
|
|
if not ( Cutting and Cutting.bIsApplicable) or ( CuttingDouble and not CuttingDouble.bIsApplicable) then
|
|
|
|
OptionalParameters.bAllowFastCuts = true
|
|
nToolIndex, EdgeToMachine, sChosenBladeType = GetSingleCutStrategy( Proc, Part, OptionalParameters)
|
|
|
|
if nToolIndex then
|
|
local OptionalParametersFaceByBlade = {
|
|
dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA,
|
|
nToolIndex = nToolIndex,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
if sChosenBladeType ~= 'TopGuillotine' then
|
|
OptionalParametersFaceByBlade.OppositeToolDirectionMode = 'Optimized'
|
|
end
|
|
|
|
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[1], EdgeToMachine, OptionalParametersFaceByBlade)
|
|
end
|
|
end
|
|
|
|
if Cutting and Cutting.bIsApplicable then
|
|
table.insert( Machinings, Cutting)
|
|
dCompletionPercentage = Cutting.dCompletionPercentage or dCompletionPercentage
|
|
|
|
if CuttingDouble and CuttingDouble.bIsApplicable then
|
|
table.insert( Machinings, CuttingDouble)
|
|
dCompletionPercentage = 0.5 * ( Cutting.dCompletionPercentage or dCompletionPercentage) + 0.5 * ( CuttingDouble.dCompletionPercentage or dCompletionPercentage)
|
|
end
|
|
end
|
|
|
|
-- risultati del calcolo
|
|
-- TODO funzione?
|
|
if ( Cutting and Cutting.bIsApplicable) and ( not CuttingDouble or CuttingDouble.bIsApplicable) then
|
|
if dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
|
Result.sStatus = 'Completed'
|
|
else
|
|
Result.sStatus = 'Not-Completed'
|
|
end
|
|
Result.dCompletionPercentage = dCompletionPercentage
|
|
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
|
Result.dQuality = FeatureLib.GetStrategyQuality( Machinings)
|
|
-- per tagli con lati brutti o ghigliottina si abbassa la qualità
|
|
if ( sChosenBladeType ~= 'Top') and ( sChosenBladeType ~= 'Bottom') then
|
|
Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
|
end
|
|
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
|
Result.dMRR = ( FeatureInfo.dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
|
|
local function CalculateDiceMachinings( vCuts, Parameters)
|
|
local Machinings = {}
|
|
local bMoveAfterSplit = false
|
|
|
|
local Proc = Parameters.Proc
|
|
local Part = Parameters.Part
|
|
local MainFace = Parameters.MainFace
|
|
local Tool = Parameters.Tool
|
|
local sChosenBladeType = Parameters.sChosenBladeType
|
|
local dExtendAfterTail = Parameters.dExtendAfterTail
|
|
local bReduceBladePath = Parameters.bReduceBladePath
|
|
local sRestLengthSideForPreSimulation = Parameters.sRestLengthSideForPreSimulation
|
|
local bCannotSplitRestLength = Parameters.bCannotSplitRestLength
|
|
local bReduceDiceDepth = Parameters.bReduceDiceDepth
|
|
|
|
-- eventuale inversione tagli ortogonali e aggiunta informazioni alla geometria
|
|
local bAreOrthogonalCutsInverted = false
|
|
for i = 1, #vCuts do
|
|
for j = 1, #vCuts[i] do
|
|
SetDiceFaceInfo( Proc, vCuts[i][j])
|
|
-- TODO vedere se questa parte serve ancora; in teoria no perchè il taglio è girato automaticamente nella FaceByBlade
|
|
-- if ( i % 2) == 1 then
|
|
-- local vtO = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
|
-- if MachiningLib.IsFaceZOutOfRange( vtO, Tool) then
|
|
-- EgtInvertSurf( vCuts[i][j])
|
|
-- local vtCurrentFaceNormal = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
|
-- EgtMove( vCuts[i][j], -vtCurrentFaceNormal * Tool.dThickness, GDB_RT.GLOB)
|
|
-- bAreOrthogonalCutsInverted = true
|
|
-- end
|
|
-- end
|
|
end
|
|
end
|
|
-- calcolo lavorazioni
|
|
for i = 1, #vCuts do
|
|
-- determinazione direzione di taglio
|
|
local vtToolDirection
|
|
local bNoPerpCuts = false
|
|
if i % 2 == 1 then
|
|
vtToolDirection = Vector3d( MainFace.vtN)
|
|
else
|
|
local vtO
|
|
if #vCuts[i-1] > 0 then
|
|
vtO = EgtSurfTmFacetNormVersor( vCuts[i-1][1], 0, GDB_ID.ROOT)
|
|
elseif vCuts[i+1] and #vCuts[i+1] > 0 then
|
|
-- lunghezza faccia nell'eventuale direzione ortogonale
|
|
local asseX = EgtSurfTmFacetNormVersor( vCuts[i+1][1], 0, GDB_ID.ROOT)
|
|
local asseY = asseX ^ MainFace.vtN
|
|
local Frame = Frame3d( MainFace.ptCenter, MainFace.ptCenter + asseX, MainFace.ptCenter + asseY)
|
|
local b3Fac = EgtGetBBoxRef( vCuts[i][1], GDB_BB.STANDARD, Frame)
|
|
-- se lunghezza inferiore al limite, accetto la direzione
|
|
if b3Fac:getDimX() < Tool.dMaxDepth - BeamData.CUT_EXTRA then
|
|
vtO = asseX
|
|
else
|
|
bNoPerpCuts = true
|
|
end
|
|
else
|
|
bNoPerpCuts = true
|
|
end
|
|
if vtO then
|
|
vtToolDirection = Vector3d( vtO) * EgtIf( bAreOrthogonalCutsInverted, -1, 1)
|
|
else
|
|
-- scelta lato da lavorare per stabilire la vtToolDirection
|
|
local EdgeToMachine = {}
|
|
local _, Edges = FaceData.GetEdgesInfo( vCuts[i][1], 0)
|
|
EdgeToMachine = GetEdgeToMachine( Edges, sChosenBladeType)
|
|
vtToolDirection = EdgeToMachine.vtN
|
|
end
|
|
end
|
|
-- calcolo lavorazione della singola faccia
|
|
-- per tagli paralleli e faccia aperta si prova a tagliare come se fosse una faccia singola, accorpando i tagli
|
|
-- TODO bIsDicing è da mettere a true?
|
|
local bCanMergeParallelCuts = ( ( i % 2) == 0) and ( Proc.nFct == 1)
|
|
local bIsDicingOk = true
|
|
if bCanMergeParallelCuts then
|
|
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
|
local nSurfToCut = EgtSurfTmBySewing( nAddGrpId, vCuts[i], false)
|
|
local ProcTrimesh = FeatureLib.GetProcFromTrimesh( nSurfToCut, Part)
|
|
|
|
local OptionalParametersCutWholeWaste = {
|
|
nToolIndex = Tool.nIndex,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
bIsDicing = false,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
local CutWholeWasteMachinings, CutWholeWasteResult = CutWholeWaste( ProcTrimesh, Part, OptionalParametersCutWholeWaste)
|
|
|
|
if CutWholeWasteResult.sStatus == 'Completed' then
|
|
for k = 1, #CutWholeWasteMachinings do
|
|
table.insert( Machinings, CutWholeWasteMachinings[k])
|
|
if CutWholeWasteMachinings[k].sStage == 'AfterTail' then
|
|
bMoveAfterSplit = true
|
|
end
|
|
end
|
|
else
|
|
EgtErase( nSurfToCut)
|
|
bIsDicingOk = false
|
|
end
|
|
end
|
|
-- caso standard (tagli perpendicolari o paralleli non accorpabili)
|
|
if ( not bCanMergeParallelCuts) or ( not bIsDicingOk) then
|
|
for j = 1, #vCuts[i] do
|
|
-- se abilitato, la lama sta sollevata per non rovinare le facce
|
|
local dExtraCut
|
|
if bReduceDiceDepth == false then
|
|
dExtraCut = 0
|
|
else
|
|
dExtraCut = -0.1
|
|
end
|
|
-- se tagli paralleli
|
|
if ( i % 2) == 0 then
|
|
-- se non ci sono tagli ortogonali devo affondare
|
|
if bNoPerpCuts then
|
|
dExtraCut = BeamData.CUT_EXTRA
|
|
-- se è faccia singola si affonda
|
|
elseif Proc.nFct < 2 then
|
|
-- se tagli ortogonali invertiti, devo approfondire dello spessore lama
|
|
if bAreOrthogonalCutsInverted then
|
|
dExtraCut = Tool.dThickness
|
|
-- se ultimo taglio, devo affondare
|
|
elseif j == #vCuts[i] then
|
|
dExtraCut = BeamData.CUT_EXTRA
|
|
end
|
|
end
|
|
end
|
|
local Cutting = {}
|
|
local ProcTrimesh = FeatureLib.GetProcFromTrimesh( vCuts[i][j], Part)
|
|
local FaceToMachine = ProcTrimesh.Faces[1]
|
|
local EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( FaceToMachine.Edges, vtToolDirection)
|
|
local dDepthToMachine = EdgeToMachine.dElevation + dExtraCut
|
|
local OptionalParametersFaceByBlade = {
|
|
dDepthToMachine = dDepthToMachine,
|
|
nToolIndex = Tool.nIndex,
|
|
dRadialStepSpan = 0,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bIsDicing = true,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength,
|
|
bDisableRealElevationCheck = ( i % 2) > 0 -- se taglio perpendicolare non si deve mai considerare il materiale precedente
|
|
}
|
|
Cutting = FaceByBlade.Make( ProcTrimesh, Part, FaceToMachine, EdgeToMachine, OptionalParametersFaceByBlade)
|
|
Cutting.ptCenter = Point3d( ProcTrimesh.Faces[1].ptCenter:getX(), 0, 0)
|
|
|
|
if Cutting.bIsApplicable then
|
|
table.insert( Machinings, Cutting)
|
|
-- se un cubetto fallisce è inutile proseguire
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable( 'Dicing failed')
|
|
return false, Machinings
|
|
end
|
|
if Cutting.sStage == 'AfterTail' then
|
|
bMoveAfterSplit = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return true, Machinings, bMoveAfterSplit
|
|
end
|
|
|
|
|
|
local function CutWithDicing( Proc, Part, OptionalParameters)
|
|
local Machinings = {}
|
|
local Result = {}
|
|
|
|
-- parametri opzionali e default
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000
|
|
local b3BoxDicing = OptionalParameters.b3BoxDicing
|
|
local bSaveAddedGeometries = ( OptionalParameters.bSaveAddedGeometries ~= false)
|
|
local bReduceBladePath = OptionalParameters.bReduceBladePath or false
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
|
|
|
-- scelta faccia da lavorare
|
|
-- se due facce, la faccia principale Face1 è la più grande
|
|
local Face1 = Proc.Faces[1]
|
|
local Face2 = {}
|
|
if Proc.nFct == 2 then
|
|
Face2 = Proc.Faces[2]
|
|
if Face2.dArea > Face1.dArea then
|
|
Face1, Face2 = Face2, Face1
|
|
end
|
|
end
|
|
|
|
-- angolo tra le facce, se più di una
|
|
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2] or 0
|
|
|
|
-- scelta lama da sopra o da sotto
|
|
local sChosenBladeType = ''
|
|
if not nToolIndex then
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, Face1)
|
|
end
|
|
|
|
-- se non trovata lama la lavorazione non è fattibile
|
|
if not nToolIndex then
|
|
Result = FeatureLib.GetStrategyResultNotApplicable( 'Blade not found')
|
|
|
|
return {}, Result
|
|
end
|
|
|
|
-- calcolo dimensione cubetto
|
|
local dDiceDimension = min( TOOLS[nToolIndex].dMaxMaterial, Part.GeneralParameters.GEN_dMaxDimDice)
|
|
dDiceDimension = dDiceDimension - BeamData.CUT_EXTRA
|
|
|
|
-- calcolo cubetti
|
|
local OptionalParametersDiceCut = {}
|
|
OptionalParametersDiceCut.dOffsetParallel = dDiceDimension
|
|
OptionalParametersDiceCut.dOffsetOrthogonal = dDiceDimension
|
|
OptionalParametersDiceCut.b3BoxDicing = b3BoxDicing
|
|
OptionalParametersDiceCut.bSaveAddedGeometries = bSaveAddedGeometries
|
|
local vCuts = DiceCut.GetDice( Part, Face1, Face2, OptionalParametersDiceCut)
|
|
|
|
-- se nessun cubetto trovato, si richiama ricorsivamente la BladeToWaste forzando di non fare i cubetti
|
|
if #vCuts == 0 then
|
|
OptionalParameters.bDisableDicing = true
|
|
Machinings, Result = BLADETOWASTE.Make( Proc, Part, OptionalParameters)
|
|
return Machinings, Result
|
|
end
|
|
|
|
-- lavorazione cubetti
|
|
local bIsDicingOk
|
|
local bMoveAfterSplit
|
|
local Parameters = {
|
|
Proc = Proc,
|
|
Part = Part,
|
|
MainFace = Face1,
|
|
Tool = TOOLS[nToolIndex],
|
|
sChosenBladeType = sChosenBladeType,
|
|
dExtendAfterTail = dExtendAfterTail,
|
|
bReduceBladePath = bReduceBladePath,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength,
|
|
bReduceDiceDepth = ( dAngleBetweenFaces < - 10) -- per facce molto aperte non si riduce l'affondamento della lama nei cubetti (rischio che non si stacchino)
|
|
}
|
|
|
|
bIsDicingOk, Machinings, bMoveAfterSplit = CalculateDiceMachinings( vCuts, Parameters)
|
|
|
|
-- se i cubetti falliscono si riprova con la dimensione ridotta (ad esempio quando tocca l'asse Z nei cubetti in coda)
|
|
if not bIsDicingOk and BeamData.SAFE_DIM_DICE then
|
|
dDiceDimension = BeamData.SAFE_DIM_DICE - BeamData.CUT_EXTRA
|
|
OptionalParametersDiceCut.dOffsetParallel = dDiceDimension
|
|
OptionalParametersDiceCut.dOffsetOrthogonal = dDiceDimension
|
|
vCuts = DiceCut.GetDice( Part, Face1, Face2, OptionalParametersDiceCut)
|
|
|
|
-- se nessun cubetto trovato, si richiama ricorsivamente la BladeToWaste forzando di non fare i cubetti
|
|
if #vCuts == 0 then
|
|
OptionalParameters.bDisableDicing = true
|
|
Machinings, Result = BLADETOWASTE.Make( Proc, Part, OptionalParameters)
|
|
return Machinings, Result
|
|
end
|
|
|
|
bIsDicingOk, Machinings, bMoveAfterSplit = CalculateDiceMachinings( vCuts, Parameters)
|
|
end
|
|
|
|
if not bIsDicingOk then
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
return {}, Result
|
|
end
|
|
|
|
-- se presente anche solo una lavorazione AfterTail si spostano tutte
|
|
if bMoveAfterSplit then
|
|
for i = 1, #Machinings do
|
|
Machinings[i].sStage = 'AfterTail'
|
|
end
|
|
end
|
|
|
|
-- risultati del calcolo
|
|
Result.sStatus = 'Completed'
|
|
Result.dCompletionPercentage = 100
|
|
Result.dQuality = FeatureLib.GetStrategyQuality( TOOLS[nToolIndex].sFamily)
|
|
Result.dTimeToMachineOriginal = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
|
Result.dTimeToMachine = Result.dTimeToMachineOriginal * 2
|
|
Result.dMRR = ( FeatureInfo.dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
|
|
local function MakeOneFace( ProcOrId, Part, OptionalParameters)
|
|
local Machinings = {}
|
|
local Result = {}
|
|
|
|
-- disambiguazione feature vs id trimesh
|
|
local Proc = {}
|
|
if type( ProcOrId) == "table" then
|
|
Proc = ProcOrId
|
|
elseif type( ProcOrId) == "number" then
|
|
Proc = FeatureLib.GetProcFromTrimesh( ProcOrId, Part)
|
|
else
|
|
error( 'BLADETOWASTE : Only feature or trimesh supported')
|
|
end
|
|
|
|
-- parametri opzionali e default
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local bDisableDicing = OptionalParameters.bDisableDicing or false
|
|
|
|
-- si taglia tutto lo scarto in una sola lavorazione
|
|
-- TODO qui si deve entrare anche se lo spessore lama è maggiore dell'elevazione delle faccia
|
|
if bDisableDicing or FeatureInfo.bIsFeatureSmall then
|
|
Machinings, Result = CutWholeWaste( Proc, Part, OptionalParameters)
|
|
end
|
|
|
|
-- se non completata con taglio singolo, lavorazione con cubetti
|
|
if ( not bDisableDicing) and ( not Result.sStatus or Result.sStatus ~= 'Completed') then
|
|
Machinings, Result = CutWithDicing( Proc, Part, OptionalParameters)
|
|
end
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
|
|
function BLADETOWASTE.Make( ProcOrId, Part, OptionalParameters)
|
|
local Machinings = {}
|
|
local Result = {}
|
|
|
|
-- disambiguazione feature vs id trimesh
|
|
local Proc = {}
|
|
if type( ProcOrId) == "table" then
|
|
Proc = ProcOrId
|
|
elseif type( ProcOrId) == "number" then
|
|
Proc = FeatureLib.GetProcFromTrimesh( ProcOrId, Part)
|
|
else
|
|
error( 'BLADETOWASTE : Only feature or trimesh supported')
|
|
end
|
|
|
|
-- controlli preventivi
|
|
if Proc.nFct > 2 then
|
|
error( 'BladeToWaste : max 2 faces supported')
|
|
elseif Proc.Topology and ( Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind') then
|
|
-- ricerca lato in comune
|
|
local nCommonEdge
|
|
for i = 1, #Proc.Faces[1].Edges do
|
|
if Proc.Faces[1].Edges[i].idAdjacentFace > -1 then
|
|
nCommonEdge = i
|
|
end
|
|
end
|
|
-- se due facce, cubetti troppo lunghi in X non si possono fare
|
|
local ptEdge1, ptEdge2 = Proc.Faces[1].Edges[nCommonEdge].ptStart, Proc.Faces[1].Edges[nCommonEdge].ptEnd
|
|
local b3BoxEdge = BBox3d( ptEdge1, ptEdge2)
|
|
local dEdgeLengthOnX = b3BoxEdge:getDimX()
|
|
if FeatureLib.IsMachiningLong( dEdgeLengthOnX, Part) then
|
|
-- TODO qui meglio return nil? è una funzione di libreria
|
|
error( 'BLADETOWASTE : common edge too long')
|
|
end
|
|
end
|
|
|
|
-- parametri opzionali e default
|
|
-- quelli non censiti sono gestiti direttamente nelle funzioni sotto e devono quindi solo transitare
|
|
OptionalParameters = OptionalParameters or {}
|
|
local dMaxWasteVolume = OptionalParameters.dMaxWasteVolume or 0
|
|
local dMaxWasteLength = OptionalParameters.dMaxWasteLength or 0
|
|
local bDisableDicing = OptionalParameters.bDisableDicing or false
|
|
local bSaveAddedGeometries = ( OptionalParameters.bSaveAddedGeometries ~= false)
|
|
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
|
|
|
-- dimensioni feature
|
|
if OptionalParameters.b3BoxDicing then
|
|
FeatureInfo.dFeatureVolume = OptionalParameters.b3BoxDicing:getDimX() * OptionalParameters.b3BoxDicing:getDimY() * OptionalParameters.b3BoxDicing:getDimZ()
|
|
FeatureInfo.dFeatureMaxDimension = max( OptionalParameters.b3BoxDicing:getDimX(), OptionalParameters.b3BoxDicing:getDimY())
|
|
else
|
|
FeatureInfo.dFeatureVolume = Proc.dVolume
|
|
FeatureInfo.dFeatureMaxDimension = max( Proc.b3Box:getDimX(), Proc.b3Box:getDimY())
|
|
end
|
|
FeatureInfo.bIsFeatureSmall = FeatureInfo.dFeatureVolume < dMaxWasteVolume + 10 * GEO.EPS_SMALL
|
|
and FeatureInfo.dFeatureMaxDimension < dMaxWasteLength + 10 * GEO.EPS_SMALL
|
|
|
|
-- calcolo lavorazioni
|
|
if Proc.nFct == 1 then
|
|
|
|
Machinings, Result = MakeOneFace( Proc, Part, OptionalParameters)
|
|
|
|
elseif Proc.nFct == 2 then
|
|
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2]
|
|
|
|
-- feature convessa: lavorata come 2 facce singole con prolungamento
|
|
-- TODO qui sostituire con check topologia DoubleBevel
|
|
if dAngleBetweenFaces > 10 * GEO.EPS_SMALL then
|
|
-- si creano superfici singole per le facce, estese fino al box della parte
|
|
local idAddGroup
|
|
if bSaveAddedGeometries then
|
|
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
|
else
|
|
idAddGroup = Part.idTempGroup
|
|
end
|
|
local idFace1 = EgtSurfTmPlaneInBBox( idAddGroup, Proc.Faces[1].ptCenter, Proc.Faces[1].vtN, Part.b3Part, GDB_ID.ROOT)
|
|
local idFace2 = EgtSurfTmPlaneInBBox( idAddGroup, Proc.Faces[2].ptCenter, Proc.Faces[2].vtN, Part.b3Part, GDB_ID.ROOT)
|
|
|
|
-- lavorazione facce
|
|
local Machinings1, Result1 = MakeOneFace( idFace1, Part, OptionalParameters)
|
|
local Machinings2, Result2 = MakeOneFace( idFace2, Part, OptionalParameters)
|
|
|
|
-- tutte le lavorazioni raggruppatee e calcolo area lavorata
|
|
local dAreaToMachineTotal = 0
|
|
-- TODO SISTEMARE!! A volte la lavorazione risulta completa, ma l'area lavorata è inferiore all'area totale e ritorna lavorazione incompleta (vedi i due casi sotto)
|
|
for i = 1, #Machinings1 do
|
|
if Machinings1[i].bIsApplicable then
|
|
table.insert( Machinings, Machinings1[i])
|
|
-- TODO controllare come mai nel progetto fiera saomad, pezzo 8 ritorna area lavorata più piccola pur lavorando tutto
|
|
if Result1.sStatus == 'Completed' then
|
|
dAreaToMachineTotal = dAreaToMachineTotal + EgtSurfArea( idFace1)
|
|
else
|
|
dAreaToMachineTotal = dAreaToMachineTotal + Machinings1[i].dAreaToMachine
|
|
end
|
|
end
|
|
end
|
|
for i = 1, #Machinings2 do
|
|
if Machinings2[i].bIsApplicable then
|
|
table.insert( Machinings, Machinings2[i])
|
|
-- TODO controllare come mai nel progetto fiera saomad, pezzo 8 ritorna area lavorata più piccola pur lavorando tutto
|
|
if Result2.sStatus == 'Completed' then
|
|
dAreaToMachineTotal = dAreaToMachineTotal + EgtSurfArea( idFace2)
|
|
else
|
|
dAreaToMachineTotal = dAreaToMachineTotal + Machinings2[i].dAreaToMachine
|
|
end
|
|
end
|
|
end
|
|
|
|
-- calcolo risultati
|
|
Result.dQuality = FeatureLib.GetStrategyQuality( Machinings)
|
|
Result.dCompletionPercentage = dAreaToMachineTotal / ( EgtSurfArea( idFace1) + EgtSurfArea( idFace2)) * 100
|
|
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
|
|
Result.dTimeToMachine = Result1.dTimeToMachine + Result2.dTimeToMachine
|
|
Result.dMRR = ( FeatureInfo.dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
|
if Result1.sStatus == 'Completed' and Result2.sStatus == 'Completed' then
|
|
Result.sStatus = 'Completed'
|
|
elseif Result1.sStatus == 'Completed' or Result2.sStatus == 'Completed' then
|
|
Result.sStatus = 'Not-Completed'
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
|
|
-- feature concava >= 90deg: lavorata con cubetti, se attivi
|
|
elseif not ( bDisableDicing or FeatureInfo.bIsFeatureSmall) and ( dAngleBetweenFaces >= -91) then
|
|
Machinings, Result = CutWithDicing( Proc, Part, OptionalParameters)
|
|
|
|
-- qui arrivano feature concave < 90deg, oppure >= 90deg con cubetti disabilitati: lavorata come 2 facce singole con eventuale accorciamento
|
|
else
|
|
-- per ogni faccia si calcola la lavorazione
|
|
for i = 1, #Proc.Faces do
|
|
-- ricerca lato in comune da lavorare; se non trovato è una feature splittata (DoubleBevel) e il lato sarà scelto della GetSingleCutStratetegy
|
|
local nCommonEdgeIndex
|
|
for j = 1, #Proc.Faces[i].Edges do
|
|
if Proc.Faces[i].Edges[j].idAdjacentFace > -1 then
|
|
nCommonEdgeIndex = j
|
|
end
|
|
end
|
|
local EdgeToMachine
|
|
if nCommonEdgeIndex then
|
|
EdgeToMachine = Proc.Faces[i].Edges[nCommonEdgeIndex]
|
|
end
|
|
local EdgeToMachineList
|
|
if EdgeToMachine then
|
|
EdgeToMachineList = { Top = EdgeToMachine, Bottom = EdgeToMachine}
|
|
end
|
|
|
|
-- scelta lama
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
if not nToolIndex then
|
|
local OptionalParametersGetSingleCutStrategy = {
|
|
bReduceBladePath = false,
|
|
nFaceToMachineIndex = i,
|
|
EdgeToMachineList = EdgeToMachineList,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
nToolIndex, EdgeToMachine = GetSingleCutStrategy( Proc, Part, OptionalParametersGetSingleCutStrategy)
|
|
end
|
|
|
|
-- se lama non trovata si provano i cubetti
|
|
if not nToolIndex then
|
|
if not ( bDisableDicing) and ( dAngleBetweenFaces >= -91) then
|
|
Machinings, Result = CutWithDicing( Proc, Part, OptionalParameters)
|
|
end
|
|
|
|
break
|
|
end
|
|
|
|
-- calcolo accorciamento
|
|
local dPathShortening = max( 0, TOOLS[nToolIndex].dThickness / tan( 180 + dAngleBetweenFaces))
|
|
|
|
-- lavorazione faccia
|
|
local OptionalParametersFaceByBlade = {
|
|
dDepthToMachine = EdgeToMachine.dElevation - dPathShortening,
|
|
nToolIndex = nToolIndex,
|
|
dExtendAfterTail = OptionalParameters.dExtendAfterTail,
|
|
bReduceBladePath = false,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[i], EdgeToMachine, OptionalParametersFaceByBlade)
|
|
|
|
-- aggiunta lavorazione
|
|
if Cutting and Cutting.bIsApplicable then
|
|
table.insert( Machinings, Cutting)
|
|
end
|
|
end
|
|
|
|
-- calcolo risultati
|
|
if #Machinings > 0 then
|
|
local dCompletionPercentage = 0
|
|
|
|
if #Machinings == 2
|
|
and Machinings[1].dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL
|
|
and Machinings[2].dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
|
|
|
Result.sStatus = 'Completed'
|
|
dCompletionPercentage = 100
|
|
else
|
|
|
|
Result.sStatus = 'Not-Completed'
|
|
dCompletionPercentage = ( ( ( Machinings[1] and Machinings[1].dCompletionPercentage) or 0) + ( ( Machinings[2] and Machinings[2].dCompletionPercentage) or 0)) / 2
|
|
end
|
|
|
|
Result.dCompletionPercentage = dCompletionPercentage
|
|
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
|
Result.dQuality = FeatureLib.GetStrategyQuality( Machinings)
|
|
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
|
Result.dMRR = ( FeatureInfo.dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
end
|
|
end
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
return BLADETOWASTE |