1580 lines
80 KiB
Lua
1580 lines
80 KiB
Lua
-- MachiningLib.lua by Egalware s.r.l. 2024/04/02
|
|
-- Libreria ricerca lavorazioni per Travi
|
|
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
|
|
|
-- Tabella per definizione modulo
|
|
local MachiningLib = {}
|
|
|
|
-- Include
|
|
require( 'EgtBase')
|
|
|
|
-- Carico i dati globali
|
|
local BeamData = require( 'BeamData')
|
|
local BeamLib = require( 'BeamLib')
|
|
local FeatureLib = require( 'FeatureLib')
|
|
local BCS = require( 'BasicCustomerStrategies')
|
|
local FaceData = require ( 'FaceData')
|
|
|
|
EgtOutLog( ' MachiningLib started', 1)
|
|
|
|
---------------------------------------------------------------------
|
|
-- TODO da considerare solo angolo 2D??
|
|
local function GetToolEntryAngle( Proc, vtTool)
|
|
local Angle = {}
|
|
|
|
local dSinAngle = -10 * GEO.EPS_SMALL
|
|
local vtNorm
|
|
if Proc.AffectedFaces.bTop then
|
|
vtNorm = Z_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
if Proc.AffectedFaces.bBottom then
|
|
vtNorm = -Z_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
if Proc.AffectedFaces.bFront then
|
|
vtNorm = -Y_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
if Proc.AffectedFaces.bBack then
|
|
vtNorm = Y_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
if Proc.AffectedFaces.bLeft then
|
|
vtNorm = -X_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
if Proc.AffectedFaces.bRight then
|
|
vtNorm = X_AX()
|
|
dSinAngle = max( dSinAngle, vtTool * vtNorm)
|
|
end
|
|
|
|
local dCosAngle = sqrt( 1 - sqr( dSinAngle))
|
|
local dAngle = acos( dCosAngle)
|
|
local dTanAngle
|
|
if dAngle ~= 0 and dAngle ~= 90 then
|
|
dTanAngle = sqrt( 1 - dCosAngle * dCosAngle) / dCosAngle
|
|
end
|
|
|
|
Angle.dValue = dAngle
|
|
Angle.dSin = dSinAngle
|
|
Angle.dCos = dCosAngle
|
|
Angle.dTan = dTanAngle
|
|
|
|
return Angle
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.StartsLeftSide( Machining)
|
|
local bStartsLeftSide = ( Machining.vtEdgeDirection:getX() > 10 * GEO.EPS_SMALL and not Machining.bInvert)
|
|
or ( not( Machining.vtEdgeDirection:getX() > 10 * GEO.EPS_SMALL) and Machining.bInvert)
|
|
|
|
return bStartsLeftSide
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- TODO valutare se c'è un modo più preciso di prevedere i casi in cui le lavorazioni dopo separazione sono da saltare
|
|
function MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
|
-- TODO controllare. Serve passare anche la posizione per capire il restante. Considerare anche HCING e TCING
|
|
local bCanMoveAfterSplitcut = ( Part.dLength > BeamData.dMinRaw + 10 * GEO.EPS_SMALL)
|
|
or ( dLengthOnX < 0.7 * Part.dLength - 10 * GEO.EPS_SMALL and Part.dLength - dLengthOnX > BeamData.dMinClampRaw)
|
|
|
|
return bCanMoveAfterSplitcut
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.CanExtendAfterTail( sCanDamageNextPiece, Part)
|
|
local bCanExtendAfterTail = false
|
|
|
|
if sCanDamageNextPiece == 'ALWAYS' then
|
|
bCanExtendAfterTail = true
|
|
elseif sCanDamageNextPiece == 'ONLY_IF_RAWPART' then
|
|
bCanExtendAfterTail = Part.bIsLastPart
|
|
end
|
|
|
|
return bCanExtendAfterTail
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.GetMachiningSteps( dMachiningDepth, dStep)
|
|
local MachiningSteps = {}
|
|
MachiningSteps.dStep = 0
|
|
MachiningSteps.nCount = ceil( ( dMachiningDepth - 50 * GEO.EPS_SMALL) / dStep)
|
|
if MachiningSteps.nCount > 1 then
|
|
MachiningSteps.dStep = ( dMachiningDepth - dStep) / ( MachiningSteps.nCount - 1)
|
|
else
|
|
MachiningSteps.dStep = dMachiningDepth
|
|
MachiningSteps.nCount = 1
|
|
end
|
|
|
|
return MachiningSteps
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.GetSplitMachinings( Machinings, SplittingPoints, Part)
|
|
for i = #Machinings, 1, -1 do
|
|
local nParts = #SplittingPoints + 1
|
|
local dEdgeMaxX = Machinings[i].ptEdge1:getX()
|
|
local dEdgeMinX = Machinings[i].ptEdge2:getX()
|
|
if Machinings[i].ptEdge1:getX() < Machinings[i].ptEdge2:getX() - 10 * GEO.EPS_SMALL then
|
|
dEdgeMaxX = Machinings[i].ptEdge2:getX()
|
|
dEdgeMinX = Machinings[i].ptEdge1:getX()
|
|
end
|
|
local OriginalLeadIn = BeamLib.TableCopyDeep( Machinings[i].LeadIn)
|
|
local OriginalLeadOut = BeamLib.TableCopyDeep( Machinings[i].LeadOut)
|
|
local sOriginalStage = Machinings[i].sStage
|
|
local LeadInForSplit
|
|
local LeadOutForSplit
|
|
if Machinings[i].LeadInForSplit then
|
|
LeadInForSplit = BeamLib.TableCopyDeep( Machinings[i].LeadInForSplit)
|
|
end
|
|
if Machinings[i].LeadOutForSplit then
|
|
LeadOutForSplit = BeamLib.TableCopyDeep( Machinings[i].LeadOutForSplit)
|
|
end
|
|
if FeatureLib.IsMachiningLong( Machinings[i].dLengthOnX, Part) then
|
|
local nCurrentMachiningIndex = i
|
|
-- lo spezzone attivo è quello precedente al punto di spezzatura corrente
|
|
for j = 1, nParts do
|
|
-- check ultimo segmento della lavorazione (NON della feature)
|
|
local bIsLastSegment = ( nParts == 1)
|
|
or ( ( ( j ~= 1) and SplittingPoints[j - 1]:getX() > dEdgeMinX + 10 * GEO.EPS_SMALL)
|
|
and ( j == nParts or SplittingPoints[j]:getX() < dEdgeMinX + 10 * GEO.EPS_SMALL))
|
|
-- se non è l'ultimo segmento della lavorazione, il punto di spezzatura deve essere all'interno del lato che si sta lavorando
|
|
if ( j ~= nParts and ( SplittingPoints[j]:getX() > dEdgeMinX + 10 * GEO.EPS_SMALL and SplittingPoints[j]:getX() < dEdgeMaxX - 10 * GEO.EPS_SMALL))
|
|
or bIsLastSegment then
|
|
if j > 1 then
|
|
nCurrentMachiningIndex = nCurrentMachiningIndex + 1
|
|
table.insert( Machinings, nCurrentMachiningIndex, BeamLib.TableCopyDeep( Machinings[i]))
|
|
Machinings[nCurrentMachiningIndex].LeadIn = BeamLib.TableCopyDeep( OriginalLeadIn)
|
|
Machinings[nCurrentMachiningIndex].LeadOut = BeamLib.TableCopyDeep( OriginalLeadOut)
|
|
end
|
|
local dStartAddLength = OriginalLeadIn.dStartAddLength
|
|
local dEndAddLength = OriginalLeadOut.dEndAddLength
|
|
if MachiningLib.StartsLeftSide( Machinings[i]) then
|
|
dStartAddLength, dEndAddLength = dEndAddLength, dStartAddLength
|
|
end
|
|
if j == 1 then
|
|
dEndAddLength = - ( SplittingPoints[j]:getX() - dEdgeMinX) + BeamData.MILL_OVERLAP
|
|
if LeadOutForSplit then
|
|
Machinings[nCurrentMachiningIndex].LeadOut = BeamLib.TableCopyDeep( LeadOutForSplit)
|
|
end
|
|
Machinings[nCurrentMachiningIndex].ptCenter = Point3d( SplittingPoints[j]:getX() + ( dEdgeMaxX - SplittingPoints[j]:getX()) / 2, 0, 0)
|
|
elseif j == nParts then
|
|
dStartAddLength = - ( dEdgeMaxX - SplittingPoints[j - 1]:getX()) + BeamData.MILL_OVERLAP
|
|
if LeadInForSplit then
|
|
Machinings[nCurrentMachiningIndex].LeadIn = BeamLib.TableCopyDeep( LeadInForSplit)
|
|
end
|
|
Machinings[nCurrentMachiningIndex].ptCenter = Point3d( dEdgeMinX + ( SplittingPoints[j - 1]:getX() - dEdgeMinX) / 2, 0, 0)
|
|
else
|
|
dStartAddLength = - ( dEdgeMaxX - SplittingPoints[j - 1]:getX()) + BeamData.MILL_OVERLAP
|
|
dEndAddLength = - ( SplittingPoints[j]:getX() - dEdgeMinX) + BeamData.MILL_OVERLAP
|
|
if LeadInForSplit then
|
|
Machinings[nCurrentMachiningIndex].LeadIn = BeamLib.TableCopyDeep( LeadInForSplit)
|
|
end
|
|
if LeadOutForSplit then
|
|
Machinings[nCurrentMachiningIndex].LeadOut = BeamLib.TableCopyDeep( LeadOutForSplit)
|
|
end
|
|
Machinings[nCurrentMachiningIndex].ptCenter = Point3d( SplittingPoints[j]:getX() + ( SplittingPoints[j - 1]:getX() - SplittingPoints[j]:getX()) / 2, 0, 0)
|
|
end
|
|
if MachiningLib.StartsLeftSide( Machinings[nCurrentMachiningIndex]) then
|
|
dStartAddLength, dEndAddLength = dEndAddLength, dStartAddLength
|
|
local LeadInCopy = BeamLib.TableCopyDeep( Machinings[nCurrentMachiningIndex].LeadIn)
|
|
Machinings[nCurrentMachiningIndex].LeadIn = BeamLib.TableCopyDeep( Machinings[nCurrentMachiningIndex].LeadOut)
|
|
Machinings[nCurrentMachiningIndex].LeadOut = BeamLib.TableCopyDeep( LeadInCopy)
|
|
end
|
|
|
|
Machinings[nCurrentMachiningIndex].LeadIn.dStartAddLength = dStartAddLength
|
|
Machinings[nCurrentMachiningIndex].LeadOut.dEndAddLength = dEndAddLength
|
|
end
|
|
if not bIsLastSegment then
|
|
Machinings[nCurrentMachiningIndex].sStage = ''
|
|
else
|
|
Machinings[nCurrentMachiningIndex].sStage = sOriginalStage
|
|
end
|
|
Machinings[nCurrentMachiningIndex].nFeatureSegment = j
|
|
Machinings[nCurrentMachiningIndex].dLengthToMachine = Machinings[nCurrentMachiningIndex].dEdgeLength + Machinings[nCurrentMachiningIndex].LeadIn.dStartAddLength + Machinings[nCurrentMachiningIndex].LeadOut.dEndAddLength
|
|
Machinings[nCurrentMachiningIndex].dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machinings[nCurrentMachiningIndex], Part)
|
|
end
|
|
-- anche le lavorazioni non splittate necessitano del segmento assegnato
|
|
else
|
|
local dRightAddLength = 0
|
|
local dLeftAddLength = 0
|
|
-- si considerano allungamenti e accorciamenti solo se la feature è orientata principalmente lungo X
|
|
-- TODO il modo corretto è proiettare tutto, allungamenti e accorciamenti compresi, sulla faccia frontale
|
|
if abs( Machinings[i].vtToolDirection:getX()) < 0.707 then
|
|
dRightAddLength = OriginalLeadIn.dStartAddLength
|
|
dLeftAddLength = OriginalLeadOut.dEndAddLength
|
|
if MachiningLib.StartsLeftSide( Machinings[i]) then
|
|
dRightAddLength, dLeftAddLength = dLeftAddLength, dRightAddLength
|
|
end
|
|
end
|
|
for j = 1, nParts do
|
|
local dNextSplitX = dEdgeMinX
|
|
local dPreviousSplitX = dEdgeMaxX
|
|
if j ~= 1 then
|
|
dPreviousSplitX = SplittingPoints[j - 1]:getX()
|
|
end
|
|
if j ~= nParts then
|
|
dNextSplitX = SplittingPoints[j]:getX()
|
|
end
|
|
if ( dEdgeMinX - dLeftAddLength) > dNextSplitX - 10 * GEO.EPS_SMALL and ( dEdgeMinX - dLeftAddLength) < dPreviousSplitX + 10 * GEO.EPS_SMALL then
|
|
Machinings[i].nFeatureSegment = j
|
|
Machinings[i].ptCenter = Point3d( dNextSplitX + ( dPreviousSplitX - dNextSplitX) / 2, 0, 0)
|
|
end
|
|
end
|
|
Machinings[i].dLengthToMachine = Machinings[i].dEdgeLength + Machinings[i].LeadIn.dStartAddLength + Machinings[i].LeadOut.dEndAddLength
|
|
Machinings[i].dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machinings[i], Part)
|
|
end
|
|
end
|
|
|
|
return Machinings
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che ritorna la posizione nella quale si trova l'utensile cercato. Serve in caso l'utente voglia rispettare l'ordine degli utensili settato
|
|
local function GetIndexToolInAvailableToolList( AvailableToolList, sToolName)
|
|
for nIndex = 1, #AvailableToolList do
|
|
if sToolName == AvailableToolList[nIndex].sName then
|
|
return nIndex
|
|
end
|
|
end
|
|
-- se non trovato
|
|
return nil
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per verifica se l'utensile è presente tra gli utensili disponibili per la strategia
|
|
local function IsToolInAvailableToolList( AvailableToolList, sTool)
|
|
local bToolFound = false
|
|
-- si cerca utensile con UUID se presente
|
|
for nIndex = 1, #AvailableToolList do
|
|
if AvailableToolList[nIndex].sUUID then
|
|
if sTool.sUUID == AvailableToolList[nIndex].sUUID then
|
|
bToolFound = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
-- se non trovato con UUID, allora ci cerca per nome
|
|
for nIndex = 1, #AvailableToolList do
|
|
if AvailableToolList[nIndex].sName then
|
|
if sTool.sName == AvailableToolList[nIndex].sName then
|
|
bToolFound = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
return bToolFound
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo FRESA con certe caratteristiche
|
|
-- TODO qui vtToolDirection è in realtà vtN
|
|
function MachiningLib.FindMill( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
for i = 1, #TOOLS do
|
|
-- prima verifico che utensile sia compatibile
|
|
local bIsToolCompatible = true
|
|
-- se viene passato il nome, tutti gli altri sono incompatibili
|
|
if ToolSearchParameters.sName and ToolSearchParameters.sName ~= TOOLS[i].sName then
|
|
bIsToolCompatible = false
|
|
-- se c'è una lista di utensili disponibili, si verifica che l'utensile attuale sia tra quelli
|
|
elseif ToolSearchParameters.AvailableToolList and not IsToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i]) then
|
|
bIsToolCompatible = false
|
|
-- si cercano solo frese standard. Se utensile disegnato manualmente, si setta subito che è incompatibile
|
|
elseif TOOLS[i].bIsProfiledTool then
|
|
bIsToolCompatible = false
|
|
-- controlli standard
|
|
elseif ToolSearchParameters.dMaxToolDiameter and TOOLS[i].dDiameter > ToolSearchParameters.dMaxToolDiameter then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.dMinToolDiameter and TOOLS[i].dDiameter < ToolSearchParameters.dMinToolDiameter then
|
|
bIsToolCompatible = false
|
|
elseif ( ToolSearchParameters.bCCW and not TOOLS[i].bIsCCW) or ( ToolSearchParameters.bCW and TOOLS[i].bIsCCW) then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].SetupInfo.HeadType.bTop and ToolSearchParameters.vtToolDirection:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtToolDirection, TOOLS[i]) - GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].SetupInfo.HeadType.bBottom and ToolSearchParameters.vtToolDirection:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtToolDirection, TOOLS[i]) + GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sMillShape == 'STANDARD' and ( TOOLS[i].dSideAngle ~= 0 or TOOLS[i].bIsPen) then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sMillShape == 'DOVETAIL' and not TOOLS[i].bIsDoveTail then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sMillShape == 'TSHAPEMILL' and not TOOLS[i].bIsTMill then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sMillShape == 'PEN' and not TOOLS[i].bIsPen then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sMillShape == 'VMILL' and not TOOLS[i].bIsVMill then
|
|
bIsToolCompatible = false
|
|
elseif ToolSearchParameters.sType and TOOLS[i].sType ~= ToolSearchParameters.sType then
|
|
-- se sto cercando una fresa che non può lavorare di testa, quelle che lavorano di testa sono comunque ammesse
|
|
if TOOLS[i].sType == 'MILL_STD' and ToolSearchParameters.sType == 'MILL_NOTIP' then
|
|
bIsToolCompatible = true
|
|
else
|
|
bIsToolCompatible = false
|
|
end
|
|
end
|
|
|
|
-- scelgo il migliore
|
|
if bIsToolCompatible then
|
|
-- calcolo riduzione del massimo materiale utilizzabile
|
|
local ToolEntryAngle = GetToolEntryAngle( Proc, ToolSearchParameters.vtToolDirection)
|
|
-- se ToolHolder più grande dell'utensile, il primo oggetto in collisione è il ToolHolder. Altrimenti il motore.
|
|
local dDimObjToCheck = EgtIf( TOOLS[i].ToolHolder.dDiameter > TOOLS[i].dDiameter, TOOLS[i].ToolHolder.dDiameter, TOOLS[i].SetupInfo.dCAxisEncumbrance)
|
|
local dCurrentMaxMatReduction = BeamData.COLL_SIC or 5
|
|
|
|
-- TODO implementare le funzioni di Tool Collision Avoidance (vedi wiki e FacesBysaw -> CalcLeadInOutPerpGeom)
|
|
-- TODO considerare anche il caso in cui lo stelo sia più grande del diametro utensile
|
|
-- TODO nei confronti tra valori gestire tolleranze
|
|
-- calcolo riduzione per non toccare con ToolHolder / Motore
|
|
if ToolEntryAngle.dValue > 0 and ToolEntryAngle.dValue < 90 then
|
|
dCurrentMaxMatReduction = dCurrentMaxMatReduction / ToolEntryAngle.dSin + ( ( dDimObjToCheck - TOOLS[i].dDiameter) / 2) / ToolEntryAngle.dTan
|
|
end
|
|
-- dCurrentResidualDepth = negativo -> mm extra disponibili, positivo -> limitare
|
|
local dCurrentResidualDepth = ToolSearchParameters.dElevation + dCurrentMaxMatReduction - TOOLS[i].dMaxDepth
|
|
|
|
-- se non ancora trovato, oppure se completo e il migliore fino ad ora non è completo: corrente è il migliore
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 0) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- altrimenti scelgo il migliore
|
|
else
|
|
-- se entrambi completi
|
|
if dBestToolResidualDepth <= 0 and dCurrentResidualDepth <= 0 then
|
|
-- se è presente una lista di utensili disponibili, si prende quello che arriva primo in quella lista
|
|
if ToolSearchParameters.AvailableToolList and ToolSearchParameters.AvailableToolList.bRespectListOrder then
|
|
if GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) and
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) <
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[nBestToolIndex].sName) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- se il migliore era su aggregato e corrente montanto direttamente, prediligo utensile montato direttamente
|
|
elseif not TOOLS[i].SetupInfo.bToolOnAggregate and TOOLS[nBestToolIndex].SetupInfo.bToolOnAggregate then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- se hanno stesso montaggio
|
|
elseif TOOLS[i].SetupInfo.bToolOnAggregate == TOOLS[nBestToolIndex].SetupInfo.bToolOnAggregate then
|
|
-- scelgo utensile con indice di bontà utensile calcolato come: lunghezza / massimo materiale / diametro
|
|
if TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
-- se entrambi incompleti
|
|
elseif dBestToolResidualDepth > 0 and dCurrentResidualDepth > 0 then
|
|
--scelgo quello che lavora di più
|
|
if dCurrentResidualDepth < dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo LAMA con certe caratteristiche
|
|
-- TODO da completare
|
|
-- TODO 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)
|
|
function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
|
|
-- parametri obbligatori
|
|
if type( ToolSearchParameters.vtN) ~= 'table' then
|
|
error( 'FindBlade : missing tool direction')
|
|
end
|
|
if type( ToolSearchParameters.bAllowTopHead) ~= 'boolean' then
|
|
error( 'FindBlade : missing top head info')
|
|
end
|
|
if type( ToolSearchParameters.bAllowBottomHead) ~= 'boolean' then
|
|
error( 'FindBlade : missing bottom head info')
|
|
end
|
|
if not ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
error( 'FindBlade : wrong head info')
|
|
end
|
|
|
|
-- parametri opzionali
|
|
ToolSearchParameters.dElevation = ToolSearchParameters.dElevation or 0
|
|
ToolSearchParameters.bForceLongcutBlade = ToolSearchParameters.bForceLongcutBlade or false
|
|
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
for i = 1, #TOOLS do
|
|
local bIsToolCompatible = false
|
|
|
|
if TOOLS[i].sFamily == 'SAWBLADE' then
|
|
if ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bTop
|
|
elseif ToolSearchParameters.bAllowBottomHead and not ToolSearchParameters.bAllowTopHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bBottom
|
|
else
|
|
bIsToolCompatible = true
|
|
end
|
|
end
|
|
|
|
-- check angolo limite lama
|
|
if TOOLS[i].SetupInfo.HeadType.bTop and ToolSearchParameters.vtN:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtN, TOOLS[i]) - GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
end
|
|
if TOOLS[i].SetupInfo.HeadType.bBottom and ToolSearchParameters.vtN:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtN, TOOLS[i]) + GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
-- se c'è una lista di utensili disponibili, si verifica che l'utensile attuale sia tra quelli
|
|
if ToolSearchParameters.AvailableToolList and not IsToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i]) then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
if bIsToolCompatible then
|
|
-- TODO gestire accorciamento massimo materiale per inclinazione
|
|
local dCurrentResidualDepth = ToolSearchParameters.dElevation - TOOLS[i].dMaxDepth
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
else
|
|
-- prediligo utensile per tagli lunghi, se richiesto
|
|
if ToolSearchParameters.bForceLongcutBlade and not TOOLS[nBestToolIndex].bIsUsedForLongCut and TOOLS[i].bIsUsedForLongCut then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
else
|
|
-- entrambi completi
|
|
if dBestToolResidualDepth <= 10 * GEO.EPS_SMALL and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL then
|
|
-- se è presente una lista di utensili disponibili, si prende quello che arriva primo in quella lista
|
|
if ToolSearchParameters.AvailableToolList and ToolSearchParameters.AvailableToolList.bRespectListOrder then
|
|
if GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) and
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) <
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[nBestToolIndex].sName) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- si sceglie quello con le performance migliori
|
|
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex + 10 * GEO.EPS_SMALL then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- entrambi incompleti
|
|
elseif dBestToolResidualDepth > 10 * GEO.EPS_SMALL and dCurrentResidualDepth > 10 * GEO.EPS_SMALL then
|
|
-- si sceglie quello che lavora di più
|
|
if dCurrentResidualDepth > dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo PUNTA A FORARE con certe caratteristiche
|
|
function MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
|
|
-- settio valori obbligatori
|
|
if not ToolSearchParameters.dToolDiameter then
|
|
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam or 0
|
|
end
|
|
if not ToolSearchParameters.dMaxToolDiameter then
|
|
ToolSearchParameters.dMaxToolDiameter = ToolSearchParameters.dToolDiameter + ( ToolSearchParameters.dDiameterTolerance or ( 100 * GEO.EPS_SMALL))
|
|
end
|
|
if not ToolSearchParameters.dMinToolDiameter then
|
|
ToolSearchParameters.dMinToolDiameter = ToolSearchParameters.dToolDiameter - ( ToolSearchParameters.dDiameterTolerance or ( 100 * GEO.EPS_SMALL))
|
|
end
|
|
|
|
for i = 1, #TOOLS do
|
|
-- prima verifico che utensile sia compatibile
|
|
local bIsToolCompatible = true
|
|
-- se non è punta, non è compatibile
|
|
if TOOLS[i].sFamily ~= 'DRILLBIT' then
|
|
bIsToolCompatible = false
|
|
-- se viene passato il nome, tutti gli altri sono incompatibili
|
|
elseif ToolSearchParameters.sName and ToolSearchParameters.sName ~= TOOLS[i].sName then
|
|
bIsToolCompatible = false
|
|
-- se c'è una lista di utensili disponibili, si verifica che l'utensile attuale sia tra quelli
|
|
elseif ToolSearchParameters.AvailableToolList and not IsToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i]) then
|
|
bIsToolCompatible = false
|
|
-- controlli standard
|
|
elseif TOOLS[i].dDiameter > ToolSearchParameters.dMaxToolDiameter then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].dDiameter < ToolSearchParameters.dMinToolDiameter then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].SetupInfo.HeadType.bTop and
|
|
ToolSearchParameters.vtToolDirection:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtToolDirection, TOOLS[i]) - GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].SetupInfo.HeadType.bBottom and
|
|
ToolSearchParameters.vtToolDirection:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtToolDirection, TOOLS[i]) + GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
-- scelgo il migliore
|
|
if bIsToolCompatible then
|
|
-- calcolo riduzione del massimo materiale utilizzabile
|
|
local ToolEntryAngle = GetToolEntryAngle( Proc, ToolSearchParameters.vtToolDirection)
|
|
-- se ToolHolder più grande dell'utensile, il primo oggetto in collisione è il ToolHolder. Altrimenti il motore.
|
|
local dDimObjToCheck = EgtIf( TOOLS[i].ToolHolder.dDiameter > TOOLS[i].dDiameter, TOOLS[i].ToolHolder.dDiameter, TOOLS[i].SetupInfo.dCAxisEncumbrance)
|
|
local dCurrentMaxMatReduction = BeamData.COLL_SIC or 5
|
|
|
|
-- TODO implementare le funzioni di Tool Collision Avoidance (vedi wiki e FacesBysaw -> CalcLeadInOutPerpGeom)
|
|
-- TODO considerare anche il caso in cui lo stelo sia più grande del diametro utensile
|
|
-- calcolo riduzione per non toccare con ToolHolder / Motore
|
|
if ToolEntryAngle.dValue > 0 and ToolEntryAngle.dValue < 90 then
|
|
dCurrentMaxMatReduction = dCurrentMaxMatReduction / ToolEntryAngle.dSin + ( ( dDimObjToCheck - TOOLS[i].dDiameter) / 2) / ToolEntryAngle.dTan
|
|
end
|
|
-- dCurrentResidualDepth = negativo -> mm extra disponibili, positivo -> limitare
|
|
local dCurrentResidualDepth = ToolSearchParameters.dElevation + dCurrentMaxMatReduction - TOOLS[i].dMaxDepth
|
|
|
|
-- se non ancora trovato, oppure se completo e il migliore fino ad ora non è completo: corrente è il migliore
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 0) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- altrimenti scelgo il migliore
|
|
else
|
|
-- se entrambi completi
|
|
if dBestToolResidualDepth <= 0 and dCurrentResidualDepth <= 0 then
|
|
-- se il migliore era su aggregato e corrente montanto direttamente, prediligo utensile montato direttamente
|
|
if not TOOLS[i].SetupInfo.bToolOnAggregate and TOOLS[nBestToolIndex].SetupInfo.bToolOnAggregate then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- se hanno stesso montaggio
|
|
elseif TOOLS[i].SetupInfo.bToolOnAggregate == TOOLS[nBestToolIndex].SetupInfo.bToolOnAggregate then
|
|
-- se diametro diverso
|
|
if abs( TOOLS[i].dDiameter - TOOLS[nBestToolIndex].dDiameter) > 10 * GEO.EPS_SMALL then
|
|
-- si sceglie utensile con diametro più simile al foro da lavorare
|
|
if abs( TOOLS[i].dDiameter - ToolSearchParameters.dToolDiameter) < abs( TOOLS[nBestToolIndex].dDiameter - ToolSearchParameters.dToolDiameter) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- se è presente una lista di utensili disponibili, si prende quello che arriva primo in quella lista
|
|
elseif ToolSearchParameters.AvailableToolList and ToolSearchParameters.AvailableToolList.bRespectListOrder then
|
|
if GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) and
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) <
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[nBestToolIndex].sName) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- oppure utensile con performance maggiore
|
|
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex then
|
|
nBestToolIndex = i
|
|
BestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- scelgo utensile con indice di bontà utensile calcolato come: lunghezza / massimo materiale / diametro
|
|
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
-- se entrambi incompleti
|
|
elseif dBestToolResidualDepth > 0 and dCurrentResidualDepth > 0 then
|
|
--scelgo quello che lavora di più
|
|
if dCurrentResidualDepth < dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
-- si salva se la punta ha lo stesso diametro del foro
|
|
if nBestToolIndex and TOOLS[nBestToolIndex].dDiameter - ToolSearchParameters.dToolDiameter > 100 * GEO.EPS_SMALL then
|
|
ToolInfo.bDrillIsExactDiameter = true
|
|
end
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo SEGA A CATENA con certe caratteristiche
|
|
-- TODO da completare
|
|
function MachiningLib.FindChainSaw( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
|
|
-- parametri obbligatori
|
|
if type( ToolSearchParameters.vtToolDirection) ~= 'table' then
|
|
error( 'FindChainSaw : missing tool direction')
|
|
end
|
|
if type( ToolSearchParameters.bAllowTopHead) ~= 'boolean' then
|
|
error( 'FindChainSaw : missing top head info')
|
|
end
|
|
if type( ToolSearchParameters.bAllowBottomHead) ~= 'boolean' then
|
|
error( 'FindChainSaw : missing bottom head info')
|
|
end
|
|
if not ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
error( 'FindChainSaw : wrong head info')
|
|
end
|
|
|
|
-- parametri opzionali
|
|
ToolSearchParameters.dElevation = ToolSearchParameters.dElevation or 0
|
|
ToolSearchParameters.bExtendWithCornerRadius = ToolSearchParameters.bExtendWithCornerRadius or false
|
|
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
for i = 1, #TOOLS do
|
|
local bIsToolCompatible = false
|
|
|
|
if TOOLS[i].sFamily == 'MORTISE' then
|
|
if ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bTop
|
|
elseif ToolSearchParameters.bAllowBottomHead and not ToolSearchParameters.bAllowTopHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bBottom
|
|
else
|
|
bIsToolCompatible = true
|
|
end
|
|
end
|
|
|
|
-- se c'è una lista di utensili disponibili, si verifica che l'utensile attuale sia tra quelli
|
|
if ToolSearchParameters.AvailableToolList and not IsToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i]) then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
-- TODO nei confronti tra valori gestire tolleranze
|
|
if bIsToolCompatible then
|
|
if ToolSearchParameters.dElevation > 10 * GEO.EPS_SMALL and ToolSearchParameters.bExtendWithCornerRadius then
|
|
ToolSearchParameters.dElevation = ToolSearchParameters.dElevation + TOOLS[i].dCornerRadius
|
|
end
|
|
-- TODO gestire accorciamento massimo materiale per inclinazione
|
|
local dCurrentResidualDepth = ToolSearchParameters.dElevation - TOOLS[i].dMaxDepth
|
|
-- se non ancora trovato, oppure se completo e il migliore fino ad ora non è completo: corrente è il migliore
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 0) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
-- altrimenti scelgo il migliore
|
|
else
|
|
-- se entrambi completi
|
|
if dBestToolResidualDepth <= 0 and dCurrentResidualDepth <= 0 then
|
|
-- se è presente una lista di utensili disponibili, si prende quello che arriva primo in quella lista
|
|
if ToolSearchParameters.AvailableToolList and ToolSearchParameters.AvailableToolList.bRespectListOrder then
|
|
if GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) and
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[i].sName) <
|
|
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[nBestToolIndex].sName) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- scelgo utensile con rapporto lunghezza / diametro minore
|
|
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- se entrambi incompleti
|
|
elseif dBestToolResidualDepth > 10 * GEO.EPS_SMALL and dCurrentResidualDepth > 10 * GEO.EPS_SMALL then
|
|
--scelgo quello che lavora di più
|
|
if dCurrentResidualDepth > dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.GetAvailableToolList( Proc, sToolList, sType)
|
|
local ToolList = {}
|
|
-- se ci sono strategie disponibili (dovrebbe essere sempre vero dato che la funzione è chiamata proprio da una strategia)
|
|
if Proc.AvailableStrategies and #Proc.AvailableStrategies > 0 then
|
|
-- se è una strategia di base, ci deve essere per forza una lista utensili passata
|
|
if Proc.AvailableStrategies.bIsBasicStrategy then
|
|
ToolList = BCS.GetToolsFromMachiningDataFile( Proc, sType)
|
|
-- se arriva da JSON o NGE
|
|
else
|
|
if sToolList and #sToolList > 0 then
|
|
-- Lista definita come: "UUID_1,Nome_1;UUID_2,Nome_2;UUID_3,Nome_3"
|
|
local Tool = EgtSplitString( sToolList, ';')
|
|
for i = 1, #Tool do
|
|
local ToolData = EgtSplitString( Tool[i])
|
|
table.insert( ToolList, { sUUID = ToolData[1], sName = ToolData[2]} )
|
|
end
|
|
-- se non ci sono utensili forzati, annullo lista per cercare tra tutti quelli disponibili in modo automatico
|
|
else
|
|
ToolList = nil
|
|
end
|
|
end
|
|
end
|
|
return ToolList
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.InitMachiningParameters( nMachiningType)
|
|
local Machining = {}
|
|
|
|
Machining.nType = nMachiningType
|
|
Machining.sDepth = 0
|
|
Machining.bInvert = false
|
|
Machining.nSCC = MCH_SCC.NONE
|
|
Machining.bToolInvert = false
|
|
Machining.sBlockedAxis = ''
|
|
Machining.sInitialAngles = ''
|
|
Machining.dOverlap = 0
|
|
Machining.dSideAngle = 0
|
|
Machining.dStartSafetyLength = BeamData.COLL_SIC
|
|
Machining.dRadialOffset = 0
|
|
Machining.dLongitudinalOffset = 0
|
|
Machining.sUserNotes = ''
|
|
Machining.Steps = {}
|
|
Machining.Steps.dStep = 0
|
|
Machining.Steps.dSideStep = 0
|
|
|
|
if nMachiningType == MCH_MY.MILLING then
|
|
Machining.nWorkside = MCH_MILL_WS.LEFT
|
|
Machining.nFaceuse = MCH_MILL_FU.NONE
|
|
Machining.Steps.nStepType = MCH_MILL_ST.ONEWAY
|
|
Machining.LeadIn = {}
|
|
Machining.LeadIn.nType = MCH_MILL_LI.LINEAR
|
|
Machining.LeadIn.dStartAddLength = 0
|
|
Machining.LeadIn.dTangentDistance = 0
|
|
Machining.LeadIn.dPerpDistance = 0
|
|
Machining.LeadIn.dElevation = 0
|
|
Machining.LeadIn.dCompLength = 0
|
|
Machining.LeadOut = {}
|
|
Machining.LeadOut.nType = MCH_MILL_LO.LINEAR
|
|
Machining.LeadOut.dEndAddLength = 0
|
|
Machining.LeadOut.dTangentDistance = 0
|
|
Machining.LeadOut.dPerpDistance = 0
|
|
Machining.LeadOut.dElevation = 0
|
|
Machining.LeadOut.dCompLength = 0
|
|
|
|
elseif nMachiningType == MCH_MY.MORTISING then
|
|
Machining.nWorkside = MCH_MORTISE_WS.LEFT
|
|
Machining.nFaceuse = MCH_MORTISE_FU.NONE
|
|
Machining.Steps.nStepType = MCH_MORTISE_ST.ONEWAY
|
|
Machining.LeadIn = {}
|
|
Machining.LeadIn.dStartAddLength = 0
|
|
Machining.LeadOut = {}
|
|
Machining.LeadOut.dEndAddLength = 0
|
|
|
|
elseif nMachiningType == MCH_MY.DRILLING then
|
|
Machining.dReturnPos = 0
|
|
Machining.dStartSlowLen = 0
|
|
Machining.dEndSlowLen = 0
|
|
Machining.dThrouAddLen = 5
|
|
|
|
elseif nMachiningType == MCH_MY.POCKETING then
|
|
Machining.nSubType = MCH_POCK_SUB.ONEWAY
|
|
Machining.LeadIn = {}
|
|
Machining.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
|
Machining.LeadIn.dTangentDistance = 0
|
|
Machining.LeadIn.dElevation = 0
|
|
Machining.LeadOut = {}
|
|
Machining.LeadOut.nType = MCH_POCK_LO.NONE
|
|
Machining.LeadOut.dTangentDistance = 0
|
|
|
|
elseif nMachiningType == MCH_MY.SAWING then
|
|
-- TODO da completare
|
|
Machining.nWorkside = MCH_SAW_WS.CENTER
|
|
Machining.nHeadSide = MCH_SAW_HS.LEFT
|
|
Machining.Steps.nStepType = MCH_SAW_ST.ONEWAY
|
|
Machining.LeadIn.nType = MCH_SAW_LI.CENT
|
|
Machining.LeadOut.nType = MCH_SAW_LO.CENT
|
|
|
|
else
|
|
error( 'InitMachiningParameters : unknown machining type')
|
|
end
|
|
|
|
return Machining
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- salva in lista globale la lavorazione appena calcolata
|
|
local function AddNewMachining( ProcToAdd, MachiningToAdd, AuxiliaryDataToAdd)
|
|
-- Controllo parametri obbligatori
|
|
if not MachiningToAdd.nType or not MachiningToAdd.nToolIndex or not MachiningToAdd.Geometry or not ProcToAdd.id then
|
|
return false
|
|
end
|
|
|
|
-- se nome non definito, assegno alla lavorazioen un nome standard
|
|
if not MachiningToAdd.sOperationName then
|
|
-- Drilling
|
|
if MachiningToAdd.nType == MCH_MY.DRILLING then
|
|
MachiningToAdd.sTypeName = 'Drill_'
|
|
-- Milling
|
|
elseif MachiningToAdd.nType == MCH_MY.MILLING then
|
|
-- se utensile lama
|
|
if TOOLS[MachiningToAdd.nToolIndex].sFamily == 'SAWBLADE' then
|
|
MachiningToAdd.sTypeName = 'Cut_'
|
|
else
|
|
MachiningToAdd.sTypeName = 'Mill_'
|
|
end
|
|
-- Pocketing
|
|
elseif MachiningToAdd.nType == MCH_MY.POCKETING then
|
|
MachiningToAdd.sTypeName = 'Pocket_'
|
|
-- Mortising
|
|
elseif MachiningToAdd.nType == MCH_MY.MORTISING then
|
|
MachiningToAdd.sTypeName = 'ChSaw_'
|
|
end
|
|
MachiningToAdd.sOperationName = MachiningToAdd.sTypeName .. ( EgtGetName( ProcToAdd.id) or tostring( ProcToAdd.id)) -- .. '_' .. tostring( MachiningToAdd.Geometry)
|
|
end
|
|
if not MachiningToAdd.sToolName then
|
|
MachiningToAdd.sToolName = TOOLS[MachiningToAdd.nToolIndex].sName
|
|
end
|
|
local Machining = {}
|
|
Machining.Proc = ProcToAdd
|
|
Machining.Machining = MachiningToAdd
|
|
Machining.AuxiliaryData = AuxiliaryDataToAdd or {}
|
|
table.insert( MACHININGS, Machining)
|
|
|
|
-- aggiornamento info generiche lavorazioni
|
|
local nHeadCutRotation
|
|
if ProcToAdd.bDown then
|
|
nHeadCutRotation = 3
|
|
elseif ProcToAdd.bSide then
|
|
nHeadCutRotation = 2
|
|
else
|
|
nHeadCutRotation = 1
|
|
end
|
|
MACHININGS.Info.nHeadCutRotation = max( MACHININGS.Info.nHeadCutRotation or 0, nHeadCutRotation)
|
|
|
|
local nSplitCutRotation
|
|
if ProcToAdd.bDown and MachiningToAdd.sStage == 'AfterTail' then
|
|
nSplitCutRotation = 3
|
|
elseif ProcToAdd.bSide and MachiningToAdd.sStage == 'AfterTail' then
|
|
nSplitCutRotation = 2
|
|
else
|
|
nSplitCutRotation = 1
|
|
end
|
|
MACHININGS.Info.nSplitCutRotation = max( MACHININGS.Info.nSplitCutRotation or 0, nSplitCutRotation)
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- TODO funziona solo con attacco perpendicolare - da aggiungere gestione in caso di attacco tangenziale
|
|
function MachiningLib.AddMachinings( Proc, Machining, AuxiliaryData)
|
|
local bMachiningAdded = false
|
|
local NewAuxiliaryData = {}
|
|
|
|
-- se esistono i dati ausiliari li copio in locale perchè il parametro è una tabella per riferimento
|
|
if AuxiliaryData then
|
|
NewAuxiliaryData = BeamLib.TableCopyDeep( AuxiliaryData)
|
|
end
|
|
|
|
if Machining.CloneStepsRadial and Machining.CloneStepsRadial.nCount > 1 then
|
|
NewAuxiliaryData.Clones = {}
|
|
|
|
local dOriginalRadialOffset = Machining.dRadialOffset
|
|
local dOriginalLeadInPerpDistance = Machining.LeadIn.dPerpDistance
|
|
local dOriginalLeadOutPerpDistance = Machining.LeadOut.dPerpDistance
|
|
for i = 1, Machining.CloneStepsRadial.nCount do
|
|
NewAuxiliaryData.Clones[i] = {}
|
|
NewAuxiliaryData.Clones[i].dRadialOffset = dOriginalRadialOffset + Machining.CloneStepsRadial.dStep * ( Machining.CloneStepsRadial.nCount - i)
|
|
-- update distanza perpendicolare attacco per contemplare l'offset applicato
|
|
if abs( dOriginalLeadInPerpDistance) > 10 * GEO.EPS_SMALL and abs( dOriginalLeadOutPerpDistance) > 10 * GEO.EPS_SMALL then
|
|
NewAuxiliaryData.Clones[i].LeadIn = {}
|
|
NewAuxiliaryData.Clones[i].LeadOut = {}
|
|
NewAuxiliaryData.Clones[i].LeadIn.dPerpDistance = dOriginalLeadInPerpDistance - NewAuxiliaryData.Clones[i].dRadialOffset + dOriginalRadialOffset
|
|
NewAuxiliaryData.Clones[i].LeadOut.dPerpDistance = dOriginalLeadOutPerpDistance - NewAuxiliaryData.Clones[i].dRadialOffset + dOriginalRadialOffset
|
|
end
|
|
end
|
|
elseif Machining.CloneStepsLongitudinal and Machining.CloneStepsLongitudinal.nCount > 1 then
|
|
NewAuxiliaryData.Clones = {}
|
|
|
|
local dOriginalRadialOffset = Machining.dRadialOffset
|
|
for i = Machining.CloneStepsLongitudinal.nCount, 1, -1 do
|
|
NewAuxiliaryData.Clones[i] = {}
|
|
NewAuxiliaryData.Clones[i].dRadialOffset = dOriginalRadialOffset + Machining.CloneStepsLongitudinal.dStep * ( i - 1)
|
|
end
|
|
end
|
|
|
|
bMachiningAdded = AddNewMachining( Proc, Machining, NewAuxiliaryData)
|
|
|
|
return bMachiningAdded
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per aggiungere una nuova lavorazione
|
|
function MachiningLib.AddOperations( vProc, Part, sRotation)
|
|
local nErr
|
|
local sErr = ''
|
|
local bAreAllMachiningApplyOk = true
|
|
local bSplitExecuted = false
|
|
|
|
-- parametri generali lavorazione
|
|
local MachiningParameters = {
|
|
{ sName = 'sDepth', nMchParam = MCH_MP.DEPTH_STR},
|
|
{ sName = 'bInvert', nMchParam = MCH_MP.INVERT},
|
|
{ sName = 'nWorkside', nMchParam = MCH_MP.WORKSIDE},
|
|
{ sName = 'nFaceuse', nMchParam = MCH_MP.FACEUSE},
|
|
{ sName = 'nSCC', nMchParam = MCH_MP.SCC},
|
|
{ sName = 'bToolInvert', nMchParam = MCH_MP.TOOLINVERT},
|
|
{ sName = 'sBlockedAxis', nMchParam = MCH_MP.BLOCKEDAXIS},
|
|
{ sName = 'sInitialAngles', nMchParam = MCH_MP.INITANGS},
|
|
{ sName = 'nHeadSide', nMchParam = MCH_MP.HEADSIDE},
|
|
{ sName = 'nSubType', nMchParam = MCH_MP.SUBTYPE},
|
|
{ sName = 'dOverlap', nMchParam = MCH_MP.OVERL},
|
|
{ sName = 'dSideAngle', nMchParam = MCH_MP.SIDEANGLE},
|
|
{ sName = 'dStartSafetyLength', nMchParam = MCH_MP.STARTPOS},
|
|
{ sName = 'dReturnPos', nMchParam = MCH_MP.RETURNPOS},
|
|
{ sName = 'dRadialOffset', nMchParam = MCH_MP.OFFSR},
|
|
{ sName = 'dLongitudinalOffset', nMchParam = MCH_MP.OFFSL},
|
|
{ sName = 'dStartSlowLen', nMchParam = MCH_MP.STARTSLOWLEN},
|
|
{ sName = 'dEndSlowLen', nMchParam = MCH_MP.ENDSLOWLEN},
|
|
{ sName = 'dThrouAddLen', nMchParam = MCH_MP.THROUADDLEN},
|
|
{ sName = 'sSystemNotes', nMchParam = MCH_MP.SYSNOTES},
|
|
{ sName = 'sUserNotes', nMchParam = MCH_MP.USERNOTES}
|
|
}
|
|
|
|
-- parametri relativi allo step
|
|
MachiningParameters.Steps = {
|
|
{ sName = 'nStepType', nMchParam = MCH_MP.STEPTYPE},
|
|
{ sName = 'dStep', nMchParam = MCH_MP.STEP},
|
|
{ sName = 'dSideStep', nMchParam = MCH_MP.SIDESTEP}
|
|
}
|
|
|
|
-- parametri relativi all'approccio
|
|
MachiningParameters.LeadIn = {
|
|
{ sName = 'nType', nMchParam = MCH_MP.LEADINTYPE},
|
|
{ sName = 'dStartAddLength', nMchParam = MCH_MP.STARTADDLEN},
|
|
{ sName = 'dTangentDistance', nMchParam = MCH_MP.LITANG},
|
|
{ sName = 'dPerpDistance', nMchParam = MCH_MP.LIPERP},
|
|
{ sName = 'dElevation', nMchParam = MCH_MP.LIELEV},
|
|
{ sName = 'dCompLength', nMchParam = MCH_MP.LICOMPLEN}
|
|
}
|
|
|
|
-- parametri relativi alla retrazione
|
|
MachiningParameters.LeadOut = {
|
|
{ sName = 'nType', nMchParam = MCH_MP.LEADOUTTYPE},
|
|
{ sName = 'dEndAddLength', nMchParam = MCH_MP.ENDADDLEN},
|
|
{ sName = 'dTangentDistance', nMchParam = MCH_MP.LOTANG},
|
|
{ sName = 'dPerpDistance', nMchParam = MCH_MP.LOPERP},
|
|
{ sName = 'dElevation', nMchParam = MCH_MP.LOELEV},
|
|
{ sName = 'dCompLength', nMchParam = MCH_MP.LOCOMPLEN}
|
|
}
|
|
|
|
-- parametri da scrivere nelle note utente
|
|
local UserNotes = {
|
|
{ sName = 'dMaxElev', sMchParam = 'MaxElev'},
|
|
{ sName = 'dOpenMinSafe', sMchParam = 'OpenMinSafe'},
|
|
{ sName = 'nVMRS', sMchParam = 'VMRS'},
|
|
{ sName = 'dStartZmax', sMchParam = 'StartZmax'},
|
|
{ sName = 'nOutRaw', sMchParam = 'OutRaw'},
|
|
{ sName = 'nOpenOutRaw', sMchParam = 'OpenOutRaw'},
|
|
{ sName = 'nPlunge', sMchParam = 'Plunge'},
|
|
{ sName = 'vtFaceUse', sMchParam = 'VtFaceUse'},
|
|
{ sName = 'nEdgesFaceUse', sMchParam = 'EdgesFaceUse'}
|
|
}
|
|
|
|
-- parametri da scrivere nelle note di sistema
|
|
local SystemNotes = {
|
|
}
|
|
|
|
for i = 1, #MACHININGS do
|
|
-- si aggiungono solo quelle della fase richiesta
|
|
if ( sRotation == 'STD' and not MACHININGS[i].Proc.bDown and not MACHININGS[i].Proc.bSide) or
|
|
( MACHININGS[i].Proc.bDown and sRotation == 'DOWN') or
|
|
( MACHININGS[i].Proc.bSide and sRotation == 'SIDE') then
|
|
local nClonesToAdd = 1
|
|
if MACHININGS[i].AuxiliaryData.Clones then
|
|
nClonesToAdd = #MACHININGS[i].AuxiliaryData.Clones
|
|
end
|
|
for j = 1, nClonesToAdd do
|
|
-- creazione lavorazione
|
|
local nOperationId = EgtCreateMachining( MACHININGS[i].Machining.sOperationName, MACHININGS[i].Machining.nType, MACHININGS[i].Machining.sToolName)
|
|
|
|
if nOperationId then
|
|
-- impostazione geometria
|
|
local Geometry
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].Geometry then
|
|
Geometry = MACHININGS[i].AuxiliaryData.Clones[j].Geometry
|
|
elseif MACHININGS[i].Machining.Geometry then
|
|
Geometry = MACHININGS[i].Machining.Geometry
|
|
end
|
|
EgtSetMachiningGeometry( Geometry)
|
|
|
|
-- si scrive info pezzo e feature su geometria lavorazione
|
|
if Geometry then
|
|
EgtSetInfo( Geometry[1][1], 'CUTID', MACHININGS[i].Proc.idCut)
|
|
EgtSetInfo( Geometry[1][1], 'TASKID', MACHININGS[i].Proc.idTask)
|
|
end
|
|
|
|
-- impostazione parametri lavorazione
|
|
-- TODO scrivere sempre Steps, LeadIn, LeadOut nelle tabelle in modo da non dover controllare ogni volta che ci siano
|
|
for k = 1, #MachiningParameters do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][MachiningParameters[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][MachiningParameters[k].sName]
|
|
elseif MACHININGS[i].Machining[MachiningParameters[k].sName] then
|
|
sValue = MACHININGS[i].Machining[MachiningParameters[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.Steps do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].Steps and MACHININGS[i].AuxiliaryData.Clones[j].Steps[MachiningParameters.Steps[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].Steps[MachiningParameters.Steps[k].sName]
|
|
elseif MACHININGS[i].Machining.Steps and MACHININGS[i].Machining.Steps[MachiningParameters.Steps[k].sName] then
|
|
sValue = MACHININGS[i].Machining.Steps[MachiningParameters.Steps[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.Steps[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.LeadIn do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].LeadIn and MACHININGS[i].AuxiliaryData.Clones[j].LeadIn[MachiningParameters.LeadIn[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].LeadIn[MachiningParameters.LeadIn[k].sName]
|
|
elseif MACHININGS[i].Machining.LeadIn and MACHININGS[i].Machining.LeadIn[MachiningParameters.LeadIn[k].sName] then
|
|
sValue = MACHININGS[i].Machining.LeadIn[MachiningParameters.LeadIn[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.LeadIn[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.LeadOut do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].LeadOut and MACHININGS[i].AuxiliaryData.Clones[j].LeadOut[MachiningParameters.LeadOut[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].LeadOut[MachiningParameters.LeadOut[k].sName]
|
|
elseif MACHININGS[i].Machining.LeadOut and MACHININGS[i].Machining.LeadOut[MachiningParameters.LeadOut[k].sName] then
|
|
sValue = MACHININGS[i].Machining.LeadOut[MachiningParameters.LeadOut[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.LeadOut[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #UserNotes do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][UserNotes[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][UserNotes[k].sName]
|
|
elseif MACHININGS[i].Machining[UserNotes[k].sName] then
|
|
sValue = MACHININGS[i].Machining[UserNotes[k].sName]
|
|
end
|
|
if sValue then
|
|
local sUserNotes = ''
|
|
sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES)
|
|
sUserNotes = EgtSetValInNotes( sUserNotes, UserNotes[k].sMchParam, sValue)
|
|
EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes)
|
|
end
|
|
end
|
|
-- parametri da settare nelle note di sistema
|
|
-- TODO da decidere quali sono le note da salvare qui. Probabilmente tutte quelle relative all'ordine delle lavorazioni
|
|
--if MACHININGS[i].Machining.nMachiningOrder then
|
|
-- sSystemNotes = EgtSetValInNotes( sSystemNotes, 'MachiningOrder', MACHININGS[i].Machining.nMachiningOrder)
|
|
--end
|
|
for k = 1, #SystemNotes do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][SystemNotes[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][SystemNotes[k].sName]
|
|
elseif MACHININGS[i].Machining[SystemNotes[k].sName] then
|
|
sValue = MACHININGS[i].Machining[SystemNotes[k].sName]
|
|
end
|
|
if sValue then
|
|
local sSystemNotes = ''
|
|
sSystemNotes = EgtGetMachiningParam( MCH_MP.SYSNOTES)
|
|
sSystemNotes = EgtSetValInNotes( sSystemNotes, SystemNotes[k].sMchParam, sValue)
|
|
EgtSetMachiningParam( MCH_MP.SYSNOTES, sSystemNotes)
|
|
end
|
|
end
|
|
|
|
local bIsApplyOk = MachiningLib.ApplyMachining( true, false)
|
|
if not bIsApplyOk then
|
|
bAreAllMachiningApplyOk = false
|
|
nErr, sErr = EgtGetLastMachMgrError()
|
|
EgtSetOperationMode( nOperationId, false)
|
|
-- update risultati
|
|
-- TODO è corretto mettere non applicabile????? disattivare e dare un'incompleta gialla?
|
|
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.sStatus = 'Not-Applicable'
|
|
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.sApplyInfo = sErr
|
|
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.nApplyError = nErr
|
|
-- se non deve essere igniorato, si salva ingombro lavorazione attuale e fasi successive
|
|
elseif not MACHININGS[i].AuxiliaryData.bIgnoreNotClampableLength then
|
|
-- salvo ingombro non pinzabile testa/coda
|
|
local nCurrRotation = MACHININGS[i].Proc.nIndexRotation
|
|
local dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nCurrRotation)
|
|
Part.NotClampableLength[sRotation].dHead = max( Part.NotClampableLength[sRotation].dHead, dNotClampHead)
|
|
Part.NotClampableLength[sRotation].dTail = max( Part.NotClampableLength[sRotation].dTail, dNotClampTail)
|
|
|
|
if sRotation == 'DOWN' then
|
|
local nNextRotation = EgtIf( nCurrRotation - 1 < 1, nCurrRotation - 1 + 4, nCurrRotation - 1)
|
|
-- se rotazione attiva (SIDE)
|
|
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
|
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
|
Part.NotClampableLength['SIDE'].dHead = max( Part.NotClampableLength['SIDE'].dHead, dNotClampHead)
|
|
Part.NotClampableLength['SIDE'].dTail = max( Part.NotClampableLength['SIDE'].dTail, dNotClampTail)
|
|
end
|
|
nNextRotation = EgtIf( nNextRotation - 1 < 1, nNextRotation - 1 + 4, nNextRotation - 1)
|
|
-- se rotazione attiva (STD)
|
|
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
|
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
|
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
|
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
|
end
|
|
elseif sRotation == 'SIDE' then
|
|
local nNextRotation = EgtIf( nCurrRotation - 1 < 1, nCurrRotation - 1 + 4, nCurrRotation - 1)
|
|
-- se rotazione attiva (STD)
|
|
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
|
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
|
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
|
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
|
end
|
|
end
|
|
end
|
|
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.bIsApplyOk = bIsApplyOk
|
|
|
|
-- TODO è giusto inserire queste info alla fine della lavorazione? oppure conviene creare un record in MACHININGS apposito per la disposizione?
|
|
-- se era taglio di separazione, aggiungo nuova fase
|
|
if MACHININGS[i].AuxiliaryData.bIsSplitOrCut then
|
|
bSplitExecuted = true
|
|
MACHININGS.Info.bSplitExecuted = true
|
|
|
|
BeamLib.AddPhaseWithRawParts( MACHININGS[i].Proc.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET)
|
|
-- se grezzo successivo senza pezzi e finale, va tolto
|
|
local nNextRawId = EgtGetNextRawPart( MACHININGS[i].Proc.idRaw)
|
|
if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BeamData.dMinRaw then
|
|
EgtRemoveRawPartFromCurrPhase( nNextRawId)
|
|
end
|
|
MACHININGS.Info.bSplitPhase = EgtGetCurrPhase()
|
|
|
|
-- se combinazione prevede inversione, si gira il pezzo
|
|
if Part.bPartInCombiIsInverted and not Part.bIsInverted then
|
|
BeamLib.InvertRawPart( Part, 2)
|
|
end
|
|
|
|
local nPhase = EgtGetCurrPhase()
|
|
local idDisp = EgtGetPhaseDisposition( nPhase)
|
|
|
|
if sRotation == 'DOWN' then
|
|
local nRotation = EgtIf( Part.nInitialPosition + 2 > 4, Part.nInitialPosition + 2 - 4, Part.nInitialPosition + 2) - 1
|
|
BeamLib.RotateRawPart( Part, nRotation)
|
|
EgtSetInfo( idDisp, 'ROT', -2)
|
|
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
|
elseif sRotation == 'SIDE' then
|
|
local nRotation = EgtIf( Part.nInitialPosition + 1 > 4, Part.nInitialPosition + 1 - 4, Part.nInitialPosition + 1) - 1
|
|
BeamLib.RotateRawPart( Part, nRotation)
|
|
EgtSetInfo( idDisp, 'ROT', -1)
|
|
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
|
else
|
|
local nRotation = Part.nInitialPosition - 1
|
|
BeamLib.RotateRawPart( Part, nRotation)
|
|
EgtSetInfo( idDisp, 'TYPE', 'END')
|
|
end
|
|
EgtSetInfo( idDisp, 'ORD', MACHININGS[i].Proc.nIndexPartInParts)
|
|
end
|
|
else
|
|
return false, 'UNEXPECTED ERROR: Error on creating machining', bSplitExecuted
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- si settano aree non pinzabili testa/coda
|
|
local nPhase = EgtGetCurrPhase()
|
|
local idDisp = EgtGetPhaseDisposition( nPhase)
|
|
EgtSetInfo( idDisp, 'HCING', Part.NotClampableLength[sRotation].dHead or 0)
|
|
EgtSetInfo( idDisp, 'TCING', Part.NotClampableLength[sRotation].dTail or 0)
|
|
-- se è la fase della separazione, setto gli stessi dati anche sulla fase precedente
|
|
if MACHININGS.Info.bSplitPhase == nPhase then
|
|
idDisp = EgtGetPhaseDisposition( nPhase - 1)
|
|
EgtSetInfo( idDisp, 'HCING', Part.NotClampableLength[sRotation].dHead or 0)
|
|
EgtSetInfo( idDisp, 'TCING', Part.NotClampableLength[sRotation].dTail or 0)
|
|
end
|
|
|
|
return bAreAllMachiningApplyOk, sErr, bSplitExecuted
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.ApplyMachining( bRecalc, bApplyPost)
|
|
local bResult = EgtApplyMachining( bRecalc, bApplyPost)
|
|
|
|
return bResult
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che restituisce l'indice MRR (Material Removal Rate) della strategia. Dati in ingresso: Step, SideStep, Feed, ToolIndex, MachiningType
|
|
function MachiningLib.GetToolMRR( Parameters)
|
|
local dMRR = 1
|
|
|
|
-- se ho già tutti i parametri
|
|
if not Parameters.dStep or not Parameters.dSideStep or not Parameters.dFeed then
|
|
-- se manca qualche parametro, lo recupero da parametro di default dell'utensile
|
|
if Parameters.nToolIndex then
|
|
Parameters.dStep = Parameters.dStep or TOOLS[Parameters.nToolIndex].dStep
|
|
Parameters.dSideStep = Parameters.dSideStep or TOOLS[Parameters.nToolIndex].dSideStep
|
|
Parameters.dFeed = Parameters.dFeed or TOOLS[Parameters.nToolIndex].Feeds.dFeed
|
|
-- se non riesco a calcolare, ritorno un indice molto basso
|
|
else
|
|
return GEO.EPS_SMALL
|
|
end
|
|
end
|
|
|
|
dMRR = Parameters.dStep * Parameters.dSideStep * Parameters.dFeed
|
|
|
|
-- Unità: dm/min per avere un indice vicino alle unità
|
|
return dMRR / pow( 10, 6)
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
|
local dLengthToMachineAllStepsWithLeadInOut = 0
|
|
local dTimeToMachineTotal = 0
|
|
local dToolStartFeed = TOOLS[Machining.nToolIndex].Feeds.dStartFeed
|
|
local dToolEndFeed = TOOLS[Machining.nToolIndex].Feeds.dEndFeed
|
|
local dToolFeed = TOOLS[Machining.nToolIndex].Feeds.dFeed
|
|
|
|
if Machining.nType == MCH_MY.MILLING then
|
|
-- stima LeadIn e LeadOut; se non settati si impostano a valori di default
|
|
if not Machining.LeadIn.dTotalEstimatedDistance then
|
|
Machining.LeadIn.dTotalEstimatedDistance = sqrt( Machining.LeadIn.dPerpDistance ^ 2 + Machining.LeadIn.dTangentDistance ^ 2) + Machining.dStartSafetyLength
|
|
end
|
|
if not Machining.LeadOut.dTotalEstimatedDistance then
|
|
Machining.LeadOut.dTotalEstimatedDistance = sqrt( Machining.LeadOut.dPerpDistance ^ 2 + Machining.LeadOut.dTangentDistance ^ 2) + Machining.dStartSafetyLength
|
|
end
|
|
if not Machining.CloneStepsRadial then
|
|
Machining.CloneStepsRadial = {}
|
|
Machining.CloneStepsRadial.nCount = 1
|
|
end
|
|
if not Machining.Steps.nCount then
|
|
Machining.Steps.nCount = 1
|
|
end
|
|
-- stima tempi di lavorazione per i diversi tratti
|
|
local dTimeToMachineLeadIn = Machining.LeadIn.dTotalEstimatedDistance / dToolStartFeed
|
|
local dTimeToMachineLeadOut = Machining.LeadOut.dTotalEstimatedDistance / dToolEndFeed
|
|
local dTimeToMachineEdge = Machining.dLengthToMachine / dToolFeed
|
|
-- calcolo lunghezze e tempi
|
|
if Machining.Steps.nStepType == MCH_MILL_ST.ZIGZAG then
|
|
dLengthToMachineAllStepsWithLeadInOut = ( Machining.dLengthToMachine * Machining.CloneStepsRadial.nCount + ( Machining.LeadIn.dTotalEstimatedDistance + Machining.LeadOut.dTotalEstimatedDistance)) * Machining.Steps.nCount
|
|
dTimeToMachineTotal = ( dTimeToMachineEdge * Machining.CloneStepsRadial.nCount + ( dTimeToMachineLeadIn + dTimeToMachineLeadOut)) * Machining.Steps.nCount
|
|
else
|
|
dLengthToMachineAllStepsWithLeadInOut = Machining.CloneStepsRadial.nCount * ( Machining.dLengthToMachine + Machining.LeadIn.dTotalEstimatedDistance + Machining.LeadOut.dTotalEstimatedDistance) * Machining.Steps.nCount
|
|
dTimeToMachineTotal = Machining.CloneStepsRadial.nCount * ( dTimeToMachineEdge + dTimeToMachineLeadIn + dTimeToMachineLeadOut) * Machining.Steps.nCount
|
|
end
|
|
elseif Machining.nType == MCH_MY.MORTISING then
|
|
-- se non settati, imposto valori di default
|
|
if not Machining.CloneStepsLongitudinal then
|
|
Machining.CloneStepsLongitudinal = {}
|
|
Machining.CloneStepsLongitudinal.nCount = 1
|
|
end
|
|
-- stima tempi di lavorazione per i diversi tratti
|
|
local dTimeToMachineLeadIn = ( Machining.dDepthToMachine + ( TOOLS[Machining.nToolIndex].SetupInfo.dZSafeDelta or 60) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ)) / dToolStartFeed
|
|
local dTimeToMachineLeadOut = ( Machining.dDepthToMachine + ( TOOLS[Machining.nToolIndex].SetupInfo.dZSafeDelta or 60) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ)) / dToolEndFeed
|
|
local dTimeToMachineEdge = Machining.dLengthToMachine / dToolFeed
|
|
-- calcolo lunghezze e tempi
|
|
if Machining.Steps.nStepType == MCH_MILL_ST.ZIGZAG then
|
|
dLengthToMachineAllStepsWithLeadInOut = ( Machining.dLengthToMachine * Machining.Steps.nCount + 2 * ( Machining.dDepthToMachine + ( TOOLS[Machining.nToolIndex].SetupInfo.dZSafeDelta or 60) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ))) * Machining.CloneStepsLongitudinal.nCount
|
|
dTimeToMachineTotal = ( dTimeToMachineEdge * Machining.Steps.nCount + dTimeToMachineLeadIn + dTimeToMachineLeadOut) * Machining.CloneStepsLongitudinal.nCount
|
|
else
|
|
dLengthToMachineAllStepsWithLeadInOut = Machining.CloneStepsLongitudinal.nCount * ( ( 2 * Machining.Steps.nCount - 1) * Machining.dLengthToMachine + 2 * 10 * ( Machining.Steps.nCount - 1) + 2 * ( Machining.dDepthToMachine + ( TOOLS[Machining.nToolIndex].SetupInfo.dZSafeDelta or 60) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ)))
|
|
dTimeToMachineTotal = Machining.CloneStepsLongitudinal.nCount * ( ( 2 * Machining.Steps.nCount - 1) * dTimeToMachineEdge + 2 * 10 / dToolFeed * ( Machining.Steps.nCount - 1) + dTimeToMachineLeadIn + dTimeToMachineLeadOut)
|
|
end
|
|
elseif Machining.nType == MCH_MY.POCKETING then
|
|
-- TODO le chiamate alla pocketing vanno unificate e uniformate
|
|
local ProcTm = FeatureLib.GetProcFromTrimesh( Machining.Geometry[1][1], Part)
|
|
local dDepthToMachine = min( ProcTm.Faces[Machining.Geometry[1][2] + 1].dElevation, ( Machining.dMaxElev or ProcTm.Faces[Machining.Geometry[1][2] + 1].dElevation)) - ( max( 0, Machining.dResidualDepth or 0))
|
|
local nSteps = max( ceil( ( dDepthToMachine - 50 * GEO.EPS_SMALL) / TOOLS[Machining.nToolIndex].dStep), 1)
|
|
local nAddGroupId = BeamLib.GetAddGroup( Part.id)
|
|
-- TODO in futuro creare flatregion (se ci fossero isole il calcolo del percorso non sarebbe corretto)
|
|
local idFaceContour = EgtExtractSurfTmFacetLoops( ProcTm.id, Machining.Geometry[1][2], nAddGroupId)
|
|
-- si settano i lati aperti della curva derivata dalla superficie
|
|
for i = 1, #ProcTm.Faces[Machining.Geometry[1][2] + 1].Edges do
|
|
if ProcTm.Faces[Machining.Geometry[1][2] + 1].Edges[i].bIsOpen then
|
|
EgtCurveCompoSetTempProp( idFaceContour, ProcTm.Faces[Machining.Geometry[1][2] + 1].Edges[i].id, 1)
|
|
end
|
|
end
|
|
-- dal momento che la funzione EgtPocketing non considera il grezzo, nei casi ottimizzati si deve correggere l'offset
|
|
local idTestCurve = EgtCopyGlob( idFaceContour, nAddGroupId )
|
|
local bIsOptimizedPocketing = ( TOOLS[Machining.nToolIndex].dDiameter > TOOLS[Machining.nToolIndex].dSideStep - 10 * GEO.EPS_SMALL)
|
|
and EgtOffsetCurve( idTestCurve, -TOOLS[Machining.nToolIndex].dDiameter / 2 - 10 * GEO.EPS_SMALL)
|
|
if not bIsOptimizedPocketing then
|
|
local dOffset = TOOLS[Machining.nToolIndex].dDiameter / 2 + 10 * GEO.EPS_SMALL
|
|
if TOOLS[Machining.nToolIndex].dSideStep < TOOLS[Machining.nToolIndex].dDiameter / 2 - 10 * GEO.EPS_SMALL then
|
|
dOffset = TOOLS[Machining.nToolIndex].dDiameter - TOOLS[Machining.nToolIndex].dSideStep
|
|
end
|
|
EgtOffsetCurve( idFaceContour, dOffset)
|
|
-- si settano tutti i lati chiusi per la curva offsettata
|
|
local _, nFaceCountourCurveCount = EgtCurveDomain( idFaceContour)
|
|
for i = 1, nFaceCountourCurveCount do
|
|
EgtCurveCompoSetTempProp( idFaceContour, i - 1, 0)
|
|
end
|
|
end
|
|
-- calcolo percorso di svuotatura replicando il calcolo che fa la svuotatura
|
|
local idPocketingPath = EgtPocketing( idFaceContour, TOOLS[Machining.nToolIndex].dDiameter / 2, TOOLS[Machining.nToolIndex].dSideStep, 0, Machining.nSubType, true, nAddGroupId)
|
|
local dPocketingPathLength = EgtCurveLength( idPocketingPath)
|
|
-- calcolo lunghezze e tempi totali
|
|
if dPocketingPathLength then
|
|
dLengthToMachineAllStepsWithLeadInOut = dPocketingPathLength * nSteps
|
|
-- TODO da aggiungere correzione volume effettivamente lavorato
|
|
dTimeToMachineTotal = dLengthToMachineAllStepsWithLeadInOut / dToolFeed
|
|
-- se percorso non calcolato, si settano dati molto alti
|
|
else
|
|
dLengthToMachineAllStepsWithLeadInOut = 99999 * nSteps
|
|
dTimeToMachineTotal = dLengthToMachineAllStepsWithLeadInOut / dToolFeed
|
|
end
|
|
-- le geometrie create si settano da cancellare
|
|
EgtSetLevel( idFaceContour, GDB_LV.TEMP)
|
|
EgtSetLevel( idPocketingPath, GDB_LV.TEMP)
|
|
EgtSetLevel( idTestCurve, GDB_LV.TEMP)
|
|
else
|
|
error( 'GetTimeToMachineAllStepsWithLeadInOut : unknown machining type')
|
|
end
|
|
|
|
return dTimeToMachineTotal, dLengthToMachineAllStepsWithLeadInOut
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.PrepareMachiningsForSorting( Part)
|
|
local nFeatureInternalIndex = 1
|
|
for i = 1, #MACHININGS do
|
|
local MachiningCurrent = MACHININGS[i].Machining
|
|
local ProcCurrent = MACHININGS[i].Proc
|
|
if not MachiningCurrent.ptCenter then
|
|
MachiningCurrent.ptCenter = Point3d( ProcCurrent.b3Box:getCenter():getX(), 0, 0)
|
|
end
|
|
|
|
-- conversione campo sStage in nStage, numerico e ordinabile
|
|
if not MachiningCurrent.sStage or MachiningCurrent.sStage == '' then
|
|
MachiningCurrent.sStage = 'Middle'
|
|
end
|
|
if MachiningCurrent.sStage == 'Head' then
|
|
MachiningCurrent.nStage = 1
|
|
elseif MachiningCurrent.sStage == 'Tail' then
|
|
MachiningCurrent.nStage = 3
|
|
elseif MachiningCurrent.sStage == 'AfterTail' then
|
|
MachiningCurrent.nStage = 4
|
|
else
|
|
MachiningCurrent.nStage = 2
|
|
end
|
|
|
|
if i > 1 then
|
|
local MachiningPrevious = MACHININGS[i - 1].Machining
|
|
local ProcPrevious = MACHININGS[i - 1].Proc
|
|
if ProcCurrent.id == ProcPrevious.id then
|
|
-- nStage devono essere sempre uguali o crescenti nella stessa feature
|
|
if MachiningCurrent.nStage < MachiningPrevious.nStage then
|
|
MachiningCurrent.nStage = MachiningPrevious.nStage
|
|
end
|
|
-- assegnazione indice interno alla feature
|
|
nFeatureInternalIndex = nFeatureInternalIndex + 1
|
|
else
|
|
nFeatureInternalIndex = 1
|
|
end
|
|
end
|
|
MachiningCurrent.nFeatureInternalIndex = nFeatureInternalIndex
|
|
|
|
-- se fase di lavoro standard, assegnazione dello spezzone
|
|
if MachiningCurrent.nStage == 2 then
|
|
local nParts = #Part.SplittingPoints + 1
|
|
if nParts > 1 then
|
|
local dPartMinX = Part.b3Part:getMin():getX()
|
|
local dPartMaxX = Part.b3Part:getMax():getX()
|
|
for j = 1, nParts do
|
|
local dNextSplitX = dPartMinX
|
|
local dPreviousSplitX = dPartMaxX
|
|
if j ~= 1 then
|
|
dPreviousSplitX = Part.SplittingPoints[j - 1]:getX()
|
|
end
|
|
if j ~= nParts then
|
|
dNextSplitX = Part.SplittingPoints[j]:getX()
|
|
end
|
|
if MachiningCurrent.ptCenter:getX() > dNextSplitX - 10 * GEO.EPS_SMALL and MachiningCurrent.ptCenter:getX() < dPreviousSplitX + 10 * GEO.EPS_SMALL then
|
|
MachiningCurrent.nPartSegment = j
|
|
else
|
|
MachiningCurrent.nPartSegment = -1
|
|
end
|
|
end
|
|
else
|
|
MachiningCurrent.nPartSegment = -1
|
|
end
|
|
else
|
|
MachiningCurrent.nPartSegment = -1
|
|
end
|
|
end
|
|
|
|
return MACHININGS
|
|
end
|
|
|
|
-- TODO nShifts è solo per debug, si può togliere??
|
|
-- ripristina l'ordine delle lavorazioni interno alla feature, se non rispettato
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.FinalizeSorting()
|
|
local nShifts = 0
|
|
|
|
for i = #MACHININGS, 2, -1 do
|
|
for j = i - 1, 1, -1 do
|
|
if MACHININGS[i].Proc.id == MACHININGS[j].Proc.id
|
|
and MACHININGS[i].Machining.nFeatureInternalIndex < MACHININGS[j].Machining.nFeatureInternalIndex then
|
|
|
|
MACHININGS[i], MACHININGS[j] = MACHININGS[j], MACHININGS[i]
|
|
nShifts = nShifts + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
return MACHININGS, nShifts
|
|
end
|
|
|
|
-- TODO convertire in tabella in cui si chiamano direttamente i nomi delle funzioni, in modo da poter cambiare l'ordine facilmente
|
|
-- TODO libreria Sorting??
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local SortingComparisonRules = {
|
|
-- ordine interno alla feature
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Proc.id == MachiningB.Proc.id then
|
|
if MachiningA.Machining.nFeatureInternalIndex < MachiningB.Machining.nFeatureInternalIndex then
|
|
return 1
|
|
elseif MachiningA.Machining.nFeatureInternalIndex > MachiningB.Machining.nFeatureInternalIndex then
|
|
return -1
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
|
|
-- dipendenze solo spostamento stage 2->4
|
|
-- TODO da fare
|
|
|
|
-- stage
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Machining.nStage < MachiningB.Machining.nStage then
|
|
return 1
|
|
elseif MachiningA.Machining.nStage > MachiningB.Machining.nStage then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- dipendenze
|
|
-- TODO da fare
|
|
|
|
-- segment
|
|
function ( MachiningA, MachiningB)
|
|
if MachiningA.Machining.nPartSegment < MachiningB.Machining.nPartSegment then
|
|
return 1
|
|
elseif MachiningA.Machining.nPartSegment > MachiningB.Machining.nPartSegment then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- testa
|
|
-- TODO da fare
|
|
|
|
-- famiglia utensile
|
|
function ( MachiningA, MachiningB)
|
|
-- TODO tirare fuori da qua??
|
|
local ToolFamilyOrder = {
|
|
SAWBLADE = 1,
|
|
DRILLBIT = 2,
|
|
MILL = 3,
|
|
MORTISE = 4
|
|
}
|
|
local nToolFamilyOrderA = ToolFamilyOrder[ TOOLS[ MachiningA.Machining.nToolIndex].sFamily]
|
|
local nToolFamilyOrderB = ToolFamilyOrder[ TOOLS[ MachiningB.Machining.nToolIndex].sFamily]
|
|
|
|
if nToolFamilyOrderA < nToolFamilyOrderB then
|
|
return 1
|
|
elseif nToolFamilyOrderA > nToolFamilyOrderB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- performance utensile
|
|
function( MachiningA, MachiningB)
|
|
local dToolPerformanceIndexA = TOOLS[MachiningA.Machining.nToolIndex].dPerformanceIndex
|
|
local dToolPerformanceIndexB = TOOLS[MachiningB.Machining.nToolIndex].dPerformanceIndex
|
|
|
|
if dToolPerformanceIndexA > dToolPerformanceIndexB then
|
|
return 1
|
|
elseif dToolPerformanceIndexA < dToolPerformanceIndexB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- probabilmente arrivati qui significa che gli utensili A e B sono gli stessi
|
|
-- se così non fosse e tutte le caratteristiche sopra sono uguali, ordine alfabetico
|
|
function( MachiningA, MachiningB)
|
|
local sToolNameA = TOOLS[MachiningA.Machining.nToolIndex].sName
|
|
local sToolNameB = TOOLS[MachiningB.Machining.nToolIndex].sName
|
|
|
|
if sToolNameA < sToolNameB then
|
|
return 1
|
|
elseif sToolNameA > sToolNameB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- lato di lavoro
|
|
-- TODO questo, insieme all'ordinamento X, andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Machining.vtToolDirection:getY() < -0.174 and MachiningB.Machining.vtToolDirection:getY() >= 0.174 then
|
|
return 1
|
|
elseif MachiningA.Machining.vtToolDirection:getY() >= 0.174 and MachiningB.Machining.vtToolDirection:getY() < -0.174 then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- ordinamento X
|
|
-- TODO questo andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
|
function( MachiningA, MachiningB)
|
|
local bIsMachiningOnFront = MachiningA.Machining.vtToolDirection:getY() < 10 * GEO.EPS_SMALL
|
|
local nResult = 0
|
|
|
|
-- se lavorazione davanti ordine testa->coda
|
|
if bIsMachiningOnFront then
|
|
if MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
|
nResult = 1
|
|
elseif MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
|
nResult = -1
|
|
end
|
|
-- se lavorazione dietro ordine coda->testa
|
|
else
|
|
if MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
|
nResult = 1
|
|
elseif MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
|
nResult = -1
|
|
end
|
|
end
|
|
|
|
return nResult
|
|
end
|
|
}
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.CompareMachinings( MachiningA, MachiningB)
|
|
-- itera le SortingComparisonRules una per volta. Se non vi è alcuna scelta va avanti (result = 0), altrimenti ritorna true/false in base al risultato
|
|
for i = 1, #SortingComparisonRules do
|
|
local CompareFunction = SortingComparisonRules[i]
|
|
local result = CompareFunction( MachiningA, MachiningB)
|
|
if result ~= 0 then
|
|
return result > 0
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
return MachiningLib
|