431 lines
18 KiB
Lua
431 lines
18 KiB
Lua
-- 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 |