d9665b4ca9
- in MainFaces correzioni per casi convessi
697 lines
28 KiB
Lua
697 lines
28 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( 'BeamData')
|
|
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')
|
|
|
|
-- tabella per definizione modulo
|
|
local FeatureInfo = {}
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function CompareEdgesTopHead( 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 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 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 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, vtNFace, sBladeType)
|
|
local EdgeToMachine = {}
|
|
|
|
local EdgesSorted = {}
|
|
for i = 1, #Edges do
|
|
table.insert( EdgesSorted, Edges[i])
|
|
end
|
|
|
|
if sBladeType == 'Top' then
|
|
table.sort( EdgesSorted, CompareEdgesTopHead)
|
|
EdgeToMachine = EdgesSorted[1]
|
|
elseif sBladeType == 'Bottom' then
|
|
table.sort( EdgesSorted, CompareEdgesBottomHead)
|
|
EdgeToMachine = EdgesSorted[1]
|
|
elseif sBladeType == 'TopDownUp' then
|
|
local vtEdgeDirection
|
|
if vtNFace:getY() > -0.02 then
|
|
vtEdgeDirection = -Y_AX()
|
|
else
|
|
vtEdgeDirection = Y_AX()
|
|
end
|
|
EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( Edges, vtEdgeDirection)
|
|
else
|
|
table.sort( EdgesSorted, CompareEdgesNoPreference)
|
|
EdgeToMachine = EdgesSorted[1]
|
|
end
|
|
|
|
return EdgeToMachine
|
|
end
|
|
|
|
|
|
local function GetBestBlade( Proc, Part, Face, OptionalParameters)
|
|
local nChosenToolIndex
|
|
local sChosenBladeType
|
|
|
|
-- 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 dElevationTop = OptionalParameters.dElevationTopBlade
|
|
local dElevationBottom = OptionalParameters.dElevationBottomBlade
|
|
local dElevationTopDownUp = OptionalParameters.dElevationTopBladeDownUp or 0
|
|
|
|
-- ricerca lama testa sopra
|
|
local ToolSearchParameters = {}
|
|
ToolSearchParameters.vtN = Face.vtN
|
|
ToolSearchParameters.bAllowTopHead = true
|
|
ToolSearchParameters.bAllowBottomHead = false
|
|
ToolSearchParameters.bForceLongcutBlade = false
|
|
ToolSearchParameters.dElevation = dElevationTop
|
|
ToolInfo = MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
|
local nToolIndexTop
|
|
if ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
nToolIndexTop = ToolInfo.nToolIndex
|
|
end
|
|
|
|
-- ricerca lama testa sotto
|
|
ToolSearchParameters = {}
|
|
ToolSearchParameters.vtN = Face.vtN
|
|
ToolSearchParameters.bAllowTopHead = false
|
|
ToolSearchParameters.bAllowBottomHead = true
|
|
ToolSearchParameters.bForceLongcutBlade = false
|
|
ToolSearchParameters.dElevation = dElevationBottom
|
|
ToolInfo = MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
|
local nToolIndexBottom
|
|
if ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
nToolIndexBottom = ToolInfo.nToolIndex
|
|
end
|
|
|
|
-- lama sopra e sotto
|
|
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'
|
|
-- se lama sopra va verificato se va usata in DownUp
|
|
elseif nChosenToolIndex == nToolIndexTop then
|
|
local dMinNzDownUp = TOOLS[nToolIndexTop].SetupInfo.GetMinNzDownUp( Part.b3Raw, Face.vtN, nil, TOOLS[nToolIndexTop])
|
|
local dCurrentResidualDepth = dElevationTopDownUp - TOOLS[nToolIndexTop].dMaxDepth
|
|
if Face.vtN:getZ() < dMinNzDownUp then
|
|
if ( dCurrentResidualDepth > 10 * GEO.EPS_SMALL) then
|
|
-- TODO serve messaggio per motivare il non applicabile??
|
|
nChosenToolIndex = nil
|
|
end
|
|
sChosenBladeType = 'TopDownUp'
|
|
else
|
|
sChosenBladeType = 'Top'
|
|
end
|
|
end
|
|
|
|
-- se non trovata alcuna lama ritorna nil
|
|
return nChosenToolIndex, sChosenBladeType
|
|
end
|
|
|
|
|
|
local function SetDiceFaceInfo( Proc, idDiceFace, bSaveAddedGeometries)
|
|
EgtSetName( idDiceFace, 'Face' .. tostring( Proc.idFeature) .. '_Dice')
|
|
-- TODO la scrittura del TaskId probabilmente non serve (è fatta nell'AddOperations)
|
|
EgtSetInfo( idDiceFace, 'TASKID', Proc.idTask)
|
|
if not bSaveAddedGeometries then
|
|
EgtSetLevel( idDiceFace, GDB_LV.TEMP)
|
|
end
|
|
end
|
|
|
|
|
|
local function CutWholeWaste( Proc, Part, OptionalParameters)
|
|
local Machinings = {}
|
|
local Cutting = {}
|
|
local Result = {}
|
|
local EdgeToMachine = {}
|
|
local sChosenBladeType = ''
|
|
local dDepthToMachine = 0
|
|
local dCompletionPercentage = 0
|
|
|
|
-- parametri opzionali e default
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local nToolIndex = OptionalParameters.nToolIndex
|
|
local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000
|
|
|
|
-- lato da lavorare in base al tipo di lama
|
|
local EdgeToMachineTopBlade = GetEdgeToMachine( Proc.Faces[1].Edges, Proc.Faces[1].vtN, 'Top')
|
|
local EdgeToMachineBottomBlade = GetEdgeToMachine( Proc.Faces[1].Edges, Proc.Faces[1].vtN, 'Bottom')
|
|
local EdgeToMachineTopBladeDownUp = GetEdgeToMachine( Proc.Faces[1].Edges, Proc.Faces[1].vtN, 'TopDownUp')
|
|
|
|
-- scelta lama da sopra o da sotto
|
|
if nToolIndex then
|
|
nToolIndex = OptionalParameters.nToolIndex
|
|
else
|
|
local OptionalParametersGetBestBlade = { dElevationTop = EdgeToMachineTopBlade.dElevation + BeamData.CUT_EXTRA,
|
|
dElevationBottom = EdgeToMachineBottomBlade.dElevation + BeamData.CUT_EXTRA,
|
|
dElevationTopDownUp = EdgeToMachineTopBladeDownUp.dElevation + BeamData.CUT_EXTRA
|
|
}
|
|
nToolIndex, sChosenBladeType = GetBestBlade( Proc, Part, Proc.Faces[1], OptionalParametersGetBestBlade)
|
|
end
|
|
|
|
-- utensile non trovato
|
|
if not nToolIndex then
|
|
Result = FeatureLib.GetStrategyResultNotApplicable( 'Blade not found')
|
|
return Machinings, Result
|
|
end
|
|
|
|
-- lato da lavorare definitivo
|
|
if sChosenBladeType == 'Top' then
|
|
EdgeToMachine = EdgeToMachineTopBlade
|
|
elseif sChosenBladeType == 'Bottom' then
|
|
EdgeToMachine = EdgeToMachineBottomBlade
|
|
elseif sChosenBladeType == 'TopDownUp' then
|
|
EdgeToMachine = EdgeToMachineTopBladeDownUp
|
|
end
|
|
|
|
dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA
|
|
local dResidualDepth = dDepthToMachine - TOOLS[nToolIndex].dMaxMaterial
|
|
|
|
-- TODO qui gestire il caso in cui si può tagliare da due lati (inizialmente solo se vtN:Y è ~= 0?). Andranno ricercati gli utensili di nuovo con l'elevazione a metà??
|
|
if dResidualDepth < 10 * GEO.EPS_SMALL then
|
|
local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine, nToolIndex = nToolIndex, dExtendAfterTail = dExtendAfterTail}
|
|
|
|
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[1], EdgeToMachine, OptionalParametersFaceByBlade)
|
|
end
|
|
if Cutting.bIsApplicable then
|
|
table.insert( Machinings, Cutting)
|
|
dCompletionPercentage = Cutting.dCompletionPercentage or dCompletionPercentage
|
|
end
|
|
|
|
-- risultati del calcolo
|
|
-- TODO funzione?
|
|
if Cutting.bIsApplicable then
|
|
if dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
|
Result.sStatus = 'Completed'
|
|
else
|
|
Result.sStatus = 'Not-Completed'
|
|
end
|
|
else
|
|
Result.sStatus = 'Not-Applicable'
|
|
end
|
|
Result.dCompletionPercentage = dCompletionPercentage
|
|
Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
|
Result.nQuality = TOOLS[nToolIndex].nQuality
|
|
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( {Cutting})
|
|
Result.dMRR = ( FeatureInfo.dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
|
|
|
return Machinings, Result
|
|
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
|
|
if bSaveAddedGeometries == nil then
|
|
bSaveAddedGeometries = true
|
|
end
|
|
|
|
-- 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
|
|
|
|
-- 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 Machinings, Result
|
|
end
|
|
|
|
-- limite per taglio DownUp
|
|
local dMinNzDownUp = TOOLS[nToolIndex].SetupInfo.GetMinNzDownUp( Part.b3Raw, Face1.vtN, nil, TOOLS[nToolIndex])
|
|
|
|
-- calcolo dimensione cubetto e eventuale cubetto ridotto (tagli orizzontali con affondamento verticale)
|
|
local dDiceDimension = min( TOOLS[nToolIndex].dMaxMaterial, BeamData.MAX_DIM_DICE)
|
|
local dDiceDimensionReduced = dDiceDimension
|
|
dDiceDimensionReduced = min( dDiceDimension, dDiceDimension - TOOLS[nToolIndex].SetupInfo.dMaxMatDecrease)
|
|
dDiceDimension = dDiceDimension - BeamData.CUT_EXTRA
|
|
dDiceDimensionReduced = dDiceDimensionReduced - BeamData.CUT_EXTRA
|
|
|
|
-- calcolo cubetti
|
|
local OptionalParametersDiceCut = {}
|
|
OptionalParametersDiceCut.dOffsetParallel = dDiceDimension
|
|
OptionalParametersDiceCut.dOffsetOrthogonal = dDiceDimension
|
|
OptionalParametersDiceCut.dOffsetOrthogonalReduced = dDiceDimensionReduced
|
|
OptionalParametersDiceCut.dMinNzDownUp = dMinNzDownUp
|
|
OptionalParametersDiceCut.b3BoxDicing = b3BoxDicing
|
|
local vCuts = DiceCut.GetDice( Part, Face1, Face2, OptionalParametersDiceCut)
|
|
|
|
-- se nessun cubetto trovato, si richiama il taglio singolo
|
|
if #vCuts == 0 then
|
|
Machinings, Result = CutWholeWaste( Proc, Part, OptionalParameters)
|
|
return Machinings, Result
|
|
end
|
|
|
|
-- lavorazione cubetti
|
|
local bIsDicingOk = true
|
|
local bMoveAfterSplit = false
|
|
-- 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], bSaveAddedGeometries)
|
|
if ( i % 2) == 1 then
|
|
local vtO = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
|
if ( Face1.vtN:getY() > 0.766 and vtO:getY() < -0.05) or
|
|
( Face1.vtN:getY() < -0.766 and vtO:getY() > 0.05) then
|
|
EgtInvertSurf( vCuts[i][j])
|
|
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( Face1.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 ^ Face1.vtN
|
|
local Frame = Frame3d( Face1.ptCenter, Face1.ptCenter + asseX, Face1.ptCenter + asseY)
|
|
local b3Fac = EgtGetBBoxRef( vCuts[i][1], GDB_BB.STANDARD, Frame)
|
|
-- se lunghezza inferiore al limite, accetto la direzione
|
|
if b3Fac:getDimX() < TOOLS[nToolIndex].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)
|
|
local vtNCurrentFace = EgtSurfTmFacetNormVersor( vCuts[i][1], 0, GDB_ID.ROOT)
|
|
EdgeToMachine = GetEdgeToMachine( Edges, vtNCurrentFace, sChosenBladeType)
|
|
vtToolDirection = EdgeToMachine.vtN
|
|
end
|
|
end
|
|
-- calcolo lavorazione della singola faccia
|
|
for j = 1, #vCuts[i] do
|
|
local Cutting = {}
|
|
local vtNCurrentFace = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
|
local FaceToMachine = { id = 0, vtN = vtNCurrentFace}
|
|
-- se taglio DownUp e strato pari composto da 1 o 2 elementi (tutti gli altri casi vengono saltati)
|
|
if ( vtNCurrentFace:getZ() < dMinNzDownUp) and ( ( i % 2) == 0) and ( #vCuts[i] <= 2) then
|
|
-- il primo elemento prende la direzione prevista, il secondo quella opposta
|
|
local vtToolDirectionNew = Vector3d( vtToolDirection)
|
|
if j ~= 1 then
|
|
vtToolDirectionNew = -vtToolDirection
|
|
end
|
|
-- lavorazione
|
|
local ProcTrimesh = FeatureLib.GetProcFromTrimesh( vCuts[i][j], Part)
|
|
local _, Edges = FaceData.GetEdgesInfo( vCuts[i][j], 0)
|
|
local EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( Edges, vtToolDirectionNew)
|
|
local dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA
|
|
local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine,
|
|
nToolIndex = nToolIndex,
|
|
dRadialStepSpan = 0,
|
|
dExtendAfterTail = dExtendAfterTail
|
|
}
|
|
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)
|
|
else
|
|
bIsDicingOk = false
|
|
end
|
|
if Cutting.sStage == 'AfterTail' then
|
|
bMoveAfterSplit = true
|
|
end
|
|
-- caso generale
|
|
else
|
|
-- in generale sta sollevato di pochissimo
|
|
local dExtraCut = -0.1
|
|
-- se tagli paralleli
|
|
if ( i % 2) == 0 then
|
|
-- se non ci sono tagli ortogonali devo affondare
|
|
if bNoPerpCuts then
|
|
dExtraCut = BeamData.CUT_EXTRA
|
|
-- se altrimenti tagli ortogonali invertiti, devo approfondire dello spessore lama
|
|
elseif bAreOrthogonalCutsInverted then
|
|
dExtraCut = TOOLS[nToolIndex].dThickness
|
|
-- se ultimo taglio, devo affondare
|
|
elseif j == #vCuts[i] then
|
|
dExtraCut = BeamData.CUT_EXTRA
|
|
end
|
|
end
|
|
local ProcTrimesh = FeatureLib.GetProcFromTrimesh( vCuts[i][j], Part)
|
|
local _, Edges = FaceData.GetEdgesInfo( vCuts[i][j], 0)
|
|
local EdgeToMachine = BeamLib.FindEdgeBestOrientedAsDirection( Edges, vtToolDirection)
|
|
local EdgeToMachineAlternative = {}
|
|
if ( i % 2 == 0) and ( Proc.Fct == 1) and bNoPerpCuts then
|
|
EdgeToMachineAlternative = BeamLib.FindEdgeBestOrientedAsDirection( Edges, -EdgeToMachine.vtN)
|
|
end
|
|
local dDepthToMachine = EdgeToMachine.dElevation + dExtraCut
|
|
local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine,
|
|
nToolIndex = nToolIndex,
|
|
EdgeToMachineAlternative = EdgeToMachineAlternative,
|
|
dRadialStepSpan = 0,
|
|
dExtendAfterTail = dExtendAfterTail
|
|
}
|
|
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)
|
|
else
|
|
bIsDicingOk = false
|
|
end
|
|
if Cutting.sStage == 'AfterTail' then
|
|
bMoveAfterSplit = true
|
|
end
|
|
end
|
|
end
|
|
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
|
|
if bIsDicingOk then
|
|
Result.sStatus = 'Completed'
|
|
Result.dCompletionPercentage = 100
|
|
else
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
Result.nQuality = TOOLS[nToolIndex].nQuality
|
|
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
|
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 bForceDicing = OptionalParameters.bForceDicing 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 FeatureInfo.bIsFeatureSmall and not bForceDicing then
|
|
Machinings, Result = CutWholeWaste( Proc, Part, OptionalParameters)
|
|
end
|
|
|
|
-- se non completata con taglio singolo, lavorazione con cubetti
|
|
if 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')
|
|
end
|
|
|
|
-- parametri opzionali e default
|
|
-- quelli non censiti sono gestiti direttamente nelle funzioni sotto e devono quindi solo transitare
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local dMaxWasteVolume = OptionalParameters.dMaxWasteVolume or 0
|
|
local dMaxWasteLength = OptionalParameters.dMaxWasteLength or 0
|
|
local bSaveAddedGeometries = OptionalParameters.bSaveAddedGeometries
|
|
if bSaveAddedGeometries == nil then
|
|
bSaveAddedGeometries = true
|
|
end
|
|
|
|
-- 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 = FeatureLib.GetFeatureVolume( Proc, Part)
|
|
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 nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
|
local idFace1 = EgtSurfTmPlaneInBBox( nAddGrpId, Proc.Faces[1].ptCenter, Proc.Faces[1].vtN, Part.b3Part, GDB_ID.ROOT)
|
|
local idFace2 = EgtSurfTmPlaneInBBox( nAddGrpId, Proc.Faces[2].ptCenter, Proc.Faces[2].vtN, Part.b3Part, GDB_ID.ROOT)
|
|
if not bSaveAddedGeometries then
|
|
EgtSetLevel( idFace1, GDB_LV.TEMP)
|
|
EgtSetLevel( idFace2, GDB_LV.TEMP)
|
|
end
|
|
|
|
-- 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 è inferipre 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.nQuality = FeatureLib.GetStrategyQuality( Machinings)
|
|
Result.dCompletionPercentage = dAreaToMachineTotal / ( EgtSurfArea( idFace1) + EgtSurfArea( idFace2)) * 100
|
|
Result.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
|
|
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
|
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.sStatus = 'Not-Applicable'
|
|
Result = FeatureLib.GetStrategyResultNotApplicable()
|
|
end
|
|
|
|
-- feature concava >= 90deg: lavorata con cubetti
|
|
elseif dAngleBetweenFaces >= -91 then
|
|
Machinings, Result = CutWithDicing( Proc, Part, OptionalParameters)
|
|
|
|
-- feature concava < 90deg: lavorata come 2 facce singole con accorciamento
|
|
else
|
|
-- TODO da fare
|
|
end
|
|
|
|
end
|
|
|
|
return Machinings, Result
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
return BLADETOWASTE |