-- Strategia: STR0010 -- Descrizione -- fresatura perpendicolare -- Feature: cut, longcut, ... -- carico librerie local BeamLib = require( 'BeamLib') local BeamData = require( 'BeamDataNew') local MachiningLib = require( 'MachiningLib') local FeatureLib = require( 'FeatureLib') -- strategie di base local FaceByMill = require( 'FACEBYMILL') local FaceByBlade = require( 'FACEBYBLADE') local AntiSplintOnFace = require( 'ANTISPLINTONFACE') -- Tabella per definizione modulo local STR0010 = {} local Strategy = {} ------------------------------------------------------------------------------------------------------------- local function GetStrategyCompletionPercentage( Machinings) local dCompletionPercentage = 0 local dCompletionPercentageNumerator = 0 local dCompletionPercentageDenominator = 0 local nWeightsCount = 0 for i = 1, #Machinings do local Machining = Machinings[i] local dWeight = Machining.dResultWeight if not dWeight or ( dWeight < 10 * GEO.EPS_SMALL) then dWeight = 1 else nWeightsCount = nWeightsCount + 1 end -- il peso deve essere settato in tutte le lavorazioni o in nessuna if nWeightsCount ~= 0 and nWeightsCount ~= i then error( 'GetWeightedCompletionPercentage : inconsistent weights') end local dWeightedCompletionPercentage = ( Machining.dCompletionPercentage or 0) / 100 * dWeight if Machining.bIsApplicable then dCompletionPercentageNumerator = dCompletionPercentageNumerator + dWeightedCompletionPercentage end dCompletionPercentageDenominator = dCompletionPercentageDenominator + dWeight end dCompletionPercentage = min( 100 * dCompletionPercentageNumerator / dCompletionPercentageDenominator, 100) return dCompletionPercentage end ------------------------------------------------------------------------------------------------------------- local function CompareEdgesLongestTop( EdgeA, EdgeB) -- si preferiscono i lati più lunghi if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then return true elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then return false -- se stessa lunghezza si preferiscono i lati più in basso else if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then return false -- se stessa Z si preferiscono i lati verso il fronte della trave else if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 10 * GEO.EPS_SMALL then return false else return false end end end end ------------------------------------------------------------------------------------------------------------- local function CompareEdgesLongestBottom( EdgeA, EdgeB) -- si preferiscono i lati più lunghi if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then return true elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then return false -- se stessa lunghezza si preferiscono i lati più in alto else if EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then return false -- se stessa Z si preferiscono i lati verso il fronte della trave else if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then return true elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 10 * GEO.EPS_SMALL then return false else return false end end end end ------------------------------------------------------------------------------------------------------------- local function IsTopologyOk( Proc) if Proc.Topology.sFamily == 'Bevel' or Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sName == 'VGroove-2-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Cut-1-Through' then return true else return false end end ------------------------------------------------------------------------------------------------------------- -- TODO modificare funzione e verificare pinzaggio con regioni e area outline local function IsPositionOk( Proc, Part) local bIsFeatureLong = FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN}) -- se impatta su faccia retro o sotto, controllo fattibilità if Proc.AffectedFaces.bBack then if ( bIsFeatureLong and Proc.b3Box:getDimZ() > Part.dHeight / 2) or ( not bIsFeatureLong and Proc.b3Box:getDimZ() > Part.dHeight / 2) then return false end end if Proc.AffectedFaces.bBottom then if ( bIsFeatureLong and Proc.b3Box:getDimY() > Part.dHeight / 2) or ( not bIsFeatureLong and Proc.b3Box:getDimY() > Part.dHeight / 2) then return false end end -- altrimenti fattibile return true end ------------------------------------------------------------------------------------------------------------- local function GetLongEdgeToMachine( Face, bHeadType) local Edge = {} local EdgesSorted = {} for i = 1, #Face.Edges do table.insert( EdgesSorted, Face.Edges[i]) end if bHeadType.bBottom then table.sort( EdgesSorted, CompareEdgesLongestBottom) else table.sort( EdgesSorted, CompareEdgesLongestTop) end -- se il lato migliore è accessibile si sceglie questo, altrimenti il lato opposto; se entrambi non accessibili (faccia chiusa da due lati) si mantiene il lato scelto Edge = EdgesSorted[1] local EdgeOpposite = BeamLib.FindEdgeBestOrientedAsDirection( Face.Edges, -Edge.vtN) if ( not EdgeOpposite.bIsOpen) and Edge.bIsOpen then Edge = EdgeOpposite end return Edge end ------------------------------------------------------------------------------------------------------------- local function SortMachiningsBySegment( MachiningA, MachiningB) if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then return false elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then return true -- se segmento uguale, si guarda la priorità else if MachiningA.nInternalSortingPriority > MachiningB.nInternalSortingPriority then return false elseif MachiningB.nInternalSortingPriority > MachiningA.nInternalSortingPriority then return true -- se priorità uguale, si minimizzano i cambi di lato else local bIsOddSegment = ( MachiningA.nFeatureSegment % 2 ~= 0) if MachiningA.vtToolDirection:getY() < MachiningB.vtToolDirection:getY() - 10 * GEO.EPS_SMALL then if bIsOddSegment then return true else return false end elseif MachiningA.vtToolDirection:getY() > MachiningB.vtToolDirection:getY() + 10 * GEO.EPS_SMALL then if bIsOddSegment then return false else return true end else return false end end end end ------------------------------------------------------------------------------------------------------------- function STR0010.Make( bAddMachining, Proc, Part, CustomParameters) -- carico parametri da 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, Part, CustomParameters, StrategyLib.Config) Strategy.Machinings = {} Strategy.Result = {} local CalculatedMachinings = {} -- controllo su topologia if not IsTopologyOk( Proc) then Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Strategy ' .. StrategyLib.Config.sStrategyId .. ' not implemented') return false, Strategy.Result end -- controllo dimensioni solo se non è forzata if not CustomParameters.bForcedStrategy then if not IsPositionOk( Proc, Part) then Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Feature not machinable in this position') return false, Strategy.Result end end -- se la lavorazione ostacola il pinzaggio, non posso farla, serve una lavorazioen che lasci il testimone if MachiningLib.IsFeatureHinderingClamping( Proc, Part) then local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable ( Feature hinders clamping)' EgtOutLog( sErr) Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr) return false, Strategy.Result end -- volume della feature local dFeatureVolume = Proc.dVolume -- eventuali punti di spezzatura local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part) local bIsSplitFeature = false if #FeatureSplittingPoints > 0 then bIsSplitFeature = true end local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0) if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then dExtendAfterTail = 10000 end local bAreAllMachiningsAdded = true -- ricerca delle Bottom (la principale deve avere 4 lati esatti) local BottomFace1 = Proc.MainFaces.BottomFaces[1] local BottomFace2 = Proc.MainFaces.BottomFaces[2] if #BottomFace1.Edges ~= 4 then Strategy.Result = FeatureLib.GetStrategyResultNotApplicable() return false, Strategy.Result end -- ricerca utensile local ToolSearchParameters = {} ToolSearchParameters.dElevation = BottomFace1.dElevation ToolSearchParameters.vtToolDirection = BottomFace1.vtN ToolSearchParameters.bAllowTopHead = true ToolSearchParameters.bAllowBottomHead = true ToolSearchParameters.sMillShape = 'STANDARD' local ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters) local nToolIndex = ToolInfo.nToolIndex -- se utensile non trovato si esce subito if not TOOLS[nToolIndex] or not TOOLS[nToolIndex].sName then local sMessage = 'Mill not found' Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage) return false, Strategy.Result end -- per prima si lavora sempre la Bottom principale local Milling1 = {} local OptionalParametersMilling1 = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail} local BottomEdgeToMachine1 = GetLongEdgeToMachine( BottomFace1, TOOLS[nToolIndex].SetupInfo.HeadType) if BottomEdgeToMachine1.bIsOpen then OptionalParametersMilling1.dDepthToMachine = BottomEdgeToMachine1.dElevation + BeamData.CUT_EXTRA end Milling1 = FaceByMill.Make( Proc, Part, BottomFace1, BottomEdgeToMachine1, OptionalParametersMilling1) Milling1.nInternalSortingPriority = 2 Milling1.dResultWeight = 0.3 table.insert( CalculatedMachinings, Milling1) -- se necessario si lavora la seconda Bottom (solo se ha 4 lati esatti) local Milling2 local BottomEdgeToMachine2 if BottomFace2 then local dAngleBetweenFaces = Proc.AdjacencyMatrix[BottomFace1.id + 1][BottomFace2.id + 1] if dAngleBetweenFaces >= -89.5 then Milling2 = {} if #BottomFace2.Edges == 4 then local OptionalParametersMilling2 = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail} BottomEdgeToMachine2 = GetLongEdgeToMachine( BottomFace2, TOOLS[nToolIndex].SetupInfo.HeadType) if BottomEdgeToMachine2.bIsOpen then OptionalParametersMilling2.dDepthToMachine = BottomEdgeToMachine2.dElevation + BeamData.CUT_EXTRA end Milling2 = FaceByMill.Make( Proc, Part, BottomFace2, BottomEdgeToMachine2, OptionalParametersMilling2) Milling2.nInternalSortingPriority = 2 Milling2.dResultWeight = 0.3 else Milling2.bIsApplicable = false end table.insert( CalculatedMachinings, Milling2) end end -- fresatura eventuali facce di chiusura (se non già lavorate) -- TODO funzione if Strategy.Parameters.bFinishWithMill then if Milling1 then -- si recuperano i lati chiusi non lavorati local EdgesClosedNotMachined = {} for i = 1, #BottomFace1.Edges do if not( ( BottomFace1.Edges[i].id == BottomEdgeToMachine1.id) or BottomFace1.Edges[i].bIsOpen) then table.insert( EdgesClosedNotMachined, BottomFace1.Edges[i]) end end -- su ognuno si fa la fresatura di pulizia for i = 1, #EdgesClosedNotMachined do local dMillingOffsetFromSide = Strategy.Parameters.bAntiSplintWithBlade and Strategy.Parameters.dMillingOffsetFromSide or 0 local dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide local dToolMarkLength = Milling1.dToolMarkLength or 0 local OptionalParameters = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, dRadialStepSpan = dToolMarkLength, dDepthToMachine = dDepthToMachine } local Milling = FaceByMill.Make( Proc, Part, BottomFace1, EdgesClosedNotMachined[i], OptionalParameters) Milling.nInternalSortingPriority = 3 Milling.dResultWeight = 0.05 table.insert( CalculatedMachinings, Milling) end end if Milling2 then -- si recuperano i lati chiusi non lavorati local EdgesClosedNotMachined = {} for i = 1, #BottomFace2.Edges do if not( ( BottomFace2.Edges[i].id == BottomEdgeToMachine2.id) or BottomFace2.Edges[i].bIsOpen) then table.insert( EdgesClosedNotMachined, BottomFace2.Edges[i]) end end -- su ognuno si fa la fresatura di pulizia for i = 1, #EdgesClosedNotMachined do local dMillingOffsetFromSide = Strategy.Parameters.bAntiSplintWithBlade and Strategy.Parameters.dMillingOffsetFromSide or 0 local dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide local dToolMarkLength = Milling2.dToolMarkLength or 0 local OptionalParameters = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, dRadialStepSpan = dToolMarkLength, dDepthToMachine = dDepthToMachine } local Milling = FaceByMill.Make( Proc, Part, BottomFace2, EdgesClosedNotMachined[i], OptionalParameters) Milling.nInternalSortingPriority = 3 Milling.dResultWeight = 0.05 table.insert( CalculatedMachinings, Milling) end end end -- antischeggia sulle facce di chiusura delle facce lavorate local CalculatedMachiningsNoAntisplint = BeamLib.TableCopyDeep( CalculatedMachinings) if Strategy.Parameters.bAntiSplintWithBlade then local OptionalParametersAntiSplint = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nInternalSortingPriority = 1, dResultWeight = 0.15 } local AntiSplints1 = AntiSplintOnFace.Make( Proc, Part, BottomFace1, OptionalParametersAntiSplint) for i = 1, #AntiSplints1 do table.insert( CalculatedMachinings, AntiSplints1[i]) end if Milling2 then local AntiSplints2 = AntiSplintOnFace.Make( Proc, Part, BottomFace2, OptionalParametersAntiSplint) for i = 1, #AntiSplints2 do table.insert( CalculatedMachinings, AntiSplints2[i]) end end end -- calcolo completamento, serve la lista di lavorazioni che comprende le non applicabili, ma non gli antischeggia (quelle alzano la qualità e sono già contemplate) Strategy.Result.dCompletionPercentage = GetStrategyCompletionPercentage( CalculatedMachiningsNoAntisplint) Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage) -- lavorazioni da applicare spostate in lista finale for i = 1, #CalculatedMachinings do if CalculatedMachinings[i].bIsApplicable then table.insert( Strategy.Machinings, CalculatedMachinings[i]) end end Strategy.Machinings = MachiningLib.GetSplitMachinings( Strategy.Machinings, FeatureSplittingPoints, Part) table.sort( Strategy.Machinings, SortMachiningsBySegment) -- se non ci sono lati chiusi, la qualità è migliore if Proc.Topology.sName == 'Bevel-1-Through' or Proc.Topology.sName == 'DoubleBevel-2-Through' or Proc.Topology.sName == 'Cut-1-Through' then Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE') else Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Strategy.Machinings) end Strategy.Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Strategy.Machinings) Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6) if Strategy.Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then Strategy.Result.sStatus = 'Completed' else Strategy.Result.sStatus = 'Not-Completed' end -- aggiunta lavorazioni if #Strategy.Machinings > 0 then if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then -- aggiunge lavorazione for j = 1, #Strategy.Machinings do local AuxiliaryData = {} -- se strategia forzata non considero area non pinzabile if CustomParameters.bForcedStrategy then AuxiliaryData.bIgnoreNotClampableLength = true end bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j], AuxiliaryData) end end else Strategy.Result = FeatureLib.GetStrategyResultNotApplicable() end return bAreAllMachiningsAdded, Strategy.Result end ------------------------------------------------------------------------------------------------------------- return STR0010