Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8299df247 | |||
| 4a99f2bdf6 | |||
| 1e86180723 | |||
| f6d6043c0e | |||
| b048e2ebe2 | |||
| fc47bca0f1 | |||
| 0274096f57 | |||
| 983609397e | |||
| 05a8d23f6a | |||
| 40580cdc69 | |||
| f6b2477f2b | |||
| 69db74e30e | |||
| f58004dfeb | |||
| 7c485360de | |||
| 967117cc23 | |||
| 64b2e86a2d | |||
| 89b342a564 | |||
| 117e475de5 | |||
| a7b817b211 | |||
| d8c6a8ad55 | |||
| 9026acd9ca | |||
| 204346326f | |||
| 5d6e4c397d | |||
| 64bde8924d | |||
| cb6115d23f | |||
| 771c1367b1 | |||
| 6092063daa | |||
| 44650c303c | |||
| 69fa0d741d | |||
| 8e55ddda1f | |||
| 7a8fb04ebe | |||
| 77c27d911c | |||
| 3a29f273c9 | |||
| bab5b07bd1 | |||
| 683ae78c65 | |||
| 06d9529b7b | |||
| 922a7ac846 | |||
| a21a3979f1 | |||
| fcbed252e1 | |||
| b68bbb2c48 | |||
| 6fe6b41e87 | |||
| 78189631c1 | |||
| 1a6433d5f8 | |||
| 28026358b9 | |||
| b73fb86be9 | |||
| 1032557782 | |||
| 0ca5f92b96 | |||
| 0f58c026d0 | |||
| 70d170b2a3 | |||
| 06bc0f77df | |||
| a40cc026c9 | |||
| 34fb38ac00 | |||
| aaa06c1af5 | |||
| 98a48522ee | |||
| 6fd356f757 | |||
| 83895cc3bf | |||
| d001273704 | |||
| 621c9149b5 | |||
| f6f625c7cc | |||
| 9d8985093d | |||
| fe8275f05a | |||
| d32403f546 | |||
| 63d4ca7176 | |||
| 0889ae5c7a | |||
| 0fc9e1dd09 | |||
| 63308c0349 | |||
| 7e5ab8ecd3 | |||
| bddaf91fb7 | |||
| 2c77277c85 | |||
| 38a6ac237e | |||
| ed4d97ba51 | |||
| 7b12eaf331 | |||
| 3e55af917e | |||
| 73b6d80510 | |||
| 65c2c244d6 | |||
| 2ae547a24e | |||
| aff61f1daa | |||
| 0db6a74f8c | |||
| f68533944c | |||
| 37e08e3f42 | |||
| c6ced91b14 | |||
| 8efb64810a | |||
| 02390c2e9b | |||
| 7f7d75c113 | |||
| ecd50c0fea | |||
| 6f195e7fac | |||
| 626183f310 | |||
| fe6c0bb31c | |||
| 1c24f1046d | |||
| 70cfdd056f | |||
| 9ebb9c77db |
+21
-14
@@ -214,9 +214,6 @@ end
|
||||
local sLog = 'BatchProcess : ' .. BEAM.FILE .. ', ' .. ( BEAM.MACHINE or EgtGetCurrMachineName()) .. ', ' .. sFlag
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- TODO forzatura calcolo con prerotazioni. Cancellare dopo che è stata aggiunta la gestione corretta
|
||||
local bCalcBestPieceUnloadPosition = true or BEAM.FLAG == 10
|
||||
|
||||
-- Dati dei file
|
||||
-- TODO spostare a quando flag ~= 6 e 9
|
||||
local sDir, sTitle = EgtSplitPath( BEAM.FILE)
|
||||
@@ -253,6 +250,7 @@ elseif BEAM.FLAG == 9 then
|
||||
local Proc = FeatureLib.GetProcFromTrimesh( BEAM.FEATUREID, Part)
|
||||
Proc.nGrp = EgtGetInfo( Proc.id, 'GRP', 'i')
|
||||
Proc.nPrc = EgtGetInfo( Proc.id, 'PRC', 'i')
|
||||
Proc.nParts = EgtSurfTmPartCount( Proc.id) or 1
|
||||
|
||||
Proc.Topology = {}
|
||||
if FeatureLib.NeedTopologyFeature( Proc, Part) then
|
||||
@@ -494,6 +492,7 @@ if bToProcess then
|
||||
return
|
||||
end
|
||||
|
||||
-- TODO in caso di "GEN_sPiecesLoadingPosition = FULL_PRE_ROTATION" bisogna controllare anche sezione ribaltata di 90°
|
||||
-- Verifico sezione barra non troppo grande
|
||||
if not BeamData.MAX_WIDTH2 or not BeamData.MAX_HEIGHT2 then
|
||||
if ( dRawW > BeamData.MAX_WIDTH + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT + 10 * GEO.EPS_SMALL) then
|
||||
@@ -551,7 +550,7 @@ if bToProcess then
|
||||
end
|
||||
|
||||
-- Sistemo le travi nel grezzo
|
||||
local bPbOk, sPbErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, nil, PARTS, BEAM.FLAG ~= 6, bCalcBestPieceUnloadPosition)
|
||||
local bPbOk, sPbErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, nil, PARTS, BEAM.FLAG ~= 6, BEAM.FLAG == 10)
|
||||
if not bPbOk then
|
||||
BEAM.ERR = 18
|
||||
BEAM.MSG = sPbErr
|
||||
@@ -640,7 +639,8 @@ if bToProcess then
|
||||
BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig)
|
||||
PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON)
|
||||
TIMER:stopElapsed('Json')
|
||||
PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bCalcBestPieceUnloadPosition)
|
||||
-- parametro FlipRot sempre a false perchè a barra già creata non si possono più ruotare i pezzi
|
||||
PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], false)
|
||||
|
||||
-- sovramateriale in testa al pezzo
|
||||
local dDeltaS = max( PARTS[i].dPosX - ( dBarLen - dLen), 0)
|
||||
@@ -693,12 +693,9 @@ if bToProcess then
|
||||
-- TODO gestire errori e messaggi di ritorno in questo caso
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.ProcessMachinings( PARTS)
|
||||
|
||||
-- si cancella gruppo temporaneo contenente entità da cancellare
|
||||
EgtErase( idTempGroup)
|
||||
BeamExec.GetProcessings( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.GetCombinationMatrix( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.ProcessMachinings( PARTS, BEAM.FLAG == 10)
|
||||
|
||||
local sOutput = ''
|
||||
|
||||
@@ -725,7 +722,7 @@ if bToProcess then
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
end
|
||||
BEAM.ROT = -( RESULT[i].nRotation or 1) + 1
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
@@ -741,7 +738,7 @@ if bToProcess then
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = sMsg
|
||||
BEAM.ROT = -( RESULT[i].nRotation or 1) + 1
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
@@ -767,7 +764,7 @@ if bToProcess then
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = -19
|
||||
BEAM.MSG = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg
|
||||
BEAM.ROT = -( RESULT[i].nRotation or 1) + 1
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
@@ -775,6 +772,16 @@ if bToProcess then
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo alternative (scrive già le variabili globali per interfaccia)
|
||||
if BEAM.FLAG == 10 then
|
||||
TIMER:startElapsed('Alternatives')
|
||||
BeamExec.ProcessAlternatives( PARTS)
|
||||
TIMER:stopElapsed('Alternatives')
|
||||
end
|
||||
|
||||
-- si cancella gruppo temporaneo contenente entità da cancellare
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
-- TODO: se scarico a caduta (-101, -102) le lavorazioni dopo separazione vanno disattivate. Scrivere info feature incompleta su quelle feature
|
||||
|
||||
-- Salvo il progetto
|
||||
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
-- Process.lua by Egalware s.r.l. 2024/04/02
|
||||
-- Gestione calcolo disposizione e lavorazioni per Travi
|
||||
-- Si opera sulla macchina corrente
|
||||
-- 2024/04/02 PRIMA VERSIONE
|
||||
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not sMachDir then
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Segnalazione avvio
|
||||
EgtOutLog( '*** Beam Process Start ***', 1)
|
||||
|
||||
-- Carico le librerie
|
||||
_G.package.loaded.BasicCustomerStrategies = nil
|
||||
_G.package.loaded.BeamExec = nil
|
||||
_G.package.loaded.BeamLib = nil
|
||||
_G.package.loaded.DiceCut = nil
|
||||
_G.package.loaded.FaceData = nil
|
||||
_G.package.loaded.FeatureLib = nil
|
||||
_G.package.loaded.Identity = nil
|
||||
_G.package.loaded.Logs = nil
|
||||
_G.package.loaded.MachiningLib = nil
|
||||
_G.package.loaded.PreSimulationLib = nil
|
||||
_G.package.loaded.LeadInOutLib = nil
|
||||
-- strategie di base sempre presenti
|
||||
_G.package.loaded['HEADCUT\\HEADCUT'] = nil
|
||||
_G.package.loaded['TAILCUT\\TAILCUT'] = nil
|
||||
-- libreria macchina
|
||||
_G.package.loaded.BeamDataNew = nil
|
||||
-- libreria calcolo tempo esecuzione
|
||||
_G.package.loaded.TimeLib = nil
|
||||
|
||||
-- TODO controllare se c'è un modo migliore per resettare librerie delle strategie caricate precedentemente
|
||||
-- Per ottimizzare potremmo anche ciclare solo fino al numero di strategie raggiunto per il momento.
|
||||
-- Infatti difficile ci siano 9999 strategie.
|
||||
-- reset strategie caricate come librerie
|
||||
for i = 1, 9999 do
|
||||
local idSTRTemp = EgtReplaceString( EgtNumToString( i/10000, -4), '0.', '')
|
||||
local sLibraryToReload = "STR" .. idSTRTemp .. "\\STR" .. idSTRTemp
|
||||
if _G.package.loaded[sLibraryToReload] then
|
||||
_G.package.loaded[sLibraryToReload] = nil
|
||||
end
|
||||
end
|
||||
local vtCoreStrategiesNames = EgtFindAllFiles( BEAM.BASEDIR .. '\\StrategyLibs\\*.lua')
|
||||
for i = 1, #vtCoreStrategiesNames do
|
||||
local sCurrentName = EgtSplitString( vtCoreStrategiesNames[i], '.')[1]
|
||||
if _G.package.loaded[sCurrentName] then
|
||||
_G.package.loaded[sCurrentName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Variabili globali
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Recupero trave (E' SEMPRE E SOLO UNA) ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessInputData()
|
||||
-- Recupero il pezzo e i suoi dati
|
||||
local nId = EgtGetFirstPart()
|
||||
if nId then
|
||||
table.insert( PARTS, { nInd = #PARTS + 1, id = nId, sName = ( EgtGetName( nId) or ( 'Id=' .. tonumber( nId)))})
|
||||
local Ls = EgtGetFirstNameInGroup( PARTS[1].id, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
return false
|
||||
end
|
||||
PARTS[1].b3PartOriginal = b3Solid
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetDataConfig()
|
||||
-- recupero utensili dal magazzino
|
||||
BeamExec.GetToolsFromDB()
|
||||
-- TODO da gestire eventuali errori bloccanti
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle travi nel grezzo ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessBeams()
|
||||
-- Lunghezza totale delle travi
|
||||
local dLen = PARTS[1].b3PartOriginal:getDimX()
|
||||
local dRawW = PARTS[1].b3PartOriginal:getDimY()
|
||||
local dRawH = PARTS[1].b3PartOriginal:getDimZ()
|
||||
|
||||
-- Determinazione minimo grezzo scaricabile
|
||||
BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
|
||||
|
||||
local dOvmHead = BeamData.OVM_HEAD or 10
|
||||
local dOvmMid = BeamData.OVM_MID or 10
|
||||
|
||||
local dRawL = max( dLen + dOvmHead + dOvmMid, BeamData.dMinRaw)
|
||||
|
||||
-- Recupero info pezzi
|
||||
local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, true)
|
||||
if not bOk then
|
||||
EgtOutLog( sErr)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle lavorazioni nelle travi ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessFeatures()
|
||||
|
||||
BeamExec.GetProcessings( PARTS, true)
|
||||
BeamExec.GetCombinationMatrix( PARTS, true)
|
||||
BeamExec.ProcessMachinings( PARTS, true)
|
||||
|
||||
-- scrittura variabili globali per interfaccia
|
||||
BEAM.PREROTATE90 = PARTS[1].nInitialPosition - 1
|
||||
BEAM.PREINVERT = EgtIf( PARTS[1].bPartInCombiIsInverted, 1, 0)
|
||||
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
local sOutput = ''
|
||||
for i = 1, #RESULT do
|
||||
local sMsg = ''
|
||||
if RESULT[i].sType == 'Feature' then
|
||||
sMsg = RESULT[i].ChosenStrategy.sInfo
|
||||
elseif RESULT[i].sType == 'Part' then
|
||||
sMsg = RESULT[i].sMsg
|
||||
end
|
||||
sMsg = string.gsub( sMsg or '', '\n', ' ', 10)
|
||||
sMsg = string.gsub( sMsg or '', '\r', ' ', 10)
|
||||
-- trovata almeno una strategia e feature lavorata completamente
|
||||
if RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Completed' then
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg or '')
|
||||
|
||||
-- trovata almeno una strategia ma nessuna applicabile oppure non trovata alcuna strategia
|
||||
elseif RESULT[i].sType == 'Feature'
|
||||
and ( ( RESULT[i].ChosenStrategy.sStatus == 'Not-Applicable')
|
||||
or ( not RESULT[i].ChosenStrategy.sStrategyName)) then
|
||||
|
||||
nErrCnt = nErrCnt + 1
|
||||
if #sMsg == 0 then
|
||||
sMsg = 'No applicable strategy found'
|
||||
end
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
else
|
||||
-- segnalazione scarico pezzo standard, incompleto o a caduta
|
||||
if RESULT[i].sType == 'Part' and ( RESULT[i].nErr == -100 or RESULT[i].nErr == -101 or RESULT[i].nErr == -102) then
|
||||
-- nulla da segnalare
|
||||
|
||||
-- feature incompleta e altro
|
||||
elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then
|
||||
nWarnCnt = nWarnCnt + 1
|
||||
sMsg = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- si calcolano alternative
|
||||
TIMER:startElapsed('Alternatives')
|
||||
BeamExec.ProcessAlternatives( PARTS)
|
||||
TIMER:stopElapsed('Alternatives')
|
||||
|
||||
-- cancello gruppo temporaneo
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
if #sOutput > 0 then EgtOutLog( sOutput) end
|
||||
if nErrCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'ERRORS')
|
||||
return false
|
||||
elseif nWarnCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'WARNINGS')
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Esecuzione ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- calcolo tempo esecuzione
|
||||
TIMER:start()
|
||||
EgtOutLog( ' Execution timer started')
|
||||
|
||||
-- script principale
|
||||
|
||||
if not MyProcessInputData() then return end
|
||||
|
||||
-- recupero parametri generali da progetto
|
||||
BeamExec.GetGeneralParameters()
|
||||
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
BeamLib.CreateTempGroup()
|
||||
|
||||
if not MyProcessBeams() then return end
|
||||
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
-- Abilito Vmill
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
||||
|
||||
MyProcessFeatures()
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
-- GetWallData.lua by Egaltech s.r.l. 2022/06/28
|
||||
-- Recupero dati da file WallData.lua di macchina
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Per test
|
||||
--GWD = {}
|
||||
--GWD.MACHINE = 'Essetre-90480019_MW'
|
||||
|
||||
local sLog = 'GetBeamData : ' .. GWD.MACHINE
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( GWD.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
GWD.ERR = 12
|
||||
GWD.MSG = 'Error not configured for beam machine : ' .. GWD.MACHINE
|
||||
WriteErrToLogFile( GWD.ERR, GWD.MSG)
|
||||
PostErrView( GWD.ERR, GWD.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Carico i dati globali
|
||||
_G.package.loaded.BeamData = nil
|
||||
local BD = require( 'BeamDataNew')
|
||||
|
||||
-- Assegno valori di interesse
|
||||
GWD.SIMUL_VIEW_DIR = BD.SIMUL_VIEW_DIR
|
||||
GWD.OVM_MID = BD.OVM_MID
|
||||
|
||||
-- Tutto ok
|
||||
GWD.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ GetBeamData completed')
|
||||
+991
-360
File diff suppressed because it is too large
Load Diff
+116
-9
@@ -328,6 +328,18 @@ function BeamLib.RotateRawPart( Part, nNumberOfRotations)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.CreateAddGroup( PartId, sGroupName)
|
||||
AddGrpId = EgtGroup( PartId or GDB_ID.NULL)
|
||||
if not AddGrpId then
|
||||
return false
|
||||
end
|
||||
-- assegno nome, flag di layer per gruppo di lavoro e colore
|
||||
EgtSetName( AddGrpId, sGroupName)
|
||||
EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup())
|
||||
EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 25))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.CreateOrEmptyAddGroup( PartId)
|
||||
-- recupero i dati del gruppo aggiuntivo
|
||||
@@ -341,15 +353,9 @@ function BeamLib.CreateOrEmptyAddGroup( PartId)
|
||||
EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup())
|
||||
return EgtEmptyGroup( AddGrpId)
|
||||
end
|
||||
|
||||
-- altrimenti lo creo
|
||||
AddGrpId = EgtGroup( PartId or GDB_ID.NULL)
|
||||
if not AddGrpId then
|
||||
return false
|
||||
end
|
||||
-- assegno nome, flag di layer per gruppo di lavoro e colore
|
||||
EgtSetName( AddGrpId, sMchGrp)
|
||||
EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup())
|
||||
EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 25))
|
||||
BeamLib.CreateAddGroup( PartId, sMchGrp)
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -506,10 +512,69 @@ function BeamLib.GetDirectionFromSCC( nSCC)
|
||||
elseif nSCC == MCH_SCC.ADIR_ZM then
|
||||
vtSCC = -Z_AX()
|
||||
end
|
||||
|
||||
|
||||
return vtSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- Restituisce una tabella con i punti ai vertici della faccia, in globale
|
||||
-- ordinati partendo da quello ai valori minimi degli assi e i successivi secondo rotazione destrorsa X+;
|
||||
-- solo per Proc a 1 faccia
|
||||
function BeamLib.GetSortedVertices( Proc)
|
||||
local PtVerticesSorted = {}
|
||||
|
||||
-- se più di una faccia si esce subito
|
||||
if Proc.nFct > 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local PtVertices = {}
|
||||
local nFirstIndex
|
||||
local dMinYZ = GEO.INFINITO
|
||||
for i = 1, #Proc.Faces[1].Edges do
|
||||
local Edge = Proc.Faces[1].Edges[i]
|
||||
table.insert( PtVertices, Edge.ptStart)
|
||||
if ( Edge.ptStart:getY() + Edge.ptStart:getZ() < dMinYZ) then
|
||||
nFirstIndex = i
|
||||
dMinYZ = Edge.ptStart:getY() + Edge.ptStart:getZ()
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( PtVerticesSorted, PtVertices[nFirstIndex])
|
||||
local nCurrentIndex = nFirstIndex
|
||||
-- faccia che guarda verso X+, ordine ok
|
||||
if Proc.Faces[1].vtN:getX() > GEO.EPS_SMALL then
|
||||
for _ = 1, #PtVertices - 1 do
|
||||
_, nCurrentIndex = BeamLib.GetAdjacentIndices( nCurrentIndex, #PtVertices)
|
||||
table.insert( PtVerticesSorted, PtVertices[nCurrentIndex])
|
||||
end
|
||||
-- faccia che guarda verso X-, ordine da invertire
|
||||
else
|
||||
for _ = 1, #PtVertices - 1 do
|
||||
nCurrentIndex = BeamLib.GetAdjacentIndices( nCurrentIndex, #PtVertices)
|
||||
table.insert( PtVerticesSorted, PtVertices[nCurrentIndex])
|
||||
end
|
||||
end
|
||||
|
||||
return PtVerticesSorted
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- restituisce il precedente e prossimo indice 1-based, tenendo conto del massimo indice
|
||||
function BeamLib.GetAdjacentIndices( nCurrentIndex, nMaxIndex)
|
||||
local nPreviousIndex, nNextIndex
|
||||
|
||||
if ( nCurrentIndex < 1) or ( nCurrentIndex > nMaxIndex) then
|
||||
return
|
||||
end
|
||||
|
||||
-- circular indexing 1-based
|
||||
nPreviousIndex = ((nCurrentIndex - 2 + nMaxIndex) % nMaxIndex) + 1
|
||||
nNextIndex = (nCurrentIndex % nMaxIndex) + 1
|
||||
|
||||
return nPreviousIndex, nNextIndex
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- Funzione per determinare se la faccia ha lati molto corti (trascurabili) ed è quindi approssimabile ad una 3 facce
|
||||
function BeamLib.Is3EdgesApprox( Proc, idFace, nAddGrpId)
|
||||
@@ -769,6 +834,11 @@ function BeamLib.GetBlockedAxis( nToolIndex, sBlockedAxis, b3Raw, vtTool, vtOut)
|
||||
return ''
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.StringReplaceChar( sOriginal, nPosition, sChar)
|
||||
return sOriginal:sub( 1, nPosition-1) .. sChar .. sOriginal:sub( nPosition+1)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.BinaryToDecimal( dNumber)
|
||||
local sNumberToConvert = tostring( dNumber)
|
||||
@@ -819,6 +889,43 @@ function BeamLib.CalculateStringBinaryFormat( dNumber, CharNumber)
|
||||
return NumberString
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.ConvertBitIndexToRotationIndex( sBitIndexCombination)
|
||||
local nRotationIndex
|
||||
|
||||
if sBitIndexCombination == '1000' then
|
||||
return 1
|
||||
elseif sBitIndexCombination == '0100' then
|
||||
return 2
|
||||
elseif sBitIndexCombination == '0010' then
|
||||
return 3
|
||||
elseif sBitIndexCombination == '0001' then
|
||||
return 4
|
||||
elseif sBitIndexCombination == '1000_INV' then
|
||||
return 5
|
||||
elseif sBitIndexCombination == '0100_INV' then
|
||||
return 6
|
||||
elseif sBitIndexCombination == '0010_INV' then
|
||||
return 7
|
||||
elseif sBitIndexCombination == '0001_INV' then
|
||||
return 8
|
||||
end
|
||||
|
||||
return nRotationIndex
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- reindicizza una tabella passata ripartendo dall'indice nStartIndex e mantenendo l'ordine
|
||||
function BeamLib.RotateTableFromIndex( Table, nStartIndex)
|
||||
local RotatedTable = {}
|
||||
|
||||
for i = 1, #Table do
|
||||
RotatedTable[#RotatedTable + 1] = Table[((RotatedTable + i - 2) % #Table) + 1]
|
||||
end
|
||||
|
||||
return RotatedTable
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
--- copia una tabella lua in modo ricorsivo, ossia mantiene indipendenti anche tutte le sottotabelle
|
||||
--- ATTENZIONE: in caso di modifiche vanno gestiti anche i tipi custom; sarebbe meglio metterla nel LuaLibs
|
||||
|
||||
+1
-1
@@ -453,7 +453,7 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
-- se piani non ortogonali, diminuisco la distanza di offset opportunamente
|
||||
local dOffsetParallelOriginal = dOffsetParallel
|
||||
if not bGetOrtoPlanes then
|
||||
local dCoeff = ( vtNMainFace ^ vtNSubordinateFace):len()
|
||||
local dCoeff = max( ( vtNMainFace ^ vtNSubordinateFace):len(), 0.5)
|
||||
dOffsetParallel = dOffsetParallel * dCoeff
|
||||
dOffsetOrthogonal = dOffsetOrthogonal * dCoeff
|
||||
end
|
||||
|
||||
+35
-9
@@ -91,7 +91,9 @@ function FaceData.GetFacesByAdjacencyNumber( Proc)
|
||||
FacesByAdjacencyNumber[i] = {}
|
||||
end
|
||||
for i = 1, Proc.nFct do
|
||||
table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], Proc.Faces[i])
|
||||
if #Proc.Faces[i].Adjacencies > 0 then
|
||||
table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], Proc.Faces[i])
|
||||
end
|
||||
end
|
||||
|
||||
return FacesByAdjacencyNumber
|
||||
@@ -186,7 +188,7 @@ function FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
Faces[i].id = i - 1
|
||||
Faces[i].idTrimesh = Proc.id
|
||||
Faces[i].ptCenter, Faces[i].vtN = EgtSurfTmFacetCenter( Proc.id, i - 1, GDB_ID.ROOT)
|
||||
if Proc.nFct < 6 or FaceIsToGet( i) then
|
||||
if Proc.nFct < 7 or FaceIsToGet( i) then
|
||||
-- frame OCS faccia
|
||||
Faces[i].frFrameHV = Frame3d( Faces[i].ptCenter, Faces[i].vtN)
|
||||
-- elevazione calcolata rispetto al box della parte
|
||||
@@ -383,10 +385,28 @@ local function GetBottomFaces( Proc)
|
||||
return { Proc.Faces[1]}
|
||||
end
|
||||
|
||||
-- la faccia di fondo ha sempre Fct - 1 adiacenze
|
||||
-- la faccia di fondo ha sempre Fct - 1 adiacenze, tranne caso speciale DoubleBevel con facce di chiusura triangolari
|
||||
local FacesByAdjacencyNumber = FaceData.GetFacesByAdjacencyNumber( Proc)
|
||||
if FacesByAdjacencyNumber then
|
||||
BottomFaces = FacesByAdjacencyNumber[ Proc.nFct - 1]
|
||||
-- caso speciale DoubleBevel
|
||||
if #BottomFaces == 0 then
|
||||
if Proc.nParts == 1 then
|
||||
BottomFaces = FacesByAdjacencyNumber[ Proc.nFct / 2]
|
||||
-- DoubleBevel composto da più parti
|
||||
else
|
||||
for i = #FacesByAdjacencyNumber, 1, -1 do
|
||||
if #FacesByAdjacencyNumber[i] > 0 then
|
||||
BottomFaces = FacesByAdjacencyNumber[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
-- se non sono state trovate facce di fondo significa che nessuna faccia ha adiacenze -> DoubleBevel-2
|
||||
if #BottomFaces == 0 then
|
||||
BottomFaces = Proc.Faces
|
||||
end
|
||||
end
|
||||
end
|
||||
-- si rimuovono le facce non adatte ad essere lavorate
|
||||
local nBottomFaces = #BottomFaces
|
||||
local nCurrentFace = 1
|
||||
@@ -476,7 +496,7 @@ end
|
||||
local function GetLongFaces( Proc, MainFaces)
|
||||
local LongFaces = {}
|
||||
|
||||
if Proc.nFct > 5 then
|
||||
if Proc.nFct > 6 then
|
||||
error( 'GetLongFaces : Topology not implemented')
|
||||
elseif Proc.nFct == 1 then
|
||||
return {}
|
||||
@@ -584,7 +604,7 @@ end
|
||||
local function GetSideFaces( Proc, MainFaces)
|
||||
local SideFaces = {}
|
||||
|
||||
if Proc.nFct > 5 then
|
||||
if Proc.nFct > 6 then
|
||||
error( 'GetSideFaces : Topology not implemented')
|
||||
elseif Proc.nFct == 1 then
|
||||
return {}
|
||||
@@ -690,15 +710,21 @@ function FaceData.GetMainFaces( Proc, Part)
|
||||
Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Tunnel' or Proc.Topology.sFamily == 'Bevel' or
|
||||
Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sFamily == 'Cut' or Proc.Topology.sFamily == 'HeadCut' or Proc.Topology.sFamily == 'TailCut' then
|
||||
|
||||
if ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5)
|
||||
or ( Proc.nFct == 1) or Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
if Proc.nParts == 1 and ( ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5)
|
||||
or ( Proc.nFct == 1) or Proc.Topology.sName == 'Bevel-2-Blind') then
|
||||
|
||||
MainFaces.TunnelAddedFaces = GetTunnelFaces( Proc, Part)
|
||||
end
|
||||
|
||||
MainFaces.BottomFaces = GetBottomFaces( Proc)
|
||||
MainFaces.LongFaces = GetLongFaces( Proc, MainFaces)
|
||||
MainFaces.SideFaces = GetSideFaces( Proc, MainFaces)
|
||||
if Proc.nParts == 1 then
|
||||
MainFaces.LongFaces = GetLongFaces( Proc, MainFaces)
|
||||
MainFaces.SideFaces = GetSideFaces( Proc, MainFaces)
|
||||
-- caso tipo DoubleBevel con facce separate
|
||||
else
|
||||
MainFaces.LongFaces = {}
|
||||
MainFaces.SideFaces = {}
|
||||
end
|
||||
|
||||
else
|
||||
MainFaces = nil
|
||||
|
||||
+22
-24
@@ -43,7 +43,7 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- restituisce vero se la feature con box b3Proc taglia l'intera sezione della barra
|
||||
local function IsFeatureCuttingEntireSection( b3Proc, Part)
|
||||
function FeatureLib.IsFeatureCuttingEntireSection( b3Proc, Part)
|
||||
return ( b3Proc:getDimY() > ( Part.b3Part:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimZ() > ( Part.b3Part:getDimZ() - 500 * GEO.EPS_SMALL))
|
||||
end
|
||||
|
||||
@@ -198,7 +198,7 @@ function FeatureLib.ClassifyTopology( Proc, Part)
|
||||
|
||||
if not Proc.AffectedFaces then Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part) end
|
||||
|
||||
local bIsFeatureCuttingEntireSection = IsFeatureCuttingEntireSection( Proc.b3Box, Part)
|
||||
local bIsFeatureCuttingEntireSection = FeatureLib.IsFeatureCuttingEntireSection( Proc.b3Box, Part)
|
||||
local bIsFeatureCuttingEntireLength = IsFeatureCuttingEntireLength( Proc.b3Box, Part)
|
||||
local bIsAnyDimensionLongAsPart = IsAnyDimensionLongAsPart( Proc, Part)
|
||||
local vAdj = Proc.AdjacencyMatrix
|
||||
@@ -226,13 +226,13 @@ function FeatureLib.ClassifyTopology( Proc, Part)
|
||||
elseif Proc.nFct == 2 and bAllAnglesConcave and #vTriangularFaces == 1 then
|
||||
sFamily = 'Bevel'
|
||||
bIsThrough = false
|
||||
elseif Proc.nFct == 2 and bAllAnglesConcave and ( Proc.AffectedFaces.bLeft or Proc.AffectedFaces.bRight) and ( Proc.AffectedFaces.bFront or Proc.AffectedFaces.bBack) then
|
||||
elseif Proc.nFct == 2 and bAllAnglesConcave and Proc.nParts == 1 and ( Proc.AffectedFaces.bLeft or Proc.AffectedFaces.bRight) and ( Proc.AffectedFaces.bFront or Proc.AffectedFaces.bBack) then
|
||||
sFamily = 'Rabbet'
|
||||
bIsThrough = true
|
||||
elseif Proc.nFct == 2 and bAllAnglesConcave then
|
||||
elseif Proc.nFct == 2 and bAllAnglesConcave and Proc.nParts == 1 then
|
||||
sFamily = 'VGroove'
|
||||
bIsThrough = true
|
||||
elseif Proc.nFct == 2 and not bAllAnglesConcave and bIsAnyDimensionLongAsPart then
|
||||
elseif Proc.nFct == 2 and ( not bAllAnglesConcave or Proc.nParts == 2) and bIsAnyDimensionLongAsPart then
|
||||
sFamily = 'DoubleBevel'
|
||||
bIsThrough = true
|
||||
elseif Proc.nFct == 3 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 1 and #vTriangularFaces == 2 then
|
||||
@@ -244,7 +244,9 @@ function FeatureLib.ClassifyTopology( Proc, Part)
|
||||
elseif Proc.nFct == 3 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 3 then
|
||||
sFamily = 'Groove'
|
||||
bIsThrough = false
|
||||
elseif Proc.nFct == 4 and #vFacesByAdjNumber[2] == 4 and #vTriangularFaces == 2 then
|
||||
elseif Proc.nFct == 4
|
||||
and ( ( not bAllAnglesConcave and ( ( #vFacesByAdjNumber[2] == 2 and #vTriangularFaces == 2) or ( #vFacesByAdjNumber[3] == 2)))
|
||||
or ( #vTriangularFaces == 2 and Proc.nParts == 2)) then
|
||||
sFamily = 'DoubleBevel'
|
||||
bIsThrough = false
|
||||
elseif Proc.nFct == 4 and bAllAnglesConcave and #vFacesByAdjNumber[3] == 2 then
|
||||
@@ -259,7 +261,9 @@ function FeatureLib.ClassifyTopology( Proc, Part)
|
||||
elseif Proc.nFct == 5 and bAllAnglesConcave and #vFacesByAdjNumber[4] == 1 then
|
||||
sFamily = 'Pocket'
|
||||
bIsThrough = false
|
||||
elseif Proc.nFct == 6 and #vFacesByAdjNumber[2] == 4 and #vFacesByAdjNumber[3] == 2 and #vTriangularFaces == 4 then
|
||||
elseif Proc.nFct == 6
|
||||
and ( ( #vFacesByAdjNumber[1] == 4 and #vFacesByAdjNumber[3] == 2 and #vTriangularFaces == 4 and not bAllAnglesConcave)
|
||||
or ( #vFacesByAdjNumber[1] == 4 and #vTriangularFaces == 4 and Proc.nParts == 2)) then
|
||||
sFamily = 'DoubleBevel'
|
||||
bIsThrough = false
|
||||
end
|
||||
@@ -333,6 +337,9 @@ function FeatureLib.GetAdditionalInfo( Proc, Part)
|
||||
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
||||
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
||||
Proc.FeatureInfo, Proc.MainFaces = FeatureLib.GetRafterNotchData( Proc)
|
||||
elseif ( ID.IsScarfJoint( Proc) or ID.IsScarfSimple( Proc)) then
|
||||
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
||||
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
||||
end
|
||||
|
||||
return Proc
|
||||
@@ -926,8 +933,9 @@ end
|
||||
-- funzione che verifica se la feature, lavorata in questa fase, compromette lettura misura laser
|
||||
function FeatureLib.CalculateFeatureHindersLaserMeasure( Proc, Part)
|
||||
local bFeatureHindersLaserMeasure = false
|
||||
-- se la feature è aperta frontalmente, posteriormente e di testa, allora potrebbe impattare sulla misura laser, controllo caso per caso
|
||||
if Proc.AffectedFaces.bRight and Proc.AffectedFaces.bFront and Proc.AffectedFaces.bBack then
|
||||
-- se la feature è aperta frontalmente, posteriormente, di testa e più bassa di 40mm, allora potrebbe impattare sulla misura laser, controllo caso per caso
|
||||
if Proc.AffectedFaces.bRight and Proc.AffectedFaces.bFront and Proc.AffectedFaces.bBack and
|
||||
( Proc.b3Box:getMin():getZ() - Part.b3Raw:getMin():getZ()) < 40 then
|
||||
bFeatureHindersLaserMeasure = true
|
||||
end
|
||||
return bFeatureHindersLaserMeasure
|
||||
@@ -963,13 +971,13 @@ function FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part)
|
||||
-- condizioni per limitare pinzaggio testa/coda
|
||||
local bUpdateIng = true
|
||||
-- se dimensione del box della feature maggiore di metà pinzaggio minimo o metà spessore pezzo
|
||||
bUpdateIng = bUpdateIng and Proc.b3Box:getDimZ() > dMinHIng
|
||||
-- bUpdateIng = bUpdateIng and Proc.b3Box:getDimZ() > dMinHIng
|
||||
-- se la feature si trova più in basso del minimo pinzabile in Z o il 35% dello spessore pezzo
|
||||
bUpdateIng = bUpdateIng and Proc.b3Box:getMin():getZ() < Part.b3Raw:getMin():getZ() + dMinZ
|
||||
-- se feature è al di sotto del pinzaggio massimo
|
||||
bUpdateIng = bUpdateIng and Proc.b3Box:getMin():getZ() < dMaxHZ
|
||||
-- se ho le morse verticali, o se la feature è in centro o verso alto, controllo se non prendo abbastanza.
|
||||
if bIsVertClamps or ( Proc.b3Box:getMin():getZ() - Part.b3Raw:getMin():getZ()) > BeamData.MIN_HEIGHT then
|
||||
-- se ho le morse verticali, o se la feature è in centro o verso alto, controllo se non prendo abbastanza
|
||||
if bIsVertClamps or ( Proc.b3Box:getMin():getZ() - Part.b3Raw:getMin():getZ()) > BeamData.MIN_HEIGHT then
|
||||
bUpdateIng = bUpdateIng and dDeltaZClamp < BeamData.VICE_MINH
|
||||
end
|
||||
|
||||
@@ -981,24 +989,14 @@ function FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part)
|
||||
dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
|
||||
end
|
||||
dNotClampableLengthHead = dOffs
|
||||
elseif Proc.AffectedFaces.bLeft then
|
||||
end
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
local dOffs = Proc.b3Box:getMax():getX() - Part.b3Part:getMin():getX()
|
||||
-- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse
|
||||
if not bIsVertClamps and dDeltaZClamp > BeamData.VICE_MINH and BeamData.VICE_MAXH then
|
||||
dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
|
||||
end
|
||||
dNotClampableLengthTail = dOffs
|
||||
-- TODO il controllo sul punto centrale non è corretto, deve essere rivisto.
|
||||
-- Si lascia qui commentato perchè era così anche in quello vecchio, quindi potrebbe essere che in qualche caso potesse funzionare
|
||||
-- elseif Proc.b3Box:getCenter():getX() > Part.b3Part:getCenter():getX() then
|
||||
-- local dOffs = Part.b3Part:getMax():getX() - Proc.b3Box:getMin():getX()
|
||||
-- local dDist = Part.b3Part:getMax():getX() - Proc.b3Box:getMax():getX()
|
||||
-- -- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse
|
||||
-- if not bIsVertClamps and dDeltaZClamp > BeamData.VICE_MINH and BeamData.VICE_MAXH then
|
||||
-- dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
|
||||
-- end
|
||||
-- -- dDist serve??
|
||||
-- dNotClampableLengthHead = dOffs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+11
-9
@@ -5,7 +5,7 @@
|
||||
local Logs = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo)
|
||||
function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo, nReProcessCycles)
|
||||
|
||||
local nCycles = 1
|
||||
local nOffsetIndex = 0
|
||||
@@ -13,15 +13,13 @@ function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo)
|
||||
nCycles = 2
|
||||
end
|
||||
|
||||
EgtOutLog( ' === === === === === === === === === === REPROCESS CYCLES ' .. EgtNumToString( nReProcessCycles) .. ' === === === === === === === === === === === ===')
|
||||
EgtOutLog( ' === === === === === === === === === === FEATURES STRATEGIES === === === === === === === === === === === ===')
|
||||
for nCycle = 1, nCycles do
|
||||
local nStartIndex = 1 + nOffsetIndex
|
||||
local nEndIndex = 4 + nOffsetIndex
|
||||
if nCycle == 1 then
|
||||
EgtOutLog( ' === === === === === === === === === === FEATURES STRATEGIES === === === === === === === === === === === ===')
|
||||
else
|
||||
EgtOutLog( ' === === === === === === === === === === === === === === === === === === === === === === === === === === ===')
|
||||
EgtOutLog( ' === === === === === === === === FEATURES STRATEGIES PIECE INVERTED === === === === === === === === === ===')
|
||||
end
|
||||
EgtOutLog( ' === === === === === === === === === === === === === === === === === === === === === === === === === === ===')
|
||||
EgtOutLog( ' === === === === === === === === FEATURES STRATEGIES PIECE INVERTED === === === === === === === === === ===')
|
||||
EgtOutLog( ' Feature ID | BTL POSITION | 90 ROTATION | 180 ROTATION | 270 ROTATION |')
|
||||
EgtOutLog( '----------------------------------------------------------------------------------------------------------')
|
||||
|
||||
@@ -74,7 +72,11 @@ function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo)
|
||||
ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus == 'Not-Applicable' then
|
||||
sStatusStrategy = 'N'
|
||||
sRating = '----'
|
||||
sIndexes = ' (C:---|Q:---|T:---)'
|
||||
if EgtStartsWith( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sInfo, 'REJECTED') then
|
||||
sIndexes = ' ( --- REJECTED ---)'
|
||||
else
|
||||
sIndexes = ' (C:---|Q:---|T:---)'
|
||||
end
|
||||
else
|
||||
if ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus == 'Completed' then
|
||||
sStatusStrategy = 'C'
|
||||
@@ -88,7 +90,7 @@ function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo)
|
||||
end
|
||||
-- se c'è una chosen strategy, si aggiunge prefisso '*' per indicare nel log qual è la strategia che è stata scelta
|
||||
local nIndexBestStrategy = ProcessingsOnPart.Rotation[nRotLog][ProcLog].nIndexBestStrategy or 0
|
||||
local sLogLineProc = EgtIf( nIndexBestStrategy == nCountStrategies, '*', '') .. sRating .. sIndexes .. ' (' ..
|
||||
local sLogLineProc = EgtIf( nIndexBestStrategy == nCountStrategies, '*', '') .. sRating .. sIndexes .. ' (' ..
|
||||
tostring( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].sStrategyId) .. ')' ..
|
||||
sStatusStrategy .. ' |'
|
||||
while string.len( sLogLineProc) <= 38 do
|
||||
|
||||
+116
-55
@@ -363,16 +363,22 @@ local function TestEngagement( sBladeEngagement, Parameters, OptionalParameters)
|
||||
-- attacco perpendicolare
|
||||
local PerpendicularLeadInOut = LeadInOutLib.CalculateLeadInOut( 'Perpendicular', Parameters, LeadInOutOptionalParameters)
|
||||
-- check extracorsa nei punti di attacco
|
||||
|
||||
PointsOnToolTipCenter = {
|
||||
PreSimulationLib.GetPointOnToolTipCenter( PerpendicularLeadInOut.LeadIn.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool),
|
||||
PreSimulationLib.GetPointOnToolTipCenter( PerpendicularLeadInOut.LeadOut.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool)
|
||||
}
|
||||
local bOutOfStrokePerpendicular = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
-- se non è in extracorsa si aggiunge come attacco possibile
|
||||
-- attacco perpendicolare non in extracorsa: si verifica se è in collisione
|
||||
if not bOutOfStrokePerpendicular then
|
||||
LeadInOut.Perpendicular = PerpendicularLeadInOut
|
||||
LeadInOut.Perpendicular.bMoveAfterSplit = bMoveAfterSplit
|
||||
CheckCollisionOptionalParameters.PointsToCheck = {}
|
||||
table.insert( CheckCollisionOptionalParameters.PointsToCheck, PerpendicularLeadInOut.LeadIn.ptPoint)
|
||||
table.insert( CheckCollisionOptionalParameters.PointsToCheck, PerpendicularLeadInOut.LeadOut.ptPoint)
|
||||
local bCollisionFoundPerpendicular, bMoveAfterSplitPerpendicular = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters)
|
||||
-- attacco perpendicolare possibile
|
||||
if not bCollisionFoundPerpendicular then
|
||||
LeadInOut.Perpendicular = PerpendicularLeadInOut
|
||||
LeadInOut.Perpendicular.bMoveAfterSplit = bMoveAfterSplitPerpendicular
|
||||
end
|
||||
end
|
||||
-- se c'è almeno un lato chiuso l'unico attacco possibile è il perpendicolare
|
||||
if not ( Edge.bIsStartOpen and Edge.bIsEndOpen) then
|
||||
@@ -468,6 +474,11 @@ end
|
||||
function MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
local ToolInfo = {}
|
||||
|
||||
-- direzione utensile e fipo fresa obbligatori, altrimenti si esce
|
||||
if not ToolSearchParameters.vtToolDirection or not ToolSearchParameters.sMillShape then
|
||||
return ToolInfo
|
||||
end
|
||||
|
||||
local nBestToolIndex
|
||||
local dBestToolResidualDepth = 0
|
||||
for i = 1, #TOOLS do
|
||||
@@ -511,6 +522,18 @@ function MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO da sostituire con test collisione come lama
|
||||
local bIsFromBottom = ToolSearchParameters.vtToolDirection:getZ() < - 10 * GEO.EPS_SMALL
|
||||
local bIsFromTop = ToolSearchParameters.vtToolDirection:getZ() > 10 * GEO.EPS_SMALL
|
||||
local bIsSlanted = abs( ToolSearchParameters.vtToolDirection:getY()) > 0.707
|
||||
local bIsOnHeadOrTail = Proc.AffectedFaces.bLeft or Proc.AffectedFaces.bRight
|
||||
if ( ( bIsFromBottom and TOOLS[i].SetupInfo.HeadType.bTop) or ( bIsFromTop and TOOLS[i].SetupInfo.HeadType.bBottom))
|
||||
and ( not bIsSlanted)
|
||||
and ( not bIsOnHeadOrTail) then
|
||||
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
|
||||
-- scelgo il migliore
|
||||
if bIsToolCompatible then
|
||||
@@ -579,6 +602,7 @@ end
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione per cercare utensile tipo LAMA con certe caratteristiche
|
||||
-- TODO da rivedere/completare
|
||||
-- TODO per Engagement serviranno (opzionali) sBlockedAxis e vtAux
|
||||
function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
local ToolInfo = {}
|
||||
|
||||
@@ -607,6 +631,7 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
local bIsDicing = ToolSearchParameters.bIsDicing or false
|
||||
local sRestLengthSideForPreSimulation = ToolSearchParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = ToolSearchParameters.bCannotSplitRestLength or false
|
||||
local bDisableRealElevationCheck = ToolSearchParameters.bDisableRealElevationCheck or false
|
||||
|
||||
local nBestToolIndex
|
||||
local dBestToolResidualDepth = 0
|
||||
@@ -640,7 +665,8 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
bIsBladeOk, CurrentEngagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
||||
@@ -1141,13 +1167,29 @@ function MachiningLib.AddMachinings( Proc, Machining, AuxiliaryData)
|
||||
return bMachiningAdded
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione che verifica se ha senso riprocessare tutto dall'inizio,
|
||||
-- perchè ci sono buone probabilità che l'errore trovato in fase di applicazione si possa risolvere (escludendo la lavorazione scelta in precedenza)
|
||||
local function IsReProcessWorthIt( nError)
|
||||
local bReProcess = false
|
||||
|
||||
-- errori di Extra-corsa
|
||||
if nError == 2110 or nError == 2216 or nError == 2318 or nError == 2424 or nError == 2508 then
|
||||
bReProcess = true
|
||||
end
|
||||
|
||||
return bReProcess
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione per aggiungere una nuova lavorazione
|
||||
function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
function MachiningLib.AddOperations( MACHININGS, Part, sRotation)
|
||||
local nErr
|
||||
local sErr = ''
|
||||
local bAreAllMachiningApplyOk = true
|
||||
local bSplitExecuted = false
|
||||
local bTryToReProcess = false
|
||||
|
||||
-- parametri generali lavorazione
|
||||
local MachiningParameters = {
|
||||
@@ -1339,12 +1381,27 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
MachStartAxesPos = EgtGetMachiningStartAxes(),
|
||||
MachEndAxesPos = EgtGetMachiningEndAxes()}
|
||||
table.insert( DB_MACH_APPLIED, MachExtraInfo)
|
||||
|
||||
-- se non esistono punto iniziale o finale, si disattiva operazione
|
||||
if not MachExtraInfo.MachStartAxesPos or not MachExtraInfo.MachEndAxesPos then
|
||||
EgtSetOperationMode( nOperationId, false)
|
||||
end
|
||||
|
||||
-- se errore in applicazione
|
||||
if not bIsApplyOk then
|
||||
bAreAllMachiningApplyOk = false
|
||||
nErr, sErr = EgtGetLastMachMgrError()
|
||||
EgtSetOperationMode( nOperationId, false)
|
||||
local nOffsetIndex = EgtIf( Part.bPartInCombiIsInverted, 4, 0)
|
||||
local CurrProc = PROCESSINGS[MACHININGS[i].Proc.nIndexPartInParts].Rotation[MACHININGS[i].Proc.nIndexRotation+nOffsetIndex][MACHININGS[i].Proc.nIndexInVProc]
|
||||
-- si annulla la feature scelta, in modo che un successivo ricalcolo non la tenga in considerazione
|
||||
CurrProc.AvailableStrategies[CurrProc.nIndexBestStrategy].Result.sStatus = 'Not-Applicable'
|
||||
CurrProc.AvailableStrategies[CurrProc.nIndexBestStrategy].Result.sInfo = 'REJECTED (' .. sErr .. ')'
|
||||
CurrProc.ChosenStrategy= nil
|
||||
-- si verifica se vale la pena riprocessare tutto (perchè si pensa possa risolvere il problema)
|
||||
if IsReProcessWorthIt( nErr) then
|
||||
bTryToReProcess = true
|
||||
end
|
||||
-- update risultati
|
||||
-- TODO è corretto mettere non applicabile????? disattivare e dare un'incompleta gialla?
|
||||
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.sStatus = 'Not-Applicable'
|
||||
@@ -1353,7 +1410,7 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
-- se applicazione andata a buon fine
|
||||
else
|
||||
|
||||
-- se non deve essere igniorato, si salva ingombro lavorazione attuale e fasi successive
|
||||
-- se non deve essere ignorato, si salva ingombro lavorazione attuale e fasi successive
|
||||
if not MACHININGS[i].AuxiliaryData.bIgnoreNotClampableLength then
|
||||
-- salvo ingombro non pinzabile testa/coda
|
||||
local nCurrRotation = MACHININGS[i].Proc.nIndexRotation
|
||||
@@ -1395,9 +1452,9 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
bSplitExecuted = true
|
||||
MACHININGS.Info.bSplitExecuted = true
|
||||
|
||||
BeamLib.AddPhaseWithRawParts( MACHININGS[i].Proc.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET)
|
||||
BeamLib.AddPhaseWithRawParts( Part.idRaw, BeamData.ptOriXR, BeamData.dPosXR, BeamData.RAW_OFFSET)
|
||||
-- se grezzo successivo senza pezzi e finale, va tolto
|
||||
local nNextRawId = EgtGetNextRawPart( MACHININGS[i].Proc.idRaw)
|
||||
local nNextRawId = EgtGetNextRawPart( Part.idRaw)
|
||||
if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BeamData.dMinRaw then
|
||||
EgtRemoveRawPartFromCurrPhase( nNextRawId)
|
||||
end
|
||||
@@ -1411,25 +1468,27 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
local nPhase = EgtGetCurrPhase()
|
||||
local idDisp = EgtGetPhaseDisposition( nPhase)
|
||||
|
||||
-- posizione iniziale considerando eventuiali prerotazioni
|
||||
local nRealInitialPosition = Part.nInitialPosition
|
||||
if sRotation == 'DOWN' then
|
||||
local nRotation = EgtIf( Part.nInitialPosition + 2 > 4, Part.nInitialPosition + 2 - 4, Part.nInitialPosition + 2) - 1
|
||||
local nRotation = EgtIf( nRealInitialPosition + 2 > 4, nRealInitialPosition + 2 - 4, nRealInitialPosition + 2) - 1
|
||||
BeamLib.RotateRawPart( Part, nRotation)
|
||||
EgtSetInfo( idDisp, 'ROT', -2)
|
||||
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
||||
elseif sRotation == 'SIDE' then
|
||||
local nRotation = EgtIf( Part.nInitialPosition + 1 > 4, Part.nInitialPosition + 1 - 4, Part.nInitialPosition + 1) - 1
|
||||
local nRotation = EgtIf( nRealInitialPosition + 1 > 4, nRealInitialPosition + 1 - 4, nRealInitialPosition + 1) - 1
|
||||
BeamLib.RotateRawPart( Part, nRotation)
|
||||
EgtSetInfo( idDisp, 'ROT', -1)
|
||||
EgtSetInfo( idDisp, 'TYPE', 'MID2')
|
||||
else
|
||||
local nRotation = Part.nInitialPosition - 1
|
||||
local nRotation = nRealInitialPosition - 1
|
||||
BeamLib.RotateRawPart( Part, nRotation)
|
||||
EgtSetInfo( idDisp, 'TYPE', 'END')
|
||||
end
|
||||
EgtSetInfo( idDisp, 'ORD', MACHININGS[i].Proc.nIndexPartInParts)
|
||||
end
|
||||
else
|
||||
return false, 'UNEXPECTED ERROR: Error on creating machining', bSplitExecuted
|
||||
return false, 'UNEXPECTED ERROR: Error on creating machining', bSplitExecuted, false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1446,13 +1505,13 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
EgtSetInfo( idDisp, 'TCING', Part.NotClampableLength[sRotation].dTail or 0)
|
||||
end
|
||||
|
||||
return bAreAllMachiningApplyOk, sErr, bSplitExecuted
|
||||
return bAreAllMachiningApplyOk, sErr, bSplitExecuted, bTryToReProcess
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function MachiningLib.ApplyMachining( bRecalc, bApplyPost)
|
||||
local bResult = EgtApplyMachining( bRecalc, bApplyPost)
|
||||
|
||||
|
||||
return bResult
|
||||
end
|
||||
|
||||
@@ -1491,14 +1550,14 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
if Machining.nType == MCH_MY.DRILLING then
|
||||
local function fact(n) return n == 0 and 1 or n * fact(n - 1) end
|
||||
local nSteps = ceil( Machining.sDepth / Machining.dStep)
|
||||
local dLenghtEachStep = Machining.sDepth / nSteps
|
||||
local dLengthEachStep = Machining.sDepth / nSteps
|
||||
-- numero dei movimenti a step, compresi andata e ritorno per scarico truciolo
|
||||
local nTotStepMovement = 2 * fact( nSteps)
|
||||
-- in feed si lavorano solo gli step
|
||||
local dFeedTime = ( ( dLenghtEachStep + Machining.dStartSafetyLength) * nSteps) / dToolFeed
|
||||
-- ritorno per scaricare e approccio al prossimo step seno in feed finale
|
||||
local dEndFeedTime = ( dLenghtEachStep * ( nTotStepMovement - nSteps) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) * 2) / dToolEndFeed
|
||||
dLengthToMachineAllStepsWithLeadInOut = dLenghtEachStep * nTotStepMovement
|
||||
local dFeedTime = ( ( dLengthEachStep + Machining.dStartSafetyLength) * nSteps) / dToolFeed
|
||||
-- ritorno per scaricare e approccio al prossimo step sono in feed finale
|
||||
local dEndFeedTime = ( dLengthEachStep * ( nTotStepMovement - nSteps) + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) * 2) / dToolEndFeed
|
||||
dLengthToMachineAllStepsWithLeadInOut = dLengthEachStep * nTotStepMovement
|
||||
dTimeToMachineTotal = dFeedTime + dEndFeedTime
|
||||
elseif Machining.nType == MCH_MY.MILLING then
|
||||
-- stima LeadIn e LeadOut; se non settati si impostano a valori di default
|
||||
@@ -1755,44 +1814,46 @@ function MachiningLib.ShortestPathSorting()
|
||||
|
||||
-- se è una lavorazione
|
||||
while DB_MACH_APPLIED[i] and DB_MACH_APPLIED[i].sType ~= 'DISP' do
|
||||
-- se lavorazione non attiva non va considerata
|
||||
local nOperationId = DB_MACH_APPLIED[i].nOperationId
|
||||
if EgtGetOperationMode( nOperationId) then
|
||||
local ptMinX, ptMaxX
|
||||
-- aggiungo lavorazioni
|
||||
local nToolIndex = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nToolIndex
|
||||
EgtOptMachAddTool( nToolIndex, 2, 2) -- , [ num dTC_X, num dTC_Y, num dTC_Z, num dTC_A, num dTC_B, num dTC_C])
|
||||
-- viene eseguito prima il gruppo con indice più alto, quindi si inverte indice dato che lo stage è dal più piccolo al più grande
|
||||
local nGroup = 10 - MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage
|
||||
local MachStartAxesPos = DB_MACH_APPLIED[i].MachStartAxesPos
|
||||
local MachEndAxesPos = DB_MACH_APPLIED[i].MachEndAxesPos
|
||||
EgtOptMachAddMachining( i, nToolIndex, nGroup, MachStartAxesPos, MachEndAxesPos)
|
||||
table.insert( MachiningOptList, i)
|
||||
if DB_MACH_APPLIED[i].MachStartAxesPos and DB_MACH_APPLIED[i].MachEndAxesPos then
|
||||
-- se lavorazione non attiva non va considerata
|
||||
local nOperationId = DB_MACH_APPLIED[i].nOperationId
|
||||
if EgtGetOperationMode( nOperationId) then
|
||||
local ptMinX, ptMaxX
|
||||
-- aggiungo lavorazioni
|
||||
local nToolIndex = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nToolIndex
|
||||
EgtOptMachAddTool( nToolIndex, 2, 2) -- , [ num dTC_X, num dTC_Y, num dTC_Z, num dTC_A, num dTC_B, num dTC_C])
|
||||
-- viene eseguito prima il gruppo con indice più alto, quindi si inverte indice dato che lo stage è dal più piccolo al più grande
|
||||
local nGroup = 10 - MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage
|
||||
local MachStartAxesPos = DB_MACH_APPLIED[i].MachStartAxesPos
|
||||
local MachEndAxesPos = DB_MACH_APPLIED[i].MachEndAxesPos
|
||||
EgtOptMachAddMachining( i, nToolIndex, nGroup, MachStartAxesPos, MachEndAxesPos)
|
||||
table.insert( MachiningOptList, i)
|
||||
|
||||
-- si salvano i punti minimi e massimi tra tutte le lavorazioni di ogni gruppo
|
||||
if MachStartAxesPos[1] < MachEndAxesPos[1] then
|
||||
ptMinX = MachStartAxesPos
|
||||
ptMaxX = MachEndAxesPos
|
||||
else
|
||||
ptMinX = MachEndAxesPos
|
||||
ptMaxX = MachStartAxesPos
|
||||
end
|
||||
|
||||
-- si aggiungono le info di gruppo
|
||||
local bFound = false
|
||||
for t = 1, #GroupInfo do
|
||||
if GroupInfo[t].nGroup == nGroup then
|
||||
if GroupInfo[t].ptMin[1] > ptMinX[1] then GroupInfo[t].ptMin = ptMinX end
|
||||
if GroupInfo[t].ptMax[1] < ptMaxX[1] then GroupInfo[t].ptMax = ptMaxX end
|
||||
bFound = true
|
||||
-- si salvano i punti minimi e massimi tra tutte le lavorazioni di ogni gruppo
|
||||
if MachStartAxesPos[1] < MachEndAxesPos[1] then
|
||||
ptMinX = MachStartAxesPos
|
||||
ptMaxX = MachEndAxesPos
|
||||
else
|
||||
ptMinX = MachEndAxesPos
|
||||
ptMaxX = MachStartAxesPos
|
||||
end
|
||||
end
|
||||
-- se non ho trovato, si aggiunge in lista
|
||||
if not bFound then
|
||||
table.insert( GroupInfo, { nGroup = nGroup, nStage = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage, ptMin = ptMinX, ptMax = ptMaxX})
|
||||
end
|
||||
|
||||
nMachInDisp = nMachInDisp + 1
|
||||
-- si aggiungono le info di gruppo
|
||||
local bFound = false
|
||||
for t = 1, #GroupInfo do
|
||||
if GroupInfo[t].nGroup == nGroup then
|
||||
if GroupInfo[t].ptMin[1] > ptMinX[1] then GroupInfo[t].ptMin = ptMinX end
|
||||
if GroupInfo[t].ptMax[1] < ptMaxX[1] then GroupInfo[t].ptMax = ptMaxX end
|
||||
bFound = true
|
||||
end
|
||||
end
|
||||
-- se non ho trovato, si aggiunge in lista
|
||||
if not bFound then
|
||||
table.insert( GroupInfo, { nGroup = nGroup, nStage = MACHININGS[DB_MACH_APPLIED[i].nIndexInMachinings].Machining.nStage, ptMin = ptMinX, ptMax = ptMaxX})
|
||||
end
|
||||
|
||||
nMachInDisp = nMachInDisp + 1
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
+167
-108
@@ -34,12 +34,12 @@ local function GetMachineAxes()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function LogOutstroke( ptOnToolTipCenter, vtHead, OptionalParameters)
|
||||
local function LogOutstroke( sToolName, ptOnToolTipCenter, vtHead, OptionalParameters)
|
||||
|
||||
-- parametri opzionali
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
local LinearAxes = OptionalParameters.LinearAxes
|
||||
local RotativeAxes = OptionalParameters.RotativeAxes
|
||||
local LinearAxesValues = OptionalParameters.LinearAxesValues
|
||||
local RotativeAxesValues = OptionalParameters.RotativeAxesValues
|
||||
|
||||
-- gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
@@ -50,15 +50,18 @@ local function LogOutstroke( ptOnToolTipCenter, vtHead, OptionalParameters)
|
||||
EgtSetColor( idPoint, RED())
|
||||
EgtSetColor( idVector, RED())
|
||||
|
||||
-- nome utensile
|
||||
EgtOutLog( 'Tool ' .. sToolName)
|
||||
|
||||
-- si loggano valori di punto e vettore
|
||||
EgtOutLog( ' Presimulation : OutStroke, Tip Point = ' .. tostring( ptOnToolTipCenter) .. ', id = ' .. idPoint .. ', vtHead = ' .. tostring( vtHead) .. ', id = ' .. idVector)
|
||||
|
||||
-- se disponibili, si loggano anche i valori calcolati degli assi
|
||||
if LinearAxes then
|
||||
EgtOutLog( ' ' .. LinearAxes[1].sName .. ' = ' .. tostring( LinearAxes[1].dValue) .. ', ' .. LinearAxes[2].sName .. ' = ' .. tostring( LinearAxes[2].dValue) .. ', ' .. LinearAxes[3].sName .. ' = ' .. tostring( LinearAxes[3].dValue))
|
||||
if LinearAxesValues then
|
||||
EgtOutLog( ' ' .. 'Lin1' .. ' = ' .. tostring( LinearAxesValues[1]) .. ', ' .. 'Lin2' .. ' = ' .. tostring( LinearAxesValues[2]) .. ', ' .. 'Lin3' .. ' = ' .. tostring( LinearAxesValues[3]))
|
||||
end
|
||||
if RotativeAxes then
|
||||
EgtOutLog( ' ' .. RotativeAxes[1].sName .. ' = ' .. tostring( RotativeAxes[1].dValue) .. ', ' .. RotativeAxes[2].sName .. ' = ' .. tostring( RotativeAxes[2].dValue))
|
||||
if RotativeAxesValues then
|
||||
EgtOutLog( ' ' .. 'Rot1' .. ' = ' .. tostring( RotativeAxesValues[1]) .. ', ' .. 'Rot2' .. ' = ' .. tostring( RotativeAxesValues[2]) .. ', ' .. 'Rot3' .. ' = ' .. tostring( RotativeAxesValues[3]))
|
||||
end
|
||||
|
||||
return
|
||||
@@ -110,7 +113,7 @@ local function GetToolExitPoint( ptMachining, vtNEdge, vtHead, Tool, bIsDownUp)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- calcolo pivot in riferimento globale, datipunto sull'uscita utensile e direzioni
|
||||
-- calcolo pivot in riferimento globale, dati punto sull'uscita utensile e direzioni
|
||||
local function GetGlobalPivot( ptToolExit, vtC, vtHead, vtMovePivot)
|
||||
|
||||
-- frame solidale all'utensile (lo stesso in cui vtMovePivot è definito)
|
||||
@@ -150,27 +153,28 @@ local function GetCollisionPointsToCheck( Edge, dDepthToMachine)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckOutOfStrokePoint( ptOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
local function CheckOutOfStrokePoint( ptOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- impostazione utensile
|
||||
EgtSetCalcTool( Tool.sName, Tool.sHead, Tool.nExit)
|
||||
local bOkTool = EgtSetCalcTool( Tool.sName, Tool.sHead, Tool.nExit)
|
||||
if not bOkTool then
|
||||
error( 'CheckOutOfStrokePoint : cannot set calc tool')
|
||||
end
|
||||
|
||||
-- settaggio SCC per discriminare soluzioni multiple
|
||||
EgtSetCalcSolCh( nSCC)
|
||||
|
||||
-- assi macchina da calcolare
|
||||
local LinearAxes, RotativeAxes = GetMachineAxes()
|
||||
|
||||
-- se più di 3 assi lineari e 2 assi rotativi, macchina non supportata
|
||||
if #LinearAxes > 3 or #RotativeAxes > 2 then
|
||||
|
||||
error(' CheckOutOfStrokePoint : too many axes')
|
||||
-- se presente, settaggio asse bloccato
|
||||
if sBlockedAxis and type( sBlockedAxis) == "string" then
|
||||
local BlockedAxis = EgtSplitString( sBlockedAxis, '=')
|
||||
EgtSetRotAxisBlock( BlockedAxis[1], tonumber( BlockedAxis[2]))
|
||||
end
|
||||
|
||||
-- calcolo assi rotativi
|
||||
local bOkAngles, nSolutionsAngles, dRot1, dRot2 = EgtGetCalcAngles( vtHead)
|
||||
RotativeAxes[1].dValue = dRot1
|
||||
RotativeAxes[2].dValue = dRot2
|
||||
local bOkAngles, nSolutionsAngles, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
if not bOkAngles then
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
@@ -180,40 +184,27 @@ local function CheckOutOfStrokePoint( ptOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
if nSolutionsAngles == 0 then
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
LogOutstroke( ptOnToolTipCenter, vtHead)
|
||||
LogOutstroke( Tool.sName, ptOnToolTipCenter, vtHead, { RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- calcolo assi lineari
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, RotativeAxes[1].dValue, RotativeAxes[2].dValue)
|
||||
LinearAxes[1].dValue = dLinear1
|
||||
LinearAxes[2].dValue = dLinear2
|
||||
LinearAxes[3].dValue = dLinear3
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, dRotative1, dRotative2, dRotative3)
|
||||
|
||||
if not bOkPositions then
|
||||
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
end
|
||||
|
||||
-- verifica finecorsa per tutti gli assi
|
||||
-- siccome non si sa a priori il numero di assi lineari e rotativi, si aggiungono tutti a Args in ordine
|
||||
-- Args viene poi esplosa in modo da passare a EgtVerifyOutstroke i valori separati
|
||||
local Args = {}
|
||||
for i = 1, #LinearAxes do
|
||||
Args[#Args+1] = LinearAxes[i].dValue
|
||||
end
|
||||
for i = 1, #RotativeAxes do
|
||||
Args[#Args+1] = RotativeAxes[i].dValue
|
||||
end
|
||||
|
||||
local bAllAxesInStroke = EgtVerifyOutstroke( table.unpack( Args))
|
||||
-- verifica finecorsa per assi lineari (assi rotativi già verificati)
|
||||
local bAllAxesInStroke = EgtVerifyOutstroke( dLinear1, dLinear2, dLinear3)
|
||||
|
||||
-- extracorsa
|
||||
if not bAllAxesInStroke then
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
LogOutstroke( ptOnToolTipCenter, vtHead, { LinearAxes = LinearAxes, RotativeAxes = RotativeAxes})
|
||||
LogOutstroke( Tool.sName, ptOnToolTipCenter, vtHead, { LinearAxesValues = { dLinear1, dLinear2, dLinear3}, RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -230,12 +221,11 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da punti sul tip dell'utensile
|
||||
function PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
function PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- check collisione sui punti in centro lama su naso mandrino o aggregato. In base a direzione e punto
|
||||
for i = 1, #PointsOnToolTipCenter do
|
||||
|
||||
local bOutOfStroke = CheckOutOfStrokePoint( PointsOnToolTipCenter[i], vtHead, nSCC, Tool)
|
||||
local bOutOfStroke = CheckOutOfStrokePoint( PointsOnToolTipCenter[i], vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- se trovato extracorsa inutile procedere con gli altri punti
|
||||
if bOutOfStroke then
|
||||
@@ -250,7 +240,7 @@ end
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da geometria
|
||||
-- TODO da considerare anche gli attacchi
|
||||
function PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeometry, vtHead, nSCC, Tool)
|
||||
function PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeometry, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
local b3GeomMaxOffset = EgtGetBBoxGlob( idGeometry, GDB_BB.STANDARD)
|
||||
local ptBoxCenter = b3GeomMaxOffset:getCenter()
|
||||
@@ -273,38 +263,76 @@ function PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeometry, vtHead, nSCC
|
||||
-- Z-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimZ / 2 * Z_AX()))
|
||||
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
return bOutOfStroke
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckCollisionPoint( ptToolExitToCheck, vtC, vtHead, PreCollisionData, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
local function MoveMachineAxesToPosition( ptOnToolTipCenter, vtHead, vtAux)
|
||||
|
||||
local ptPivot = GetGlobalPivot( ptToolExitToCheck, vtC, vtHead, PreCollisionData.vtMovePivot)
|
||||
-- calcolo assi rotativi
|
||||
local bOkAngles, nSolutionsAngles, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
-- orientamento del riferimento locale
|
||||
local vtDirectionX = PreCollisionData.Directions.vtDirectionX
|
||||
local vtDirectionY = PreCollisionData.Directions.vtDirectionY
|
||||
local vtDirectionZ = PreCollisionData.Directions.vtDirectionZ
|
||||
if not bOkAngles then
|
||||
error( ' MoveMachineAxesToPosition : error')
|
||||
end
|
||||
|
||||
-- costruzione trimesh a partire dalla curva di collisione
|
||||
-- recupero punti da macchina per costruire trimesh
|
||||
local CollisionCurvePoints = PreCollisionData.Points
|
||||
-- curva di collisione in riferimento locale
|
||||
local idCollisionCurve = EgtCurveCompoFromPoints( Part.idTempGroup, CollisionCurvePoints)
|
||||
-- curva in riferimento globale
|
||||
local frReference = Frame3d( ptPivot, vtDirectionZ, vtDirectionX)
|
||||
EgtTransform( idCollisionCurve, frReference, GDB_RT.GLOB)
|
||||
-- trimesh di collisione
|
||||
local idCollisionSurfTm
|
||||
if PreCollisionData.bSurfTmByRevolve then
|
||||
idCollisionSurfTm = EgtSurfTmByRevolve( Part.idTempGroup, idCollisionCurve, ptPivot, vtDirectionY, true, 0.05, GDB_RT.GLOB)
|
||||
else
|
||||
local vtPreMove = -vtDirectionZ * ( PreCollisionData.dExtrusionDepth / 2)
|
||||
EgtMove( idCollisionCurve, vtPreMove, GDB_RT.GLOB)
|
||||
local vtExtrusion = vtDirectionZ * PreCollisionData.dExtrusionDepth
|
||||
idCollisionSurfTm = EgtSurfTmByRegionExtrusion( Part.idTempGroup, idCollisionCurve, vtExtrusion, 0.05, GDB_RT.GLOB)
|
||||
-- calcolo assi lineari
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, dRotative1, dRotative2, dRotative3)
|
||||
|
||||
if not bOkPositions then
|
||||
|
||||
error( ' MoveMachineAxesToPosition : error')
|
||||
end
|
||||
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
local dTHome = EgtGetAxisHomePos( AxesNames[1])
|
||||
|
||||
-- spostamento assi in posizione (la T non si sposta perchè si sposta il pezzo)
|
||||
EgtSetAxisPos( AxesNames[2], dLinear2)
|
||||
EgtSetAxisPos( AxesNames[3], dLinear3)
|
||||
EgtSetAxisPos( AxesNames[4], dRotative1)
|
||||
EgtSetAxisPos( AxesNames[5], dRotative2)
|
||||
if dRotative3 then
|
||||
EgtSetAxisPos( AxesNames[6], dRotative3)
|
||||
end
|
||||
|
||||
return dLinear1 - dTHome
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckCollisionPoint( sAxis, ptOnToolTipCenter, vtHead, vtAux, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
|
||||
-- spostamento assi macchina in posizione
|
||||
local dDeltaXHeadOffset = MoveMachineAxesToPosition( ptOnToolTipCenter, vtHead, vtAux)
|
||||
|
||||
-- si recuperano gli id delle geometrie dell'asse con cui controllare la collisione
|
||||
local idCollisionGroup = EgtGetFirstNameInGroup( EgtGetAxisId( sAxis), 'COLLISION')
|
||||
local idCollisionGroupOther = EgtGetFirstNameInGroup( EgtGetAxisId( sAxis), 'OTHER_COLLISION') or GDB_ID.NULL
|
||||
local CollisionGroupEntitiesId = EgtGetAllInGroup( idCollisionGroup)
|
||||
local CollisionGroupOtherEntitiesId = EgtGetAllInGroup( idCollisionGroupOther)
|
||||
-- si tengono solo gli elementi trimesh
|
||||
local CollisionSurfTmId = {}
|
||||
for i = 1, #CollisionGroupEntitiesId do
|
||||
if EgtGetType( CollisionGroupEntitiesId[i]) == GDB_TY.SRF_MESH then
|
||||
local idCollisionSurfTmCopy = EgtCopyGlob( CollisionGroupEntitiesId[i], Part.idTempGroup)
|
||||
EgtMove( idCollisionSurfTmCopy, Vector3d( dDeltaXHeadOffset, 0, 0), GDB_RT.GLOB)
|
||||
table.insert( CollisionSurfTmId, idCollisionSurfTmCopy)
|
||||
end
|
||||
end
|
||||
-- se presenti geometrie nel gruppo other si aggiungono anche quelle
|
||||
if CollisionGroupOtherEntitiesId and #CollisionGroupOtherEntitiesId > 0 then
|
||||
for i = 1, #CollisionGroupOtherEntitiesId do
|
||||
if EgtGetType( CollisionGroupOtherEntitiesId[i]) == GDB_TY.SRF_MESH then
|
||||
local idCollisionOtherSurfTmCopy = EgtCopyGlob( CollisionGroupOtherEntitiesId[i], Part.idTempGroup)
|
||||
EgtMove( idCollisionOtherSurfTmCopy, Vector3d( dDeltaXHeadOffset, 0, 0), GDB_RT.GLOB)
|
||||
table.insert( CollisionSurfTmId, idCollisionOtherSurfTmCopy)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- check collisione con pezzo
|
||||
@@ -316,16 +344,22 @@ local function CheckCollisionPoint( ptToolExitToCheck, vtC, vtHead, PreCollision
|
||||
local b3CheckCollision = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation)
|
||||
idCheckCollisionTm = EgtSurfTmBBox( Part.idTempGroup, b3CheckCollision, false, GDB_RT.GLOB)
|
||||
end
|
||||
bCollisionFoundPiece = EgtCDeSolidSolid( idCheckCollisionTm, idCollisionSurfTm, BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundPiece) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundPiece then
|
||||
EgtSetColor( idCollisionSurfTm, RED())
|
||||
for i = 1, #CollisionSurfTmId do
|
||||
bCollisionFoundPiece = EgtCDeSolidSolid( idCheckCollisionTm, CollisionSurfTmId[i], BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundPiece) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundPiece then
|
||||
EgtSetColor( CollisionSurfTmId[i], RED())
|
||||
end
|
||||
if bCollisionFoundPiece then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- se trovata collisione con pezzo è inutile procedere con il grezzo
|
||||
if bCollisionFoundPiece then
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -335,12 +369,17 @@ local function CheckCollisionPoint( ptToolExitToCheck, vtC, vtHead, PreCollision
|
||||
if not ( bCollisionFoundPiece or bCannotSplitRestLength) then
|
||||
local idRestLengthSurfFr = GetRestlengthSurfTm( Part, sRestLengthSideForPreSimulation)
|
||||
if idRestLengthSurfFr then
|
||||
bCollisionFoundRestLength = EgtCDeSolidSolid( idRestLengthSurfFr, idCollisionSurfTm, BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundRestLength) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundRestLength then
|
||||
EgtSetColor( idCollisionSurfTm, ORANGE())
|
||||
for i = 1, #CollisionSurfTmId do
|
||||
bCollisionFoundRestLength = EgtCDeSolidSolid( idRestLengthSurfFr, CollisionSurfTmId[i], BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundRestLength) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundRestLength then
|
||||
EgtSetColor( CollisionSurfTmId[i], ORANGE())
|
||||
end
|
||||
if bCollisionFoundRestLength then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -365,43 +404,29 @@ local function CheckCollisionWithAxis( sAxis, MachiningParameters, OptionalParam
|
||||
local bCheckOnlyRestlength = OptionalParameters.bCheckOnlyRestlength or false
|
||||
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
local vtAux = OptionalParameters.vtAux
|
||||
|
||||
-- se normale faccia non parallela a direzione testa c'è qualcosa che non va
|
||||
if not AreSameOrOppositeVectorApprox( vtNFace, vtHead) then
|
||||
error( 'CheckCollisionWithAxis : invalid directions')
|
||||
end
|
||||
|
||||
|
||||
-- punti notevoli della lavorazione in cui fare il check
|
||||
local PointsToCheck = OptionalParameters.PointsToCheck or GetCollisionPointsToCheck( Edge, dDepthToMachine)
|
||||
|
||||
-- punti in centro lama su naso mandrino o aggregato. In base a direzione e punto
|
||||
local bIsDownUp = AreOppositeVectorApprox( vtNFace, vtHead)
|
||||
local ToolExitPoints = {}
|
||||
-- punti sul tip dell'utensile, in centro
|
||||
local PointsOnToolTipCenter = {}
|
||||
for i = 1, #PointsToCheck do
|
||||
ToolExitPoints[i] = GetToolExitPoint( PointsToCheck[i], Edge.vtN, vtHead, Tool, bIsDownUp)
|
||||
PointsOnToolTipCenter[i] = PreSimulationLib.GetPointOnToolTipCenter( PointsToCheck[i], vtHead, vtNFace, Edge.vtN, Tool)
|
||||
end
|
||||
|
||||
-- vtC punta sempre verso il corpo dell'asse C o verso l'aggregato
|
||||
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, vtNFace)
|
||||
local vtSCC = BeamLib.GetDirectionFromSCC( nSCC)
|
||||
local vtC = vtHead ^ Tool.SetupInfo.vtRotationAxisC
|
||||
vtC:normalize()
|
||||
if vtC:isZero() then
|
||||
vtC = vtSCC
|
||||
elseif vtC * vtSCC < GEO.EPS_SMALL then
|
||||
vtC = -vtC
|
||||
end
|
||||
|
||||
-- punti curva collisione e direzioni check da macchina
|
||||
local PreCollisionData = Tool.SetupInfo.GetPreCollisionData( sAxis, vtC, vtHead)
|
||||
|
||||
local bMoveAfterSplit = false
|
||||
|
||||
-- se almeno in un punto c'è collisione con il pezzo si ritorna collisione
|
||||
-- se non si trova collisione si ritorna se è necessario separare prima di effettuare la lavorazione (ossia non c'è collisione con il pezzo ma c'è con il grezzo restante)
|
||||
for i = 1, #ToolExitPoints do
|
||||
for i = 1, #PointsOnToolTipCenter do
|
||||
|
||||
local bCollisionFoundPiece, bCollisionFoundRestLength = CheckCollisionPoint( ToolExitPoints[i], vtC, vtHead, PreCollisionData, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
local bCollisionFoundPiece, bCollisionFoundRestLength = CheckCollisionPoint( sAxis, PointsOnToolTipCenter[i], vtHead, vtAux, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
|
||||
-- se trovata collisione con pezzo è inutile controllare gli altri punti
|
||||
if bCollisionFoundPiece then
|
||||
@@ -423,7 +448,12 @@ end
|
||||
function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, OptionalParameters)
|
||||
|
||||
local bCollisionFound
|
||||
local bMoveAfterSplitZ, bMoveAfterSplitC, bMoveAfterSplitAB
|
||||
local bMoveAfterSplitL3, bMoveAfterSplitR3, bMoveAfterSplitR2, bMoveAfterSplitR1
|
||||
|
||||
-- parametri obbligatori
|
||||
local Edge = Parameters.Edge
|
||||
local vtNFace = Parameters.vtNFace
|
||||
local Tool = Parameters.Tool
|
||||
|
||||
-- parametri opzionali, in parte da far transitare
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
@@ -433,8 +463,12 @@ function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, Optional
|
||||
OptionalParametersCheckCollisionWithAxis.PointsToCheck = OptionalParameters.PointsToCheck or nil
|
||||
OptionalParametersCheckCollisionWithAxis.sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
OptionalParametersCheckCollisionWithAxis.bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
OptionalParametersCheckCollisionWithAxis.sBlockedAxis = OptionalParameters.sBlockedAxis
|
||||
OptionalParametersCheckCollisionWithAxis.vtAux = OptionalParameters.vtAux
|
||||
|
||||
local sBlockedAxis = OptionalParameters.sBlockedAxis
|
||||
local bIsDicing = OptionalParameters.bIsDicing or false
|
||||
local bDisableRealElevationCheck = OptionalParameters.bDisableRealElevationCheck or false
|
||||
local bCheckOnlyRestlengthForAxisABC = false
|
||||
|
||||
-- se cubetti in modalità standard (no DownUp) gli assi AB e C si controllano solo con grezzo (ci sarebbe collisione con il materiale già rimosso controllando AB e C con pezzo)
|
||||
@@ -442,7 +476,7 @@ function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, Optional
|
||||
bCheckOnlyRestlengthForAxisABC = true
|
||||
-- se l'elevazione reale (rispetto al pezzo + eventuale materiale in testa/coda) è maggiore del massimo materiale è sempre collisione
|
||||
-- TODO rifare con funzione
|
||||
else
|
||||
elseif not bDisableRealElevationCheck then
|
||||
local Edge = Parameters.Edge
|
||||
local vtNFace = Parameters.vtNFace
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
@@ -465,21 +499,46 @@ function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, Optional
|
||||
end
|
||||
end
|
||||
|
||||
-- asse Z si controlla sempre
|
||||
bCollisionFound, bMoveAfterSplitZ = CheckCollisionWithAxis( 'Z', Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
-- SCC
|
||||
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, vtNFace)
|
||||
|
||||
-- assi AB e C: se richiesto si controlla la collisione solo col grezzo
|
||||
-- si settano utensile, SCC e asse bloccato per il controllo collisione
|
||||
local bOkTool = EgtSetCalcTool( Tool.sName, Tool.sHead, Tool.nExit)
|
||||
if not bOkTool then
|
||||
error( 'CheckCollisionWithAxis : cannot set calc tool')
|
||||
end
|
||||
EgtSetCalcSolCh( nSCC)
|
||||
if sBlockedAxis and type( sBlockedAxis) == "string" then
|
||||
local BlockedAxis = EgtSplitString( sBlockedAxis, '=')
|
||||
EgtSetRotAxisBlock( BlockedAxis[1], tonumber( BlockedAxis[2]))
|
||||
end
|
||||
|
||||
-- nomi degli assi con cui controllare la collisione
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
local sL3 = AxesNames[3]
|
||||
local sR3 = AxesNames[6]
|
||||
local sR2 = AxesNames[5]
|
||||
local sR1 = AxesNames[4]
|
||||
|
||||
-- ultimo asse lineare prima dei rotativi (solitamente Z) si controlla sempre
|
||||
bCollisionFound, bMoveAfterSplitL3 = CheckCollisionWithAxis( sL3, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
|
||||
-- assi rotativi: se richiesto si controlla la collisione solo col grezzo
|
||||
OptionalParametersCheckCollisionWithAxis.bCheckOnlyRestlength = bCheckOnlyRestlengthForAxisABC
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitAB = CheckCollisionWithAxis( 'AB', Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
if sR3 and not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR3 = CheckCollisionWithAxis( sR3, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitC = CheckCollisionWithAxis( 'C', Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
bCollisionFound, bMoveAfterSplitR2 = CheckCollisionWithAxis( sR2, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
local bMoveAfterSplit = bMoveAfterSplitZ or bMoveAfterSplitC or bMoveAfterSplitAB
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR1 = CheckCollisionWithAxis( sR1, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
local bMoveAfterSplit = bMoveAfterSplitL3 or bMoveAfterSplitR3 or bMoveAfterSplitR2 or bMoveAfterSplitR1
|
||||
|
||||
return bCollisionFound, bMoveAfterSplit
|
||||
end
|
||||
|
||||
+74
-455
@@ -1,477 +1,96 @@
|
||||
-- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15
|
||||
-- Gestione nesting automatico travi
|
||||
-- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati.
|
||||
-- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione.
|
||||
-- 2023/01/15 Piccole correzioni.
|
||||
-- BeamNestProcess.lua by Egalware s.r.l. 2026/05/11
|
||||
-- Gestione nesting automatico travi anche oblique
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
EgtEnableDebug( true)
|
||||
|
||||
-- Per test
|
||||
--NEST = {}
|
||||
--NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl'
|
||||
--NEST.MACHINE = 'Essetre-90480019_MW'
|
||||
--NEST.FLAG = 3
|
||||
-- Include
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1]
|
||||
EgtOutLog( sLog)
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- stati che definiscono rotazione / inversione della parte
|
||||
local STATE = {
|
||||
STD = 1, -- Standard
|
||||
ROT180 = 2, -- Rotazione 180deg attorno a X+
|
||||
INV = 3, -- Inversione (rotazione 180deg attorno a Z+)
|
||||
INV_ROT180 = 4 -- Inversione + rotazione
|
||||
}
|
||||
|
||||
-- flag per abilitare statistiche in log
|
||||
local bLogStat = false
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- inventario grezzi
|
||||
local RawInventory = {
|
||||
Stock = {},
|
||||
ActiveBeams = {}
|
||||
}
|
||||
|
||||
-- Cancello file di log specifico
|
||||
local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt')
|
||||
EgtEraseFile( sLogFile)
|
||||
|
||||
-- Funzioni per scrittura su file di log specifico
|
||||
local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n')
|
||||
hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteTimeToLogFile( dTime)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo errore
|
||||
local function PostErrView( nErr, sMsg)
|
||||
if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo warning
|
||||
local function PostWarnView( nWarn, sMsg)
|
||||
if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per aggiornare dati ausiliari
|
||||
local function UpdateAuxData( sAuxFile)
|
||||
local bModif = false
|
||||
-- Se definito LOAD90, aggiorno
|
||||
local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile)
|
||||
if sLoad90 ~= '' then
|
||||
local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL
|
||||
EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90)
|
||||
bModif = true
|
||||
end
|
||||
return bModif
|
||||
end
|
||||
|
||||
local function PartsToFill( Parts)
|
||||
local nToFill = 0
|
||||
for i = 1, #Parts do
|
||||
if Parts[i].Cnt > 0 then
|
||||
nToFill = nToFill + Parts[i].Cnt
|
||||
end
|
||||
end
|
||||
return nToFill
|
||||
end
|
||||
|
||||
local function ExecMaximumFilling( Raw, Parts)
|
||||
-- Inizializzo maximum filler
|
||||
EgtMaxFillerStart()
|
||||
-- Inserisco i pezzi
|
||||
for i = 1, #Parts do
|
||||
EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1)
|
||||
end
|
||||
-- Eseguo l'ottimizzazione
|
||||
EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType)
|
||||
-- Recupero i risultati
|
||||
local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults()
|
||||
local OneRes = {}
|
||||
for i = 0, nDiffParts - 1 do
|
||||
local nPartId, nCount = EgtMaxFillerGetOneResult( i)
|
||||
table.insert( OneRes, { Id=nPartId, Count=nCount})
|
||||
end
|
||||
--return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes}
|
||||
return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes}
|
||||
end
|
||||
|
||||
-- Funzione per trovare nome MachGroup
|
||||
local function NewMachGroupName()
|
||||
local nMachGroupId = EgtGetFirstMachGroup()
|
||||
if not nMachGroupId then return 1 end
|
||||
local nMaxMachGroup = 0
|
||||
while nMachGroupId do
|
||||
sMachGroupName = EgtGetMachGroupName(nMachGroupId)
|
||||
local nMachGroupName = tonumber(sMachGroupName)
|
||||
if nMachGroupName > nMaxMachGroup then
|
||||
nMaxMachGroup = nMachGroupName
|
||||
end
|
||||
nMachGroupId = EgtGetNextMachGroup(nMachGroupId)
|
||||
end
|
||||
return nMaxMachGroup + 1
|
||||
end
|
||||
|
||||
local function TotRawCount(Raws)
|
||||
local nTotRaws = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
nTotRaws = nTotRaws + Raws[RawIndex].Count
|
||||
end
|
||||
return nTotRaws
|
||||
end
|
||||
|
||||
local function TotPartLen(Parts)
|
||||
local nTotPartLen = 0
|
||||
for PartIndex = 1, #Parts do
|
||||
nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt)
|
||||
end
|
||||
return nTotPartLen
|
||||
end
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi
|
||||
EgtSetCurrMachine( NEST.MACHINE)
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
NEST.ERR = 12
|
||||
NEST.MSG = 'Error not configured for beam machine : ' .. sMachine
|
||||
WriteErrToLogFile( NEST.ERR, NEST.MSG)
|
||||
PostErrView( NEST.ERR, NEST.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Inizializzo contatori errori e avvisi
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
|
||||
-- Grezzi
|
||||
local Raws = {}
|
||||
-- creo tabella dei grezzi
|
||||
for nIndex, nLen in pairs( LEN) do
|
||||
Raws[tonumber(nIndex)] = {LenToFill = nLen, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1}
|
||||
end
|
||||
for nIndex, nQty in pairs( QTY) do
|
||||
Raws[tonumber(nIndex)].Count = nQty
|
||||
end
|
||||
-- cerco il grezzo con la lunghezza maggiore, epurata dello start gap
|
||||
local maxRawLenToFillNoStartGap = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
if Raws[RawIndex].Count > 0 then
|
||||
maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Pezzi
|
||||
local Parts = {}
|
||||
-- ciclo su pezzi per aggiungerli al nesting
|
||||
local dTotLen = 0
|
||||
for nPartId, nCount in pairs( PART) do
|
||||
-- recupero lunghezza pezzo
|
||||
local Len = EgtGetInfo( nPartId, "L", 'd')
|
||||
local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0)
|
||||
-- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione
|
||||
if Len < maxRawLenToFillNoStartGap then
|
||||
for nCntIndex = 1 , nCount do
|
||||
table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1})
|
||||
dTotLen = dTotLen + Len
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lunghezza totale pezzi
|
||||
local dTotPartLen = TotPartLen( Parts)
|
||||
-- calcolo media delle barre necessarie
|
||||
local NeededRawsForType = {}
|
||||
for RawIndex = 1, #Raws do
|
||||
NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count)
|
||||
end
|
||||
local RawQtySum = 0
|
||||
for NeededRawIndex = 1, #NeededRawsForType do
|
||||
RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex]
|
||||
end
|
||||
local MediumRawQty = ceil( RawQtySum / #NeededRawsForType)
|
||||
if MediumRawQty > 1 then
|
||||
MediumRawQty = MediumRawQty - 1
|
||||
end
|
||||
|
||||
-- lista dei risultati
|
||||
local ResultList = {}
|
||||
local BestResult = nil
|
||||
local BestResultIndex = nil
|
||||
-- riordino lista pezzi per lunghezza
|
||||
table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end)
|
||||
|
||||
local function NestSolutionByIndex( Index)
|
||||
|
||||
-- creo copia lista raw
|
||||
local TempRaws = {}
|
||||
for TempRawIndex = 1, #Raws do
|
||||
table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count})
|
||||
end
|
||||
|
||||
-- recupero pezzi corti
|
||||
local ShortList = {}
|
||||
local LongList = {}
|
||||
|
||||
for PartIndex = 1, #Parts do
|
||||
if PartIndex <= Index then
|
||||
table.insert( ShortList, Parts[PartIndex])
|
||||
else
|
||||
table.insert( LongList, Parts[PartIndex])
|
||||
end
|
||||
Parts[PartIndex].Cnt = 1
|
||||
end
|
||||
-- numero di pezzi piccoli per barra
|
||||
local ShortCount = Index
|
||||
local ShortForRaw = floor( ShortCount / MediumRawQty)
|
||||
local ExtraShortForRaw = 0
|
||||
if MediumRawQty > 0 then
|
||||
ExtraShortForRaw = fmod( ShortCount, MediumRawQty)
|
||||
end
|
||||
-- creo lista pezzi corti singoli
|
||||
local SingleShortList = {}
|
||||
for ShortIndex = 1, #ShortList do
|
||||
for ShortCount = 1, ShortList[ShortIndex].Cnt do
|
||||
table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1})
|
||||
end
|
||||
end
|
||||
-- li divido per le barre previste
|
||||
local RawsShortList = {}
|
||||
local RawIndex = 0
|
||||
local ShortRawIndex = 0
|
||||
for ShortIndex = 1, #SingleShortList do
|
||||
if ShortRawIndex > 0 then
|
||||
table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex])
|
||||
ShortRawIndex = ShortRawIndex - 1
|
||||
else
|
||||
table.insert( RawsShortList, {SingleShortList[ShortIndex]})
|
||||
RawIndex = RawIndex + 1
|
||||
ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1
|
||||
end
|
||||
function RawInventory:BuildStock()
|
||||
if #LEN ~= #QTY then
|
||||
error( 'NestProcess: invalid stock data')
|
||||
end
|
||||
|
||||
-- Ciclo fino ad esaurimento pezzi o barre
|
||||
local dTotPartInRawLen = 0
|
||||
local nRawTot = 0
|
||||
local dRawTotLen = 0
|
||||
local dTime = 0
|
||||
local nCycle = 1
|
||||
local CurrResult = {}
|
||||
while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do
|
||||
|
||||
-- creo lista con pezzi lunghi e pezzi corti di questo Cycle
|
||||
local PartsToNest = {}
|
||||
for PartIndex = 1, #LongList do
|
||||
table.insert( PartsToNest, LongList[PartIndex])
|
||||
end
|
||||
for CycleIndex = 1, #RawsShortList do
|
||||
if CycleIndex <= nCycle then
|
||||
for PartIndex = 1, #RawsShortList[CycleIndex] do
|
||||
table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono pezzi da nestare, esco
|
||||
if PartsToFill( PartsToNest) <= 0 then
|
||||
break
|
||||
end
|
||||
-- Eseguo ottimizzazione per ogni lunghezza di barra
|
||||
local Results = {}
|
||||
for RawIndex = 1, #TempRaws do
|
||||
if TempRaws[RawIndex].Count > 0 then
|
||||
Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest)
|
||||
else
|
||||
Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0}
|
||||
end
|
||||
end
|
||||
-- verifico quale e' quella con meno scarto
|
||||
local nMinWasteRawIndex = GDB_ID.NULL
|
||||
local dMinWaste = 100000
|
||||
for ResultIndex = 1, #Results do
|
||||
if Results[ResultIndex] then
|
||||
local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill
|
||||
if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then
|
||||
dMinWaste = dWaste
|
||||
nMinWasteRawIndex = ResultIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
-- verifico se ci sono pezzi
|
||||
if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then
|
||||
-- riporto barra e pezzi nel risultato corrente
|
||||
local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}}
|
||||
local CurrX = TempRaws[nMinWasteRawIndex].StartGap
|
||||
local nInfoIndex = 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartIndex = Results[nMinWasteRawIndex].Data[i].Id
|
||||
local PartId = PartsToNest[PartIndex].Id
|
||||
local dLen = PartsToNest[PartIndex].Len
|
||||
for j = 1, Results[nMinWasteRawIndex].Data[i].Count do
|
||||
-- creo pezzo copia
|
||||
CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX}
|
||||
table.insert( CurrBar.Parts, CurrPart)
|
||||
CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap
|
||||
nInfoIndex = nInfoIndex + 1
|
||||
end
|
||||
end
|
||||
table.insert( CurrResult, CurrBar)
|
||||
dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill)
|
||||
nRawTot = nRawTot + 1
|
||||
dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill
|
||||
-- Aggiorno per prossima iterazione
|
||||
TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartId = Results[nMinWasteRawIndex].Data[i].Id
|
||||
PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count
|
||||
end
|
||||
else
|
||||
-- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili
|
||||
break
|
||||
end
|
||||
nCycle = nCycle + 1
|
||||
end
|
||||
-- riporto risultato in lista
|
||||
ResultList[Index] = dTotPartInRawLen
|
||||
if not BestResult or not BestResultIndex or
|
||||
( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then
|
||||
BestResult = CurrResult
|
||||
BestResult.RawTotLen = dRawTotLen
|
||||
BestResultIndex = Index
|
||||
for i = 1, #LEN do
|
||||
self.Stock[#self.Stock + 1] = {
|
||||
Length = LEN[i],
|
||||
Count = QTY[i]
|
||||
}
|
||||
end
|
||||
|
||||
return RawInventory
|
||||
end
|
||||
|
||||
local CycleCount = 0
|
||||
function RawInventory:AddActiveBeam()
|
||||
-- TODO da fare
|
||||
end
|
||||
|
||||
local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end
|
||||
local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end
|
||||
local TargetRatio = 0.98
|
||||
local dTargetRatioLen = TargetRatio * dTotLen
|
||||
if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end
|
||||
local CurrTime = 0
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- PartTemplates (informazioni geometriche pezzi univoci) e JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare)
|
||||
local PartTemplates = {}
|
||||
local JobPool = {}
|
||||
|
||||
local function NestSolutionFromSP( StartingPoint, OscillationStep)
|
||||
-- ciclo sulle possibilita' da un punto di origine con uno step fisso
|
||||
local CurrResultIndex = StartingPoint
|
||||
NestSolutionByIndex( StartingPoint)
|
||||
if OscillationStep == 0 then return end
|
||||
local CycleIndex = 1
|
||||
local nOutOfBoundary = 0
|
||||
while nOutOfBoundary ~= 3 do
|
||||
CurrTime = EgtStopCounter() / 1000
|
||||
if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end
|
||||
if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end
|
||||
-- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia
|
||||
if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then
|
||||
if bLogStat then EgtOutLog('Brake') end
|
||||
break
|
||||
end
|
||||
local bCurrOutOfBoundary = false
|
||||
if CurrResultIndex < 0 then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 2 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 1
|
||||
end
|
||||
end
|
||||
if CurrResultIndex > #Parts then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 1 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 2
|
||||
end
|
||||
end
|
||||
if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then
|
||||
NestSolutionByIndex( CurrResultIndex)
|
||||
if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end
|
||||
if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end
|
||||
CycleCount = CycleCount + 1
|
||||
end
|
||||
CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep )
|
||||
CycleIndex = CycleIndex + 1
|
||||
function PartTemplates:AddPart( id)
|
||||
PartTemplates[id] = {}
|
||||
PartTemplates[id].dLength = EgtGetInfo( id, 'L', 'd')
|
||||
-- TODO qua gli stati abilitati dovranno arrivare dalle alternatives
|
||||
local VerticesHead = EgtSplitString( EgtGetInfo( id, 'HEADOFFSETX', 'd'))
|
||||
local vtNHead = Vector3d( EgtSplitString( EgtGetInfo( id, 'HEADVTN', 'd')))
|
||||
local VerticesTail = EgtSplitString( EgtGetInfo( id, 'TAILOFFSETX', 'd'))
|
||||
local vtNTail = Vector3d( EgtSplitString( EgtGetInfo( id, 'TAILVTN', 'd')))
|
||||
PartTemplates[id].States = {
|
||||
[STATE.STD] = {
|
||||
Head = { Vertices = VerticesHead, vtN = vtNHead},
|
||||
Tail = { Vertices = VerticesTail, vtN = vtNTail}
|
||||
},
|
||||
[STATE.ROT180] = {
|
||||
Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead},
|
||||
Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead}
|
||||
},
|
||||
[STATE.INV] = {
|
||||
Head = { Vertices = VerticesTail, vtN = vtNTail},
|
||||
Tail = { Vertices = VerticesHead, vtN = vtNHead}
|
||||
},
|
||||
[STATE.INV_ROT180] = {
|
||||
Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead},
|
||||
Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
-- creazione combinata (si cicla una sola volta) di entrambe le tabelle
|
||||
local function BuildPartTemplatesAndJobPool()
|
||||
for id, nCount in pairs( PART) do
|
||||
PartTemplates:AddPart( id)
|
||||
end
|
||||
end
|
||||
|
||||
-- lancio calcolo
|
||||
EgtStartCounter()
|
||||
local StartingResult = floor( #Parts * 0.3)
|
||||
if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end
|
||||
--local Step = floor( #Parts / 10) * floor( log10( #Parts))
|
||||
local nDividendo = pow( 10, floor( log10( #Parts)) - 1)
|
||||
nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10)
|
||||
local Step = floor( #Parts / nDividendo) * floor( log10( #Parts))
|
||||
if bLogStat then EgtOutLog('Step: ' .. Step ) end
|
||||
NestSolutionFromSP( StartingResult, Step)
|
||||
if Step > 1 then
|
||||
NestSolutionFromSP( StartingResult, 1)
|
||||
|
||||
return PartTemplates, JobPool
|
||||
end
|
||||
|
||||
-- creo gruppi di lavorazione per risultato
|
||||
for MachGroupIndex = 1, #BestResult do
|
||||
local CurrMachGroup = BestResult[ MachGroupIndex]
|
||||
-- creo gruppo di lavorazione
|
||||
local MachGroupName = NewMachGroupName()
|
||||
nMachGroup = EgtAddMachGroup( MachGroupName)
|
||||
EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen)
|
||||
EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL)
|
||||
EgtSetInfo( nMachGroup, "AUTONEST", 1)
|
||||
-- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
|
||||
EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID)
|
||||
EgtSetInfo( nMachGroup, "PATTID", nMachGroup)
|
||||
-- Disegno i pezzi
|
||||
for i = 1, #CurrMachGroup.Parts do
|
||||
local CurrPart = CurrMachGroup.Parts[ i]
|
||||
-- creo pezzo copia
|
||||
local nPartDuploId = EgtDuploNew( CurrPart.PartId)
|
||||
EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX)
|
||||
end
|
||||
end
|
||||
|
||||
-- creo grezzi per ogni gruppo di lavorazione
|
||||
local nRawCnt = 0
|
||||
local nRawTot = ResultList[BestResultIndex]
|
||||
_G.BEAM = {}
|
||||
BEAM.FILE = NEST.FILE
|
||||
BEAM.MACHINE = NEST.MACHINE
|
||||
BEAM.FLAG = 6 -- CREATE_PANEL
|
||||
BEAM.BASEDIR = NEST.BASEDIR
|
||||
nMachGroup = EgtGetFirstMachGroup()
|
||||
while nMachGroup do
|
||||
local nNextMachGroup = EgtGetNextMachGroup( nMachGroup)
|
||||
EgtSetCurrMachGroup( nMachGroup)
|
||||
if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then
|
||||
EgtRemoveInfo( nMachGroup, "AUTONEST")
|
||||
EgtSetInfo( nMachGroup, "UPDATEUI", 1)
|
||||
local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua")
|
||||
if not bOk then
|
||||
EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')')
|
||||
end
|
||||
nRawCnt = nRawCnt + 1
|
||||
-- aggiorno interfaccia
|
||||
EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0)
|
||||
end
|
||||
nMachGroup = nNextMachGroup
|
||||
end
|
||||
|
||||
EgtResetCurrMachGroup()
|
||||
|
||||
NEST.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ BeamNestProcess completed')
|
||||
|
||||
|
||||
RawInventory:BuildStock()
|
||||
BuildPartTemplatesAndJobPool()
|
||||
@@ -0,0 +1,477 @@
|
||||
-- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15
|
||||
-- Gestione nesting automatico travi
|
||||
-- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati.
|
||||
-- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione.
|
||||
-- 2023/01/15 Piccole correzioni.
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Per test
|
||||
--NEST = {}
|
||||
--NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl'
|
||||
--NEST.MACHINE = 'Essetre-90480019_MW'
|
||||
--NEST.FLAG = 3
|
||||
|
||||
local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1]
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- flag per abilitare statistiche in log
|
||||
local bLogStat = false
|
||||
|
||||
-- Cancello file di log specifico
|
||||
local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt')
|
||||
EgtEraseFile( sLogFile)
|
||||
|
||||
-- Funzioni per scrittura su file di log specifico
|
||||
local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n')
|
||||
hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteTimeToLogFile( dTime)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo errore
|
||||
local function PostErrView( nErr, sMsg)
|
||||
if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo warning
|
||||
local function PostWarnView( nWarn, sMsg)
|
||||
if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per aggiornare dati ausiliari
|
||||
local function UpdateAuxData( sAuxFile)
|
||||
local bModif = false
|
||||
-- Se definito LOAD90, aggiorno
|
||||
local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile)
|
||||
if sLoad90 ~= '' then
|
||||
local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL
|
||||
EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90)
|
||||
bModif = true
|
||||
end
|
||||
return bModif
|
||||
end
|
||||
|
||||
local function PartsToFill( Parts)
|
||||
local nToFill = 0
|
||||
for i = 1, #Parts do
|
||||
if Parts[i].Cnt > 0 then
|
||||
nToFill = nToFill + Parts[i].Cnt
|
||||
end
|
||||
end
|
||||
return nToFill
|
||||
end
|
||||
|
||||
local function ExecMaximumFilling( Raw, Parts)
|
||||
-- Inizializzo maximum filler
|
||||
EgtMaxFillerStart()
|
||||
-- Inserisco i pezzi
|
||||
for i = 1, #Parts do
|
||||
EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1)
|
||||
end
|
||||
-- Eseguo l'ottimizzazione
|
||||
EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType)
|
||||
-- Recupero i risultati
|
||||
local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults()
|
||||
local OneRes = {}
|
||||
for i = 0, nDiffParts - 1 do
|
||||
local nPartId, nCount = EgtMaxFillerGetOneResult( i)
|
||||
table.insert( OneRes, { Id=nPartId, Count=nCount})
|
||||
end
|
||||
--return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes}
|
||||
return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes}
|
||||
end
|
||||
|
||||
-- Funzione per trovare nome MachGroup
|
||||
local function NewMachGroupName()
|
||||
local nMachGroupId = EgtGetFirstMachGroup()
|
||||
if not nMachGroupId then return 1 end
|
||||
local nMaxMachGroup = 0
|
||||
while nMachGroupId do
|
||||
sMachGroupName = EgtGetMachGroupName(nMachGroupId)
|
||||
local nMachGroupName = tonumber(sMachGroupName)
|
||||
if nMachGroupName > nMaxMachGroup then
|
||||
nMaxMachGroup = nMachGroupName
|
||||
end
|
||||
nMachGroupId = EgtGetNextMachGroup(nMachGroupId)
|
||||
end
|
||||
return nMaxMachGroup + 1
|
||||
end
|
||||
|
||||
local function TotRawCount(Raws)
|
||||
local nTotRaws = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
nTotRaws = nTotRaws + Raws[RawIndex].Count
|
||||
end
|
||||
return nTotRaws
|
||||
end
|
||||
|
||||
local function TotPartLen(Parts)
|
||||
local nTotPartLen = 0
|
||||
for PartIndex = 1, #Parts do
|
||||
nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt)
|
||||
end
|
||||
return nTotPartLen
|
||||
end
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi
|
||||
EgtSetCurrMachine( NEST.MACHINE)
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
NEST.ERR = 12
|
||||
NEST.MSG = 'Error not configured for beam machine : ' .. sMachine
|
||||
WriteErrToLogFile( NEST.ERR, NEST.MSG)
|
||||
PostErrView( NEST.ERR, NEST.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Inizializzo contatori errori e avvisi
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
|
||||
-- Grezzi
|
||||
local Raws = {}
|
||||
-- creo tabella dei grezzi
|
||||
for nIndex, nLen in pairs( LEN) do
|
||||
Raws[tonumber(nIndex)] = {LenToFill = nLen, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1}
|
||||
end
|
||||
for nIndex, nQty in pairs( QTY) do
|
||||
Raws[tonumber(nIndex)].Count = nQty
|
||||
end
|
||||
-- cerco il grezzo con la lunghezza maggiore, epurata dello start gap
|
||||
local maxRawLenToFillNoStartGap = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
if Raws[RawIndex].Count > 0 then
|
||||
maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Pezzi
|
||||
local Parts = {}
|
||||
-- ciclo su pezzi per aggiungerli al nesting
|
||||
local dTotLen = 0
|
||||
for nPartId, nCount in pairs( PART) do
|
||||
-- recupero lunghezza pezzo
|
||||
local Len = EgtGetInfo( nPartId, "L", 'd')
|
||||
local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0)
|
||||
-- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione
|
||||
if Len < maxRawLenToFillNoStartGap then
|
||||
for nCntIndex = 1 , nCount do
|
||||
table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1})
|
||||
dTotLen = dTotLen + Len
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lunghezza totale pezzi
|
||||
local dTotPartLen = TotPartLen( Parts)
|
||||
-- calcolo media delle barre necessarie
|
||||
local NeededRawsForType = {}
|
||||
for RawIndex = 1, #Raws do
|
||||
NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count)
|
||||
end
|
||||
local RawQtySum = 0
|
||||
for NeededRawIndex = 1, #NeededRawsForType do
|
||||
RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex]
|
||||
end
|
||||
local MediumRawQty = ceil( RawQtySum / #NeededRawsForType)
|
||||
if MediumRawQty > 1 then
|
||||
MediumRawQty = MediumRawQty - 1
|
||||
end
|
||||
|
||||
-- lista dei risultati
|
||||
local ResultList = {}
|
||||
local BestResult = nil
|
||||
local BestResultIndex = nil
|
||||
-- riordino lista pezzi per lunghezza
|
||||
table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end)
|
||||
|
||||
local function NestSolutionByIndex( Index)
|
||||
|
||||
-- creo copia lista raw
|
||||
local TempRaws = {}
|
||||
for TempRawIndex = 1, #Raws do
|
||||
table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count})
|
||||
end
|
||||
|
||||
-- recupero pezzi corti
|
||||
local ShortList = {}
|
||||
local LongList = {}
|
||||
|
||||
for PartIndex = 1, #Parts do
|
||||
if PartIndex <= Index then
|
||||
table.insert( ShortList, Parts[PartIndex])
|
||||
else
|
||||
table.insert( LongList, Parts[PartIndex])
|
||||
end
|
||||
Parts[PartIndex].Cnt = 1
|
||||
end
|
||||
-- numero di pezzi piccoli per barra
|
||||
local ShortCount = Index
|
||||
local ShortForRaw = floor( ShortCount / MediumRawQty)
|
||||
local ExtraShortForRaw = 0
|
||||
if MediumRawQty > 0 then
|
||||
ExtraShortForRaw = fmod( ShortCount, MediumRawQty)
|
||||
end
|
||||
-- creo lista pezzi corti singoli
|
||||
local SingleShortList = {}
|
||||
for ShortIndex = 1, #ShortList do
|
||||
for ShortCount = 1, ShortList[ShortIndex].Cnt do
|
||||
table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1})
|
||||
end
|
||||
end
|
||||
-- li divido per le barre previste
|
||||
local RawsShortList = {}
|
||||
local RawIndex = 0
|
||||
local ShortRawIndex = 0
|
||||
for ShortIndex = 1, #SingleShortList do
|
||||
if ShortRawIndex > 0 then
|
||||
table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex])
|
||||
ShortRawIndex = ShortRawIndex - 1
|
||||
else
|
||||
table.insert( RawsShortList, {SingleShortList[ShortIndex]})
|
||||
RawIndex = RawIndex + 1
|
||||
ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Ciclo fino ad esaurimento pezzi o barre
|
||||
local dTotPartInRawLen = 0
|
||||
local nRawTot = 0
|
||||
local dRawTotLen = 0
|
||||
local dTime = 0
|
||||
local nCycle = 1
|
||||
local CurrResult = {}
|
||||
while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do
|
||||
|
||||
-- creo lista con pezzi lunghi e pezzi corti di questo Cycle
|
||||
local PartsToNest = {}
|
||||
for PartIndex = 1, #LongList do
|
||||
table.insert( PartsToNest, LongList[PartIndex])
|
||||
end
|
||||
for CycleIndex = 1, #RawsShortList do
|
||||
if CycleIndex <= nCycle then
|
||||
for PartIndex = 1, #RawsShortList[CycleIndex] do
|
||||
table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono pezzi da nestare, esco
|
||||
if PartsToFill( PartsToNest) <= 0 then
|
||||
break
|
||||
end
|
||||
-- Eseguo ottimizzazione per ogni lunghezza di barra
|
||||
local Results = {}
|
||||
for RawIndex = 1, #TempRaws do
|
||||
if TempRaws[RawIndex].Count > 0 then
|
||||
Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest)
|
||||
else
|
||||
Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0}
|
||||
end
|
||||
end
|
||||
-- verifico quale e' quella con meno scarto
|
||||
local nMinWasteRawIndex = GDB_ID.NULL
|
||||
local dMinWaste = 100000
|
||||
for ResultIndex = 1, #Results do
|
||||
if Results[ResultIndex] then
|
||||
local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill
|
||||
if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then
|
||||
dMinWaste = dWaste
|
||||
nMinWasteRawIndex = ResultIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
-- verifico se ci sono pezzi
|
||||
if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then
|
||||
-- riporto barra e pezzi nel risultato corrente
|
||||
local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}}
|
||||
local CurrX = TempRaws[nMinWasteRawIndex].StartGap
|
||||
local nInfoIndex = 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartIndex = Results[nMinWasteRawIndex].Data[i].Id
|
||||
local PartId = PartsToNest[PartIndex].Id
|
||||
local dLen = PartsToNest[PartIndex].Len
|
||||
for j = 1, Results[nMinWasteRawIndex].Data[i].Count do
|
||||
-- creo pezzo copia
|
||||
CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX}
|
||||
table.insert( CurrBar.Parts, CurrPart)
|
||||
CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap
|
||||
nInfoIndex = nInfoIndex + 1
|
||||
end
|
||||
end
|
||||
table.insert( CurrResult, CurrBar)
|
||||
dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill)
|
||||
nRawTot = nRawTot + 1
|
||||
dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill
|
||||
-- Aggiorno per prossima iterazione
|
||||
TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartId = Results[nMinWasteRawIndex].Data[i].Id
|
||||
PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count
|
||||
end
|
||||
else
|
||||
-- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili
|
||||
break
|
||||
end
|
||||
nCycle = nCycle + 1
|
||||
end
|
||||
-- riporto risultato in lista
|
||||
ResultList[Index] = dTotPartInRawLen
|
||||
if not BestResult or not BestResultIndex or
|
||||
( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then
|
||||
BestResult = CurrResult
|
||||
BestResult.RawTotLen = dRawTotLen
|
||||
BestResultIndex = Index
|
||||
end
|
||||
end
|
||||
|
||||
local CycleCount = 0
|
||||
|
||||
local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end
|
||||
local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end
|
||||
local TargetRatio = 0.98
|
||||
local dTargetRatioLen = TargetRatio * dTotLen
|
||||
if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end
|
||||
local CurrTime = 0
|
||||
|
||||
local function NestSolutionFromSP( StartingPoint, OscillationStep)
|
||||
-- ciclo sulle possibilita' da un punto di origine con uno step fisso
|
||||
local CurrResultIndex = StartingPoint
|
||||
NestSolutionByIndex( StartingPoint)
|
||||
if OscillationStep == 0 then return end
|
||||
local CycleIndex = 1
|
||||
local nOutOfBoundary = 0
|
||||
while nOutOfBoundary ~= 3 do
|
||||
CurrTime = EgtStopCounter() / 1000
|
||||
if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end
|
||||
if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end
|
||||
-- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia
|
||||
if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then
|
||||
if bLogStat then EgtOutLog('Brake') end
|
||||
break
|
||||
end
|
||||
local bCurrOutOfBoundary = false
|
||||
if CurrResultIndex < 0 then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 2 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 1
|
||||
end
|
||||
end
|
||||
if CurrResultIndex > #Parts then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 1 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 2
|
||||
end
|
||||
end
|
||||
if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then
|
||||
NestSolutionByIndex( CurrResultIndex)
|
||||
if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end
|
||||
if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end
|
||||
CycleCount = CycleCount + 1
|
||||
end
|
||||
CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep )
|
||||
CycleIndex = CycleIndex + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- lancio calcolo
|
||||
EgtStartCounter()
|
||||
local StartingResult = floor( #Parts * 0.3)
|
||||
if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end
|
||||
--local Step = floor( #Parts / 10) * floor( log10( #Parts))
|
||||
local nDividendo = pow( 10, floor( log10( #Parts)) - 1)
|
||||
nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10)
|
||||
local Step = floor( #Parts / nDividendo) * floor( log10( #Parts))
|
||||
if bLogStat then EgtOutLog('Step: ' .. Step ) end
|
||||
NestSolutionFromSP( StartingResult, Step)
|
||||
if Step > 1 then
|
||||
NestSolutionFromSP( StartingResult, 1)
|
||||
end
|
||||
|
||||
-- creo gruppi di lavorazione per risultato
|
||||
for MachGroupIndex = 1, #BestResult do
|
||||
local CurrMachGroup = BestResult[ MachGroupIndex]
|
||||
-- creo gruppo di lavorazione
|
||||
local MachGroupName = NewMachGroupName()
|
||||
nMachGroup = EgtAddMachGroup( MachGroupName)
|
||||
EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen)
|
||||
EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL)
|
||||
EgtSetInfo( nMachGroup, "AUTONEST", 1)
|
||||
-- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
|
||||
EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID)
|
||||
EgtSetInfo( nMachGroup, "PATTID", nMachGroup)
|
||||
-- Disegno i pezzi
|
||||
for i = 1, #CurrMachGroup.Parts do
|
||||
local CurrPart = CurrMachGroup.Parts[ i]
|
||||
-- creo pezzo copia
|
||||
local nPartDuploId = EgtDuploNew( CurrPart.PartId)
|
||||
EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX)
|
||||
end
|
||||
end
|
||||
|
||||
-- creo grezzi per ogni gruppo di lavorazione
|
||||
local nRawCnt = 0
|
||||
local nRawTot = ResultList[BestResultIndex]
|
||||
_G.BEAM = {}
|
||||
BEAM.FILE = NEST.FILE
|
||||
BEAM.MACHINE = NEST.MACHINE
|
||||
BEAM.FLAG = 6 -- CREATE_PANEL
|
||||
BEAM.BASEDIR = NEST.BASEDIR
|
||||
nMachGroup = EgtGetFirstMachGroup()
|
||||
while nMachGroup do
|
||||
local nNextMachGroup = EgtGetNextMachGroup( nMachGroup)
|
||||
EgtSetCurrMachGroup( nMachGroup)
|
||||
if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then
|
||||
EgtRemoveInfo( nMachGroup, "AUTONEST")
|
||||
EgtSetInfo( nMachGroup, "UPDATEUI", 1)
|
||||
local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua")
|
||||
if not bOk then
|
||||
EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')')
|
||||
end
|
||||
nRawCnt = nRawCnt + 1
|
||||
-- aggiorno interfaccia
|
||||
EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0)
|
||||
end
|
||||
nMachGroup = nNextMachGroup
|
||||
end
|
||||
|
||||
EgtResetCurrMachGroup()
|
||||
|
||||
NEST.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ BeamNestProcess completed')
|
||||
+5
-8
@@ -7,7 +7,7 @@
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( true)
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
@@ -15,9 +15,6 @@ EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua')
|
||||
|
||||
-- TODO forzatura calcolo con prerotazioni. Cancellare dopo che è stata aggiunta la gestione corretta
|
||||
local bCalcBestPieceUnloadPosition = true
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not sMachDir then
|
||||
@@ -290,7 +287,7 @@ local function MyProcessBeams()
|
||||
end
|
||||
|
||||
-- Sistemo le travi nel grezzo
|
||||
local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, bCalcBestPieceUnloadPosition)
|
||||
local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, false)
|
||||
if not bOk then
|
||||
EgtOutLog( sErr)
|
||||
EgtOutBox( sErr, 'Lavora Travi', 'ERROR')
|
||||
@@ -305,9 +302,9 @@ end
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessFeatures()
|
||||
|
||||
BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.ProcessMachinings( PARTS)
|
||||
BeamExec.GetProcessings( PARTS, false)
|
||||
BeamExec.GetCombinationMatrix( PARTS, false)
|
||||
BeamExec.ProcessMachinings( PARTS, false)
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
local sOutput = ''
|
||||
|
||||
@@ -688,7 +688,7 @@
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ScarfJoint.png",
|
||||
"StrategyList" : [ ]
|
||||
"StrategyList" : [ { "sStrategyId": "STR0009" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
[
|
||||
{
|
||||
"nGroup": "MACHINE",
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_sPiecesLoadingPosition",
|
||||
"sNameNge": "GEN_PIECES_LOADING",
|
||||
"sValue": "BEST_POSITION",
|
||||
"sValue": "BTL_POSITION",
|
||||
"sDescriptionShort": "Part loading position",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
@@ -12,24 +12,46 @@
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "BTL_POSITION",
|
||||
"sDescriptionShort": "Last piece position as BTL",
|
||||
"sDescriptionShort": "Loading position from BTL, no pre-rotation",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BEST_ROTATION",
|
||||
"sDescriptionShort": "Allow piece rotations",
|
||||
"sValue": "STD_PRE_ROTATION",
|
||||
"sDescriptionShort": "Get Best loading position from 0° and 180°",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BEST_POSITION",
|
||||
"sDescriptionShort": "Allow piece rotation and inversion",
|
||||
"sValue": "FULL_PRE_ROTATION",
|
||||
"sDescriptionShort": "Get Best loading position in each piece rotation",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_bAllowPieceInversion",
|
||||
"sNameNge": "ADMIT_INVERSION",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Allow piece inversion",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_bGetAlternativesNesting2D",
|
||||
"sNameNge": "GET_ALTERNATIVES_NEST2D",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Enable material optimization function in nesting",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINE",
|
||||
"sName": "GEN_sPieceRotation",
|
||||
@@ -90,6 +112,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_nMaxReProcessCycles",
|
||||
"sNameNge": "MAX_REPROCESS_CYCLES",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Max number of reprocessing cycles",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "10"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_bReduceBladePath",
|
||||
|
||||
@@ -40,6 +40,11 @@ function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- si setta che è taglio di testa
|
||||
Strategy.bIsHeadCut = true
|
||||
-- quando si aggiunge la lavorazione, si cambia il nome della feature
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'StartCut')
|
||||
end
|
||||
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
@@ -67,9 +72,6 @@ function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- se devo applicare le lavorazioni
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'StartCut')
|
||||
|
||||
-- inserimento smussi su spigoli del taglio
|
||||
if Strategy.Parameters.bMakeChamfer then
|
||||
MakeChamfer()
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOpenMinSafe",
|
||||
"sNameNge": "OPENMINSAFE",
|
||||
|
||||
@@ -19,6 +19,7 @@ local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0002 = {}
|
||||
@@ -107,7 +108,7 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
local Milling = {}
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
Machining.sTypeMachining = 'None' -- Bottom-Side1-Side2\ Bottom-Side1\ Bottom-Side2\ Side1-Side2\ Bottom\ Side1 \ Side2 \ None
|
||||
Machining.sTypeMachining = 'None' -- Bottom-Side1-Side2\ Bottom-Bottom2\ Bottom-Side1\ Bottom-Side2\ Side1-Side2\ Bottom\ Side1 \ Side2 \ None
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
|
||||
-- caso speciale Tunnel che non ha faccia bottom
|
||||
@@ -170,10 +171,14 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
-- cerco utensile per lavorare faccia Bottom
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName ~= 'Tunnel-4-Through' then
|
||||
-- TODO in caso che la faccia crei un piano asportando tutto il materiale, si potrebbe forzare elevazione a zero e scegliere quindi fresa di diametro maggiore.
|
||||
-- Il discorso non vale se la feature viene spezzata o se non ancora separata, in quanto ci sarebbe comunque del materiale da considerare nell'elevazione.
|
||||
-- In quel caso, un 'Bevel-1-Through' è come se fosse un 'Bevel-2-Blind', quindi l'elevazione deve essere considerata.
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[1].vtN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[1].id
|
||||
Milling.bAddAntiSplint = Strategy.Parameters.bAntiSplint
|
||||
Milling.idProc = Proc.id
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[1].vtN
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[1].dElevation
|
||||
@@ -204,13 +209,14 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
-- caso speciale 'Rabbet-2-Through' seconda faccia principale
|
||||
Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or
|
||||
if Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or
|
||||
Proc.Topology.sName == 'DoubleBevel-2-Through' or Proc.Topology.sName == 'VGroove-2-Through' then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[2].vtN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[2].id
|
||||
Milling.bAddAntiSplint = Strategy.Parameters.bAntiSplint
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
Milling.ToolInfo = {}
|
||||
@@ -238,12 +244,21 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' or Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.LongFaces[1].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
if Proc.MainFaces.LongFaces and Proc.MainFaces.LongFaces[1] then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.LongFaces[1].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
elseif Proc.MainFaces.BottomFaces[2] then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[2].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
end
|
||||
elseif Proc.MainFaces.TunnelAddedFaces then -- 'Tunnel-4-Through', 'Groove-3-Through', 'Rabbet-2-Through', 'VGroove-2-Through', 'Bevel-2-Blind'
|
||||
-- se lavoro di fianco, devo comunque rispettare il raggio massimo
|
||||
ToolSearchParameters.dMaxToolDiameter = min( ToolSearchParameters.dMaxToolDiameter, Strategy.Parameters.dMaxCornerRadius * 2)
|
||||
@@ -254,6 +269,8 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
Milling.idProc = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.id
|
||||
Milling.dElevation = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP
|
||||
Milling.bMachAppliedToTunnelFace = true
|
||||
else
|
||||
ToolSearchParameters.vtToolDirection = nil
|
||||
end
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
@@ -263,6 +280,19 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- se la faccia tunnel è troppo piccola non si lavora
|
||||
if Milling.bMachAppliedToTunnelFace then
|
||||
local dLongestEdgeLength = 0
|
||||
for i = 1, #Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges do
|
||||
if Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength > dLongestEdgeLength + 10 * GEO.EPS_SMALL then
|
||||
dLongestEdgeLength = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength
|
||||
end
|
||||
end
|
||||
if dLongestEdgeLength < TOOLS[Milling.ToolInfo.nToolIndex].dDiameter then
|
||||
Milling.bIsApplicable = false
|
||||
ParametersMRR = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
@@ -294,6 +324,8 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
Milling.idFaceToMachine = Proc.MainFaces.SideFaces[1].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.SideFaces[1].dElevation
|
||||
else
|
||||
ToolSearchParameters.vtToolDirection = nil
|
||||
end
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
@@ -303,13 +335,60 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- se la faccia tunnel è troppo piccola non si lavora
|
||||
if Milling.bMachAppliedToTunnelFace then
|
||||
local dLongestEdgeLength = 0
|
||||
for i = 1, #Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges do
|
||||
if Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength > dLongestEdgeLength + 10 * GEO.EPS_SMALL then
|
||||
dLongestEdgeLength = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength
|
||||
end
|
||||
end
|
||||
if dLongestEdgeLength < TOOLS[Milling.ToolInfo.nToolIndex].dDiameter then
|
||||
Milling.bIsApplicable = false
|
||||
ParametersMRR = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
-- ===== SCELTA LAVORAZIONI =====
|
||||
-- TODO per DoubleBevel-2-Through si potrebbe lavorare la faccia tunnel su ogni faccia. Bisogna calcolarla!!
|
||||
-- caso speciale DoubleBevel-2-Through bisogna lavorare entrambe le bottom
|
||||
if Proc.Topology.sName == 'DoubleBevel-2-Through' then
|
||||
-- se entrambe applicabili significa che è completo
|
||||
if Machining[1].bIsApplicable and Machining[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom-Bottom2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[1].dMRR + Machining[2].dMRR / 2
|
||||
Machining[1].ToolInfo.dResidualDepth = 0
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
return Machining
|
||||
else
|
||||
local dMachinedPrercentage = 0
|
||||
-- se applicabile solo Bottom
|
||||
if Machining[1].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Machining[1].ToolInfo.dResidualDepth = 0
|
||||
Strategy.Result.dMRR = Machining[1].dMRR
|
||||
dMachinedPrercentage = ( Machining[1].dElevation / ( Machining[1].dElevation + Machining[2].dElevation)) * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
-- se applicabile solo Bottom2
|
||||
elseif Machining[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom2'
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
Strategy.Result.dMRR = Machining[2].dMRR
|
||||
dMachinedPrercentage = ( Machining[2].dElevation / ( Machining[1].dElevation + Machining[2].dElevation)) * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
end
|
||||
Strategy.Result.sInfo = 'Machining not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
end
|
||||
return Machining
|
||||
-- se bottom completa tutto
|
||||
if Machining[1].bIsApplicable and Machining[1].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
elseif Machining[1].bIsApplicable and Machining[1].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
@@ -321,10 +400,10 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
if ( Proc.nFct == 2 and Proc.AdjacencyMatrix[1][2] >= -89.9)
|
||||
and Machining[2].bIsApplicable and Machining[2].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
|
||||
Machining.sTypeMachining = 'Bottom2'
|
||||
Machining.sTypeMachining = 'Bottom-Bottom2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[2].dMRR
|
||||
Strategy.Result.dMRR = Machining[1].dMRR + Machining[2].dMRR / 2
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
else
|
||||
Machining[2].bIsApplicable = false
|
||||
@@ -549,8 +628,8 @@ function STR0002.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Pocketing.Steps.dStep = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dStep
|
||||
Pocketing.Steps.dSideStep = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dSideStep
|
||||
Pocketing.nToolIndex = Strategy.Machining[j].ToolInfo.nToolIndex
|
||||
Pocketing.LeadIn.dTangentDistance = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter/2
|
||||
Pocketing.LeadIn.dElevation = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter/2
|
||||
Pocketing.LeadIn.dTangentDistance = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter / 2
|
||||
Pocketing.LeadIn.dElevation = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter / 2
|
||||
Pocketing.sDepth = -Strategy.Machining[j].ToolInfo.dResidualDepth
|
||||
Pocketing.dResidualDepth = Strategy.Machining[j].ToolInfo.dResidualDepth
|
||||
-- TODO vedere se questo parametro con svuotature nuove si può rimuovere
|
||||
@@ -559,11 +638,35 @@ function STR0002.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
if Strategy.Machining[j].bToolInvert then
|
||||
Pocketing.bToolInvert = true
|
||||
end
|
||||
-- eventuali antischeggia
|
||||
if Strategy.Machining[j].bAddAntiSplint then
|
||||
local OptionalParametersAntiSplint = {
|
||||
bIsSplitFeature = ( #vAddId > 1),
|
||||
dExtendAfterTail = Strategy.Parameters.dExtendAfterTail
|
||||
}
|
||||
local AntiSplints = AntiSplintOnFace.Make( Proc, Part, Proc.Faces[ Strategy.Machining[j].idFaceToMachine + 1], OptionalParametersAntiSplint)
|
||||
local bAreAllAntisplintsApplicable = true
|
||||
for k = 1, #AntiSplints do
|
||||
if AntiSplints[k].bIsApplicable then
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, AntiSplints[k])
|
||||
end
|
||||
else
|
||||
bAreAllAntisplintsApplicable = false
|
||||
end
|
||||
end
|
||||
if bAreAllAntisplintsApplicable then
|
||||
-- TODO qui si dovrà distinguere tra antischeggia di lama e di fresa; al momento è solo di lama
|
||||
if Strategy.Result.dQuality == FeatureLib.GetStrategyQuality( 'STD') then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'BEST')
|
||||
end
|
||||
end
|
||||
end
|
||||
-- se ho una sola trimesh, sto lavorando la Proc direttamente e non ho spezzato. Applico direttamente alla geometria calcolata prima
|
||||
if #vAddId == 1 then
|
||||
Pocketing.Geometry = {{ Strategy.Machining[j].idProc, Strategy.Machining[j].idFaceToMachine}}
|
||||
Pocketing.vtToolDirection = Strategy.Machining[j].vtFaceNormal
|
||||
|
||||
|
||||
-- TODO controllare parametro danneggiamento ammesso per decidere se spostare dopo taglio seprazione
|
||||
-- se è aperta sulla coda, dico che deve essere fatta dopo la separazione
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
@@ -593,10 +696,10 @@ function STR0002.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
if vtNSplitFace and AreSameVectorApprox( vtNSplitFace * EgtIf( Pocketing.bToolInvert, -1, 1), Strategy.Machining[j].vtFaceNormal) then
|
||||
Pocketing.Geometry = {{ nIdTm, k - 1}}
|
||||
|
||||
|
||||
Pocketing.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Pocketing, Part)
|
||||
Strategy.Result.dTimeToMachine = Strategy.Result.dTimeToMachine + Pocketing.dTimeToMachine
|
||||
|
||||
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Pocketing)
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this lenght as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
|
||||
@@ -35,12 +35,19 @@ Chainsaw.Result = {}
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.bAllRightAngles and
|
||||
( Proc.Topology.sName == 'Pocket-5-Blind' or
|
||||
Proc.Topology.sName == 'Groove-3-Through' or
|
||||
Proc.Topology.sName == 'Groove-4-Blind' or
|
||||
Proc.Topology.sName == 'Tunnel-4-Through') then
|
||||
|
||||
return true
|
||||
|
||||
-- canale ammesso solo se lati paralleli a 2 a 2
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through'
|
||||
and ( AreOppositeVectorApprox( Proc.MainFaces.BottomFaces[1].MainEdges.LongEdges[1].vtN, Proc.MainFaces.BottomFaces[1].MainEdges.LongEdges[2].vtN)) then
|
||||
|
||||
return true
|
||||
|
||||
else
|
||||
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -188,6 +195,17 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Blade.Result = {}
|
||||
Chainsaw.Result = {}
|
||||
|
||||
|
||||
-- se arriva una feature senza MainFaces o MainEdges necessari la strategia non è applicabile
|
||||
-- TODO riuniure a IsTopologyOk?
|
||||
if not Proc.MainFaces
|
||||
or not Proc.MainFaces.LongFaces[1]
|
||||
or not Proc.MainFaces.LongFaces[1].MainEdges then
|
||||
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
@@ -195,13 +213,15 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se tasca su faccia sotto la strategia non è applicabile (la sega a catena in generale non può lavorare da sotto)
|
||||
-- TODO se OnlySaw questo test è da rimuovere ma bisogna considerare anche la lama da sotto
|
||||
if Proc.AffectedFaces.bBottom and ( Proc.nFct > 3 or not Proc.AffectedFaces.bTop) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not applicable - pocket on bottom face'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Direction')
|
||||
return false, Strategy.Result
|
||||
-- se canale e lati non a 90deg la strategia non è applicabile
|
||||
-- TODO questo è temporaneo finchè non si gestiscono correttamente i lati obliqui per le groove-3-through
|
||||
-- la dPocketHeight è già gestita, ma va allungato il percorso dove c'è l'angolo > 90
|
||||
if Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
if abs( BottomFace.Edges[1].vtEdge * BottomFace.Edges[2].vtEdge) > 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
@@ -223,6 +243,11 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local dPocketHeight = 0
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
dPocketHeight = Proc.MainFaces.SideFaces[1].MainEdges.OppositeEdges[1].dLength
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
local frFrame = Frame3d( BottomFace.ptCenter, BottomFace.vtN, BottomFace.MainEdges.LongEdges[1].vtEdge)
|
||||
local b3BottomFace = EgtSurfTmGetFacetBBoxRef( Proc.id, BottomFace.id, GDB_BB.STANDARD, frFrame)
|
||||
dPocketHeight = b3BottomFace:getDimY()
|
||||
else
|
||||
dPocketHeight = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this lenght as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
|
||||
@@ -112,8 +112,6 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Chainsaw.Result = {}
|
||||
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
@@ -134,10 +132,25 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
-- se arriva una feature senza MainFaces o MainEdges necessari la strategia non è applicabile
|
||||
-- TODO riuniure a IsTopologyOk?
|
||||
if not Proc.MainFaces
|
||||
or not Proc.MainFaces.LongFaces[1]
|
||||
or not Proc.MainFaces.LongFaces[1].MainEdges then
|
||||
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- altezza tasca
|
||||
local dPocketHeight = 0
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
dPocketHeight = Proc.MainFaces.SideFaces[1].MainEdges.OppositeEdges[1].dLength
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
local frFrame = Frame3d( BottomFace.ptCenter, BottomFace.vtN, BottomFace.MainEdges.LongEdges[1].vtEdge)
|
||||
local b3BottomFace = EgtSurfTmGetFacetBBoxRef( Proc.id, BottomFace.id, GDB_BB.STANDARD, frFrame)
|
||||
dPocketHeight = b3BottomFace:getDimY()
|
||||
else
|
||||
dPocketHeight = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
end
|
||||
@@ -172,13 +185,17 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
and #Proc.MainFaces.SideFaces == 1 then
|
||||
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
local dLengthAlreadyMachined = 0
|
||||
if Chainsaw.Result.Bottom[1].bIsApplicable then
|
||||
dLengthAlreadyMachined = Chainsaw.Result.Bottom[1].dDepthToMachine
|
||||
end
|
||||
|
||||
if BottomEdge.bIsStartOpen then
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - dLengthAlreadyMachined)
|
||||
elseif BottomEdge.bIsEndOpen then
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - dLengthAlreadyMachined)
|
||||
end
|
||||
|
||||
Chainsaw.AddResult( Mortising)
|
||||
@@ -235,10 +252,21 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- se dal lato OppositeEdge1 non è applicabile (solitamente per finecorsa) si prova dal lato opposto
|
||||
if not Chainsaw.Result.Opposite[1].bIsApplicable then
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge2.dElevation + BeamData.CUT_EXTRA
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
-- se lavorando solo da un lato rimane materiale residuo, si lavora da entrambi
|
||||
if Chainsaw.Result.Opposite[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
if Chainsaw.Result.Opposite[1].dResidualDepth > 10 * GEO.EPS_SMALL
|
||||
or ( Chainsaw.Result.Opposite[2] and Chainsaw.Result.Opposite[2].dResidualDepth > 10 * GEO.EPS_SMALL) then
|
||||
|
||||
Chainsaw.Result.Opposite[1].bIsApplicable = false
|
||||
if Chainsaw.Result.Opposite[2] then
|
||||
Chainsaw.Result.Opposite[2].bIsApplicable = false
|
||||
end
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this lenght as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
|
||||
@@ -66,7 +66,7 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local dQualityAddedFace = 0
|
||||
|
||||
-- più di 3 facce non supportate
|
||||
if Proc.nFct > 3 then
|
||||
if Proc.nFct > 3 and ( not Proc.Topology.sFamily == 'DoubleBevel') then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'More than 3 faces not supported')
|
||||
end
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ function STR0007.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
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 = Part.idTempGroup
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
Strategy.idMortiseCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCutC, vtCutN, Part.b3Part, GDB_RT.GLOB)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,13 +174,13 @@ local function GetBestPocketingStrategy( Proc, Part)
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[2].ToolInfo)
|
||||
Machining.Pocketing[1].bIsApplicable = false
|
||||
-- solo svuotatura diretta come normale mortasa, incompleta
|
||||
elseif not Machining.Pocketing[2].bIsApplicable then
|
||||
elseif Machining.Pocketing[1].bIsApplicable and not Machining.Pocketing[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Side1'
|
||||
Machining.dResidual = Machining.Pocketing[1].ToolInfo.dResidualDepth
|
||||
Machining.Pocketing[1].sDepth = -Machining.dResidual
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[1].ToolInfo)
|
||||
-- solo svuotatura diretta come normale mortasa, incompleta
|
||||
elseif not Machining.Pocketing[1].bIsApplicable then
|
||||
elseif Machining.Pocketing[2].bIsApplicable and not Machining.Pocketing[1].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Side2'
|
||||
Machining.dResidual = Machining.Pocketing[2].ToolInfo.dResidualDepth
|
||||
Machining.Pocketing[2].sDepth = Proc.FeatureInfo.dMortiseDepth - Machining.dResidual
|
||||
@@ -311,10 +311,7 @@ function STR0008.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- si applicano le lavorazioni di svuotatura
|
||||
for i = 1, #Strategy.Machining.Pocketing do
|
||||
if Strategy.Machining.Pocketing[i].bIsApplicable then
|
||||
Pocketing = {}
|
||||
Pocketing.Steps = {}
|
||||
Pocketing.LeadIn = {}
|
||||
Pocketing.nType = MCH_MY.POCKETING
|
||||
Pocketing = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
Pocketing.nSubType = MCH_POCK_SUB.SPIRALOUT
|
||||
Pocketing.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Pocketing.Steps.dStep = TOOLS[Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex].dStep
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"sStrategyId": "STR0009",
|
||||
"sStrategyName": "Mill Heading",
|
||||
"sStrategyName": "ScarfJoint",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDepthChamfer",
|
||||
@@ -13,35 +13,15 @@
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMaterial",
|
||||
"sNameNge": "OVERMAT",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bForceStrip",
|
||||
"sNameNge": "FORCE_STRIP",
|
||||
"sName": "bAntiSplint",
|
||||
"sNameNge": "ANTISPLINT",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force strip",
|
||||
"sDescriptionLong": "Enable the parameter to force the software to leave a strip to sustain the piece",
|
||||
"sDescriptionShort": "Use Anti-Splint strategy",
|
||||
"sDescriptionLong": "The strategy will apply blade cuts on corner to avoid wood splint",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dStripWidth",
|
||||
"sNameNge": "STRIP_WIDTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Strip width",
|
||||
"sDescriptionLong": "Width of the strip in case if foreseen from the machining",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "PROFILE_TOOL_LIST",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
-- Strategia: STR0009
|
||||
-- Descrizione
|
||||
-- Fresatura di contorno
|
||||
-- Feature tipo Arco
|
||||
-- Feature tipo ScarfJoint
|
||||
|
||||
|
||||
-- carico librerie
|
||||
@@ -10,156 +9,182 @@ local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
local FaceByMill = require( 'FACEBYMILL')
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0009 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO gestire il caso in cui non si trova l'utensile
|
||||
local function GetArcStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
local ToolSearchParameters = {}
|
||||
local function GetFacesIdOrder( Proc, Part)
|
||||
local Faces = {}
|
||||
if Proc.nFct == 5 then
|
||||
-- carico gli id delle facce
|
||||
for i = 1, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
elseif Proc.nFct == 4 then
|
||||
local vtN1 = Proc.Faces[1].vtN
|
||||
local vtN2 = Proc.Faces[2].vtN
|
||||
local nIndex = EgtIf( abs( vtN1:getX()) > abs( vtN2:getX()), 1, 2)
|
||||
for i = nIndex, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
-- TODO manca il caso in cui mancano facce 4 e 5
|
||||
else -- Proc.nFct == 3
|
||||
for i = 2, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- recupero e verifico l'entità curva
|
||||
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
|
||||
if idAux then idAux = idAux + Proc.id end
|
||||
if not idAux or ( EgtGetType( idAux) & GDB_FY.GEO_CURVE) == 0 then
|
||||
local sErr = 'Error on process ' .. tostring( Proc.id) .. ' missing profile geometry'
|
||||
return Faces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetEdgeToMachine( ClosingFace, idBottomFace)
|
||||
local EdgeToMachine
|
||||
|
||||
for i = 1, #ClosingFace.Edges do
|
||||
if ClosingFace.Edges[i].idAdjacentFace == idBottomFace then
|
||||
EdgeToMachine = ClosingFace.Edges[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return EdgeToMachine
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetScarfJointStrategy( Proc, Part)
|
||||
-- ordino le facce in base al loro numero e al parallelismo delle due facce principali
|
||||
-- faccia 0: superficie tappo (*potrebbe non esserci)
|
||||
-- faccia 1: superficie principale di fondo
|
||||
-- faccia 2: superficie opposta alla faccia 1
|
||||
-- faccia 3: superficie principale superiore
|
||||
-- faccia 4: superficie di testa (*potrebbe non esserci)
|
||||
-- creo una tabella unica contenente tutte le lavorazioni
|
||||
local Result = {}
|
||||
local Cutting = { Machinings = {}, Result = {}}
|
||||
local AntiSplints = {}
|
||||
local Pocketing = {}
|
||||
|
||||
Result.dTimeToMachine = 0
|
||||
local Faces = GetFacesIdOrder( Proc)
|
||||
-- taglio su faccia 4
|
||||
if Faces[4] and Faces[4].vtN then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- TODO la nuova faccia creata sulla 4 può tagliare faccia 1. In caso tagliasse faccia 1, bisogna calcolare i cubetti con 2 facce
|
||||
Strategy.idFeatureCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, Faces[4].ptCenter, Faces[4].vtN, Part.b3Part, GDB_RT.GLOB)
|
||||
Cutting.Machinings, Cutting.Result = BladeToWaste.Make( Strategy.idFeatureCutPlane, Part)
|
||||
if Cutting.Result.sStatus == 'Completed' then
|
||||
Cutting.Machinings.bIsApplicable = true
|
||||
end
|
||||
end
|
||||
|
||||
-- antischeggia facce 1 e 3
|
||||
local bAreAllAntisplintsApplicable = true
|
||||
if Strategy.Parameters.bAntiSplint then
|
||||
AntiSplints = AntiSplintOnFace.Make( Proc, Part, Faces[2])
|
||||
for k = 1, #AntiSplints do
|
||||
if not AntiSplints[k].bIsApplicable then
|
||||
bAreAllAntisplintsApplicable = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- svuotatura faccia 2
|
||||
if Faces[2] then
|
||||
local frPock, dL, dW = EgtSurfTmFacetMinAreaRectangle( Proc.id, Faces[2].id, GDB_ID.ROOT)
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.vtToolDirection = Faces[2].vtN
|
||||
ToolSearchParameters.dElevation = abs( ( Faces[2].ptCenter - Faces[4].ptCenter) * Faces[2].vtN)
|
||||
ToolSearchParameters.dMaxToolDiameter = min( dL, dW)
|
||||
ToolSearchParameters.ToolInfo = {}
|
||||
ToolSearchParameters.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if ToolSearchParameters.ToolInfo.nToolIndex then
|
||||
local Machining = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
Machining.Geometry = {{ Proc.id, Faces[2].id}}
|
||||
Machining.dElevation = ToolSearchParameters.dElevation
|
||||
Machining.dMaxElev = Machining.dElevation
|
||||
Machining.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
Machining.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Machining.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Machining.Steps.dStep = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dStep
|
||||
Machining.Steps.dSideStep = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.nToolIndex = ToolSearchParameters.ToolInfo.nToolIndex
|
||||
Machining.LeadIn.dTangentDistance = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dDiameter / 2
|
||||
Machining.LeadIn.dElevation = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dDiameter / 2
|
||||
Machining.sDepth = 0
|
||||
Machining.dResidualDepth = ToolSearchParameters.ToolInfo.dResidualDepth
|
||||
-- TODO vedere se questo parametro con svuotature nuove si può rimuovere
|
||||
Machining.dOpenMinSafe = Strategy.Parameters.dOpenMinSafe
|
||||
Machining.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
Result.dTimeToMachine = Result.dTimeToMachine + Machining.dTimeToMachine
|
||||
table.insert( Pocketing, Machining)
|
||||
Pocketing.bIsApplicable = true
|
||||
-- se non sono stati fatti i passaggi antischeggia si verifica che le facce siano a 90°, altrimenti serve passaggio con fresa
|
||||
if not Strategy.Parameters.bAntiSplint or not bAreAllAntisplintsApplicable then
|
||||
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2] or 0
|
||||
-- si fa passaggio con fresa
|
||||
if dAngleBetweenFaces > -90 then
|
||||
local EdgeToMachine = GetEdgeToMachine( Faces[1], Faces[2].id)
|
||||
local CuttingClosingFace = FaceByBlade.Make( Proc, Part, Faces[1], EdgeToMachine)
|
||||
if CuttingClosingFace.bIsApplicable then
|
||||
table.insert( AntiSplints, CuttingClosingFace)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se manca taglio principale, feature non eseguibile
|
||||
if not Cutting.Machinings.bIsApplicable then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not applicable'
|
||||
EgtOutLog( sErr)
|
||||
return false, sErr
|
||||
end
|
||||
Proc.idAddAuxGeom = idAux
|
||||
|
||||
-- recupero i dati della curva e del profilo
|
||||
local dDepth = abs( EgtCurveThickness( idAux))
|
||||
local vtExtr = EgtCurveExtrusion( idAux, GDB_RT.GLOB)
|
||||
local bToolInvert = ( vtExtr:getZ() < -0.1)
|
||||
local bIsHorizontal = abs( vtExtr:getZ()) < 10 * GEO.EPS_SMALL
|
||||
local bIsFeatureDown = Proc.AffectedFaces.bBottom and not Proc.AffectedFaces.bTop
|
||||
local bIsFeatureBack = Proc.AffectedFaces.bBack and not Proc.AffectedFaces.bFront
|
||||
local bForceStrip = Strategy.Parameters.bForceStrip
|
||||
local dDimStrip = EgtIf( Strategy.Parameters.dStripWidth < 100 * GEO.EPS_SMALL, nil, Strategy.Parameters.dStripWidth)
|
||||
|
||||
local bExecStrip = false
|
||||
-- se la lavorazione si trova nella parte inferiore o in battuta dietro, il codolo va sempre lasciato
|
||||
if bIsFeatureDown or bIsFeatureBack or bForceStrip then
|
||||
if bIsFeatureDown or bIsFeatureBack then
|
||||
dDimStrip = dDimStrip or max( BeamData.DIM_STRIP or 5, 5)
|
||||
else
|
||||
dDimStrip = dDimStrip or max( BeamData.DIM_STRIP_SMALL or 5, 1)
|
||||
end
|
||||
bExecStrip = true
|
||||
end
|
||||
if not bExecStrip then
|
||||
dDimStrip = 0
|
||||
end
|
||||
|
||||
-- se lavorazione orizzontale
|
||||
if bIsHorizontal then
|
||||
local bDouble
|
||||
local Milling = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
Milling.bIsApplicable = false
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dElevation = EgtIf( bExecStrip, ( dDepth - dDimStrip) / 2, dDepth + BeamData.MILL_OVERLAP)
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
-- se posso lavorare in una passata, ma utensile trovato non completa la lavorazione,
|
||||
-- allora provo a cercare utensile con massimo materiale sufficiente per fare le due passate, magari trova un utensile più prestante
|
||||
if Milling.ToolInfo.dResidualDepth > 10 * GEO.EPS_SMALL and not bExecStrip then
|
||||
bDouble = true
|
||||
ToolSearchParameters.dElevation = ( dDepth + BeamData.MILL_OVERLAP) / 2
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
end
|
||||
Milling.bToolInvert = bToolInvert
|
||||
Milling.vtToolDirection = vtExtr
|
||||
|
||||
if bDouble or bExecStrip then
|
||||
if bDouble then
|
||||
Milling.sDepth = ( dDepth + BeamData.MILL_OVERLAP) / 2
|
||||
else
|
||||
Milling.sDepth = ( dDepth - dDimStrip) / 2
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
local Milling2 = BeamLib.TableCopyDeep( Milling)
|
||||
table.insert( Machining, Milling2)
|
||||
else
|
||||
Milling.sDepth = dDepth + BeamData.MILL_OVERLAP
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
-- se lavorazione verticale
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
else
|
||||
-- si cerca utensile 1
|
||||
local Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dElevation = dDepth + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
-- si cerca utensile 2
|
||||
local Milling2 = {}
|
||||
Milling2.bIsApplicable = false
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dElevation = dDepth + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, vtExtr, -vtExtr)
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Milling2.ToolInfo = {}
|
||||
Milling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- se serve codolo
|
||||
if bExecStrip then
|
||||
-- se a disposizione entrambi gli utensili
|
||||
if Milling.ToolInfo.nToolIndex and Milling2.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling)
|
||||
table.insert( Machining, Milling2)
|
||||
-- se disponibile solo primo utensile
|
||||
elseif Milling.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling)
|
||||
-- se disponibile solo secondo utensile
|
||||
elseif Milling2.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling2)
|
||||
-- nessun utensile disponibile
|
||||
local dCompletionPercentage = 100
|
||||
-- completa se svuotatura eseguita e antisplit eseguiti (o non richiesti)
|
||||
if Pocketing.bIsApplicable and ( bAreAllAntisplintsApplicable or not Strategy.Parameters.bAntiSplint) then
|
||||
Result.sStatus = 'Completed'
|
||||
if bAreAllAntisplintsApplicable then
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
else
|
||||
-- non si fa nulla
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
end
|
||||
-- altrimenti senza codolo
|
||||
-- altrimenti non completa
|
||||
else
|
||||
-- se utensile 1 esegue completamente
|
||||
if Milling.ToolInfo.nToolIndex and Milling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
table.insert( Machining, Milling)
|
||||
-- se utensile 2 esegue completamente
|
||||
elseif Milling2.ToolInfo.nToolIndex and Milling2.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
table.insert( Machining, Milling2)
|
||||
-- se possono lavorare entrambi
|
||||
elseif Milling.ToolInfo.nToolIndex and Milling2.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling)
|
||||
table.insert( Machining, Milling2)
|
||||
-- se utensile 1 non completo
|
||||
elseif Milling.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling)
|
||||
-- se utensile 2 non completo
|
||||
elseif Milling2.ToolInfo.nToolIndex then
|
||||
table.insert( Machining, Milling2)
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
Result.sStatus = 'Not-Completed'
|
||||
-- se fa solo svuotatura
|
||||
if Pocketing.bIsApplicable then
|
||||
dCompletionPercentage = 90
|
||||
Result.sInfo = 'Anti-Split not executed'
|
||||
elseif Strategy.Parameters.bAntiSplint and bAreAllAntisplintsApplicable then
|
||||
dCompletionPercentage = 75
|
||||
Result.sInfo = 'Pocketing not executed'
|
||||
else
|
||||
dCompletionPercentage = 50
|
||||
Result.sInfo = 'Only the cut has been executed'
|
||||
end
|
||||
end
|
||||
|
||||
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
||||
end
|
||||
|
||||
-- TODO VOTO DA FARE!!!!
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo or Machining[2].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
Strategy.Result.sInfo = ''
|
||||
-- creo una tabella unica contenente tutte le lavorazioni
|
||||
local Machinings = {}
|
||||
EgtJoinTables( Machinings, Cutting.Machinings)
|
||||
EgtJoinTables( Machinings, AntiSplints)
|
||||
EgtJoinTables( Machinings, Pocketing)
|
||||
|
||||
return Machining
|
||||
return Machinings, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
@@ -173,79 +198,33 @@ function STR0009.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local Milling = {}
|
||||
|
||||
Strategy.Machinings = GetArcStrategy( Proc, Part)
|
||||
-- controlli preliminari
|
||||
if Proc.nFct < 3 or Proc.nFct > 5 then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
Strategy.Machinings, Strategy.Result = GetScarfJointStrategy( Proc, Part)
|
||||
|
||||
for i = 1, #Strategy.Machinings do
|
||||
|
||||
Strategy.Machinings[i].Geometry = {{ Proc.idAddAuxGeom, -1}}
|
||||
Strategy.Machinings[i].nToolIndex = Strategy.Machinings[i].ToolInfo.nToolIndex
|
||||
Strategy.Machinings[i].nType = MCH_MY.MILLING
|
||||
Strategy.Machinings[i].dStartSafetyLength = 0
|
||||
Strategy.Machinings[i].Steps = {}
|
||||
Strategy.Machinings[i].Steps = MachiningLib.GetMachiningSteps( false, tonumber( Strategy.Machinings[i].sDepth), TOOLS[Strategy.Machinings[i].nToolIndex].dStep)
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Strategy.Machinings[i].LeadIn = {}
|
||||
Strategy.Machinings[i].LeadOut = {}
|
||||
Strategy.Machinings[i].LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Machinings[i].LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Machinings[i].LeadIn.dTangentDistance = TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Machinings[i].LeadIn.dPerpDistance = 0
|
||||
Strategy.Machinings[i].LeadIn.dStartAddLength = 0
|
||||
Strategy.Machinings[i].LeadOut.dTangentDistance = TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Machinings[i].LeadOut.dPerpDistance = 0
|
||||
Strategy.Machinings[i].LeadOut.dEndAddLength = 0
|
||||
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machinings[i].sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- preparo attacco/uscita in caso di spezzatura arco
|
||||
Strategy.Machinings[i].LeadInForSplit = BeamLib.TableCopyDeep( Strategy.Machinings[i].LeadIn)
|
||||
Strategy.Machinings[i].LeadOutForSplit = BeamLib.TableCopyDeep( Strategy.Machinings[i].LeadOut)
|
||||
Strategy.Machinings[i].LeadInForSplit.nType = MCH_MILL_LI.LINEAR
|
||||
Strategy.Machinings[i].LeadOutForSplit.nType = MCH_MILL_LI.LINEAR
|
||||
Strategy.Machinings[i].LeadInForSplit.dTangentDistance = 0
|
||||
Strategy.Machinings[i].LeadInForSplit.dPerpDistance = TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Machinings[i].LeadOutForSplit.dTangentDistance = 0
|
||||
Strategy.Machinings[i].LeadOutForSplit.dPerpDistance = TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
if i == 1 then
|
||||
Strategy.Machinings[i].bInvert = EgtIf( TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Strategy.Machinings[i].nWorkside = EgtIf( TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
else
|
||||
Strategy.Machinings[i].bToolInvert = true
|
||||
Strategy.Machinings[i].bInvert = EgtIf( TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].bIsCCW, true, false)
|
||||
Strategy.Machinings[i].nWorkside = EgtIf( TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
end
|
||||
Strategy.Machinings[i].ptEdge1 = EgtSP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Machinings[i].ptEdge2 = EgtEP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Machinings[i].dEdgeLength = EgtCurveLength( Proc.idAddAuxGeom)
|
||||
Strategy.Machinings[i].vtEdgeDirection = EgtSV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtMV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtEV( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Machinings[i].dLengthOnX = Proc.b3Box:getDimX()
|
||||
|
||||
local MachiningToSplit = {}
|
||||
table.insert( MachiningToSplit, Strategy.Machinings[i])
|
||||
local MachiningResult = MachiningLib.GetSplitMachinings( MachiningToSplit, FeatureSplittingPoints, Part)
|
||||
-- aggiunta lavorazioni
|
||||
if #Strategy.Machinings > 0 then
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #MachiningResult do
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, MachiningResult[j])
|
||||
for j = 1, #Strategy.Machinings do
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
Strategy.Machinings[j].sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j])
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
bAreAllMachiningsAdded = false
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"sStrategyName": "Milling",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dAntiSplintWithBlade",
|
||||
"sName": "bAntiSplintWithBlade",
|
||||
"sNameNge": "ANTISPLINT_BLADE",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Antisplint with blade",
|
||||
@@ -17,7 +17,27 @@
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this lenght as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "ALLOW_FINISH_MILL",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Clean radius with mill",
|
||||
"sDescriptionLong": "Clean radius with mill",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMillingOffsetFromSide",
|
||||
"sNameNge": "MILLING_OFFSET_SIDE",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Milling offset from side",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
|
||||
@@ -9,7 +9,9 @@ local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local FaceByMill = require('FACEBYMILL')
|
||||
local FaceByMill = require( 'FACEBYMILL')
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0010 = {}
|
||||
@@ -34,7 +36,7 @@ local function GetStrategyCompletionPercentage( Machinings)
|
||||
if nWeightsCount ~= 0 and nWeightsCount ~= i then
|
||||
error( 'GetWeightedCompletionPercentage : inconsistent weights')
|
||||
end
|
||||
local dWeightedCompletionPercentage = Machining.dCompletionPercentage / 100 * dWeight
|
||||
local dWeightedCompletionPercentage = ( Machining.dCompletionPercentage or 0) / 100 * dWeight
|
||||
if Machining.bIsApplicable then
|
||||
dCompletionPercentageNumerator = dCompletionPercentageNumerator + dWeightedCompletionPercentage
|
||||
end
|
||||
@@ -47,34 +49,52 @@ local function GetStrategyCompletionPercentage( Machinings)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdges( EdgeA, EdgeB)
|
||||
-- prima i lati orientati lungo X
|
||||
if abs( EdgeA.vtN:getX()) < abs( EdgeB.vtN:getX()) - 10 * GEO.EPS_SMALL then
|
||||
local function CompareEdgesLongestTop( EdgeA, EdgeB)
|
||||
-- si preferiscono i lati più lunghi
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif abs( EdgeA.vtN:getX()) > abs( EdgeB.vtN:getX()) + 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa X si preferiscono i lati più lunghi (nel caso di 5 lati è quello non spezzato)
|
||||
-- se stessa lunghezza si preferiscono i lati più in basso
|
||||
else
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa lunghezza si preferiscono i lati più in basso
|
||||
-- TODO qui dipenderà dalla lama scelta
|
||||
-- se stessa Z si preferiscono i lati verso il fronte della trave
|
||||
else
|
||||
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 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
|
||||
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
|
||||
@@ -93,7 +113,7 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO modificare funzione e verificare pinzaggio con regioni e area outline
|
||||
local function IsPositionOK( Proc, Part)
|
||||
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
|
||||
@@ -112,31 +132,24 @@ local function IsPositionOK( Proc, Part)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO da sistemare
|
||||
local function GetBottomFaceEdge( Proc, nIndexFace)
|
||||
local function GetLongEdgeToMachine( Face, bHeadType)
|
||||
local Edge = {}
|
||||
|
||||
-- si lavora la bottom longitudinalmente
|
||||
if Proc.nFct == 1 or Proc.Topology.sFamily == 'DoubleBevel' then
|
||||
local BottomEdgesSorted = {}
|
||||
for i = 1, #Proc.MainFaces.BottomFaces[nIndexFace].Edges do
|
||||
table.insert( BottomEdgesSorted, Proc.MainFaces.BottomFaces[nIndexFace].Edges[i])
|
||||
end
|
||||
table.sort( BottomEdgesSorted, CompareEdges)
|
||||
Edge = BottomEdgesSorted[1]
|
||||
-- edge in comune tra le due facce
|
||||
elseif Proc.nFct == 2 then
|
||||
if nIndexFace == 1 then
|
||||
Edge = Proc.MainFaces.BottomFaces[nIndexFace].MainEdges.LongEdges[1]
|
||||
elseif nIndexFace == 2 then
|
||||
Edge = Proc.MainFaces.BottomFaces[nIndexFace].MainEdges.BottomEdge
|
||||
end
|
||||
local EdgesSorted = {}
|
||||
for i = 1, #Face.Edges do
|
||||
table.insert( EdgesSorted, Face.Edges[i])
|
||||
end
|
||||
if bHeadType.bBottom then
|
||||
table.sort( EdgesSorted, CompareEdgesLongestBottom)
|
||||
else
|
||||
if nIndexFace == 1 then
|
||||
Edge = Proc.MainFaces.BottomFaces[nIndexFace].MainEdges.LongEdges[1]
|
||||
elseif nIndexFace == 2 then
|
||||
Edge = Proc.MainFaces.BottomFaces[nIndexFace].MainEdges.BottomEdge
|
||||
end
|
||||
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
|
||||
@@ -148,15 +161,28 @@ local function SortMachiningsBySegment( MachiningA, MachiningB)
|
||||
return false
|
||||
elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then
|
||||
return true
|
||||
-- se segmento uguale, si guarda la priorità
|
||||
else
|
||||
if TOOLS[ MachiningA.nToolIndex].sFamily == 'SAWBLADE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'MORTISE' then
|
||||
return true
|
||||
elseif TOOLS[ MachiningA.nToolIndex].sFamily == 'MORTISE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'SAWBLADE' then
|
||||
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
|
||||
if MachiningA.sEdgeType == 'Side' and MachiningB.sEdgeType ~= 'Side' then
|
||||
return true
|
||||
elseif MachiningB.sEdgeType == 'Side' and MachiningA.sEdgeType ~= 'Side' then
|
||||
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
|
||||
@@ -172,6 +198,7 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machinings = {}
|
||||
Strategy.Result = {}
|
||||
local CalculatedMachinings = {}
|
||||
|
||||
-- controllo su topologia
|
||||
if not IsTopologyOk( Proc) then
|
||||
@@ -181,7 +208,7 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- controllo dimensioni solo se non è forzata
|
||||
if not CustomParameters.bForcedStrategy then
|
||||
if not IsPositionOK( Proc, Part) then
|
||||
if not IsPositionOk( Proc, Part) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Feature not machinable in this position')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
@@ -198,8 +225,6 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- volume della feature
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- TODO taglio su eventuali facce di chiusura
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
@@ -212,45 +237,167 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
-- lavorazione della BottomFace
|
||||
local bAreAllMachiningsAdded = true
|
||||
local Milling = {}
|
||||
local OptionalParametersFaceByMill = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail}
|
||||
local EdgeToMachine = GetBottomFaceEdge( Proc, 1)
|
||||
if EdgeToMachine.bIsOpen then
|
||||
OptionalParametersFaceByMill.dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA
|
||||
end
|
||||
Milling = FaceByMill.Make( Proc, Part, Proc.MainFaces.BottomFaces[1], EdgeToMachine, OptionalParametersFaceByMill)
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Strategy.Machinings, Milling)
|
||||
|
||||
-- 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
|
||||
|
||||
-- si lavora seconda BottomFace
|
||||
if Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2]
|
||||
-- se convesso o concavo maggiore di angolo retto
|
||||
if dAngleBetweenFaces >= -91 then
|
||||
Milling = {}
|
||||
OptionalParametersFaceByMill = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail}
|
||||
EdgeToMachine = GetBottomFaceEdge( Proc, 2)
|
||||
if EdgeToMachine.bIsOpen then
|
||||
OptionalParametersFaceByMill.dDepthToMachine = EdgeToMachine.dElevation + BeamData.CUT_EXTRA
|
||||
-- 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
|
||||
Milling = FaceByMill.Make( Proc, Part, Proc.MainFaces.BottomFaces[2], EdgeToMachine, OptionalParametersFaceByMill)
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Strategy.Machinings, Milling)
|
||||
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
|
||||
|
||||
-- calcolo completamento, serve la lista di lavorazioni che comprende le non applicabili
|
||||
Strategy.Result.dCompletionPercentage = GetStrategyCompletionPercentage( Strategy.Machinings)
|
||||
-- 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)
|
||||
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Strategy.Machinings)
|
||||
-- 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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this lenght as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
|
||||
@@ -74,7 +74,7 @@ local function GetDrillingWithMillStrategy( Proc, Part)
|
||||
HalfMilling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- se entrambi gli utensili lavorano in modo completo fino alla metà del foro, li sostituisco a qeulli trovati in precedenza
|
||||
if HalfMilling.ToolInfo.dResidualDepth < 0 and HalfMilling2.ToolInfo.dResidualDepth < 0 then
|
||||
if HalfMilling.ToolInfo.dResidualDepth and HalfMilling2.ToolInfo.dResidualDepth and HalfMilling.ToolInfo.dResidualDepth < 0 and HalfMilling2.ToolInfo.dResidualDepth < 0 then
|
||||
if Milling.ToolInfo.nToolIndex ~= HalfMilling.ToolInfo.nToolIndex then
|
||||
Milling.ToolInfo.nToolIndex, Milling.ToolInfo.dResidualDepth = HalfMilling.ToolInfo.nToolIndex, HalfMilling.ToolInfo.dResidualDepth
|
||||
end
|
||||
|
||||
@@ -109,7 +109,7 @@ function STR0014.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
for i = 1, #Proc.FeatureInfo.AdditionalGeometries do
|
||||
local AuxId = Proc.id + Proc.FeatureInfo.AdditionalGeometries[i]
|
||||
Strategy.AuxiliaryData.Clones[i+1] = {}
|
||||
Strategy.AuxiliaryData.Clones[i+1].Geometry = EgtSetMachiningGeometry( {{ AuxId, -1}})
|
||||
Strategy.AuxiliaryData.Clones[i+1].Geometry = {{ AuxId, -1}}
|
||||
end
|
||||
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining, Strategy.AuxiliaryData)
|
||||
|
||||
@@ -41,6 +41,11 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- si setta che è taglio di coda
|
||||
Strategy.bIsTailCut = true
|
||||
-- quando si aggiunge la lavorazione, si cambia il nome della feature
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'EndCut')
|
||||
end
|
||||
|
||||
-- separazione solo se esiste grezzo successivo con pezzi o scaricabile
|
||||
Strategy.bSplit = not( Part.bIsLastPart) or Part.dRestLength >= BeamData.dMinRaw
|
||||
@@ -89,9 +94,6 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- se devo applicare le lavorazioni
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'EndCut')
|
||||
|
||||
-- inserimento smussi su spigoli del taglio
|
||||
if Strategy.Parameters.bMakeChamfer then
|
||||
MakeChamfer()
|
||||
|
||||
@@ -7,8 +7,8 @@ STR0004 = Topologia tipo LapJoint. Motosega
|
||||
STR0005 = 1, 2 o 3 facce. Lama con taglio singolo o cubetti. Se richiesto o necessario codolo.
|
||||
STR0006 = Tenone. Lama + fresa
|
||||
STR0007 = Mortasa a coda di rondine e mortasa frontale a coda di rondine
|
||||
STR0008 = Svuotatura tasca
|
||||
STR0009 = !!DEPRECATA!! Sostituita da STR0015. RIUTILIZZABILE!
|
||||
STR0008 = Svuotatura mortasa (raggiata)
|
||||
STR0009 = ScarfJoint
|
||||
STR0010 = Fresatura perpendicolare (tipo cut, longcut)
|
||||
STR0011 = Foratura
|
||||
STR0012 = RidgeLap
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
-- Strategia: FACEBYBLADE
|
||||
-- Descrizione
|
||||
-- Strategia di base per la lavorazione delle facce con lama
|
||||
|
||||
-- carico librerie
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local ANTISPLINTONFACE = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function ANTISPLINTONFACE.Make( Proc, Part, Face, OptionalParameters)
|
||||
local Machinings = {}
|
||||
|
||||
-- parametri opzionali
|
||||
if not OptionalParameters then
|
||||
OptionalParameters = {}
|
||||
end
|
||||
local bIsSplitFeature = OptionalParameters.bIsSplitFeature or false
|
||||
local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000
|
||||
local nInternalSortingPriority = OptionalParameters.nInternalSortingPriority or 1
|
||||
local dResultWeight = OptionalParameters.dResultWeight or 0.15
|
||||
local bMachineAllClosedEdges = OptionalParameters.bMachineAllClosedEdges or false
|
||||
|
||||
local ClosingFacesAgainstGrain = {}
|
||||
for i = 1, #Face.Edges do
|
||||
local CurrentFace = Proc.Faces[Face.Edges[i].idAdjacentFace + 1]
|
||||
if ( not Face.Edges[i].bIsOpen) and ( Face.Edges[i].bIsStartOpen or Face.Edges[i].bIsEndOpen or bMachineAllClosedEdges) then
|
||||
table.insert( ClosingFacesAgainstGrain, CurrentFace)
|
||||
end
|
||||
end
|
||||
for i = 1, #ClosingFacesAgainstGrain do
|
||||
local EdgeToMachine = {}
|
||||
for j = 1, #ClosingFacesAgainstGrain[i].Edges do
|
||||
if ClosingFacesAgainstGrain[i].Edges[j].idAdjacentFace == Face.id then
|
||||
EdgeToMachine = ClosingFacesAgainstGrain[i].Edges[j]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local Cutting = {}
|
||||
local OptionalParametersFaceByBlade = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail}
|
||||
Cutting = FaceByBlade.Make( Proc, Part, ClosingFacesAgainstGrain[i], EdgeToMachine, OptionalParametersFaceByBlade)
|
||||
|
||||
Cutting.nInternalSortingPriority = nInternalSortingPriority
|
||||
Cutting.dResultWeight = dResultWeight
|
||||
table.insert( Machinings, Cutting)
|
||||
end
|
||||
|
||||
return Machinings
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return ANTISPLINTONFACE
|
||||
+240
-124
@@ -14,45 +14,63 @@ local MachiningLib = require( 'MachiningLib')
|
||||
local BeamLib = require('BeamLib')
|
||||
-- strategie di base
|
||||
local FaceByBlade = require('FACEBYBLADE')
|
||||
local FaceByMill = require('FACEBYMILL')
|
||||
local FaceByMill = require( 'FACEBYMILL')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- tabelle per definizione modulo
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdges( EdgeA, EdgeB)
|
||||
-- prima i lati orientati lungo X
|
||||
if abs( EdgeA.vtN:getX()) < abs( EdgeB.vtN:getX()) - 10 * GEO.EPS_SMALL then
|
||||
local function CompareEdgesLongestTop( EdgeA, EdgeB)
|
||||
-- si preferiscono i lati più lunghi
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif abs( EdgeA.vtN:getX()) > abs( EdgeB.vtN:getX()) + 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa X si preferiscono i lati più lunghi (nel caso di 5 lati è quello non spezzato)
|
||||
-- se stessa lunghezza si preferiscono i lati più in basso
|
||||
else
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa lunghezza si preferiscono i lati più in basso
|
||||
-- TODO qui dipenderà dalla lama scelta
|
||||
-- se stessa Z si preferiscono i lati verso il fronte della trave
|
||||
else
|
||||
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 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
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function GetLongEdgeToMachine( Face, bHeadType)
|
||||
local Edge = {}
|
||||
|
||||
local EdgesSorted = {}
|
||||
for i = 1, #Face.Edges do
|
||||
table.insert( EdgesSorted, Face.Edges[i])
|
||||
end
|
||||
table.sort( EdgesSorted, CompareEdgesLongestTop)
|
||||
|
||||
-- se il lato migliore è accessibile si sceglie questo, altrimenti il lato opposto; se entrambi non accessibili (faccia chiusa da due lati) la lavorazione non è applicabile
|
||||
Edge = EdgesSorted[1]
|
||||
local EdgeOpposite = BeamLib.FindEdgeBestOrientedAsDirection( Face.Edges, -Edge.vtN)
|
||||
if not EdgeOpposite.bIsOpen then
|
||||
if Edge.bIsOpen then
|
||||
Edge = EdgeOpposite
|
||||
-- entrambi i lati non accessibili: codolo non applicabile
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
return Edge
|
||||
end
|
||||
|
||||
|
||||
local function SortMachiningsBySegment( MachiningA, MachiningB)
|
||||
if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then
|
||||
return false
|
||||
@@ -118,6 +136,76 @@ local function GetStrategyCompletionPercentage( Machinings)
|
||||
end
|
||||
|
||||
|
||||
local function MakeBottomFace( Proc, Part, BottomFace, EdgeToMachine, Parameters)
|
||||
local Cuttings = {}
|
||||
local Cutting1 = {}
|
||||
local Cutting2 = {}
|
||||
|
||||
-- parametri dal chiamante
|
||||
local bIsSplitFeature = Parameters.bIsSplitFeature
|
||||
local dExtendAfterTail = Parameters.dExtendAfterTail
|
||||
local nToolIndex = Parameters.nToolIndex
|
||||
local dStripWidth = Parameters.dStripWidth
|
||||
local OtherBottomFace = Parameters.OtherBottomFace
|
||||
|
||||
local dDepthToMachine = EdgeToMachine.dElevation / 2 - dStripWidth / 2
|
||||
local OptionalParametersFaceByBlade1 = { dDepthToMachine = dDepthToMachine, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex}
|
||||
local EdgeToMachineOpposite = BeamLib.FindEdgeBestOrientedAsDirection( BottomFace.Edges, -EdgeToMachine.vtN)
|
||||
|
||||
-- primo lato
|
||||
if EdgeToMachineOpposite.bIsOpen then
|
||||
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade1)
|
||||
end
|
||||
Cutting1.nInternalSortingPriority = 2
|
||||
Cutting1.dResultWeight = 0.3
|
||||
|
||||
-- secondo lato
|
||||
local OptionalParametersFaceByBlade2 = BeamLib.TableCopyDeep( OptionalParametersFaceByBlade1)
|
||||
OptionalParametersFaceByBlade2.OppositeToolDirectionMode = 'Enabled'
|
||||
if EdgeToMachine.bIsOpen then
|
||||
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade2)
|
||||
end
|
||||
Cutting2.nInternalSortingPriority = 2
|
||||
Cutting2.dResultWeight = 0.3
|
||||
|
||||
-- se uno dei due lati non è riuscito, si estende il più possibile il lato rimasto
|
||||
if not Cutting1.bIsApplicable and Cutting2.bIsApplicable then
|
||||
|
||||
-- se si lavora il lato in comune con l'altra BottomFace significa ci si deve fermare piú indietro
|
||||
if OtherBottomFace and ( EdgeToMachine.idAdjacentFace == OtherBottomFace.id) then
|
||||
dStripWidth = TOOLS[Cutting2.nToolIndex].dThickness + 2 * dStripWidth
|
||||
end
|
||||
dDepthToMachine = min( TOOLS[Cutting2.nToolIndex].dMaxMaterial, EdgeToMachine.dElevation - dStripWidth)
|
||||
OptionalParametersFaceByBlade2.dDepthToMachine = dDepthToMachine
|
||||
|
||||
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade2)
|
||||
Cutting2.nInternalSortingPriority = 2
|
||||
Cutting2.dResultWeight = 0.3
|
||||
table.insert( Cuttings, Cutting2)
|
||||
|
||||
elseif not Cutting2.bIsApplicable and Cutting1.bIsApplicable then
|
||||
|
||||
-- se si lavora il lato in comune con l'altra BottomFace significa ci si deve fermare piú indietro
|
||||
if OtherBottomFace and ( EdgeToMachine.idAdjacentFace == OtherBottomFace.id) then
|
||||
dStripWidth = TOOLS[Cutting1.nToolIndex].dThickness + 2 * dStripWidth
|
||||
end
|
||||
dDepthToMachine = min( TOOLS[Cutting1.nToolIndex].dMaxMaterial, EdgeToMachine.dElevation - dStripWidth)
|
||||
OptionalParametersFaceByBlade1.dDepthToMachine = dDepthToMachine
|
||||
|
||||
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, EdgeToMachine, OptionalParametersFaceByBlade1)
|
||||
Cutting1.nInternalSortingPriority = 2
|
||||
Cutting1.dResultWeight = 0.3
|
||||
table.insert( Cuttings, Cutting1)
|
||||
|
||||
else
|
||||
table.insert( Cuttings, Cutting1)
|
||||
table.insert( Cuttings, Cutting2)
|
||||
end
|
||||
|
||||
return Cuttings
|
||||
end
|
||||
|
||||
|
||||
function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
-- TODO verificare funzionamento con lama da sotto
|
||||
-- TODO scelta utensile è corretto lasciarla a FaceByBlade?
|
||||
@@ -126,12 +214,11 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
local Result = {}
|
||||
local Machinings = {}
|
||||
local CalculatedMachinings = {}
|
||||
local Cutting1 = {}
|
||||
local Cutting2 = {}
|
||||
|
||||
-- controlli preventivi
|
||||
if Proc.nFct > 3 then
|
||||
error( 'BladeKeepWaste : max 3 faces supported')
|
||||
if Proc.nFct > 3 and ( not Proc.Topology.sFamily == 'DoubleBevel') then
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( 'BladeKeepWaste : max 3 faces supported')
|
||||
return Machinings, Result
|
||||
elseif Proc.nFct == 2 then
|
||||
-- per angolo tra le facce >= 90deg (feature convessa) non applicabile
|
||||
if Proc.AdjacencyMatrix[1][2] > 10 * GEO.EPS_SMALL or Proc.AdjacencyMatrix[1][2] < -91 then
|
||||
@@ -160,12 +247,7 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
end
|
||||
local nToolIndex = OptionalParameters.nToolIndex
|
||||
local dExtendAfterTail = OptionalParameters.dExtendAfterTail or 10000
|
||||
local bFinishWithMill
|
||||
if OptionalParameters.bFinishWithMill == nil then
|
||||
bFinishWithMill = true
|
||||
else
|
||||
bFinishWithMill = OptionalParameters.bFinishWithMill
|
||||
end
|
||||
local bFinishWithMill = ( OptionalParameters.bFinishWithMill ~= false)
|
||||
local dMillingOffsetFromSide = OptionalParameters.dMillingOffsetFromSide or 1
|
||||
local dStripWidth = OptionalParameters.dStripWidth or 5
|
||||
local bForced = OptionalParameters.bForced or false
|
||||
@@ -173,28 +255,26 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
-- volume della feature
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- si trovano le facce da lavorare
|
||||
local BottomFace = {}
|
||||
local LongFaces = {}
|
||||
-- si trovano le facce da lavorare (solo 4 lati esatti)
|
||||
local BottomFace1
|
||||
local BottomFace2
|
||||
if Proc.nFct == 1 then
|
||||
BottomFace = Proc.Faces[1]
|
||||
BottomFace1 = Proc.Faces[1]
|
||||
else
|
||||
if not Proc.MainFaces then
|
||||
Proc.MainFaces = FaceData.GetMainFaces( Proc, Part)
|
||||
end
|
||||
BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
LongFaces = Proc.MainFaces.LongFaces
|
||||
BottomFace1 = Proc.MainFaces.BottomFaces[1]
|
||||
BottomFace2 = Proc.MainFaces.BottomFaces[2]
|
||||
end
|
||||
|
||||
|
||||
-- si trova il lato della faccia di fondo da lavorare
|
||||
local BottomEdgeToMachine = {}
|
||||
local BottomEdgesSorted = {}
|
||||
for i = 1, #BottomFace.Edges do
|
||||
table.insert( BottomEdgesSorted, BottomFace.Edges[i])
|
||||
if #BottomFace1.Edges ~= 4 then
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
return Machinings, Result
|
||||
end
|
||||
local bConvexAngle
|
||||
if BottomFace2 then
|
||||
bConvexAngle = ( Proc.AdjacencyMatrix[BottomFace1.id + 1][BottomFace2.id + 1]) > 0
|
||||
end
|
||||
table.sort( BottomEdgesSorted, CompareEdges)
|
||||
BottomEdgeToMachine = BottomEdgesSorted[1]
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
@@ -203,92 +283,126 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
-- calcolo lavorazioni
|
||||
-- taglio eventuali facce di chiusura o seconda faccia
|
||||
for i = 1, #LongFaces do
|
||||
local Cutting = {}
|
||||
local OptionalParametersFaceByBlade = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex}
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFaces[i], LongFaces[i].MainEdges.BottomEdge, OptionalParametersFaceByBlade)
|
||||
Cutting.nInternalSortingPriority = 1
|
||||
Cutting.dResultWeight = 0.15
|
||||
table.insert( CalculatedMachinings, Cutting)
|
||||
end
|
||||
|
||||
-- taglio con codolo faccia di fondo; si provano solo i lati a cui si può accedere (lato opposto aperto)
|
||||
-- TODO il check del lato opposto aperto andrà messo nella FaceByBlade
|
||||
-- TODO verificare se il calcolo del completamento (aggiunta lavorazioni applicabili/non) é corretto
|
||||
local dDepthToMachine = BottomEdgeToMachine.dElevation / 2 - dStripWidth / 2
|
||||
local OptionalParametersFaceByBlade1 = { dDepthToMachine = dDepthToMachine, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex}
|
||||
local BottomEdgeToMachineOpposite = BeamLib.FindEdgeBestOrientedAsDirection( BottomFace.Edges, -BottomEdgeToMachine.vtN)
|
||||
-- primo lato
|
||||
if BottomEdgeToMachineOpposite.bIsOpen then
|
||||
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade1)
|
||||
-- calcolo lavorazioni faccia principale
|
||||
-- ricerca lato da lavorare
|
||||
local BottomEdgeToMachine1 = GetLongEdgeToMachine( BottomFace1, { bTop = true})
|
||||
if not BottomEdgeToMachine1 then
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
return Machinings, Result
|
||||
end
|
||||
Cutting1.nInternalSortingPriority = 3
|
||||
Cutting1.dResultWeight = 0.3
|
||||
|
||||
-- secondo lato
|
||||
local OptionalParametersFaceByBlade2 = BeamLib.TableCopyDeep( OptionalParametersFaceByBlade1)
|
||||
OptionalParametersFaceByBlade2.OppositeToolDirectionMode = 'Enabled'
|
||||
if BottomEdgeToMachine.bIsOpen then
|
||||
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade2)
|
||||
-- calcolo lavorazione
|
||||
local Parameters1 = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
nToolIndex = nToolIndex,
|
||||
dStripWidth = dStripWidth,
|
||||
OtherBottomFace = BottomFace2
|
||||
}
|
||||
local Cuttings1 = MakeBottomFace( Proc, Part, BottomFace1, BottomEdgeToMachine1, Parameters1)
|
||||
-- aggiunta lavorazioni alla lista principale
|
||||
for i = 1, #Cuttings1 do
|
||||
table.insert( CalculatedMachinings, Cuttings1[i])
|
||||
end
|
||||
Cutting2.nInternalSortingPriority = 3
|
||||
Cutting2.dResultWeight = 0.3
|
||||
|
||||
-- se uno dei due lati non è riuscito, si estende il più possibile il lato rimasto
|
||||
if not Cutting1.bIsApplicable and Cutting2.bIsApplicable then
|
||||
|
||||
-- se si lavora il lato in comune con la LongFace significa che la LongFace non é di chiusura ma un'altra faccia vera e propria
|
||||
-- ci si deve quindi fermare piú indietro
|
||||
for i = 1, #LongFaces do
|
||||
if BottomEdgeToMachine.idAdjacentFace == LongFaces[i].id then
|
||||
dStripWidth = TOOLS[Cutting2.nToolIndex].dThickness + 2 * dStripWidth
|
||||
break
|
||||
-- calcolo lavorazioni faccia secondaria, solo se lato convesso; se concavo, sarà lavorato come antisplint
|
||||
local Cuttings2
|
||||
local BottomEdgeToMachine2
|
||||
if BottomFace2 then
|
||||
if bConvexAngle then
|
||||
-- ricerca lato da lavorare
|
||||
BottomEdgeToMachine2 = GetLongEdgeToMachine( BottomFace2, { bTop = true})
|
||||
if BottomEdgeToMachine2 then
|
||||
-- calcolo lavorazione
|
||||
local Parameters2 = BeamLib.TableCopyDeep( Parameters1)
|
||||
Parameters2.OtherBottomFace = BottomFace1
|
||||
Cuttings2 = MakeBottomFace( Proc, Part, BottomFace2, BottomEdgeToMachine2, Parameters2)
|
||||
for i = 1, #Cuttings2 do
|
||||
table.insert( CalculatedMachinings, Cuttings2[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
dDepthToMachine = min( TOOLS[Cutting2.nToolIndex].dMaxMaterial, BottomEdgeToMachine.dElevation - dStripWidth)
|
||||
OptionalParametersFaceByBlade2.dDepthToMachine = dDepthToMachine
|
||||
|
||||
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade2)
|
||||
Cutting2.nInternalSortingPriority = 3
|
||||
Cutting2.dResultWeight = 0.3
|
||||
table.insert( CalculatedMachinings, Cutting2)
|
||||
|
||||
elseif not Cutting2.bIsApplicable and Cutting1.bIsApplicable then
|
||||
|
||||
-- se si lavora il lato in comune con la LongFace significa che la LongFace non é di chiusura ma un'altra faccia vera e propria
|
||||
-- ci si deve quindi fermare piú indietro
|
||||
for i = 1, #LongFaces do
|
||||
if BottomEdgeToMachine.idAdjacentFace == LongFaces[i].id then
|
||||
dStripWidth = TOOLS[Cutting1.nToolIndex].dThickness + 2 * dStripWidth
|
||||
break
|
||||
end
|
||||
end
|
||||
dDepthToMachine = min( TOOLS[Cutting1.nToolIndex].dMaxMaterial, BottomEdgeToMachine.dElevation - dStripWidth)
|
||||
OptionalParametersFaceByBlade1.dDepthToMachine = dDepthToMachine
|
||||
|
||||
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade1)
|
||||
Cutting1.nInternalSortingPriority = 3
|
||||
Cutting1.dResultWeight = 0.3
|
||||
table.insert( CalculatedMachinings, Cutting1)
|
||||
|
||||
else
|
||||
table.insert( CalculatedMachinings, Cutting1)
|
||||
table.insert( CalculatedMachinings, Cutting2)
|
||||
end
|
||||
|
||||
-- fresatura eventuali facce di chiusura
|
||||
-- antischeggia sulle facce di chiusura delle facce lavorate
|
||||
local OptionalParametersAntiSplint = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
nInternalSortingPriority = 1,
|
||||
dResultWeight = 0.15,
|
||||
bMachineAllClosedEdges = true
|
||||
}
|
||||
local AntiSplints1 = AntiSplintOnFace.Make( Proc, Part, BottomFace1, OptionalParametersAntiSplint)
|
||||
for i = 1, #AntiSplints1 do
|
||||
table.insert( CalculatedMachinings, AntiSplints1[i])
|
||||
end
|
||||
if BottomFace2 and bConvexAngle then
|
||||
OptionalParametersAntiSplint.bMachineAllClosedEdges = false
|
||||
local AntiSplints2 = AntiSplintOnFace.Make( Proc, Part, BottomFace2, OptionalParametersAntiSplint)
|
||||
for i = 1, #AntiSplints2 do
|
||||
table.insert( CalculatedMachinings, AntiSplints2[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- pulitura con fresa dei lati chiusi non lavorati
|
||||
-- TODO funzione
|
||||
if bFinishWithMill then
|
||||
for i = 1, #LongFaces do
|
||||
if BottomEdgeToMachine.idAdjacentFace ~= LongFaces[i].id then
|
||||
local dDepthToMachineMill = BottomFace.MainEdges.LongEdges[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = max( Cutting1.dToolMarkLength or 0, Cutting2.dToolMarkLength or 0)
|
||||
local OptionalParametersFaceByMill = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail,
|
||||
dRadialStepSpan = dToolMarkLength, dDepthToMachine = dDepthToMachineMill
|
||||
}
|
||||
local Milling = FaceByMill.Make( Proc, Part, BottomFace, BottomFace.MainEdges.LongEdges[i], OptionalParametersFaceByMill)
|
||||
Milling.nInternalSortingPriority = 2
|
||||
|
||||
if Cuttings1 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 dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = 0
|
||||
-- si prende l'impronta dell'utensile più grande
|
||||
for j = 1, #Cuttings1 do
|
||||
if Cuttings1[j].dToolMarkLength > dToolMarkLength + 10 * GEO.EPS_SMALL then
|
||||
dToolMarkLength = Cuttings1[j].dToolMarkLength
|
||||
end
|
||||
end
|
||||
local OptionalParametersMilling = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dRadialStepSpan = dToolMarkLength,
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local Milling = FaceByMill.Make( Proc, Part, BottomFace1, EdgesClosedNotMachined[i], OptionalParametersMilling)
|
||||
Milling.nInternalSortingPriority = 3
|
||||
Milling.dResultWeight = 0.05
|
||||
table.insert( CalculatedMachinings, Milling)
|
||||
end
|
||||
end
|
||||
if Cuttings2 and BottomEdgeToMachine2 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 dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = 0
|
||||
-- si prende l'impronta dell'utensile più grande
|
||||
for j = 1, #Cuttings2 do
|
||||
if Cuttings2[j].dToolMarkLength > dToolMarkLength + 10 * GEO.EPS_SMALL then
|
||||
dToolMarkLength = Cuttings2[j].dToolMarkLength
|
||||
end
|
||||
end
|
||||
local OptionalParametersMilling = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dRadialStepSpan = dToolMarkLength,
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local Milling = FaceByMill.Make( Proc, Part, BottomFace2, EdgesClosedNotMachined[i], OptionalParametersMilling)
|
||||
Milling.nInternalSortingPriority = 3
|
||||
Milling.dResultWeight = 0.05
|
||||
table.insert( CalculatedMachinings, Milling)
|
||||
end
|
||||
@@ -317,7 +431,9 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
table.sort( Machinings, SortMachiningsBySegment)
|
||||
|
||||
-- calcolo risultati
|
||||
if Cutting1.bIsApplicable or Cutting2.bIsApplicable then
|
||||
if ( Cuttings1 and ( ( Cuttings1[1] and Cuttings1[1].bIsApplicable) or ( Cuttings1[2] and Cuttings1[2].bIsApplicable)))
|
||||
or ( Cuttings2 and ( ( Cuttings2[1] and Cuttings2[1].bIsApplicable) or ( Cuttings2[2] and Cuttings2[2].bIsApplicable))) then
|
||||
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( Machinings)
|
||||
Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Machinings)
|
||||
Result.dMRR = ( dFeatureVolume / Result.dTimeToMachine) / pow( 10, 6)
|
||||
|
||||
@@ -795,19 +795,23 @@ local function CalculateDiceMachinings( vCuts, Parameters)
|
||||
local bReduceBladePath = Parameters.bReduceBladePath
|
||||
local sRestLengthSideForPreSimulation = Parameters.sRestLengthSideForPreSimulation
|
||||
local bCannotSplitRestLength = Parameters.bCannotSplitRestLength
|
||||
local bReduceDiceDepth = Parameters.bReduceDiceDepth
|
||||
|
||||
-- eventuale inversione tagli ortogonali e aggiunta informazioni alla geometria
|
||||
local bAreOrthogonalCutsInverted = false
|
||||
for i = 1, #vCuts do
|
||||
for j = 1, #vCuts[i] do
|
||||
SetDiceFaceInfo( Proc, vCuts[i][j])
|
||||
if ( i % 2) == 1 then
|
||||
local vtO = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
||||
if MachiningLib.IsFaceZOutOfRange( vtO, Tool) then
|
||||
EgtInvertSurf( vCuts[i][j])
|
||||
bAreOrthogonalCutsInverted = true
|
||||
end
|
||||
end
|
||||
-- TODO vedere se questa parte serve ancora; in teoria no perchè il taglio è girato automaticamente nella FaceByBlade
|
||||
-- if ( i % 2) == 1 then
|
||||
-- local vtO = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
||||
-- if MachiningLib.IsFaceZOutOfRange( vtO, Tool) then
|
||||
-- EgtInvertSurf( vCuts[i][j])
|
||||
-- local vtCurrentFaceNormal = EgtSurfTmFacetNormVersor( vCuts[i][j], 0, GDB_ID.ROOT)
|
||||
-- EgtMove( vCuts[i][j], -vtCurrentFaceNormal * Tool.dThickness, GDB_RT.GLOB)
|
||||
-- bAreOrthogonalCutsInverted = true
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
end
|
||||
-- calcolo lavorazioni
|
||||
@@ -881,8 +885,13 @@ local function CalculateDiceMachinings( vCuts, Parameters)
|
||||
-- caso standard (tagli perpendicolari o paralleli non accorpabili)
|
||||
if ( not bCanMergeParallelCuts) or ( not bIsDicingOk) then
|
||||
for j = 1, #vCuts[i] do
|
||||
-- in generale sta sollevato di pochissimo
|
||||
local dExtraCut = -0.1
|
||||
-- se abilitato, la lama sta sollevata per non rovinare le facce
|
||||
local dExtraCut
|
||||
if bReduceDiceDepth == false then
|
||||
dExtraCut = 0
|
||||
else
|
||||
dExtraCut = -0.1
|
||||
end
|
||||
-- se tagli paralleli
|
||||
if ( i % 2) == 0 then
|
||||
-- se non ci sono tagli ortogonali devo affondare
|
||||
@@ -911,7 +920,8 @@ local function CalculateDiceMachinings( vCuts, Parameters)
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bIsDicing = true,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = ( i % 2) > 0 -- se taglio perpendicolare non si deve mai considerare il materiale precedente
|
||||
}
|
||||
Cutting = FaceByBlade.Make( ProcTrimesh, Part, FaceToMachine, EdgeToMachine, OptionalParametersFaceByBlade)
|
||||
Cutting.ptCenter = Point3d( ProcTrimesh.Faces[1].ptCenter:getX(), 0, 0)
|
||||
@@ -961,6 +971,9 @@ local function CutWithDicing( Proc, Part, OptionalParameters)
|
||||
end
|
||||
end
|
||||
|
||||
-- angolo tra le facce, se più di una
|
||||
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2] or 0
|
||||
|
||||
-- scelta lama da sopra o da sotto
|
||||
local sChosenBladeType = ''
|
||||
if not nToolIndex then
|
||||
@@ -1005,7 +1018,8 @@ local function CutWithDicing( Proc, Part, OptionalParameters)
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bReduceBladePath = bReduceBladePath,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bReduceDiceDepth = ( dAngleBetweenFaces < - 10) -- per facce molto aperte non si riduce l'affondamento della lama nei cubetti (rischio che non si stacchino)
|
||||
}
|
||||
|
||||
bIsDicingOk, Machinings, bMoveAfterSplit = CalculateDiceMachinings( vCuts, Parameters)
|
||||
@@ -1215,14 +1229,21 @@ function BLADETOWASTE.Make( ProcOrId, Part, OptionalParameters)
|
||||
else
|
||||
-- per ogni faccia si calcola la lavorazione
|
||||
for i = 1, #Proc.Faces do
|
||||
-- ricerca lato in comune da lavorare
|
||||
-- ricerca lato in comune da lavorare; se non trovato è una feature splittata (DoubleBevel) e il lato sarà scelto della GetSingleCutStratetegy
|
||||
local nCommonEdgeIndex
|
||||
for j = 1, #Proc.Faces[i].Edges do
|
||||
if Proc.Faces[i].Edges[j].idAdjacentFace > -1 then
|
||||
nCommonEdgeIndex = j
|
||||
end
|
||||
end
|
||||
local EdgeToMachine = Proc.Faces[i].Edges[nCommonEdgeIndex]
|
||||
local EdgeToMachine
|
||||
if nCommonEdgeIndex then
|
||||
EdgeToMachine = Proc.Faces[i].Edges[nCommonEdgeIndex]
|
||||
end
|
||||
local EdgeToMachineList
|
||||
if EdgeToMachine then
|
||||
EdgeToMachineList = { Top = EdgeToMachine, Bottom = EdgeToMachine}
|
||||
end
|
||||
|
||||
-- scelta lama
|
||||
local nToolIndex = OptionalParameters.nToolIndex
|
||||
@@ -1230,11 +1251,11 @@ function BLADETOWASTE.Make( ProcOrId, Part, OptionalParameters)
|
||||
local OptionalParametersGetSingleCutStrategy = {
|
||||
bReduceBladePath = false,
|
||||
nFaceToMachineIndex = i,
|
||||
EdgeToMachineList = { Top = EdgeToMachine, Bottom = EdgeToMachine},
|
||||
EdgeToMachineList = EdgeToMachineList,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
}
|
||||
nToolIndex = GetSingleCutStrategy( Proc, Part, OptionalParametersGetSingleCutStrategy)
|
||||
nToolIndex, EdgeToMachine = GetSingleCutStrategy( Proc, Part, OptionalParametersGetSingleCutStrategy)
|
||||
end
|
||||
|
||||
-- se lama non trovata si provano i cubetti
|
||||
|
||||
@@ -72,6 +72,12 @@ local function GetLeadInOut( Machining, EdgeToMachine, bIsSplitFeature)
|
||||
LeadOut.dTotalLength = sqrt( LeadOut.dPerpDistance ^ 2 + LeadOut.dTangentDistance ^ 2)
|
||||
end
|
||||
|
||||
-- se accorciamenti maggiori della lunghezza lato, la lavorazione non è fattibile
|
||||
if LeadIn.dStartAddLength + LeadOut.dEndAddLength + EdgeToMachine.dLength < 1 then
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- se lavorazione con OppositeToolDirection o ridotta l'attacco va corretto
|
||||
if not AreSameVectorApprox( Machining.vtToolDirection, EdgeToMachine.vtN) then
|
||||
LeadIn.dPerpDistance = BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
@@ -205,6 +211,7 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
local bIsDicing = OptionalParameters.bIsDicing or false
|
||||
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
local bDisableRealElevationCheck = OptionalParameters.bDisableRealElevationCheck or false
|
||||
|
||||
-- lunghezze, direzioni e punti caratteristici della lavorazione e del lato lavorato
|
||||
Cutting.dEdgeLength = EdgeToMachine.dLength
|
||||
@@ -225,10 +232,14 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
Tool = TOOLS[Cutting.nToolIndex],
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
BladeEngagementParameters.Edge = EdgeToMachineOpposite
|
||||
end
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
local Engagement
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
@@ -252,6 +263,7 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
ToolSearchParameters.Part = Part
|
||||
ToolSearchParameters.sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation
|
||||
ToolSearchParameters.bCannotSplitRestLength = bCannotSplitRestLength
|
||||
ToolSearchParameters.bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
|
||||
local ToolInfo = MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
Cutting.nToolIndex = ToolInfo.nToolIndex
|
||||
@@ -285,16 +297,18 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
|
||||
return Cutting, EdgeToMachine.dElevation
|
||||
end
|
||||
|
||||
-- TODO vedere se la rimozione di questo crea problemi
|
||||
-- se tasca chiusa da entrambi i lati e più stretta della lama la lavorazione non è applicabile
|
||||
if not ( EdgeToMachine.bIsStartOpen or EdgeToMachine.bIsEndOpen) then
|
||||
if TOOLS[Cutting.nToolIndex].dDiameter > EdgeToMachine.dLength + 10 * GEO.EPS_SMALL then
|
||||
Cutting.sMessage = 'Pocket too narrow for blade diameter'
|
||||
Cutting.bIsApplicable = false
|
||||
EgtOutLog( Cutting.sMessage)
|
||||
-- if not ( EdgeToMachine.bIsStartOpen or EdgeToMachine.bIsEndOpen) then
|
||||
-- if TOOLS[Cutting.nToolIndex].dDiameter > EdgeToMachine.dLength + 10 * GEO.EPS_SMALL then
|
||||
-- Cutting.sMessage = 'Pocket too narrow for blade diameter'
|
||||
-- Cutting.bIsApplicable = false
|
||||
-- EgtOutLog( Cutting.sMessage)
|
||||
|
||||
return Cutting, EdgeToMachine.dElevation
|
||||
end
|
||||
end
|
||||
-- return Cutting, EdgeToMachine.dElevation
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- parametri della lavorazione
|
||||
|
||||
@@ -320,7 +334,6 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
end
|
||||
|
||||
-- TODO al momento commentato per trovare i casi in cui nei riposizionamenti scende sul pezzo; poi valutare se lasciare o togliere
|
||||
-- se dicing, lato di lavoro e inversione per avere taglio sempre verso l'alto
|
||||
if bIsDicing
|
||||
and ( Cutting.bInvert and Cutting.vtEdgeDirection:getZ() > 100 * GEO.EPS_SMALL)
|
||||
@@ -348,7 +361,8 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
local bIsApplicableOpposite, EngagementOpposite = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
||||
@@ -465,7 +479,8 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
local bIsApplicable, CurrentEngagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters )
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local FACEBYCHAINSAW = {}
|
||||
@@ -42,6 +43,10 @@ local function CalculateLeadInOut( Machining, EdgeToMachine, sSideToMachine, dLe
|
||||
LeadOut.dEndAddLength = BeamData.CUT_EXTRA
|
||||
end
|
||||
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = EdgeToMachine.ptStart - EdgeToMachine.vtEdge * LeadIn.dStartAddLength + EdgeToMachine.vtN * ( EdgeToMachine.dElevation - Machining.dDepthToMachine)
|
||||
LeadOut.ptPoint = EdgeToMachine.ptEnd + EdgeToMachine.vtEdge * LeadOut.dEndAddLength + EdgeToMachine.vtN * ( EdgeToMachine.dElevation - Machining.dDepthToMachine)
|
||||
|
||||
return LeadIn, LeadOut
|
||||
end
|
||||
|
||||
@@ -196,9 +201,28 @@ function FACEBYCHAINSAW.Make( Proc, Part, FaceToMachine, EdgeToMachine, Optional
|
||||
elseif EdgeToMachine.vtN:getZ() < 10 * GEO.EPS_SMALL then
|
||||
Mortising.sBlockedAxis = BeamLib.GetBlockedAxis( Mortising.nToolIndex, 'parallel', Part.b3Raw, FaceToMachine.vtN)
|
||||
Mortising.sSuggestedAngles = BeamLib.GetChainSawInitAngs( FaceToMachine.vtN, EdgeToMachine.vtN, 2)
|
||||
-- TODO al momento si contempla solo sega a catena con asse bloccato
|
||||
else
|
||||
Mortising.bIsApplicable = false
|
||||
return Mortising
|
||||
end
|
||||
-- approccio e retrazione
|
||||
Mortising.LeadIn, Mortising.LeadOut = CalculateLeadInOut( Mortising, EdgeToMachine, sSideToMachine, dLengthToMachine)
|
||||
-- check finecorsa nei punti di attacco
|
||||
local PointsOnToolTipCenter = {
|
||||
Mortising.LeadIn.ptPoint,
|
||||
Mortising.LeadOut.ptPoint
|
||||
}
|
||||
local vtAux = FaceToMachine.vtN
|
||||
if Mortising.bToolInvert then
|
||||
vtAux = -FaceToMachine.vtN
|
||||
end
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, Mortising.vtToolDirection, Mortising.nSCC, TOOLS[Mortising.nToolIndex], vtAux, Mortising.sBlockedAxis)
|
||||
if bOutOfStroke then
|
||||
Mortising.sMessage = 'Out of stroke'
|
||||
Mortising.bIsApplicable = false
|
||||
return Mortising
|
||||
end
|
||||
-- eventuale step verticale
|
||||
Mortising.CloneStepsLongitudinal = {}
|
||||
if not dLongitudinalStepSpan then
|
||||
@@ -211,7 +235,7 @@ function FACEBYCHAINSAW.Make( Proc, Part, FaceToMachine, EdgeToMachine, Optional
|
||||
Mortising.CloneStepsLongitudinal.dStep = dPocketHeight
|
||||
end
|
||||
-- lunghezza lavorata
|
||||
-- TODO per il calcolo della dLenghtOnX ripetere il calcolo del FACEBYBLADE con proiezione del lato; serve prolungare con la Add Length secondo la vtEdgeDirection
|
||||
-- TODO per il calcolo della dlengthOnX ripetere il calcolo del FACEBYBLADE con proiezione del lato; serve prolungare con la Add Length secondo la vtEdgeDirection
|
||||
-- TODO fare funzione EstimatePathLength o simile
|
||||
Mortising.dLengthToMachine = Mortising.dEdgeLength + Mortising.LeadIn.dStartAddLength + Mortising.LeadOut.dEndAddLength
|
||||
Mortising.dLengthOnX = abs( dLengthToMachine * EdgeToMachine.vtN:getY())
|
||||
|
||||
Reference in New Issue
Block a user