Files
databeamnew/LuaLibs/MachiningLib.lua
T
andrea.villa 570e41a40d - In ShortestPathSorting si settano ora inizio e fine di ogni gruppo per ordine lavorazioni
- In STR0010 in caso che la strategia sia stata forzata da utente, non viene bocciata a causa della sua posizione/forma. Se forzata il cliente si è preso al responsabilità della sua scelta ed è giusto che venga provata. Al massimo si avranno errori di extra-corsa o colisioni.
2025-12-23 16:42:04 +01:00

1811 lines
91 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.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
-------------------------------------------------------------------------------------------------------------
-- in base a tipo testa e angolo soglia, verifica se la faccia è troppo inclinata per la lavorazione scelta (per DownUp passare vtNFace opposta)
local function 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 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.CheckOutOfStroke( 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 = {}
-- attacco perpendicolare
local PerpendicularLeadInOut = LeadInOutLib.CalculateLeadInOut( 'Perpendicular', Parameters)
-- 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.CheckOutOfStroke( 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)
-- 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.CheckOutOfStroke( PointsOnToolTipCenter, vtHead, nSCC, Tool)
-- attacco tangenziale non in extracorsa: si verifica se è in collisione
if not bOutOfStrokeTangent then
local bCollisionFoundTangent, bMoveAfterSplitTangent = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters) -- TODO passare punti custom attacco tangenziale
-- 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
-- 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.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 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
}
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 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 ( 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 -- 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 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 ( 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 errore in applicazione
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 applicazione andata a buon fine
else
-- se non deve essere igniorato, 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( 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 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 nStartIndex
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
nStartIndex = i
EgtOptMachInit()
-- leggere feed dalla macchina
EgtOptMachSetFeeds( 10000, 2000)
-- 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
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 nOperationId = DB_MACH_APPLIED[i].nOperationId
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
i = i + 1
end
local nStopIndex = nStartIndex + nMachInDisp - 1
-- cliclo su tutte le lavorazioni
for k = nStartIndex, nStopIndex do
for j = nStartIndex, nStopIndex do
-- se non è stessa lavorazione, imposto dati e dipendenze
if k ~= j then
-- se stessa Proc
if MACHININGS[DB_MACH_APPLIED[k].nIndexInMachinings].Proc.id == MACHININGS[DB_MACH_APPLIED[j].nIndexInMachinings].Proc.id then
-- se lavorazioni della stessa feature, obbligatorio rispettare ordine
if MACHININGS[DB_MACH_APPLIED[k].nIndexInMachinings].Machining.nFeatureInternalIndex <= MACHININGS[DB_MACH_APPLIED[j].nIndexInMachinings].Machining.nFeatureInternalIndex then
EgtOptMachAddDependence( k, j)
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