-- Strategia: STR0007 -- Descrizione -- Mortasa a coda di rondine e mortasa frontale a coda di rondine -- Feature: 55/56,0 -- carico librerie local BeamLib = require( 'BeamLib') local BeamData = require( 'BeamData') local MachiningLib = require( 'MachiningLib') local FeatureLib = require( 'FeatureLib') -- strategie di base local BladeToWaste = require('BLADETOWASTE') -- Tabella per definizione modulo local STR0007 = {} local Strategy = {} ------------------------------------------------------------------------------------------------------------- function GetMortiseStrategy( Proc, Part) local Machining = {} Machining.Milling = {} Machining.Cutting = {} Machining.Pocketing = {} local Result = {} Result.Milling = {} Result.Cutting = {} Result.Pocketing = {} local ToolSearchParameters = {} -- in caso sia una mortasa frontale, bisogna lavorare il taglio if Proc.FeatureInfo.bIsFrontMortise then -- scelta automatica lavorazione. Non viene mai scelta la motosega if Strategy.Parameters.sCuttingStrategy == 'AUTO' then -- creo piano di taglio sulla testa del tenone local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume, dMaxWasteLength = Strategy.Parameters.dMaxWasteLength } Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters) -- se presente almeno una lavorazione e completo, il taglio è applicabile if #Machining.Cutting > 0 and Result.Cutting and Result.Cutting.sStatus == 'Completed' then Machining.Cutting.bIsApplicable = true end -- se non possibile di lama si prova con fresa if not Machining.Cutting or Result.Cutting.sStatus ~= 'Completed' then Machining.bCuttingWithMill = true end -- lavorazione forzata con utensile lama elseif Strategy.Parameters.sCuttingStrategy == 'BLADE_FORCED' then local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume, dMaxWasteLength = Strategy.Parameters.dMaxWasteLength } Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters) -- se presente almeno una lavorazione e completo, il taglio è applicabile if #Machining.Cutting > 0 and Result.Cutting.sStatus == 'Completed' then Machining.Cutting.bIsApplicable = true else Machining.Cutting.bIsApplicable = false end -- lavorazione forzata con utensile fresa elseif Strategy.Parameters.sCuttingStrategy == 'MILL_FORCED' then Machining.bCuttingWithMill = true -- lavorazione forzata con utensile motosega elseif Strategy.Parameters.sCuttingStrategy == 'CHAINSAW_FORCED' then -- DA FARE!! end -- === ricerca utensile per svuotare taglio iniziale, se taglio non possibile === if Machining.bCuttingWithMill and ( not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit) then ToolSearchParameters = {} ToolSearchParameters.dElevation = 0 ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN Machining.Cutting.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters) if Machining.Cutting.ToolInfo.nToolIndex then Machining.Cutting.bIsApplicable = true local ParametersMRR = {} ParametersMRR.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex Result.Cutting.dMRR = MachiningLib.GetToolMRR( ParametersMRR) Result.Cutting.sStatus = 'Completed' end end end -- === ricerca utensile per lavorare tenone coda di rondine === Machining.Milling.bIsApplicable = false -- se tenone in testa oppure se di coda ma è possibile lavorare dopo separazione if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then ToolSearchParameters.dElevation = Proc.FeatureInfo.dMortiseDepth ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN ToolSearchParameters.sMillShape = 'DOVETAIL' Machining.Milling.ToolInfo = {} Machining.Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters) if Machining.Milling.ToolInfo.nToolIndex then Machining.Milling.bIsApplicable = true -- calcolo numero passate necessarie if Proc.FeatureInfo.dMortiseMaxDist > TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter * 1.5 then Machining.nMillingPathsNeeded = ceil( ( Proc.FeatureInfo.dMortiseMaxDist / 2) / ( TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep * 1.5)) else Machining.nMillingPathsNeeded = 1 end local ParametersMRR = {} ParametersMRR.nToolIndex = Machining.Milling.ToolInfo.nToolIndex Result.Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR) -- l'utensile a coda di rondine deve per forza riuscire a lavorare tutto, altrimenti errore if Machining.Milling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then Result.Milling.sStatus = 'Completed' else Machining.Milling.bIsApplicable = false end end end return Machining, Result end ------------------------------------------------------------------------------------------------------------- local function GetFeatureRotationIndex( Proc) local nVoteIndex -- se fatto con testa sopra if TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop then if Proc.FeatureInfo.vtMortiseN:getZ() < 0 then nVoteIndex = 2 elseif Proc.FeatureInfo.vtMortiseN:getZ() > abs( Proc.FeatureInfo.vtMortiseN:getY()) then nVoteIndex = 4 else nVoteIndex = 3 end -- se fatto con testa sotto elseif TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom then if Proc.FeatureInfo.vtMortiseN:getZ() > 0 then nVoteIndex = 2 elseif Proc.FeatureInfo.vtMortiseN:getZ() < - abs( Proc.FeatureInfo.vtMortiseN:getY()) then nVoteIndex = 4 else nVoteIndex = 3 end end return nVoteIndex end ------------------------------------------------------------------------------------------------------------- -- TODO vedere se leggere direttamente la quality dell'utensile e mediarle nel caso di utensile doppio function GetMortiseMachiningResult( Proc, Result) local TotalResult = {} -- setto il risultato in base agli utensili trovati -- lavorazione mortasa frontale completa if Strategy.Machining.Milling.bIsApplicable and Strategy.Machining.Cutting.bIsApplicable and Proc.FeatureInfo.bIsFrontMortise then TotalResult.sStatus = Result.Milling.sStatus TotalResult.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100) TotalResult.dMRR = ( Result.Milling.dMRR + Result.Cutting.dMRR) / 2 TotalResult.nQuality = FeatureLib.GetFeatureQuality( EgtIf( Strategy.Machining.bCuttingWithMill, 'Mill,Mill', 'Mill,Blade')) TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc) TotalResult.sInfo = '' -- lavorazione mortasa completa elseif Strategy.Machining.Milling.bIsApplicable and not( Proc.FeatureInfo.bIsFrontMortise) then TotalResult.sStatus = Result.Milling.sStatus TotalResult.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100) TotalResult.dMRR = Result.Milling.dMRR TotalResult.nQuality = FeatureLib.GetFeatureQuality( 'Mill') TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc) TotalResult.sInfo = '' -- lavorazione incompleta elseif Strategy.Machining.Cutting.bIsApplicable then TotalResult.sStatus = 'Not-Completed' TotalResult.nCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 50) TotalResult.dMRR = Result.Cutting.dMRR TotalResult.nQuality = FeatureLib.GetFeatureQuality( EgtIf( Strategy.Machining.bCuttingWithMill, 'Mill', 'Blade')) TotalResult.sInfo = 'Tenon not completed' -- strategia non applicabile, manca il taglio di lama sulla lunghezza del tenone else TotalResult = FeatureLib.GetStrategyResultNotApplicable( 'Error on Tenon cutting') end return TotalResult end --------------------------------------------------------------------- local function CalcTopPath( nProcId, AuxId, nAddGrpId, dAltMort, dSideAng, b3Solid) -- copio la curva di base local NewAuxId = EgtCopyGlob( AuxId, nAddGrpId) if not NewAuxId then return end -- ne allungo gli estremi EgtAddCurveCompoLineTg( NewAuxId, 100, false) EgtAddCurveCompoLineTg( NewAuxId, 100, true) EgtMergeCurvesInCurveCompo( NewAuxId) local dOffset = dAltMort * tan( dSideAng) if not EgtOffsetCurveAdv( NewAuxId, dOffset) then return end -- la limito entro la trave local refBox = Frame3d( b3Solid:getMin()) local vtBoxDiag = b3Solid:getMax() - b3Solid:getMin() local nCount NewAuxId, nCount = EgtTrimFlatCurveWithBox( NewAuxId, refBox, vtBoxDiag, true, true, GDB_RT.GLOB) -- eseguo traslazione e offset per portarla sul top local vtMove = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) * ( dAltMort - 10 * GEO.EPS_SMALL) EgtMove( NewAuxId, vtMove, GDB_RT.GLOB) -- se divisa in più parti, le unisco congiungendole con segmenti if nCount > 1 then if EgtGetType( NewAuxId) ~= GDB_TY.CRV_COMPO then NewAuxId = EgtCurveCompo( nAddGrpId, NewAuxId) end for i = 2, nCount do local CrvId = NewAuxId + i - 1 local ptStart = EgtSP( CrvId) EgtAddCurveCompoLine( NewAuxId, ptStart) EgtAddCurveCompoCurve( NewAuxId, CrvId) end end return NewAuxId end ------------------------------------------------------------------------------------------------------------- function ApplyMortiseAntiSplint( Proc, Part) -- se il percorso non è chiuso, aggiungo percorso e lavorazione antischeggia if not EgtCurveIsClosed( Proc.FeatureInfo.idAddAuxGeom) then -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( Part.id) -- calcolo il percorso top mortise local dSideAng = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dSideAngle local dToolDiam = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter local vtExtr = Proc.FeatureInfo.vtMortiseN local nAuxId1 = CalcTopPath( Proc.id, Proc.FeatureInfo.idAddAuxGeom, nAddGrpId, Proc.FeatureInfo.dMortiseDepth, dSideAng, Part.b3Part) -- se esiste il percorso if nAuxId1 then -- creo percorso sulla parte alta della mortasa local dToolRadDelta = Proc.FeatureInfo.dMortiseDepth * tan( dSideAng) local dTopDiam = dToolDiam + 2 * dToolRadDelta -- recupero punto iniziale e finale del percorso local ptStart = EgtSP( nAuxId1, GDB_RT.GLOB) local ptEnd = EgtEP( nAuxId1, GDB_RT.GLOB) if ptStart and ptEnd then local nId1 -- direzione del segmento local vtDir = ptEnd - ptStart ; local dLen = vtDir:len() vtDir:normalize() -- direzioni tangenti iniziale e finale local vtStart = EgtSV( nAuxId1, GDB_RT.GLOB) local vtEnd = EgtEV( nAuxId1, GDB_RT.GLOB) -- angoli local dAngStart = acos( vtStart * vtDir) local dAngEnd = acos( vtEnd * vtDir) local dMaxAng = min( 30, dAngStart, dAngEnd) if dLen < dTopDiam then dMaxAng = min( dMaxAng, asin( dLen / dTopDiam)) end local vtTg = vtDir ; vtTg:rotate( vtExtr, -dMaxAng) -- creo l'arco nId1 = EgtArc2PV( nAddGrpId, ptStart, ptEnd, vtTg, GDB_RT.GLOB) if not nId1 then local sErr = 'Wrong geometry : Error on DtMortise ' EgtOutLog( sErr) return false, sErr end EgtModifyCurveExtrusion( nId1, vtExtr, GDB_RT.GLOB) local Machining = {} Machining.nToolIndex = Strategy.Machining.Milling.ToolInfo.nToolIndex Machining.nType = MCH_MY.MILLING Machining.vtToolDirection = Proc.FeatureInfo.vtMortiseN -- LeadIn / LeadOut Machining.LeadIn = {} Machining.LeadOut = {} Machining.LeadIn.nType = MCH_MILL_LI.TANGENT Machining.LeadOut.nType = MCH_MILL_LI.TANGENT Machining.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC Machining.LeadIn.dPerpDistance = 0 Machining.LeadOut.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC Machining.LeadOut.dPerpDistance = 0 Machining.dRadialOffset = dToolRadDelta - 1 Machining.sDepth = Proc.FeatureInfo.dMortiseDepth - Strategy.Parameters.dOverMatOnLength Machining.Geometry = {{ nId1, -1}} Machining.bInvert = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true) Machining.nWorkside = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT) Machining.dMaxElev = Proc.FeatureInfo.dMortiseDepth if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then Machining.sStage = 'AfterTail' end MachiningLib.AddMachinings( Proc, Machining) else local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id) EgtOutLog( sErr) return false, sErr end else local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id) EgtOutLog( sErr) return false, sErr end end end ------------------------------------------------------------------------------------------------------------- function STR0007.Make( bAddMachining, Proc, Part, CustomParameters) -- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti) local StrategyLib = {} StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId] Strategy.sName = StrategyLib.Config.sStrategyId Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, CustomParameters, StrategyLib.Config) Strategy.Machining = {} Strategy.Result = {} local bAreAllMachiningsAdded = true local Results = {} -- controllo conformità offset mortasa Strategy.Parameters.dOverMatOnRadius = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5) Strategy.Parameters.dOverMatOnLength = EgtClamp( Strategy.Parameters.dOverMatOnLength, -2, 2) -- calcolo se la lavorazione della mortasa può essere spostata dopo taglio di coda local dLengthOnX = Proc.b3Box:getDimX() Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part) -- se mortasa frontale, verifico che esista faccia di taglio if Proc.FeatureInfo.bIsFrontMortise then -- verifico esista la faccia di taglio local ptCutC, vtCutN = EgtSurfTmFacetCenter( Proc.id, 1, GDB_ID.ROOT) if ptCutC and vtCutN and AreSameVectorApprox( Proc.FeatureInfo.vtMortiseN, vtCutN) then -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( Part.id) Strategy.idMortiseCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCutC, vtCutN, Part.b3Part, GDB_RT.GLOB) end end Strategy.Machining, Results = GetMortiseStrategy( Proc, Part) Strategy.Result = GetMortiseMachiningResult( Proc, Results) -- applicazione delle lavorazioni if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then -- taglio in lunghezza sul tenone if Strategy.Machining.Cutting.bIsApplicable then OptionalParameters = {} -- se cutting da fare come svuotatura if Strategy.Machining.bCuttingWithMill then Strategy.Machining.Cutting.Steps = {} Strategy.Machining.Cutting.LeadIn = {} Strategy.Machining.Cutting.nType = MCH_MY.POCKETING Strategy.Machining.Cutting.nSubType = MCH_POCK_SUB.SPIRALIN Strategy.Machining.Cutting.LeadIn.nType = MCH_POCK_LI.ZIGZAG Strategy.Machining.Cutting.Steps.dStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dStep Strategy.Machining.Cutting.Steps.dSideStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dSideStep Strategy.Machining.Cutting.nToolIndex = Strategy.Machining.Cutting.ToolInfo.nToolIndex Strategy.Machining.Cutting.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2 Strategy.Machining.Cutting.LeadIn.dElevation = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2 Strategy.Machining.Cutting.sDepth = 0 Strategy.Machining.Cutting.Geometry = {{ Strategy.idMortiseCutPlane, 0}} Strategy.Machining.Cutting.vtToolDirection = Proc.FeatureInfo.vtMortiseN if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then Strategy.Machining.Cutting.sStage = 'AfterTail' end bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting) -- taglio di lama else for i = 1, #Strategy.Machining.Cutting do if Strategy.Machining.Cutting.bIsApplicable then if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then Strategy.Machining.Cutting[i].sStage = 'AfterTail' end local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting[i]) if not bIsMachiningAdded then bAreAllMachiningsAdded = false end end end end end -- se richiesta passata antischeggia if Strategy.Parameters.bAntiSplint then ApplyMortiseAntiSplint( Proc, Part) end -- passaggio sul profilo if Strategy.Machining.Milling.bIsApplicable then local AuxiliaryData = {} -- se molti passaggi richiesti, si fa svuotatura -- TODO in attesa delle svuotature, si fanno passaggi senza limiti sul numero massimo. Poi togliere il FALSE nella condizione. if false and Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then -- TODO. SERVONO NUOVE SVUOTATURE!!!! else -- aggiungo geometria Strategy.Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}} Strategy.Machining.Milling.nToolIndex = Strategy.Machining.Milling.ToolInfo.nToolIndex Strategy.Machining.Milling.nType = MCH_MY.MILLING Strategy.Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtMortiseN Strategy.Machining.Milling.sDepth = Strategy.Parameters.dOverMatOnLength -- LeadIn / LeadOut Strategy.Machining.Milling.LeadIn = {} Strategy.Machining.Milling.LeadOut = {} Strategy.Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT Strategy.Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT Strategy.Machining.Milling.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC Strategy.Machining.Milling.LeadIn.dPerpDistance = 0 Strategy.Machining.Milling.LeadOut.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC Strategy.Machining.Milling.LeadOut.dPerpDistance = 0 if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then Strategy.Machining.Milling.sStage = 'AfterTail' end -- sistemo il lato e la direzione di lavoro Strategy.Machining.Milling.bInvert = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true) Strategy.Machining.Milling.nWorkside = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT) Strategy.Machining.Milling.dMaxElev = Proc.FeatureInfo.dMortiseDepth -- TODO calcolare SCC -- passate con sovramateriale AuxiliaryData.Clones = {} for i = Strategy.Machining.nMillingPathsNeeded, 1, -1 do -- il primo è il passaggio più esterno local nIndexClones = Strategy.Machining.nMillingPathsNeeded - i + 1 -- cambia solo sovrmateriale radiale AuxiliaryData.Clones[nIndexClones] = {} -- ultima passata con sovramateriale impostato if i == 1 then AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius else -- suddivido step in base al numero passate da fare local dRealSideStep = floor( ( Proc.FeatureInfo.dMortiseMaxDist - TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter) / Strategy.Machining.nMillingPathsNeeded) AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * dRealSideStep end end -- aggiunge lavorazione bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, AuxiliaryData) end end end return bAreAllMachiningsAdded, Strategy.Result end ------------------------------------------------------------------------------------------------------------- return STR0007