b68bbb2c48
- Corretta info indice rotazione su Proc
1905 lines
97 KiB
Lua
1905 lines
97 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( 'BeamDataNew')
|
|
local BeamLib = require( 'BeamLib')
|
|
local FeatureLib = require( 'FeatureLib')
|
|
local BCS = require( 'BasicCustomerStrategies')
|
|
local PreSimulationLib = require( 'PreSimulationLib')
|
|
local LeadInOutLib = require( 'LeadInOutLib')
|
|
|
|
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.IsFeatureHinderingClamping( Proc, Part)
|
|
local bFeatureHindersClamping
|
|
|
|
local dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail = FeatureLib.GetFeatureMaxNotClampableLengths( Proc, Part)
|
|
bFeatureHindersClamping = FeatureLib.IsMachiningLong( max( dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
|
|
|
return bFeatureHindersClamping
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.GetMachiningSteps( bIsSlot, dMachiningDepth, dStep)
|
|
local MachiningSteps = {}
|
|
MachiningSteps.nCount = ceil( ( dMachiningDepth - 50 * GEO.EPS_SMALL) / dStep)
|
|
-- se è una slot, dMachiningDepth è l'altezza della tasca e nel calcolo step si deve considerare lo spessore dell'utensile
|
|
if bIsSlot then
|
|
if MachiningSteps.nCount > 1 then
|
|
MachiningSteps.dStep = ( dMachiningDepth - dStep) / ( MachiningSteps.nCount - 1)
|
|
else
|
|
MachiningSteps.dStep = dMachiningDepth
|
|
MachiningSteps.nCount = 1
|
|
end
|
|
else
|
|
MachiningSteps.dStep = dStep
|
|
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
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- in base a tipo testa e angolo soglia, verifica se la faccia è troppo inclinata per la lavorazione scelta (per DownUp passare vtNFace opposta)
|
|
function MachiningLib.IsFaceZOutOfRange( vtNFace, Tool)
|
|
|
|
-- lama sopra: angolo negativo troppo basso
|
|
if Tool.SetupInfo.HeadType.bTop and vtNFace:getZ() < Tool.SetupInfo.GetMinNz( vtNFace, Tool) - GEO.EPS_ZERO then
|
|
return true
|
|
end
|
|
-- lama sotto: angolo positivo troppo elevato
|
|
if Tool.SetupInfo.HeadType.bBottom and vtNFace:getZ() > Tool.SetupInfo.GetMaxNz( vtNFace, Tool) + GEO.EPS_ZERO then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function TestEngagement( sBladeEngagement, Parameters, OptionalParameters)
|
|
|
|
-- parametri obbligatori (parametri opzionali transitano solamente)
|
|
local Face = Parameters.Face
|
|
local Edge = Parameters.Edge
|
|
local Part = Parameters.Part
|
|
local Tool = Parameters.Tool
|
|
local dDepthToMachine = Parameters.dDepthToMachine
|
|
|
|
-- il lato della testa cambia in base all'Engagement
|
|
local vtHead
|
|
if sBladeEngagement == 'Standard' then
|
|
vtHead = Face.vtN
|
|
elseif sBladeEngagement == 'DownUp' then
|
|
vtHead = -Face.vtN
|
|
else
|
|
error( 'TestEngagement : unknown engagement')
|
|
end
|
|
|
|
-- se l'angolo non può essere raggiunto dall'utensile la lavorazione non è fattibile
|
|
if MachiningLib.IsFaceZOutOfRange( vtHead, Tool) then
|
|
return false
|
|
end
|
|
|
|
local CheckCollisionParameters = {
|
|
Edge = Edge,
|
|
vtNFace = Face.vtN,
|
|
vtHead = vtHead,
|
|
Part = Part,
|
|
Tool = Tool,
|
|
dDepthToMachine = dDepthToMachine
|
|
}
|
|
|
|
local CheckCollisionOptionalParameters = BeamLib.TableCopyDeep( OptionalParameters or {})
|
|
|
|
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, Face.vtN)
|
|
|
|
-- check punti lavorazione
|
|
-- lavorazione oltre le corse: non fattibile
|
|
local PointsOnToolTipCenter = {
|
|
PreSimulationLib.GetPointOnToolTipCenter( Edge.ptStart + Edge.vtN * ( Edge.dElevation - dDepthToMachine), vtHead, Face.vtN, Edge.vtN, Tool),
|
|
PreSimulationLib.GetPointOnToolTipCenter( Edge.ptEnd + Edge.vtN * ( Edge.dElevation - dDepthToMachine), vtHead, Face.vtN, Edge.vtN, Tool)
|
|
}
|
|
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
|
if bOutOfStroke then
|
|
return false
|
|
end
|
|
-- lavorazione in collisione con il pezzo: non fattibile
|
|
local bCollisionFound, bMoveAfterSplit = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters)
|
|
if bCollisionFound then
|
|
return false
|
|
end
|
|
|
|
-- calcolo e check attacchi
|
|
local LeadInOut = {}
|
|
local LeadInOutOptionalParameters = {
|
|
sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength,
|
|
bMoveAfterSplit = bMoveAfterSplit
|
|
}
|
|
|
|
-- attacco perpendicolare
|
|
local PerpendicularLeadInOut = LeadInOutLib.CalculateLeadInOut( 'Perpendicular', Parameters, LeadInOutOptionalParameters)
|
|
-- check extracorsa nei punti di attacco
|
|
|
|
PointsOnToolTipCenter = {
|
|
PreSimulationLib.GetPointOnToolTipCenter( PerpendicularLeadInOut.LeadIn.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool),
|
|
PreSimulationLib.GetPointOnToolTipCenter( PerpendicularLeadInOut.LeadOut.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool)
|
|
}
|
|
local bOutOfStrokePerpendicular = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
|
-- se non è in extracorsa si aggiunge come attacco possibile
|
|
if not bOutOfStrokePerpendicular then
|
|
LeadInOut.Perpendicular = PerpendicularLeadInOut
|
|
LeadInOut.Perpendicular.bMoveAfterSplit = bMoveAfterSplit
|
|
end
|
|
-- se c'è almeno un lato chiuso l'unico attacco possibile è il perpendicolare
|
|
if not ( Edge.bIsStartOpen and Edge.bIsEndOpen) then
|
|
if bOutOfStrokePerpendicular then
|
|
return false
|
|
else
|
|
LeadInOut.sChosen = 'Perpendicular'
|
|
return true, bMoveAfterSplit, LeadInOut
|
|
end
|
|
end
|
|
|
|
-- attacco tangenziale
|
|
local TangentLeadInOut = LeadInOutLib.CalculateLeadInOut( 'Tangent', Parameters, LeadInOutOptionalParameters)
|
|
-- check extracorsa nei punti di attacco
|
|
PointsOnToolTipCenter = {
|
|
PreSimulationLib.GetPointOnToolTipCenter( TangentLeadInOut.LeadIn.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool),
|
|
PreSimulationLib.GetPointOnToolTipCenter( TangentLeadInOut.LeadOut.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool)
|
|
}
|
|
local bOutOfStrokeTangent = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
|
-- attacco tangenziale non in extracorsa: si verifica se è in collisione
|
|
if not bOutOfStrokeTangent then
|
|
CheckCollisionOptionalParameters.PointsToCheck = {}
|
|
table.insert( CheckCollisionOptionalParameters.PointsToCheck, TangentLeadInOut.LeadIn.ptPoint)
|
|
table.insert( CheckCollisionOptionalParameters.PointsToCheck, TangentLeadInOut.LeadOut.ptPoint)
|
|
local bCollisionFoundTangent, bMoveAfterSplitTangent = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters)
|
|
-- attacco tangenziale possibile
|
|
if not bCollisionFoundTangent then
|
|
LeadInOut.Tangent = TangentLeadInOut
|
|
LeadInOut.Tangent.bMoveAfterSplit = bMoveAfterSplitTangent
|
|
end
|
|
end
|
|
|
|
-- se disponibili più attacchi si sceglie il più corto, altrimenti quello possibile
|
|
if LeadInOut.Perpendicular and LeadInOut.Tangent then
|
|
if LeadInOut.Perpendicular.dTotalLength > LeadInOut.Tangent.dTotalLength + 10 then
|
|
LeadInOut.sChosen = 'Tangent'
|
|
else
|
|
LeadInOut.sChosen = 'Perpendicular'
|
|
end
|
|
elseif LeadInOut.Perpendicular and not LeadInOut.Tangent then
|
|
LeadInOut.sChosen = 'Perpendicular'
|
|
elseif LeadInOut.Tangent and not LeadInOut.Perpendicular then
|
|
LeadInOut.sChosen = 'Tangent'
|
|
-- nessun attacco possibile
|
|
-- TODO qui invece di uscire si dovranno provare i due attacchi SpecialTangent e SpecialTangentInverted
|
|
else
|
|
return false
|
|
end
|
|
|
|
return true, bMoveAfterSplit, LeadInOut
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- ritorna se la faccia e il lato sono lavorabili e, se sì, il modo di lavorare (standard/DownUp) e i tipi di attacco disponibili
|
|
-- TODO si dovrà decidere come tagliare anche se pezzo corto (il motore non deve ingombrare con il pinzaggio)
|
|
-- TODO da gestire riduzione percorso
|
|
function MachiningLib.GetBladeEngagement( Parameters, OptionalParameters)
|
|
|
|
local Engagement
|
|
|
|
-- test lavorazione faccia in modo standard (no DownUp)
|
|
local bIsEngagementOk, bMoveAfterSplit, LeadInOut = TestEngagement( 'Standard', Parameters, OptionalParameters)
|
|
|
|
if bIsEngagementOk then
|
|
|
|
Engagement = {
|
|
sBladeEngagement = 'Standard',
|
|
bMoveAfterSplit = bMoveAfterSplit,
|
|
LeadInOut = LeadInOut
|
|
}
|
|
return true, Engagement
|
|
end
|
|
|
|
-- faccia non lavorabile in modo standard: si verifica se il DownUp è fattibile
|
|
bIsEngagementOk, bMoveAfterSplit, LeadInOut = TestEngagement( 'DownUp', Parameters, OptionalParameters)
|
|
|
|
if bIsEngagementOk then
|
|
|
|
Engagement = {
|
|
sBladeEngagement = 'DownUp',
|
|
bMoveAfterSplit = bMoveAfterSplit,
|
|
LeadInOut = LeadInOut
|
|
}
|
|
return true, Engagement
|
|
end
|
|
|
|
return false
|
|
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 rivedere/completare
|
|
function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
|
|
-- parametri obbligatori
|
|
if type( ToolSearchParameters.FaceToMachine) ~= 'table' then
|
|
error( 'FindBlade : missing face info')
|
|
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
|
|
local FaceToMachine = ToolSearchParameters.FaceToMachine
|
|
local bAllowTopHead = ToolSearchParameters.bAllowTopHead
|
|
local bAllowBottomHead = ToolSearchParameters.bAllowBottomHead
|
|
|
|
-- parametri opzionali
|
|
local dElevation = ToolSearchParameters.dElevation
|
|
local bForceLongcutBlade = ToolSearchParameters.bForceLongcutBlade or false
|
|
local EdgeToMachine = ToolSearchParameters.EdgeToMachine
|
|
local Part = ToolSearchParameters.Part
|
|
local bIsDicing = ToolSearchParameters.bIsDicing or false
|
|
local sRestLengthSideForPreSimulation = ToolSearchParameters.sRestLengthSideForPreSimulation or 'Tail'
|
|
local bCannotSplitRestLength = ToolSearchParameters.bCannotSplitRestLength or false
|
|
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
local CurrentEngagement
|
|
local BestEngagement
|
|
for i = 1, #TOOLS do
|
|
local bIsToolCompatible = false
|
|
|
|
if TOOLS[i].sFamily == 'SAWBLADE' then
|
|
if bAllowTopHead and not bAllowBottomHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bTop
|
|
elseif bAllowBottomHead and not bAllowTopHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bBottom
|
|
else
|
|
bIsToolCompatible = true
|
|
end
|
|
end
|
|
|
|
-- se dati sufficienti, si determina se con questo utensile il taglio è fattibile e il modo di lavorare della lama
|
|
-- TODO corretto il calcolo della dDepthToMachine? è comunque inutile calcolare per una profondità che so già andrà in collisione
|
|
if bIsToolCompatible then
|
|
if FaceToMachine and EdgeToMachine and Part and dElevation then
|
|
local bIsBladeOk = false
|
|
local BladeEngagementParameters = {
|
|
Face = FaceToMachine,
|
|
Edge = EdgeToMachine,
|
|
Part = Part,
|
|
Tool = TOOLS[i],
|
|
dDepthToMachine = min( dElevation, TOOLS[i].dMaxDepth)
|
|
}
|
|
local BladeEngagementOptionalParameters = {
|
|
bIsDicing = bIsDicing,
|
|
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
|
bCannotSplitRestLength = bCannotSplitRestLength
|
|
}
|
|
TIMER:startElapsed( 'GetBladeEngagement')
|
|
bIsBladeOk, CurrentEngagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
|
TIMER:stopElapsed( 'GetBladeEngagement')
|
|
-- orientamento non raggiungibile
|
|
if not bIsBladeOk then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
-- se si ha solo la faccia si può verificare se questa è orientata correttamente
|
|
elseif FaceToMachine then
|
|
if MachiningLib.IsFaceZOutOfRange( FaceToMachine.vtN, TOOLS[i]) then
|
|
bIsToolCompatible = false
|
|
end
|
|
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
|
|
|
|
if bIsToolCompatible then
|
|
-- TODO gestire accorciamento massimo materiale per inclinazione
|
|
local dCurrentResidualDepth = ( dElevation or 0) - TOOLS[i].dMaxDepth
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
BestEngagement = CurrentEngagement
|
|
else
|
|
-- prediligo utensile per tagli lungo vena, se richiesto
|
|
if bForceLongcutBlade and not TOOLS[nBestToolIndex].bIsUsedForLongCut and TOOLS[i].bIsUsedForLongCut then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
BestEngagement = CurrentEngagement
|
|
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
|
|
BestEngagement = CurrentEngagement
|
|
end
|
|
-- si sceglie quello con le performance migliori
|
|
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex + 10 * GEO.EPS_SMALL then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
BestEngagement = CurrentEngagement
|
|
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
|
|
BestEngagement = CurrentEngagement
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
ToolInfo.Engagement = BestEngagement
|
|
|
|
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 0) + ( 10 * GEO.EPS_SMALL)
|
|
end
|
|
if not ToolSearchParameters.dMinToolDiameter then
|
|
ToolSearchParameters.dMinToolDiameter = ToolSearchParameters.dToolDiameter - ( ToolSearchParameters.dDiameterTolerance or 0) - ( 10 * 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
|
|
elseif PreSimulationLib.CheckOutOfStrokeFromPoints( ToolSearchParameters.ptCheckOutStroke, ToolSearchParameters.vtToolDirection, 0, TOOLS[i]) 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 -- ProcToAdd.bStd
|
|
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 -- ProcToAdd.bStd
|
|
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 che verifica se ha senso riprocessare tutto dall'inizio,
|
|
-- perchè ci sono buone probabilità che l'errore trovato in fase di applicazione si possa risolvere (escludendo la lavorazione scelta in precedenza)
|
|
local function IsReProcessWorthIt( nError)
|
|
local bReProcess = false
|
|
|
|
-- errori di Extra-corsa
|
|
if nError == 2110 or nError == 2216 or nError == 2318 or nError == 2424 or nError == 2508 then
|
|
bReProcess = true
|
|
end
|
|
|
|
return bReProcess
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per aggiungere una nuova lavorazione
|
|
function MachiningLib.AddOperations( MACHININGS, Part, sRotation)
|
|
local nErr
|
|
local sErr = ''
|
|
local bAreAllMachiningApplyOk = true
|
|
local bSplitExecuted = false
|
|
local bTryToReProcess = 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 ( MACHININGS[i].Proc.bStd and sRotation == 'STD') 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
|
|
-- dati da salvare dopo applicazione della lavorazione
|
|
MACHININGS[i].Machining.MachStartAxesPos = {}
|
|
MACHININGS[i].Machining.MachEndAxesPos = {}
|
|
MACHININGS[i].Machining.nOperationId = {}
|
|
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)
|
|
|
|
-- si salva sulla lista info lavorazione applicata
|
|
local MachExtraInfo = { sType = 'MACH',
|
|
nIndexInMachinings = i,
|
|
nOperationId = nOperationId,
|
|
MachStartAxesPos = EgtGetMachiningStartAxes(),
|
|
MachEndAxesPos = EgtGetMachiningEndAxes()}
|
|
table.insert( DB_MACH_APPLIED, MachExtraInfo)
|
|
|
|
-- se non esistono punto iniziale o finale, si disattiva operazione
|
|
if not MachExtraInfo.MachStartAxesPos or not MachExtraInfo.MachEndAxesPos then
|
|
EgtSetOperationMode( nOperationId, false)
|
|
end
|
|
|
|
-- se errore in applicazione
|
|
if not bIsApplyOk then
|
|
bAreAllMachiningApplyOk = false
|
|
nErr, sErr = EgtGetLastMachMgrError()
|
|
EgtSetOperationMode( nOperationId, false)
|
|
local nOffsetIndex = EgtIf( Part.bPartInCombiIsInverted, 4, 0)
|
|
local CurrProc = PROCESSINGS[MACHININGS[i].Proc.nIndexPartInParts].Rotation[MACHININGS[i].Proc.nIndexRotation+nOffsetIndex][MACHININGS[i].Proc.nIndexInVProc]
|
|
-- si annulla la feature scelta, in modo che un successivo ricalcolo non la tenga in considerazione
|
|
CurrProc.AvailableStrategies[CurrProc.nIndexBestStrategy].Result.sStatus = 'Not-Applicable'
|
|
CurrProc.AvailableStrategies[CurrProc.nIndexBestStrategy].Result.sInfo = 'REJECTED (' .. sErr .. ')'
|
|
CurrProc.ChosenStrategy= nil
|
|
-- si verifica se vale la pena riprocessare tutto (perchè si pensa possa risolvere il problema)
|
|
if IsReProcessWorthIt( nErr) then
|
|
bTryToReProcess = true
|
|
end
|
|
-- 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 applicazione andata a buon fine
|
|
else
|
|
|
|
-- se non deve essere ignorato, si salva ingombro lavorazione attuale e fasi successive
|
|
if 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
|
|
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( Part.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET)
|
|
-- se grezzo successivo senza pezzi e finale, va tolto
|
|
local nNextRawId = EgtGetNextRawPart( Part.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)
|
|
|
|
-- posizione iniziale considerando eventuiali prerotazioni
|
|
local nRealInitialPosition = Part.nInitialPosition - ( BEAM.PREROTATE90 or 0)
|
|
if sRotation == 'DOWN' then
|
|
local nRotation = EgtIf( nRealInitialPosition + 2 > 4, nRealInitialPosition + 2 - 4, nRealInitialPosition + 2) - 1
|
|
BeamLib.RotateRawPart( Part, nRotation)
|
|
EgtSetInfo( idDisp, 'ROT', -2)
|
|
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
|
elseif sRotation == 'SIDE' then
|
|
local nRotation = EgtIf( nRealInitialPosition + 1 > 4, nRealInitialPosition + 1 - 4, nRealInitialPosition + 1) - 1
|
|
BeamLib.RotateRawPart( Part, nRotation)
|
|
EgtSetInfo( idDisp, 'ROT', -1)
|
|
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
|
else
|
|
local nRotation = nRealInitialPosition - 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, false
|
|
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, bTryToReProcess
|
|
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.DRILLING then
|
|
local function fact(n) return n == 0 and 1 or n * fact(n - 1) end
|
|
local nSteps = ceil( Machining.sDepth / Machining.dStep)
|
|
local dLengthEachStep = Machining.sDepth / nSteps
|
|
-- numero dei movimenti a step, compresi andata e ritorno per scarico truciolo
|
|
local nTotStepMovement = 2 * fact( nSteps)
|
|
-- in feed si lavorano solo gli step
|
|
local dFeedTime = ( ( dLengthEachStep + Machining.dStartSafetyLength) * nSteps) / dToolFeed
|
|
-- ritorno per scaricare e approccio al prossimo step sono in feed finale
|
|
local dEndFeedTime = ( dLengthEachStep * ( nTotStepMovement - nSteps) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) * 2) / dToolEndFeed
|
|
dLengthToMachineAllStepsWithLeadInOut = dLengthEachStep * nTotStepMovement
|
|
dTimeToMachineTotal = dFeedTime + dEndFeedTime
|
|
elseif 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 idTempGroup = Part.idTempGroup
|
|
-- 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], idTempGroup)
|
|
-- 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, idTempGroup )
|
|
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, idTempGroup)
|
|
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
|
|
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 = {
|
|
-- 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,
|
|
}
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
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
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function OrderMachining( MachiningOptList)
|
|
-- Recupero l'identificativo del gruppo di lavoro corrente
|
|
for i = 1, #MachiningOptList - 1 do
|
|
local idSource = DB_MACH_APPLIED[MachiningOptList[i+1]].nOperationId
|
|
local idRef = DB_MACH_APPLIED[MachiningOptList[i]].nOperationId
|
|
EgtRelocateGlob( idSource, idRef, GDB_IN.AFTER)
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.ShortestPathSorting()
|
|
local i = 1
|
|
while i <= #DB_MACH_APPLIED do
|
|
local nMachInDisp = 0
|
|
local MachiningOptList = {}
|
|
local GroupInfo = {}
|
|
|
|
-- se è una lavorazione
|
|
if DB_MACH_APPLIED[i].sType ~= 'DISP' then
|
|
-- inizio
|
|
EgtOptMachInit()
|
|
|
|
-- feed dalla macchina
|
|
-- TODO abbassare per considere accelerazioni??
|
|
SetupInfo = BeamData.GetSetupInfo()
|
|
EgtOptMachSetFeeds( SetupInfo.dFeedLinearAxesAverage or 10000, SetupInfo.dFeedRotativeAxesAverage or 1000)
|
|
|
|
-- tra gruppi (stage) non si può ottimizzare
|
|
EgtOptMachSetAllGroupsDependencesAsMandatory( true)
|
|
EgtOptMachSetOptimizationForGroups( true)
|
|
|
|
-- se è una lavorazione
|
|
while DB_MACH_APPLIED[i] and DB_MACH_APPLIED[i].sType ~= 'DISP' do
|
|
if DB_MACH_APPLIED[i].MachStartAxesPos and DB_MACH_APPLIED[i].MachEndAxesPos then
|
|
-- se lavorazione non attiva non va considerata
|
|
local nOperationId = DB_MACH_APPLIED[i].nOperationId
|
|
if EgtGetOperationMode( nOperationId) then
|
|
local ptMinX, ptMaxX
|
|
-- aggiungo lavorazioni
|
|
local nToolIndex = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nToolIndex
|
|
EgtOptMachAddTool( nToolIndex, 2, 2) -- , [ num dTC_X, num dTC_Y, num dTC_Z, num dTC_A, num dTC_B, num dTC_C])
|
|
-- viene eseguito prima il gruppo con indice più alto, quindi si inverte indice dato che lo stage è dal più piccolo al più grande
|
|
local nGroup = 10 - MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage
|
|
local MachStartAxesPos = DB_MACH_APPLIED[i].MachStartAxesPos
|
|
local MachEndAxesPos = DB_MACH_APPLIED[i].MachEndAxesPos
|
|
EgtOptMachAddMachining( i, nToolIndex, nGroup, MachStartAxesPos, MachEndAxesPos)
|
|
table.insert( MachiningOptList, i)
|
|
|
|
-- si salvano i punti minimi e massimi tra tutte le lavorazioni di ogni gruppo
|
|
if MachStartAxesPos[1] < MachEndAxesPos[1] then
|
|
ptMinX = MachStartAxesPos
|
|
ptMaxX = MachEndAxesPos
|
|
else
|
|
ptMinX = MachEndAxesPos
|
|
ptMaxX = MachStartAxesPos
|
|
end
|
|
|
|
-- si aggiungono le info di gruppo
|
|
local bFound = false
|
|
for t = 1, #GroupInfo do
|
|
if GroupInfo[t].nGroup == nGroup then
|
|
if GroupInfo[t].ptMin[1] > ptMinX[1] then GroupInfo[t].ptMin = ptMinX end
|
|
if GroupInfo[t].ptMax[1] < ptMaxX[1] then GroupInfo[t].ptMax = ptMaxX end
|
|
bFound = true
|
|
end
|
|
end
|
|
-- se non ho trovato, si aggiunge in lista
|
|
if not bFound then
|
|
table.insert( GroupInfo, { nGroup = nGroup, nStage = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage, ptMin = ptMinX, ptMax = ptMaxX})
|
|
end
|
|
|
|
nMachInDisp = nMachInDisp + 1
|
|
end
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
-- cliclo su tutte le lavorazioni
|
|
for k = 1, #MachiningOptList do
|
|
if not DB_MACH_APPLIED[MachiningOptList[k]].Dependances then
|
|
DB_MACH_APPLIED[MachiningOptList[k]].Dependances = {}
|
|
end
|
|
for j = 1, #MachiningOptList do
|
|
-- se non è stessa lavorazione, imposto dati e dipendenze
|
|
if k ~= j then
|
|
local MachiningK = MACHININGS[DB_MACH_APPLIED[MachiningOptList[k]].nIndexInMachinings]
|
|
local MachiningJ = MACHININGS[DB_MACH_APPLIED[MachiningOptList[j]].nIndexInMachinings]
|
|
-- se stessa Proc
|
|
if MachiningK.Proc.id == MachiningJ.Proc.id then
|
|
-- se lavorazioni della stessa feature, obbligatorio rispettare ordine
|
|
if MachiningK.Machining.nFeatureInternalIndex < MachiningJ.Machining.nFeatureInternalIndex then
|
|
local bOk = EgtOptMachAddDependence( MachiningOptList[k], MachiningOptList[j])
|
|
if not bOk then
|
|
error( 'Machining sorting : error in dependencies')
|
|
end
|
|
table.insert( DB_MACH_APPLIED[MachiningOptList[k]].Dependances, MachiningOptList[j])
|
|
-- se l'indice interno è uguale, sono cloni: si ordinano in base all'ordine in tabella
|
|
elseif MachiningK.Machining.nFeatureInternalIndex == MachiningJ.Machining.nFeatureInternalIndex then
|
|
if k < j then
|
|
local bOk = EgtOptMachAddDependence( MachiningOptList[k], MachiningOptList[j])
|
|
if not bOk then
|
|
error( 'Machining sorting : error in dependencies')
|
|
end
|
|
table.insert( DB_MACH_APPLIED[MachiningOptList[k]].Dependances, MachiningOptList[j])
|
|
end
|
|
end
|
|
-- se tra due Proc diverse
|
|
else
|
|
-- TODO :
|
|
-- se ci sono dipendenze tra due feature diverse, la dipendenza è obbligatoria! ATTENZIONE A DIPENDENZE INCROCIATE A->B, B->C, C->A
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- definisco gruppo per gruppo la direzione preferita di ottimizzazione
|
|
for t = 1, #GroupInfo do
|
|
-- se gruppo "Taglio di coda" l'ordinamento è al contrario
|
|
if GroupInfo[t].nStage == 3 then
|
|
-- start point
|
|
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, true, SHP_OB.NEAR_PNT, GroupInfo[t].ptMin[1], GroupInfo[t].ptMin[2], GroupInfo[t].ptMin[3])
|
|
-- end point
|
|
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, false, SHP_OB.NEAR_PNT, GroupInfo[t].ptMax[1], GroupInfo[t].ptMax[2], GroupInfo[t].ptMax[3])
|
|
-- in tutti gli altri gruppi si ordina sempre dalla testa alla coda
|
|
else
|
|
-- start point
|
|
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, true, SHP_OB.NEAR_PNT, GroupInfo[t].ptMax[1], GroupInfo[t].ptMax[2], GroupInfo[t].ptMax[3])
|
|
-- end point
|
|
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, false, SHP_OB.NEAR_PNT, GroupInfo[t].ptMin[1], GroupInfo[t].ptMin[2], GroupInfo[t].ptMin[3])
|
|
end
|
|
end
|
|
|
|
-- calcolo ordine lavorazioni
|
|
MachiningOptList = EgtOptMachCalculate( MachiningOptList)
|
|
|
|
OrderMachining( MachiningOptList)
|
|
|
|
-- fine
|
|
EgtOptMachTerminate()
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
return MachiningLib
|