36f1ae5513
- calcolo lunghezza stimata aggiunto anche nel caso di lavorazione splittata
1102 lines
52 KiB
Lua
1102 lines
52 KiB
Lua
-- MachiningLib.lua by Egalware s.r.l. 2024/04/02
|
|
-- Libreria ricerca lavorazioni per Travi
|
|
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
|
|
|
-- Tabella per definizione modulo
|
|
local MachiningLib = {}
|
|
|
|
-- Include
|
|
require( 'EgtBase')
|
|
|
|
-- Carico i dati globali
|
|
local BeamData = require( 'BeamData')
|
|
local BeamLib = require( 'BeamLib')
|
|
local FeatureLib = require( 'FeatureLib')
|
|
|
|
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)
|
|
local bCanMoveAfterSplitcut = ( Part.dLength > BeamData.dMinRaw + 10 * GEO.EPS_SMALL)
|
|
and ( dLengthOnX < 0.7 * Part.dLength - 10 * GEO.EPS_SMALL)
|
|
|
|
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 - 10 * 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 dOriginalStartAddLength = Machinings[i].LeadIn.dStartAddLength
|
|
local dOriginalEndAddLength = Machinings[i].LeadOut.dEndAddLength
|
|
local sOriginalStage = Machinings[i].sStage
|
|
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]))
|
|
end
|
|
local dStartAddLength = dOriginalStartAddLength
|
|
local dEndAddLength = dOriginalEndAddLength
|
|
if MachiningLib.StartsLeftSide( Machinings[i]) then
|
|
dStartAddLength, dEndAddLength = dEndAddLength, dStartAddLength
|
|
end
|
|
if j == 1 then
|
|
dEndAddLength = - ( SplittingPoints[j]:getX() - dEdgeMinX) + BeamData.MILL_OVERLAP
|
|
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
|
|
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
|
|
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
|
|
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].dLengthToMachineAllStepsWithLeadInOut = MachiningLib.GetLengthToMachineAllStepsWithLeadInOut( Machinings[nCurrentMachiningIndex])
|
|
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 = dOriginalStartAddLength
|
|
dLeftAddLength = dOriginalEndAddLength
|
|
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].dLengthToMachineAllStepsWithLeadInOut = MachiningLib.GetLengthToMachineAllStepsWithLeadInOut( Machinings[i])
|
|
end
|
|
end
|
|
|
|
return Machinings
|
|
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
|
|
-- 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 TOOLS[i].SetupInfo.HeadType.bTop and ToolSearchParameters.vtToolDirection:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtToolDirection) - GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
elseif TOOLS[i].SetupInfo.HeadType.bBottom and ToolSearchParameters.vtToolDirection:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtToolDirection) + 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.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 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
|
|
-- scelgo utensile con indice di bontà utensile calcolato come: lunghezza / massimo materiale / diametro
|
|
if TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
-- se entrambi incompleti
|
|
elseif dBestToolResidualDepth > 0 and dCurrentResidualDepth > 0 then
|
|
--scelgo quello che lavora di più
|
|
if dCurrentResidualDepth < dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo LAMA con certe caratteristiche
|
|
-- TODO da completare
|
|
-- TODO il FindBlade dovrà restituire di utilizzare sempre la lama sopra se l'angolo lo permette, ma avendo un'altezza massima (da macchina) oltre cui il DownUp non sarà fattibile (evita collisioni tra asse e pezzo)
|
|
function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
|
local ToolInfo = {}
|
|
|
|
-- parametri obbligatori
|
|
if type( ToolSearchParameters.vtN) ~= 'table' then
|
|
error( 'FindBlade : missing tool direction')
|
|
end
|
|
if type( ToolSearchParameters.bAllowTopHead) ~= 'boolean' then
|
|
error( 'FindBlade : missing top head info')
|
|
end
|
|
if type( ToolSearchParameters.bAllowBottomHead) ~= 'boolean' then
|
|
error( 'FindBlade : missing bottom head info')
|
|
end
|
|
if not ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
error( 'FindBlade : wrong head info')
|
|
end
|
|
|
|
-- parametri opzionali
|
|
ToolSearchParameters.dElevation = ToolSearchParameters.dElevation or 0
|
|
ToolSearchParameters.bForceLongcutBlade = ToolSearchParameters.bForceLongcutBlade or false
|
|
|
|
local nBestToolIndex
|
|
local dBestToolResidualDepth = 0
|
|
for i = 1, #TOOLS do
|
|
local bIsToolCompatible = false
|
|
|
|
if TOOLS[i].sFamily == 'SAWBLADE' then
|
|
if ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bTop
|
|
elseif ToolSearchParameters.bAllowBottomHead and not ToolSearchParameters.bAllowTopHead then
|
|
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bBottom
|
|
else
|
|
bIsToolCompatible = true
|
|
end
|
|
end
|
|
|
|
-- check angolo limite lama
|
|
if TOOLS[i].SetupInfo.HeadType.bTop and ToolSearchParameters.vtN:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtN) - GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
end
|
|
if TOOLS[i].SetupInfo.HeadType.bBottom and ToolSearchParameters.vtN:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtN) + GEO.EPS_ZERO then
|
|
bIsToolCompatible = false
|
|
end
|
|
|
|
if bIsToolCompatible then
|
|
-- TODO gestire accorciamento massimo materiale per inclinazione
|
|
local dCurrentResidualDepth = ToolSearchParameters.dElevation - TOOLS[i].dMaxDepth
|
|
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL) then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
else
|
|
-- prediligo utensile per tagli lunghi, se richiesto
|
|
if ToolSearchParameters.bForceLongcutBlade and not TOOLS[nBestToolIndex].bIsUsedForLongCut and TOOLS[i].bIsUsedForLongCut then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
else
|
|
-- entrambi completi
|
|
if dBestToolResidualDepth <= 10 * GEO.EPS_SMALL and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL then
|
|
-- si sceglie quello con le performance migliori
|
|
if TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex + 10 * GEO.EPS_SMALL then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
-- entrambi incompleti
|
|
elseif dBestToolResidualDepth > 10 * GEO.EPS_SMALL and dCurrentResidualDepth > 10 * GEO.EPS_SMALL then
|
|
-- si sceglie quello che lavora di più
|
|
if dCurrentResidualDepth > dBestToolResidualDepth then
|
|
nBestToolIndex = i
|
|
dBestToolResidualDepth = dCurrentResidualDepth
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ToolInfo.nToolIndex = nBestToolIndex
|
|
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
|
|
|
return ToolInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione per cercare utensile tipo PUNTA A FORARE con certe caratteristiche
|
|
-- TODO da fare
|
|
function MachiningLib.FindDrill()
|
|
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
|
|
|
|
-- 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
|
|
-- scelgo utensile con rapporto lunghezza / diametro minore
|
|
if 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
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- salva in lista globale la lavorazione appena calcolata
|
|
local function AddNewMachining( ProcToAdd, MachiningToAdd, AuxiliaryDataToAdd)
|
|
-- Controllo parametri obbligatori
|
|
if not MachiningToAdd.nType or not MachiningToAdd.nToolIndex or not MachiningToAdd.Geometry or not ProcToAdd.id then
|
|
return false
|
|
end
|
|
|
|
-- se nome non definito, assegno alla lavorazioen un nome standard
|
|
if not MachiningToAdd.sOperationName then
|
|
-- Drilling
|
|
if MachiningToAdd.nType == MCH_MY.DRILLING then
|
|
MachiningToAdd.sTypeName = 'Drill_'
|
|
-- Milling
|
|
elseif MachiningToAdd.nType == MCH_MY.MILLING then
|
|
-- se utensile lama
|
|
if TOOLS[MachiningToAdd.nToolIndex].sFamily == 'SAWBLADE' then
|
|
MachiningToAdd.sTypeName = 'Cut_'
|
|
else
|
|
MachiningToAdd.sTypeName = 'Mill_'
|
|
end
|
|
-- Pocketing
|
|
elseif MachiningToAdd.nType == MCH_MY.POCKETING then
|
|
MachiningToAdd.sTypeName = 'Pocket_'
|
|
-- Mortising
|
|
elseif MachiningToAdd.nType == MCH_MY.MORTISING then
|
|
MachiningToAdd.sTypeName = 'ChSaw_'
|
|
end
|
|
MachiningToAdd.sOperationName = MachiningToAdd.sTypeName .. ( EgtGetName( ProcToAdd.id) or tostring( ProcToAdd.id)) -- .. '_' .. tostring( MachiningToAdd.Geometry)
|
|
end
|
|
if not MachiningToAdd.sToolName then
|
|
MachiningToAdd.sToolName = TOOLS[MachiningToAdd.nToolIndex].sName
|
|
end
|
|
local Machining = {}
|
|
Machining.Proc = ProcToAdd
|
|
Machining.Machining = MachiningToAdd
|
|
Machining.AuxiliaryData = AuxiliaryDataToAdd or {}
|
|
table.insert( MACHININGS, Machining)
|
|
|
|
-- aggiornamento info generiche lavorazioni
|
|
local nHeadCutRotation
|
|
if ProcToAdd.bDown then
|
|
nHeadCutRotation = 3
|
|
elseif ProcToAdd.bSide then
|
|
nHeadCutRotation = 2
|
|
else
|
|
nHeadCutRotation = 1
|
|
end
|
|
MACHININGS.Info.nHeadCutRotation = max( MACHININGS.Info.nHeadCutRotation or 0, nHeadCutRotation)
|
|
|
|
local nSplitCutRotation
|
|
if ProcToAdd.bDown and MachiningToAdd.sStage == 'AfterTail' then
|
|
nSplitCutRotation = 3
|
|
elseif ProcToAdd.bSide and MachiningToAdd.sStage == 'AfterTail' then
|
|
nSplitCutRotation = 2
|
|
else
|
|
nSplitCutRotation = 1
|
|
end
|
|
MACHININGS.Info.nSplitCutRotation = max( MACHININGS.Info.nSplitCutRotation or 0, nSplitCutRotation)
|
|
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- TODO funziona solo con attacco perpendicolare - da aggiungere gestione in caso di attacco tangenziale
|
|
function MachiningLib.AddMachinings( Proc, Machining, AuxiliaryData)
|
|
local bMachiningAdded = false
|
|
|
|
if Machining.CloneStepsHorizontal and Machining.CloneStepsHorizontal.nCount > 1 then
|
|
if not AuxiliaryData then
|
|
AuxiliaryData = {}
|
|
end
|
|
AuxiliaryData.Clones = {}
|
|
|
|
local dOriginalRadialOffset = Machining.dRadialOffset
|
|
local dOriginalLeadInPerpDistance = Machining.LeadIn.dPerpDistance
|
|
local dOriginalLeadOutPerpDistance = Machining.LeadOut.dPerpDistance
|
|
for i = 1, Machining.CloneStepsHorizontal.nCount do
|
|
AuxiliaryData.Clones[i] = {}
|
|
AuxiliaryData.Clones[i].dRadialOffset = dOriginalRadialOffset + Machining.CloneStepsHorizontal.dStep * ( Machining.CloneStepsHorizontal.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
|
|
AuxiliaryData.Clones[i].LeadIn = {}
|
|
AuxiliaryData.Clones[i].LeadOut = {}
|
|
AuxiliaryData.Clones[i].LeadIn.dPerpDistance = dOriginalLeadInPerpDistance - AuxiliaryData.Clones[i].dRadialOffset + dOriginalRadialOffset
|
|
AuxiliaryData.Clones[i].LeadOut.dPerpDistance = dOriginalLeadOutPerpDistance - AuxiliaryData.Clones[i].dRadialOffset + dOriginalRadialOffset
|
|
end
|
|
end
|
|
elseif Machining.CloneStepsVertical and Machining.CloneStepsVertical.nCount > 1 then
|
|
if not AuxiliaryData then
|
|
AuxiliaryData = {}
|
|
end
|
|
AuxiliaryData.Clones = {}
|
|
|
|
local dOriginalRadialOffset = Machining.dRadialOffset
|
|
for i = Machining.CloneStepsVertical.nCount, 1, -1 do
|
|
AuxiliaryData.Clones[i] = {}
|
|
AuxiliaryData.Clones[i].dRadialOffset = dOriginalRadialOffset + Machining.CloneStepsVertical.dStep * ( i - 1)
|
|
end
|
|
end
|
|
|
|
bMachiningAdded = AddNewMachining( Proc, Machining, AuxiliaryData)
|
|
|
|
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 = 'nStepType', nMchParam = MCH_MP.STEPTYPE},
|
|
{ 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'}
|
|
}
|
|
|
|
-- parametri da scrivere nelle note di sistema
|
|
local SystemNotes = {
|
|
}
|
|
|
|
for i = 1, #MACHININGS do
|
|
-- si aggiungono solo quelle della fase richiesta
|
|
if ( sRotation == 'STD' and not MACHININGS[i].Proc.bDown and not MACHININGS[i].Proc.bSide) or
|
|
( MACHININGS[i].Proc.bDown and sRotation == 'DOWN') or
|
|
( MACHININGS[i].Proc.bSide and sRotation == 'SIDE') then
|
|
local nClonesToAdd = 1
|
|
if MACHININGS[i].AuxiliaryData.Clones then
|
|
nClonesToAdd = #MACHININGS[i].AuxiliaryData.Clones
|
|
end
|
|
for j = 1, nClonesToAdd do
|
|
-- creazione lavorazione
|
|
local nOperationId = EgtCreateMachining( MACHININGS[i].Machining.sOperationName, MACHININGS[i].Machining.nType, MACHININGS[i].Machining.sToolName)
|
|
|
|
if nOperationId then
|
|
-- impostazione geometria
|
|
local Geometry
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].Geometry then
|
|
Geometry = MACHININGS[i].AuxiliaryData.Clones[j].Geometry
|
|
elseif MACHININGS[i].Machining.Geometry then
|
|
Geometry = MACHININGS[i].Machining.Geometry
|
|
end
|
|
EgtSetMachiningGeometry( Geometry)
|
|
|
|
-- si scrive info pezzo e feature su geometria lavorazione
|
|
if Geometry then
|
|
EgtSetInfo( Geometry[1][1], 'CUTID', MACHININGS[i].Proc.idCut)
|
|
EgtSetInfo( Geometry[1][1], 'TASKID', MACHININGS[i].Proc.idTask)
|
|
end
|
|
|
|
-- impostazione parametri lavorazione
|
|
-- TODO scrivere sempre Steps, LeadIn, LeadOut nelle tabelle in modo da non dover controllare ogni volta che ci siano
|
|
for k = 1, #MachiningParameters do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][MachiningParameters[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][MachiningParameters[k].sName]
|
|
elseif MACHININGS[i].Machining[MachiningParameters[k].sName] then
|
|
sValue = MACHININGS[i].Machining[MachiningParameters[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.Steps do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].Steps and MACHININGS[i].AuxiliaryData.Clones[j].Steps[MachiningParameters.Steps[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].Steps[MachiningParameters.Steps[k].sName]
|
|
elseif MACHININGS[i].Machining.Steps and MACHININGS[i].Machining.Steps[MachiningParameters.Steps[k].sName] then
|
|
sValue = MACHININGS[i].Machining.Steps[MachiningParameters.Steps[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.Steps[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.LeadIn do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].LeadIn and MACHININGS[i].AuxiliaryData.Clones[j].LeadIn[MachiningParameters.LeadIn[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].LeadIn[MachiningParameters.LeadIn[k].sName]
|
|
elseif MACHININGS[i].Machining.LeadIn and MACHININGS[i].Machining.LeadIn[MachiningParameters.LeadIn[k].sName] then
|
|
sValue = MACHININGS[i].Machining.LeadIn[MachiningParameters.LeadIn[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.LeadIn[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #MachiningParameters.LeadOut do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j].LeadOut and MACHININGS[i].AuxiliaryData.Clones[j].LeadOut[MachiningParameters.LeadOut[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j].LeadOut[MachiningParameters.LeadOut[k].sName]
|
|
elseif MACHININGS[i].Machining.LeadOut and MACHININGS[i].Machining.LeadOut[MachiningParameters.LeadOut[k].sName] then
|
|
sValue = MACHININGS[i].Machining.LeadOut[MachiningParameters.LeadOut[k].sName]
|
|
end
|
|
if sValue then
|
|
EgtSetMachiningParam( MachiningParameters.LeadOut[k].nMchParam, sValue)
|
|
end
|
|
end
|
|
for k = 1, #UserNotes do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][UserNotes[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][UserNotes[k].sName]
|
|
elseif MACHININGS[i].Machining[UserNotes[k].sName] then
|
|
sValue = MACHININGS[i].Machining[UserNotes[k].sName]
|
|
end
|
|
if sValue then
|
|
local sUserNotes = ''
|
|
sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES)
|
|
sUserNotes = EgtSetValInNotes( sUserNotes, UserNotes[k].sMchParam, sValue)
|
|
EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes)
|
|
end
|
|
end
|
|
-- parametri da settare nelle note di sistema
|
|
-- TODO da decidere quali sono le note da salvare qui. Probabilmente tutte quelle relative all'ordine delle lavorazioni
|
|
--if MACHININGS[i].Machining.nMachiningOrder then
|
|
-- sSystemNotes = EgtSetValInNotes( sSystemNotes, 'MachiningOrder', MACHININGS[i].Machining.nMachiningOrder)
|
|
--end
|
|
for k = 1, #SystemNotes do
|
|
local sValue
|
|
if MACHININGS[i].AuxiliaryData.Clones and MACHININGS[i].AuxiliaryData.Clones[j][SystemNotes[k].sName] then
|
|
sValue = MACHININGS[i].AuxiliaryData.Clones[j][SystemNotes[k].sName]
|
|
elseif MACHININGS[i].Machining[SystemNotes[k].sName] then
|
|
sValue = MACHININGS[i].Machining[SystemNotes[k].sName]
|
|
end
|
|
if sValue then
|
|
local sSystemNotes = ''
|
|
sSystemNotes = EgtGetMachiningParam( MCH_MP.SYSNOTES)
|
|
sSystemNotes = EgtSetValInNotes( sSystemNotes, SystemNotes[k].sMchParam, sValue)
|
|
EgtSetMachiningParam( MCH_MP.SYSNOTES, sSystemNotes)
|
|
end
|
|
end
|
|
|
|
local bIsApplyOk = MachiningLib.ApplyMachining( true, false)
|
|
if not bIsApplyOk then
|
|
bAreAllMachiningApplyOk = false
|
|
nErr, sErr = EgtGetLastMachMgrError()
|
|
EgtSetOperationMode( nOperationId, false)
|
|
end
|
|
|
|
-- 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
|
|
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
|
|
local nPhase = EgtGetCurrPhase()
|
|
local nDispId = EgtGetPhaseDisposition( nPhase)
|
|
|
|
if sRotation == 'DOWN' then
|
|
BeamLib.RotatePart( Part, Part.nInitialPosition - 3)
|
|
EgtSetInfo( nDispId, 'ROT', -2)
|
|
EgtSetInfo( nDispId, 'TYPE', 'MID2')
|
|
elseif sRotation == 'SIDE' then
|
|
BeamLib.RotatePart( Part, Part.nInitialPosition - 2)
|
|
EgtSetInfo( nDispId, 'ROT', -1)
|
|
EgtSetInfo( nDispId, 'TYPE', 'MID2')
|
|
else
|
|
BeamLib.RotatePart( Part, Part.nInitialPosition - 1)
|
|
EgtSetInfo( nDispId, 'TYPE', 'END')
|
|
end
|
|
EgtSetInfo( nDispId, 'ORD', MACHININGS[i].Proc.nIndexPartInParts)
|
|
end
|
|
else
|
|
return false, 'UNEXPECTED ERROR: Error on creating machining', bSplitExecuted
|
|
end
|
|
end
|
|
end
|
|
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.GetLengthToMachineAllStepsWithLeadInOut( Machining)
|
|
local dLengthToMachineAllStepsWithLeadInOut = 0
|
|
|
|
if Machining.nType == MCH_OY.MILLING then
|
|
if Machining.Steps.nStepType == MCH_MILL_ST.ZIGZAG then
|
|
dLengthToMachineAllStepsWithLeadInOut = ( Machining.dLengthToMachine * Machining.CloneStepsHorizontal.nCount + ( Machining.LeadIn.dTotalEstimatedDistance + Machining.LeadOut.dTotalEstimatedDistance)) * Machining.Steps.nCount
|
|
else
|
|
dLengthToMachineAllStepsWithLeadInOut = Machining.CloneStepsHorizontal.nCount * ( Machining.dLengthToMachine + Machining.LeadIn.dTotalEstimatedDistance + Machining.LeadOut.dTotalEstimatedDistance) * Machining.Steps.nCount
|
|
end
|
|
elseif Machining.nType == MCH_OY.MORTISING then
|
|
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.CloneStepsVertical.nCount
|
|
else
|
|
dLengthToMachineAllStepsWithLeadInOut = Machining.CloneStepsVertical.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)))
|
|
end
|
|
else
|
|
error( 'GetLengthToMachineAllStepsWithLeadInOut : unknown machining type')
|
|
end
|
|
|
|
return 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
|
|
end
|
|
end
|
|
else
|
|
MachiningCurrent.nPartSegment = -1
|
|
end
|
|
else
|
|
MachiningCurrent.nPartSegment = -1
|
|
end
|
|
end
|
|
|
|
return MACHININGS
|
|
end
|
|
|
|
-- TODO nShifts è solo per debug, si può togliere??
|
|
-- ripristina l'ordine delle lavorazioni interno alla feature, se non rispettato
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.FinalizeSorting()
|
|
local nShifts = 0
|
|
|
|
for i = #MACHININGS, 2, -1 do
|
|
for j = i - 1, 1, -1 do
|
|
if MACHININGS[i].Proc.id == MACHININGS[j].Proc.id
|
|
and MACHININGS[i].Machining.nFeatureInternalIndex < MACHININGS[j].Machining.nFeatureInternalIndex then
|
|
|
|
MACHININGS[i], MACHININGS[j] = MACHININGS[j], MACHININGS[i]
|
|
nShifts = nShifts + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
return MACHININGS, nShifts
|
|
end
|
|
|
|
-- TODO convertire in tabella in cui si chiamano direttamente i nomi delle funzioni, in modo da poter cambiare l'ordine facilmente
|
|
-- TODO libreria Sorting??
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local SortingComparisonRules = {
|
|
-- ordine interno alla feature
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Proc.id == MachiningB.Proc.id then
|
|
if MachiningA.Machining.nFeatureInternalIndex < MachiningB.Machining.nFeatureInternalIndex then
|
|
return 1
|
|
elseif MachiningA.Machining.nFeatureInternalIndex > MachiningB.Machining.nFeatureInternalIndex then
|
|
return -1
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
|
|
-- dipendenze solo spostamento stage 2->4
|
|
-- TODO da fare
|
|
|
|
-- stage
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Machining.nStage < MachiningB.Machining.nStage then
|
|
return 1
|
|
elseif MachiningA.Machining.nStage > MachiningB.Machining.nStage then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- dipendenze
|
|
-- TODO da fare
|
|
|
|
-- segment
|
|
function ( MachiningA, MachiningB)
|
|
if MachiningA.Machining.nPartSegment < MachiningB.Machining.nPartSegment then
|
|
return 1
|
|
elseif MachiningA.Machining.nPartSegment > MachiningB.Machining.nPartSegment then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- testa
|
|
-- TODO da fare
|
|
|
|
-- famiglia utensile
|
|
function ( MachiningA, MachiningB)
|
|
-- TODO tirare fuori da qua??
|
|
local ToolFamilyOrder = {
|
|
SAWBLADE = 1,
|
|
DRILLBIT = 2,
|
|
MILL = 3,
|
|
MORTISE = 4
|
|
}
|
|
local nToolFamilyOrderA = ToolFamilyOrder[ TOOLS[ MachiningA.Machining.nToolIndex].sFamily]
|
|
local nToolFamilyOrderB = ToolFamilyOrder[ TOOLS[ MachiningB.Machining.nToolIndex].sFamily]
|
|
|
|
if nToolFamilyOrderA < nToolFamilyOrderB then
|
|
return 1
|
|
elseif nToolFamilyOrderA > nToolFamilyOrderB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- performance utensile
|
|
function( MachiningA, MachiningB)
|
|
local dToolPerformanceIndexA = TOOLS[MachiningA.Machining.nToolIndex].dPerformanceIndex
|
|
local dToolPerformanceIndexB = TOOLS[MachiningB.Machining.nToolIndex].dPerformanceIndex
|
|
|
|
if dToolPerformanceIndexA > dToolPerformanceIndexB then
|
|
return 1
|
|
elseif dToolPerformanceIndexA < dToolPerformanceIndexB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- probabilmente arrivati qui significa che gli utensili A e B sono gli stessi
|
|
-- se così non fosse e tutte le caratteristiche sopra sono uguali, ordine alfabetico
|
|
function( MachiningA, MachiningB)
|
|
local sToolNameA = TOOLS[MachiningA.Machining.nToolIndex].sName
|
|
local sToolNameB = TOOLS[MachiningB.Machining.nToolIndex].sName
|
|
|
|
if sToolNameA < sToolNameB then
|
|
return 1
|
|
elseif sToolNameA > sToolNameB then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- lato di lavoro
|
|
-- TODO questo, insieme all'ordinamento X, andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
|
function( MachiningA, MachiningB)
|
|
if MachiningA.Machining.vtToolDirection:getY() < -0.174 and MachiningB.Machining.vtToolDirection:getY() >= 0.174 then
|
|
return 1
|
|
elseif MachiningA.Machining.vtToolDirection:getY() >= 0.174 and MachiningB.Machining.vtToolDirection:getY() < -0.174 then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end,
|
|
|
|
-- ordinamento X
|
|
-- TODO questo andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
|
function( MachiningA, MachiningB)
|
|
local bIsMachiningOnFront = MachiningA.Machining.vtToolDirection:getY() < 10 * GEO.EPS_SMALL
|
|
local nResult = 0
|
|
|
|
-- se lavorazione davanti ordine testa->coda
|
|
if bIsMachiningOnFront then
|
|
if MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
|
nResult = 1
|
|
elseif MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
|
nResult = -1
|
|
end
|
|
-- se lavorazione dietro ordine coda->testa
|
|
else
|
|
if MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
|
nResult = 1
|
|
elseif MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
|
nResult = -1
|
|
end
|
|
end
|
|
|
|
return nResult
|
|
end
|
|
}
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function MachiningLib.CompareMachinings( MachiningA, MachiningB)
|
|
-- itera le SortingComparisonRules una per volta. Se non vi è alcuna scelta va avanti (result = 0), altrimenti ritorna true/false in base al risultato
|
|
for i = 1, #SortingComparisonRules do
|
|
local CompareFunction = SortingComparisonRules[i]
|
|
local result = CompareFunction( MachiningA, MachiningB)
|
|
if result ~= 0 then
|
|
return result > 0
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
return MachiningLib
|