Compare commits
270 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 | |||
| a54fbb1259 | |||
| 1345c5a5cb | |||
| 9add357cb6 | |||
| b1ae9db859 | |||
| 57d555fb0b | |||
| 28a6049c77 | |||
| c8848974a4 | |||
| 6591396009 | |||
| b0531f8df8 | |||
| 67a595e311 | |||
| 7a84f2c396 | |||
| 19f62cdc90 | |||
| 0f20358607 | |||
| 8875fc4c68 | |||
| ee4d443074 | |||
| 995917672c | |||
| d5b9612406 | |||
| 4521910c56 | |||
| 267fc9daa3 | |||
| c997cb4440 | |||
| b98b03adba | |||
| f2f57be09f | |||
| efe7f2e0f9 | |||
| 8f04694232 | |||
| c14377fb67 | |||
| c491d635e7 | |||
| 18fe9ceccb | |||
| 86c36512a0 | |||
| 4bdb1b32b1 | |||
| 0a073ead4c | |||
| 76c8f45284 | |||
| 5c463298da | |||
| 7b16ace7a4 | |||
| 66159b25a8 | |||
| 518ad5e10a | |||
| fc7432a97a | |||
| 583aa789c4 | |||
| 92036b09b4 | |||
| 6d2a1664ce | |||
| 5934b07947 | |||
| 85147dc34a | |||
| 465ffc7e37 | |||
| 31f1f50d04 | |||
| 7867317982 | |||
| ab9ea95b45 | |||
| c52a3f4af6 | |||
| 598d717dbc | |||
| ab606d759e | |||
| a6d9a36dab | |||
| 8c573d25b2 | |||
| 5554977011 | |||
| d3a9284944 | |||
| 90f06cb7ec | |||
| 8897f3f00b | |||
| 1e4e75115c | |||
| d3bf465923 | |||
| 9f6a89d5ae | |||
| 6f730dcaec | |||
| f1cdaa498d | |||
| 217a359ba0 | |||
| da23b96a9c | |||
| fe358e3ca4 | |||
| 6a7f32b5c1 | |||
| 9b9758fd2c | |||
| 667da4e3d1 | |||
| fe309e338b | |||
| 340a249948 | |||
| 0f5a1215f9 | |||
| 5d461bbc39 | |||
| 4986d3bf67 | |||
| d5243cda37 | |||
| e1e46445b0 | |||
| 570e41a40d | |||
| f3938ee0b6 | |||
| 309bae0265 | |||
| c068479ec1 | |||
| 608a9c63c8 | |||
| 38d432fd79 | |||
| 3b65f6233d | |||
| f1805625d3 | |||
| 568de09954 | |||
| 70025d1816 | |||
| fb74d28926 | |||
| 73acee6695 | |||
| c3a82a0804 | |||
| 6d1cae6ff3 | |||
| 2bcaeca91f | |||
| 3136604e14 | |||
| 82cd8f5d8c | |||
| e9493ead6b | |||
| e9417ba322 | |||
| 79417998a2 | |||
| c290254bae | |||
| 604a2676ce | |||
| 827a709af0 | |||
| 05f729df45 | |||
| 646e69e3af | |||
| ef155ad1fb | |||
| 6609c7ee16 | |||
| 5068d75362 | |||
| e646351f3f | |||
| 660cca04ca | |||
| 5d15189d59 | |||
| 50dee06493 | |||
| 3d3ae22f87 | |||
| 21b2e1cd0a | |||
| 7bd18a8fb4 | |||
| 1c4970fdb6 | |||
| 77d6d89e13 | |||
| eb3cf0d7ff | |||
| 5ad9e0bf4f | |||
| c3ea568d99 | |||
| 30f59b0175 | |||
| c18e80a70d | |||
| ae30cb5736 | |||
| cd586673c7 | |||
| f426311b28 | |||
| e2a2d0fd4e | |||
| 69c31e4c2b | |||
| 56ca5a74b9 | |||
| ad1ea741d0 | |||
| 322412a1f3 | |||
| c1a563351a | |||
| 327a5a960d | |||
| fdfefaba74 | |||
| c76eba6e74 | |||
| c6b3b5a003 | |||
| a4fbfcf2c9 | |||
| fa1a12b41c | |||
| d162b27493 | |||
| 68da716da1 | |||
| d6900a2c59 | |||
| 4bbadb8581 | |||
| cb60773216 | |||
| 1e327819c6 | |||
| d5b4edea14 | |||
| 530dce3d0d | |||
| dc8c5e8ba2 | |||
| a2ed6f5789 | |||
| 198fa3a546 | |||
| 1ad5a74a8b | |||
| a8c6424839 | |||
| 9ed315ab9b | |||
| 1c8049d9a9 | |||
| 155fd09ee5 | |||
| 86adb74131 | |||
| 74a12a4a42 | |||
| 06a73a069f | |||
| e6a2ce3702 | |||
| e3cd0d3033 | |||
| eb0a46d545 | |||
| f9b1a957f6 | |||
| 8f2a09e5c7 | |||
| 711ac3930d | |||
| 4ce77a4792 | |||
| 15db75dfad | |||
| 6d319d17b6 | |||
| d8a3f257d8 | |||
| 43b096f531 | |||
| d9d505fc44 | |||
| ddff655240 | |||
| 2536244f1b | |||
| 7b4673acef | |||
| 2d1abbb3cc | |||
| 25dbaed63b | |||
| ecd2147e83 | |||
| 84cd799565 | |||
| 9468e3d013 | |||
| e095806a7a | |||
| f21e1ea557 | |||
| 21bb95c0e9 | |||
| b8b71ff73a | |||
| 0afcd786d1 | |||
| 070ad50d73 | |||
| d6bdbab510 | |||
| 44273e15a7 | |||
| 711e0c82f7 | |||
| c62f1818c7 | |||
| 9fe22368cb |
+125
-29
@@ -32,7 +32,7 @@ if not sMachDir then
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
BEAM.ERR = 12
|
||||
BEAM.MSG = 'Error not configured for beams machine : ' .. sMachine
|
||||
@@ -58,11 +58,15 @@ _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.BeamData = nil
|
||||
_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.
|
||||
@@ -88,7 +92,7 @@ end
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
@@ -178,6 +182,13 @@ local function WriteResultToJson( RESULT)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- calcolo tempo esecuzione
|
||||
TIMER:start()
|
||||
EgtOutLog( ' Execution timer started')
|
||||
|
||||
-- script principale
|
||||
|
||||
local sFlag = ''
|
||||
if BEAM.FLAG == 0 then
|
||||
sFlag = 'GENERATE'
|
||||
@@ -200,12 +211,9 @@ elseif BEAM.FLAG == 10 then
|
||||
else
|
||||
sFlag = 'FLAG='..tostring( BEAM.FLAG)
|
||||
end
|
||||
local sLog = 'BatchProcess : ' .. BEAM.FILE .. ', ' .. BEAM.MACHINE .. ', ' .. sFlag
|
||||
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)
|
||||
@@ -235,11 +243,14 @@ elseif BEAM.FLAG == 9 then
|
||||
|
||||
local Part = {}
|
||||
Part.id = EgtGetParent( EgtGetParent( BEAM.FEATUREID))
|
||||
Part.b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Part.id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
Part.idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( Part.id, 'Box') or GDB_ID.NULL)
|
||||
Part.b3Part = EgtGetBBoxGlob( Part.idBoxTm, GDB_BB.STANDARD)
|
||||
Part.idTempGroup = idTempGroup
|
||||
|
||||
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
|
||||
@@ -299,6 +310,9 @@ if bToProcess then
|
||||
BEAM.MSG = 'Error opening BWE file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
-- Faccio copia del file originale
|
||||
@@ -319,6 +333,9 @@ if bToProcess then
|
||||
BEAM.MSG = 'Error no Raw Parts in the file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
local b3Raw = EgtGetRawPartBBox( nRawId)
|
||||
@@ -343,6 +360,9 @@ if bToProcess then
|
||||
BEAM.MSG = 'Error no beams in the file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
local sOut = ''
|
||||
@@ -361,6 +381,9 @@ if bToProcess then
|
||||
BEAM.MSG = 'Box undefined for beam ' .. PARTS[i].sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
PARTS[i].b3PartOriginal = b3Solid
|
||||
@@ -397,6 +420,9 @@ if bToProcess then
|
||||
BEAM.ERR = 14
|
||||
BEAM.MSG = 'Error : no beams in the project'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
local sOut = ''
|
||||
@@ -414,6 +440,9 @@ if bToProcess then
|
||||
BEAM.ERR = 15
|
||||
BEAM.MSG = 'Box undefined for beam ' .. PARTS[i].sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
PARTS[i].b3PartOriginal = b3Solid
|
||||
@@ -424,6 +453,9 @@ if bToProcess then
|
||||
-- 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
|
||||
local idTempGroup = BeamLib.CreateTempGroup()
|
||||
|
||||
-- Se devo creare la barra
|
||||
if bCreateBar then
|
||||
if #PARTS == 0 then
|
||||
@@ -460,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
|
||||
@@ -470,6 +503,9 @@ if bToProcess then
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
else
|
||||
@@ -483,6 +519,9 @@ if bToProcess then
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -496,6 +535,9 @@ if bToProcess then
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -508,12 +550,15 @@ 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
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
-- Scrivo altezza e larghezza barra nel gruppo di lavoro corrente
|
||||
@@ -573,7 +618,8 @@ if bToProcess then
|
||||
PARTS[i].dRawWidth = PARTS[i].b3Raw:getDimY()
|
||||
PARTS[i].dRawHeight = PARTS[i].b3Raw:getDimZ()
|
||||
-- dimensione pezzo finito
|
||||
PARTS[i].b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( PARTS[i].id, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
PARTS[i].idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PARTS[i].id, 'Box') or GDB_ID.NULL)
|
||||
PARTS[i].b3Part = EgtGetBBoxGlob( PARTS[i].idBoxTm, GDB_BB.STANDARD)
|
||||
PARTS[i].dLength = PARTS[i].b3Part:getDimX()
|
||||
PARTS[i].dWidth = PARTS[i].b3Part:getDimY()
|
||||
PARTS[i].dHeight = PARTS[i].b3Part:getDimZ()
|
||||
@@ -582,15 +628,19 @@ if bToProcess then
|
||||
PARTS[i].SplittingPoints = BeamLib.GetPartSplittingPoints( PARTS[i])
|
||||
PARTS[i].NotClampableLength = { STD = { dHead = 0, dTail = 0}, SIDE = { dHead = 0, dTail = 0}, DOWN = { dHead = 0, dTail = 0}}
|
||||
PARTS[i].sBTLInfo = EgtGetInfo( PARTS[i].id, 'PROJ', 's') or nil
|
||||
PARTS[i].idTempGroup = idTempGroup
|
||||
|
||||
PARTS[i].sAISetupConfig = EgtGetInfo( PARTS[i].id, 'AISETUP', 's') or
|
||||
( GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo] and GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo].sAISetupConfig) or -- i parametri BTL potrebbero non esistere
|
||||
GENERAL_PARAMETERS.PROJECT.sAISetupConfig or nil
|
||||
|
||||
-- si carica configurazione lavorazioni
|
||||
TIMER:startElapsed('Json')
|
||||
BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig)
|
||||
PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON)
|
||||
PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], bCalcBestPieceUnloadPosition)
|
||||
TIMER:stopElapsed('Json')
|
||||
-- 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)
|
||||
@@ -621,6 +671,9 @@ if bToProcess then
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
end
|
||||
EgtOutLog( ' +++ BatchProcess completed')
|
||||
return
|
||||
@@ -637,23 +690,15 @@ if bToProcess then
|
||||
EgtImportSetup()
|
||||
|
||||
-- Lavoro le features
|
||||
-- TODO gestire errori e messaggi di ritorno in questo caso
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
BeamLib.CreateTempGroup()
|
||||
|
||||
BeamExec.GetProcessings( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.GetCombinationMatrix( PARTS, bCalcBestPieceUnloadPosition)
|
||||
BeamExec.ProcessMachinings( PARTS)
|
||||
|
||||
-- si cancella gruppo temporaneo contenente entità da cancellare
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
EgtErase( idTempGroup)
|
||||
BeamExec.GetProcessings( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.GetCombinationMatrix( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.ProcessMachinings( PARTS, BEAM.FLAG == 10)
|
||||
|
||||
local sOutput = ''
|
||||
|
||||
-- Scrittura json risultati
|
||||
WriteResultToJson( RESULT)
|
||||
-- scrittura txt risultati
|
||||
for i = 1, #RESULT do
|
||||
local sMsg = ''
|
||||
@@ -670,9 +715,14 @@ if bToProcess then
|
||||
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
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
BEAM.ROT = -( RESULT[i].nRotation or 1) + 1
|
||||
if #EgtTrim( sMsg) > 0 then
|
||||
BEAM.ERR = -19
|
||||
BEAM.MSG = sMsg
|
||||
else
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
end
|
||||
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)
|
||||
@@ -688,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)
|
||||
@@ -700,13 +750,21 @@ if bToProcess then
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.FALL = abs( RESULT[i].nErr + 100)
|
||||
WriteFallToLogFile( BEAM.ERR, BEAM.MSG, BEAM.CUTID, BEAM.FALL)
|
||||
-- errore da post apply, al momento non specifico
|
||||
elseif RESULT[i].sType == 'Part' and RESULT[i].nErr > 0 then
|
||||
nErrCnt = nErrCnt + 1
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = 'Clamp impossible'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
return
|
||||
-- feature incompleta e altro
|
||||
elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then
|
||||
nWarnCnt = nWarnCnt + 1
|
||||
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)
|
||||
@@ -714,6 +772,18 @@ 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
|
||||
EgtSaveFile( sNgeFile)
|
||||
-- copio come originale (per dichiarare progetto ricalcolato)
|
||||
@@ -746,6 +816,11 @@ else
|
||||
end
|
||||
end
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
-- *** Eseguo simulazione con verifica collisione in cieco ***
|
||||
if ( BEAM.FLAG == 0 and ( bToProcess or bToRecalc)) or BEAM.FLAG == 3 or BEAM.FLAG == 4 then
|
||||
EgtOutLog( ' +++ Simulating with collision check >>>')
|
||||
@@ -759,7 +834,12 @@ if ( BEAM.FLAG == 0 and ( bToProcess or bToRecalc)) or BEAM.FLAG == 3 or BEAM.F
|
||||
sToolsList = sToolsList .. ", "
|
||||
end
|
||||
end
|
||||
WriteErrToLogFile( 19, 'Error in setup: tool/s ' .. sToolsList .. ' not found', 0, 0, 0)
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = 'Error in setup: tool/s ' .. sToolsList .. ' not found'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, 0, 0, 0)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
-- lancio simulazione
|
||||
@@ -794,6 +874,10 @@ if ( BEAM.FLAG == 0 and ( bToProcess or bToRecalc)) or BEAM.FLAG == 3 or BEAM.F
|
||||
end
|
||||
end
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
-- TODO gestire collisione su feature specifica!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, BEAM.CUTID, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -813,6 +897,9 @@ if bIsGenerationEnabled and ( BEAM.FLAG == 0 or BEAM.FLAG == 4) then
|
||||
BEAM.MSG = 'Error generating NC part program : ' .. sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -825,6 +912,9 @@ if not EgtEstimate( '', 'EgtCAM5 - ' .. sNgeFile) then
|
||||
BEAM.MSG = 'Error estimating production time : ' .. sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
local Ttot = EgtGetInfo( EgtGetCurrMachGroup(), 'Ttot', 'd')
|
||||
@@ -847,5 +937,11 @@ end
|
||||
|
||||
-- Scrittura tempo totale stimato di lavorazione
|
||||
WriteTimeToLogFile( Ttot)
|
||||
RESULT[#RESULT+1] = { dTime = Ttot, sType = 'Time'}
|
||||
|
||||
-- Riporto risultati in tabella globale BEAM
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
-- Scrittura json risultati
|
||||
WriteResultToJson( RESULT)
|
||||
|
||||
EgtOutLog( ' +++ BatchProcess completed')
|
||||
|
||||
+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')
|
||||
@@ -9,7 +9,7 @@ local BasicCustomerStrategies = {}
|
||||
require( 'EgtBase')
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local ID = require( 'Identity')
|
||||
|
||||
|
||||
+1040
-404
File diff suppressed because it is too large
Load Diff
+251
-43
@@ -8,7 +8,7 @@ local BeamLib = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
|
||||
EgtOutLog( ' BeamLib started', 1)
|
||||
@@ -65,6 +65,64 @@ function BeamLib.AddPartEndFace( PartId, b3Solid)
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.GetPartBoxWithHeadTail( Part, sSide)
|
||||
local _sSide = sSide or ''
|
||||
|
||||
-- si può usare il box del grezzo che contiene sempre il sovramateriale di testa
|
||||
if _sSide == 'Head' then
|
||||
|
||||
local b3WithHead = BBox3d( Part.b3Raw)
|
||||
return b3WithHead
|
||||
|
||||
-- se è l'ultimo pezzo della barra si aggiunge il box dell'eventuale grezzo successivo
|
||||
-- se non lo è, si estende il box del pezzo fino alla fine della barra
|
||||
elseif _sSide == 'Tail' then
|
||||
|
||||
local b3WithTail = BBox3d( Part.b3Part)
|
||||
if Part.bIsLastPart then
|
||||
local nNextRawId = EgtGetNextRawPart( Part.idRaw)
|
||||
if nNextRawId then
|
||||
local b3Tail = EgtGetRawPartBBox( nNextRawId)
|
||||
b3WithTail:Add( b3Tail)
|
||||
end
|
||||
else
|
||||
-- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende)
|
||||
local ptXMin = Point3d( Part.b3Raw:getMin():getX() - Part.dRestLength, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3WithTail:Add( ptXMin)
|
||||
end
|
||||
|
||||
return b3WithTail
|
||||
|
||||
-- per aggiungere entrambi si procede come per la coda ma partendo dal box del grezzo, che già contiene la testa
|
||||
elseif sSide == 'HeadTail' then
|
||||
|
||||
local b3WithHeadTail = BBox3d( Part.b3Raw)
|
||||
if Part.bIsLastPart then
|
||||
local nNextRawId = EgtGetNextRawPart( Part.idRaw)
|
||||
if nNextRawId then
|
||||
local b3Tail = EgtGetRawPartBBox( nNextRawId)
|
||||
b3WithHeadTail:Add( b3Tail)
|
||||
end
|
||||
else
|
||||
-- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende)
|
||||
local ptXMin = Point3d( Part.b3Raw:getMin():getX() - Part.dRestLength, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3WithHeadTail:Add( ptXMin)
|
||||
end
|
||||
|
||||
return b3WithHeadTail
|
||||
|
||||
-- sSide non definito, si restituisce il box del pezzo con l'aggiunta dello spessore lama/catena in coda
|
||||
else
|
||||
local b3WithSplit = BBox3d( Part.b3Part)
|
||||
-- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende)
|
||||
local ptXMin = Point3d( Part.b3Raw:getMin():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3WithSplit:Add( ptXMin)
|
||||
|
||||
return b3WithSplit
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.GetPartSplittingPoints( Part)
|
||||
local PartSplittingPoints = {}
|
||||
@@ -104,7 +162,7 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.AddPhaseWithRawParts( idRaw, OriXR, PosXR, dDeltaSucc)
|
||||
EgtAddPhase()
|
||||
local nPhase = EgtAddPhase()
|
||||
-- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola
|
||||
EgtSetTableAreaOffset( 2000, 2000, 2000, 2000)
|
||||
local dRawMove = 0
|
||||
@@ -116,6 +174,10 @@ function BeamLib.AddPhaseWithRawParts( idRaw, OriXR, PosXR, dDeltaSucc)
|
||||
dRawMove = dRawMove + EgtGetRawPartBBox( idRaw):getDimX()
|
||||
idRaw = EgtGetNextRawPart( idRaw)
|
||||
end
|
||||
-- salvo info nuova fase aggiunta
|
||||
local MachExtraInfo = { sType = 'DISP',
|
||||
nPhase = nPhase}
|
||||
table.insert( DB_MACH_APPLIED, MachExtraInfo)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
@@ -266,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
|
||||
@@ -279,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
|
||||
@@ -299,7 +367,9 @@ function BeamLib.CreateTempGroup()
|
||||
if not idTempGroup then
|
||||
idTempGroup = EgtGroup( GDB_ID.ROOT)
|
||||
EgtSetName( idTempGroup, "#TEMP_GROUP#")
|
||||
EgtSetColor( idTempGroup, Color3d( 80, 160, 160, 1))
|
||||
EgtSetLevel( idTempGroup, GDB_LV.TEMP)
|
||||
EgtSetStatus( idTempGroup, GDB_ST.OFF)
|
||||
end
|
||||
return idTempGroup
|
||||
end
|
||||
@@ -424,6 +494,87 @@ function BeamLib.GetNearestParalOpposite( vtRef, vtNorm)
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO gestire anche altri valori
|
||||
function BeamLib.GetDirectionFromSCC( nSCC)
|
||||
local vtSCC
|
||||
|
||||
if nSCC == MCH_SCC.ADIR_XP then
|
||||
vtSCC = X_AX()
|
||||
elseif nSCC == MCH_SCC.ADIR_XM then
|
||||
vtSCC = -X_AX()
|
||||
elseif nSCC == MCH_SCC.ADIR_YP then
|
||||
vtSCC = Y_AX()
|
||||
elseif nSCC == MCH_SCC.ADIR_YM then
|
||||
vtSCC = -Y_AX()
|
||||
elseif nSCC == MCH_SCC.ADIR_ZP then
|
||||
vtSCC = Z_AX()
|
||||
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)
|
||||
@@ -502,7 +653,7 @@ function BeamLib.GetPieceGeneralParameters( Part, DefaultGeneralParamList)
|
||||
else
|
||||
if GENERAL_PARAMETERS.BTL and GENERAL_PARAMETERS.BTL[Part.sBTLInfo] and GENERAL_PARAMETERS.BTL[Part.sBTLInfo][DefaultGeneralParamList[i].sName] ~= nil then
|
||||
GeneralParameters[DefaultGeneralParamList[i].sName] = GENERAL_PARAMETERS.BTL[Part.sBTLInfo][DefaultGeneralParamList[i].sName]
|
||||
elseif GENERAL_PARAMETERS.PROJECT[DefaultGeneralParamList[i].sName] then
|
||||
elseif GENERAL_PARAMETERS.PROJECT[DefaultGeneralParamList[i].sName] ~= nil then
|
||||
GeneralParameters[DefaultGeneralParamList[i].sName] = GENERAL_PARAMETERS.PROJECT[DefaultGeneralParamList[i].sName]
|
||||
end
|
||||
end
|
||||
@@ -593,18 +744,21 @@ function BeamLib.LoadGeneralParametersInList( DefaultGeneralParamList)
|
||||
for i = 1, #DefaultGeneralParamList do
|
||||
local sParamNameNGE = DefaultGeneralParamList[i].sNameNge
|
||||
local xParameterValue = EgtGetInfo( idProjectInfo, sParamNameNGE, 's') or DefaultGeneralParamList[i].sValue
|
||||
-- salvataggio dato su lista con accesso diretto
|
||||
if DefaultGeneralParamList[i].sType == 'b' then
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true
|
||||
elseif DefaultGeneralParamList[i].sType == 'd' then
|
||||
if #DefaultGeneralParamList[i].sValue > 0 then
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = tonumber( xParameterValue)
|
||||
-- stringa vuota equivale a non passare alcun valore (deciderà la strategia)
|
||||
else
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = nil
|
||||
-- se parametro non trovato si salta tutto. N.B. = I parametri progetto non dovrebbero mai essere nil
|
||||
if xParameterValue then
|
||||
-- salvataggio dato su lista con accesso diretto
|
||||
if DefaultGeneralParamList[i].sType == 'b' then
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true
|
||||
elseif DefaultGeneralParamList[i].sType == 'd' then
|
||||
if #DefaultGeneralParamList[i].sValue > 0 then
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = tonumber( xParameterValue)
|
||||
-- stringa vuota equivale a non passare alcun valore (deciderà la strategia)
|
||||
else
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = nil
|
||||
end
|
||||
else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo'
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue
|
||||
end
|
||||
else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo'
|
||||
UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue
|
||||
end
|
||||
end
|
||||
|
||||
@@ -618,18 +772,21 @@ function BeamLib.LoadGeneralParametersInList( DefaultGeneralParamList)
|
||||
for i = 1, #DefaultGeneralParamList do
|
||||
local sParamNameNGE = DefaultGeneralParamList[i].sNameNge
|
||||
local xParameterValue = EgtGetInfo( BTLInfo[j], sParamNameNGE, 's')
|
||||
-- salvataggio dato su lista con accesso diretto
|
||||
if DefaultGeneralParamList[i].sType == 'b' then
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true
|
||||
elseif DefaultGeneralParamList[i].sType == 'd' then
|
||||
if #DefaultGeneralParamList[i].sValue > 0 then
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = tonumber( xParameterValue)
|
||||
-- stringa vuota equivale a non passare alcun valore (deciderà la strategia)
|
||||
else
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = nil
|
||||
-- se parametro non trovato si salta tutto
|
||||
if xParameterValue then
|
||||
-- salvataggio dato su lista con accesso diretto
|
||||
if DefaultGeneralParamList[i].sType == 'b' then
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true
|
||||
elseif DefaultGeneralParamList[i].sType == 'd' then
|
||||
if #DefaultGeneralParamList[i].sValue > 0 then
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = tonumber( xParameterValue)
|
||||
-- stringa vuota equivale a non passare alcun valore (deciderà la strategia)
|
||||
else
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = nil
|
||||
end
|
||||
else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo'
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue
|
||||
end
|
||||
else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo'
|
||||
UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -677,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)
|
||||
@@ -727,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
|
||||
@@ -852,7 +1051,7 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function BeamLib.GetStrategiesFromList( Proc, StrategyList)
|
||||
-- cerco tra le feature
|
||||
-- cerco tra le feature
|
||||
for i = 1, #StrategyList.FEATURE do
|
||||
-- se trovo la feature
|
||||
if Proc.nPrc == StrategyList.FEATURE[i].nPrc then
|
||||
@@ -870,16 +1069,25 @@ function BeamLib.GetStrategiesFromList( Proc, StrategyList)
|
||||
|
||||
-- si controlla gruppo
|
||||
if bGroupIsCompatible then
|
||||
if #StrategyList.FEATURE[i].TopologyList == 1 and StrategyList.FEATURE[i].TopologyList[1].sName == 'Feature' then
|
||||
return BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[1].StrategyList)
|
||||
else
|
||||
-- cerco tra le topologie
|
||||
for j = 1, #StrategyList.FEATURE[i].TopologyList do
|
||||
-- se trovo la topologia
|
||||
if Proc.Topology.sName == StrategyList.FEATURE[i].TopologyList[j].sName then
|
||||
-- ritorno le strategie disponibili per la feature che sto analizzando
|
||||
return BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[j].StrategyList)
|
||||
-- cerco tra le topologie
|
||||
for j = 1, #StrategyList.FEATURE[i].TopologyList do
|
||||
-- non si possono mischiare topologie specifiche con topologia 'Feature'. Se presente topologia 'Feature' allora deve essere esclusiva
|
||||
if StrategyList.FEATURE[i].TopologyList[j].sName == 'Feature' and #StrategyList.FEATURE[i].TopologyList > 1 then
|
||||
error( "UNEXPECTED ERROR: topology 'Feature' can't be mixed with others")
|
||||
end
|
||||
-- se trovo la topologia oppure se è 'Feature'
|
||||
if Proc.Topology.sName == StrategyList.FEATURE[i].TopologyList[j].sName or StrategyList.FEATURE[i].TopologyList[j].sName == 'Feature' then
|
||||
local ActiveStrategyList = {}
|
||||
-- aggiungo in lista solo le strategie attive
|
||||
if StrategyList.FEATURE[i].TopologyList[j].StrategyList then
|
||||
for k = 1, #StrategyList.FEATURE[i].TopologyList[j].StrategyList do
|
||||
if ( not StrategyList.FEATURE[i].TopologyList[j].StrategyList[k].nIndexInList) or ( StrategyList.FEATURE[i].TopologyList[j].StrategyList[k].nIndexInList) >= 0 then
|
||||
table.insert( ActiveStrategyList, BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[j].StrategyList[k]))
|
||||
end
|
||||
end
|
||||
end
|
||||
-- ritorno le strategie disponibili per la feature che sto analizzando, altrimenti nil se non ho trovato nulla
|
||||
return EgtIf( #ActiveStrategyList > 0, ActiveStrategyList, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+36
-41
@@ -11,12 +11,12 @@ local BeamLib = require( 'BeamLib')
|
||||
EgtOutLog( ' DiceCut started', 1)
|
||||
|
||||
-- Dati
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- creo i piani paralleli
|
||||
-- GetParallelPlanes: restituisce un vettore con gli indici delle superfici
|
||||
-- nAddGrpId: il layer
|
||||
-- idAddGroup: il layer
|
||||
-- b3BoxDicing: il grezzo della barra
|
||||
-- ptC: il punto centrale del piano della feature
|
||||
-- vtN: il versore normale del piano della feature
|
||||
@@ -30,7 +30,7 @@ local BeamData = require( 'BeamData')
|
||||
-- vtNCut*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- ptCCut1*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- vtNCut1*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
local function GetParallelPlanes( nAddGrpId, b3BoxDicing, ptC, vtN, nCopyPlane, dOffset, nStep, Color, dTolerance, bNoTolOnFirstCut, ptCCut, vtNCut, ptCCut1, vtNCut1 )
|
||||
local function GetParallelPlanes( idAddGroup, b3BoxDicing, ptC, vtN, nCopyPlane, dOffset, nStep, Color, dTolerance, bNoTolOnFirstCut, ptCCut, vtNCut, ptCCut1, vtNCut1 )
|
||||
local ptMyCCut
|
||||
local AreaMin = 5*5
|
||||
if ptCCut and vtNCut then
|
||||
@@ -46,7 +46,7 @@ local function GetParallelPlanes( nAddGrpId, b3BoxDicing, ptC, vtN, nCopyPlane,
|
||||
local TabellaTmSurfParallel = {}
|
||||
local i = nCopyPlane
|
||||
while i < nStep do
|
||||
local SurfId = EgtSurfTmPlaneInBBox( nAddGrpId, ptC + ( i * dOffset) * vtN, vtN, b3BoxDicing, GDB_RT.GLOB)
|
||||
local SurfId = EgtSurfTmPlaneInBBox( idAddGroup, ptC + ( i * dOffset) * vtN, vtN, b3BoxDicing, GDB_RT.GLOB)
|
||||
local nFacet = EgtSurfTmFacetCount( SurfId or GDB_ID.NULL)
|
||||
if nFacet == 0 then
|
||||
-- se sono al primo taglio do una possibilità in più di girare
|
||||
@@ -86,11 +86,11 @@ end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- GetOrderedCutTable:
|
||||
-- nAddGrpId: il layer
|
||||
-- idAddGroup: il layer
|
||||
-- TabParallelPlanes: tabella delle superfici dei piani paralleli
|
||||
-- TabOrtoPlanes: tabella delle superfici dei piani ortogonali
|
||||
-- stampo l'ordine dei piani di taglio (prima tagli ortogonali piu' esterni poi taglio parallelo collettivo)
|
||||
local function GetOrderedCutTable( nAddGrpId, TabParallelPlanes, TabOrtoPlanes)
|
||||
local function GetOrderedCutTable( idAddGroup, TabParallelPlanes, TabOrtoPlanes)
|
||||
local StepParallel = #TabParallelPlanes
|
||||
local StepOrto = #TabOrtoPlanes
|
||||
local TabellaOrderParallelCut1 = {}
|
||||
@@ -99,8 +99,8 @@ local function GetOrderedCutTable( nAddGrpId, TabParallelPlanes, TabOrtoPlanes)
|
||||
TabellaOrderParallelCut1[IndexTmP] = {}
|
||||
for IndexOrto=1, StepOrto do
|
||||
local ptOrtoN, vtNOrtoN = EgtSurfTmFacetCenter( TabOrtoPlanes[IndexOrto ], 0, GDB_ID.ROOT)
|
||||
local Copy1Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, nAddGrpId)
|
||||
local Copy2Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, nAddGrpId)
|
||||
local Copy1Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, idAddGroup)
|
||||
local Copy2Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, idAddGroup)
|
||||
if Copy1Id and ptOrtoN then
|
||||
EgtCutSurfTmPlane( Copy1Id, ptOrtoN, -vtNOrtoN, false, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( Copy2Id, ptOrtoN, vtNOrtoN, false, GDB_RT.GLOB)
|
||||
@@ -134,7 +134,7 @@ end
|
||||
-- vtO: il versore dei piani ortogonali
|
||||
-- dOffsetEff: offset della distanza dal punto centrale
|
||||
-- Verifica se l'asse X del box costruito sopra la superficie è più grande di un certo offset
|
||||
local function GetOrtoCutCenter( FacetId, ptC, vtN, vtO, dOffsetEff, dMinNzDownUp)
|
||||
local function GetOrtoCutCenter( FacetId, ptC, vtN, vtO, dOffsetEff)
|
||||
local FrameLocal = Frame3d( EgtSurfTmFacetCenter( FacetId, 0, GDB_ID.ROOT))
|
||||
EgtSetGridFrame(FrameLocal)
|
||||
local IdAuxLocal = EgtGroup(EgtGetParent( FacetId), FrameLocal)
|
||||
@@ -156,7 +156,7 @@ local function GetOrtoCutCenter( FacetId, ptC, vtN, vtO, dOffsetEff, dMinNzDownU
|
||||
-- TODO si può eliminare questo test dato che vengono verificate già volume e dimensione del cubetto??
|
||||
local dMaxLen = BeamData.MAX_LEN_DICE or 600
|
||||
if dLen < dMaxLen and dWidth < dMaxLen and
|
||||
( dLen < dOffsetEff + 1.0 or dWidth < dOffsetEff + 1.0) and vtN:getZ() > dMinNzDownUp then
|
||||
( dLen < dOffsetEff + 1.0 or dWidth < dOffsetEff + 1.0) then
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
@@ -261,7 +261,7 @@ end
|
||||
-- dOffsetParallel: offset della distanza dal punto centrale
|
||||
-- b3BoxDicing: il grezzo della barra
|
||||
-- Verifica se l'asse X del box costruito sopra le 2 facce è più piccolo di un certo offset e quindi la faccia O è superflua
|
||||
local function VerifyFirstOrthoCut( CutTable, dOffsetParallel, b3BoxDicing, dMinNzDownUp)
|
||||
local function VerifyFirstOrthoCut( CutTable, dOffsetParallel, b3BoxDicing)
|
||||
|
||||
if not CutTable[1] or not CutTable[2] then return end
|
||||
|
||||
@@ -294,9 +294,9 @@ local function VerifyFirstOrthoCut( CutTable, dOffsetParallel, b3BoxDicing, dMin
|
||||
-- lunghezza totale faccia
|
||||
local dLongSize = x1 + x2
|
||||
-- se faccia piccola e non orientata verso il basso, elimino ortogonale e unisco le due parti
|
||||
if dLongSize <= dOffsetParallel + 1.0 and vtN1:getZ() > dMinNzDownUp then
|
||||
local nAddGrpId = EgtGetParent( Cut1Id)
|
||||
local SurfId = EgtSurfTmBySewing( nAddGrpId, { Cut1Id, Cut2Id})
|
||||
if dLongSize <= dOffsetParallel + 1.0 then
|
||||
local idAddGroup = EgtGetParent( Cut1Id)
|
||||
local SurfId = EgtSurfTmBySewing( idAddGroup, { Cut1Id, Cut2Id})
|
||||
--EgtSetColor( SurfId, Color3d( FUCHSIA(), 60))
|
||||
EgtErase( CutOId)
|
||||
table.remove( CutTable[1], 1)
|
||||
@@ -338,7 +338,7 @@ end
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ricavo l'altezza del BoundingBox assegnati gli estremi del grezzo e la feature
|
||||
-- le funzioni commentate permettono di vedere la creazione di BoundingBox
|
||||
local function DistanzaMassima( nAddGrpId, ptC1, vtN1, ptC2, vtN2, b3BoxDicing, TPoint)
|
||||
local function DistanzaMassima( idAddGroup, ptC1, vtN1, ptC2, vtN2, b3BoxDicing, TPoint)
|
||||
-- calcolo il riferimento nel piano 1
|
||||
local Frame1 = Frame3d( ptC1, vtN1)
|
||||
-- determino l'ingombro in questo riferimento della parte di trave compresa nel o nei piani
|
||||
@@ -353,7 +353,7 @@ local function DistanzaMassima( nAddGrpId, ptC1, vtN1, ptC2, vtN2, b3BoxDicing,
|
||||
end
|
||||
-- eventuale altra faccia
|
||||
if ptC2 and vtN2 then
|
||||
local IdAux = EgtGroup( nAddGrpId)
|
||||
local IdAux = EgtGroup( idAddGroup)
|
||||
local IdSurf2 = EgtSurfTmPlaneInBBox( IdAux, ptC2, vtN2, b3BoxDicing, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( IdSurf2, ptC1, -vtN1, false, GDB_RT.GLOB)
|
||||
if IdSurf2 then
|
||||
@@ -394,7 +394,12 @@ end
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
-- gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
local idAddGroup
|
||||
if OptionalParameters.bSaveAddedGeometries then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
|
||||
-- faccia primaria
|
||||
local ptCMainFace
|
||||
@@ -422,16 +427,12 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
local dOffsetParallel = OptionalParameters.dOffsetParallel or BeamData.MAX_DIM_DICE
|
||||
-- distanza tra piani ortogonali
|
||||
local dOffsetOrthogonal = OptionalParameters.dOffsetOrthogonal or BeamData.MAX_DIM_DICE
|
||||
-- distanza ridotta tra piani ortogonali - usato in tagli orizzontali con affondamento verticale
|
||||
local dOffsetOrthogonalReduced = OptionalParameters.dOffsetOrthogonalReduced or BeamData.MAX_DIM_HTCUT
|
||||
-- numero massimo piani paralleli
|
||||
local nStepParallel = OptionalParameters.nStepParallel or 100
|
||||
-- numero massimo piani perpendicolari
|
||||
local nStepOrthogonal = OptionalParameters.nStepOrthogonal or 100
|
||||
-- distanza tra piani paralleli e piani di taglio (era sempre 0, serve???)
|
||||
local dTolerance = OptionalParameters.dTolerance or 0
|
||||
-- inclinazione limite per taglio da sotto
|
||||
local dMinNzDownUp = OptionalParameters.dMinNzDownUp or -2
|
||||
|
||||
--Ricavo le altezze dei BoundingBox contenente feature e estremi del grezzo
|
||||
local TBoxPoint = CalcolaPuntiEstremiBox( b3BoxDicing)
|
||||
@@ -439,18 +440,12 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
if ptCSubordinateFace and vtNSubordinateFace then
|
||||
TBoxPoint = VerificaEstremiGrezzo( ptCSubordinateFace, vtNSubordinateFace, TBoxPoint)
|
||||
end
|
||||
local dElevP = DistanzaMassima( nAddGrpId, ptCMainFace, vtNMainFace, ptCSubordinateFace, vtNSubordinateFace, b3BoxDicing, TBoxPoint)
|
||||
local dElevP = DistanzaMassima( idAddGroup, ptCMainFace, vtNMainFace, ptCSubordinateFace, vtNSubordinateFace, b3BoxDicing, TBoxPoint)
|
||||
local dElevO
|
||||
if ptCSubordinateFace and vtNSubordinateFace and not AreOppositeVectorApprox( vtNSubordinateFace, vtNMainFace) then
|
||||
dElevO = DistanzaMassima( nAddGrpId, ptCSubordinateFace, vtNSubordinateFace, ptCMainFace, vtNMainFace, b3BoxDicing, TBoxPoint)
|
||||
dElevO = DistanzaMassima( idAddGroup, ptCSubordinateFace, vtNSubordinateFace, ptCMainFace, vtNMainFace, b3BoxDicing, TBoxPoint)
|
||||
end
|
||||
|
||||
-- TODO parte sotto da aggiungere???? se sì va passata anche la dimensione cubetto ridotta dOffsetOrthogonalReduced
|
||||
-- se non c'è testa da sotto e normali senza componenti in Y con faccia quasi verticale e trave non alta, uso per offset i limiti dei tagli di testa e coda
|
||||
-- if not BD.TURN and not BD.DOWN_HEAD and abs( vtNPlanes:getY()) < 0.1 and vtNPlanes:getZ() < 0.7071 and ( not vtNBond or abs( vtNBond:getY()) < 0.1) and BBoxRawPart:getDimZ() < BD.MIN_DIM_HBEAM then
|
||||
-- dOffsetOrthogonal = dOffsetOrthogonalReduced
|
||||
-- end
|
||||
|
||||
-- aggiungo piccolo extra agli offset
|
||||
dOffsetParallel = dOffsetParallel + 10 * GEO.EPS_SMALL
|
||||
dOffsetOrthogonal = dOffsetOrthogonal + 10 * GEO.EPS_SMALL
|
||||
@@ -458,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
|
||||
@@ -476,7 +471,7 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
|
||||
-- PIANI PARALLELI alla faccia di taglio
|
||||
local TabellaTmSurfP = {}
|
||||
local TabFromIn = GetParallelPlanes( nAddGrpId, b3BoxDicing, ptCMainFace, vtNMainFace, 0, dOffsetParallel, nStepParallel, Color3d( FUCHSIA(), 60), dTolerance, true, ptCSubordinateFace, vtNSubordinateFace)
|
||||
local TabFromIn = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCMainFace, vtNMainFace, 0, dOffsetParallel, nStepParallel, Color3d( FUCHSIA(), 60), dTolerance, true, ptCSubordinateFace, vtNSubordinateFace)
|
||||
for i = #TabFromIn, 1, -1 do
|
||||
table.insert( TabellaTmSurfP, TabFromIn[i])
|
||||
end
|
||||
@@ -485,12 +480,12 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
-- orientamento definito da seconda faccia
|
||||
if not bGetOrtoPlanes then
|
||||
local TabellaTmSurfOrto = {}
|
||||
local TabFromIn = GetParallelPlanes( nAddGrpId, b3BoxDicing, ptCSubordinateFace, vtNSubordinateFace, 0, dOffsetOrthogonal, nStepOrthogonal, Color3d( GREEN(), 60), dTolerance, false, ptCMainFace, vtNMainFace)
|
||||
local TabFromIn = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCSubordinateFace, vtNSubordinateFace, 0, dOffsetOrthogonal, nStepOrthogonal, Color3d( GREEN(), 60), dTolerance, false, ptCMainFace, vtNMainFace)
|
||||
for i = #TabFromIn, 1, -1 do
|
||||
table.insert( TabellaTmSurfOrto, TabFromIn[i])
|
||||
end
|
||||
local TabellaOrderParallelCut = GetOrderedCutTable( nAddGrpId, TabellaTmSurfP, TabellaTmSurfOrto) -- Ottiene la tabella dei tagli paralleli ordinati
|
||||
local TabellaOrderOrtoCut = GetOrderedCutTable( nAddGrpId, TabellaTmSurfOrto, TabellaTmSurfP) -- Ottiene la tabella dei tagli ortogonali da riordinare per strato
|
||||
local TabellaOrderParallelCut = GetOrderedCutTable( idAddGroup, TabellaTmSurfP, TabellaTmSurfOrto) -- Ottiene la tabella dei tagli paralleli ordinati
|
||||
local TabellaOrderOrtoCut = GetOrderedCutTable( idAddGroup, TabellaTmSurfOrto, TabellaTmSurfP) -- Ottiene la tabella dei tagli ortogonali da riordinare per strato
|
||||
|
||||
TabGREEN = SortOrtoCutsByNormalMethod( TabellaOrderParallelCut, TabellaOrderOrtoCut) -- I tagli ortogonali vengono ordinati per strato
|
||||
TabFUCHSIA = TabellaOrderParallelCut -- I tagli paralleli sono già ordinati
|
||||
@@ -508,10 +503,10 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
end
|
||||
-- calcolo la direzione dei piani ortogonali
|
||||
local vtO = VectorFromUprightOrtho( vtNInner)
|
||||
if vtNInner:getZ() > -0.0175 or vtNInner:getZ() < dMinNzDownUp or abs( vtNInner:getY()) > 0.8 then
|
||||
if vtNInner:getZ() > -0.0175 or abs( vtNInner:getY()) > 0.8 then
|
||||
vtO:rotate( vtNInner, 90)
|
||||
-- se diretto troppo ortogonalmente all'asse trave e taglio non da sotto, lo ruoto ulteriormente
|
||||
if ( abs( vtO:getY()) > 4 * abs( vtO:getX()) or b3BoxDicing:getDimZ() > 620) and vtNInner:getZ() > dMinNzDownUp then
|
||||
if ( abs( vtO:getY()) > 4 * abs( vtO:getX()) or b3BoxDicing:getDimZ() > 620) then
|
||||
vtO:rotate( vtNInner, 90)
|
||||
-- se faccia principale verso il basso (almeno -3deg), lo inverto per iniziare da sopra
|
||||
if vtNInner:getZ() < -0.05 then
|
||||
@@ -533,16 +528,16 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
-- CopyPlane: 0 => crea la prima faccia direttamente sul punto passato
|
||||
-- CopyPlane: 1 => crea la prima faccia e tutte le altre con l'offset passato
|
||||
-- CopyPlane: 0.5 => crea la prima faccia a metà offset e tutte le altre con l'offest intero
|
||||
local OffsetRel, CopyPlane, dCenOffs, ptCStart = GetOrtoCutCenter( TabellaTmSurfP[PlnInd], ptCInner, vtNInner, vtO, dOffsetOrthogonal, dMinNzDownUp)
|
||||
local OffsetRel, CopyPlane, dCenOffs, ptCStart = GetOrtoCutCenter( TabellaTmSurfP[PlnInd], ptCInner, vtNInner, vtO, dOffsetOrthogonal)
|
||||
|
||||
if OffsetRel and CopyPlane and dCenOffs then
|
||||
ptCInner = ptCInner + dCenOffs * vtO
|
||||
local TabRight = GetParallelPlanes( nAddGrpId, b3BoxDicing, ptCStart, vtO, CopyPlane, -OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
local TabRight = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCStart, vtO, CopyPlane, -OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
dTolerance, false, ptCInner, vtNInner, ptCOuter, vtNOuter)
|
||||
if CopyPlane == 0 then
|
||||
CopyPlane = 1
|
||||
end
|
||||
local TabLeft = GetParallelPlanes( nAddGrpId, b3BoxDicing, ptCStart, vtO, CopyPlane, OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
local TabLeft = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCStart, vtO, CopyPlane, OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
dTolerance, false, ptCInner, vtNInner, ptCOuter, vtNOuter)
|
||||
-- carico la tabella con gli indici riordinati
|
||||
local TempOrtoTab = {}
|
||||
@@ -553,7 +548,7 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
table.insert( TempOrtoTab, TabRight[i])
|
||||
end
|
||||
-- creo una tabella per ogni piano per generare i tagli sulla Inner
|
||||
local TempParTab = GetOrderedCutTable( nAddGrpId, {TabellaTmSurfP[PlnInd]}, TempOrtoTab)
|
||||
local TempParTab = GetOrderedCutTable( idAddGroup, {TabellaTmSurfP[PlnInd]}, TempOrtoTab)
|
||||
for i = 1, #TempParTab do
|
||||
table.insert( TabFUCHSIA, TempParTab[i])
|
||||
end
|
||||
@@ -582,7 +577,7 @@ function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
|
||||
-- Se esiste la superficie limitante (nFacet == 2) verifica se il taglio più esterno è superfluo e quindi viene eliminato
|
||||
if not bGetOrtoPlanes then
|
||||
VerifyFirstOrthoCut( UltimateTable, dOffsetParallelOriginal, b3BoxDicing, dMinNzDownUp)
|
||||
VerifyFirstOrthoCut( UltimateTable, dOffsetParallelOriginal, b3BoxDicing)
|
||||
-- se rimangono due sole facce, devono coincidere con le originali e quindi sono superflue
|
||||
if #UltimateTable == 2 and #UltimateTable[1] == 1 and #UltimateTable[2] == 1 then
|
||||
EgtErase( UltimateTable[1][1])
|
||||
|
||||
+97
-48
@@ -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
|
||||
@@ -136,9 +138,19 @@ function FaceData.GetEdgesInfo( ProcOrId, idFace )
|
||||
end
|
||||
CurrentEdge.bIsStartOpen = EdgesEgt[nPreviousEdgeIndex].Open
|
||||
CurrentEdge.bIsEndOpen = EdgesEgt[nNextEdgeIndex].Open
|
||||
CurrentEdge.ptStart = Point3d( EdgesEgt[i].Start)
|
||||
CurrentEdge.ptEnd = Point3d( EdgesEgt[nNextEdgeIndex].Start)
|
||||
CurrentEdge.vtEdge = CurrentEdge.ptEnd - CurrentEdge.ptStart ; CurrentEdge.vtEdge:normalize()
|
||||
CurrentEdge.sType = 'Standard'
|
||||
CurrentEdge.id = i - 1
|
||||
|
||||
-- se nella Proc ci sono le adiacenze e il lato ha adiacenza, si salva l'angolo con la faccia adiacente
|
||||
if Proc.AdjacencyMatrix then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
CurrentEdge.dAdjacencyAngle = Proc.AdjacencyMatrix[idFace + 1][CurrentEdge.idAdjacentFace + 1]
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( Edges, CurrentEdge)
|
||||
end
|
||||
|
||||
@@ -147,7 +159,6 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
EgtOutLog( '---Faces START---')
|
||||
local Faces = {}
|
||||
|
||||
local function FaceIsToGet( nIndex)
|
||||
@@ -175,10 +186,11 @@ function FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
for i = 1, Proc.nFct do
|
||||
Faces[i] = {}
|
||||
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].vtFrameHV = Frame3d( Faces[i].ptCenter, Faces[i].vtN)
|
||||
Faces[i].frFrameHV = Frame3d( Faces[i].ptCenter, Faces[i].vtN)
|
||||
-- elevazione calcolata rispetto al box della parte
|
||||
Faces[i].dElevation = EgtSurfTmFacetElevationInBBox( Proc.id, i - 1, Part.b3Part, true, GDB_ID.ROOT)
|
||||
-- TODO qui sarebbe meglio l'area vera e non quella del rettangolo minimo
|
||||
@@ -186,78 +198,86 @@ function FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
Faces[i].dArea = dShortDimension * dLongDimension
|
||||
Faces[i].dLMinRectangle = dLongDimension
|
||||
Faces[i].dWMinRectangle = dShortDimension
|
||||
-- volume approssimato di materiale asportato lavorando questa faccia
|
||||
Faces[i].dMachinedVolumeApprox = Faces[i].dArea * Faces[i].dElevation
|
||||
|
||||
local nFaceType, Edges = FaceData.GetEdgesInfo( Proc, i - 1)
|
||||
Faces[i].bIsOkForMachining = nFaceType < 1
|
||||
Faces[i].Edges = Edges
|
||||
|
||||
-- TODO valutare se fare un output unico alla fine o gestire log in altro modo
|
||||
EgtOutLog( 'Facet ' .. Faces[i].id .. ' of ' .. Proc.nFct - 1)
|
||||
EgtOutLog( ' vtN: ' .. tostring( Faces[i].vtN))
|
||||
|
||||
-- adiacenze della faccia
|
||||
-- TODO chiamarle in modo che si capisca che sono solo gli id e non l'intero oggetto faccia
|
||||
Faces[i].Adjacencies = {}
|
||||
for j = 1, Proc.nFct do
|
||||
if vAdj[i][j] and vAdj[i][j] ~= 0 and ( i ~= j) then
|
||||
table.insert( Faces[i].Adjacencies, j - 1)
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
EgtOutLog( ' Adjacent to facet: ' .. j - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
EgtOutLog( '---Faces END---')
|
||||
return Faces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.IsFaceRectangular( Proc, idFace)
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Proc.idPart)
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Proc.id, idFace, nAddGrpId)
|
||||
function FaceData.IsFaceRectangle( Face)
|
||||
-- recupero gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup)
|
||||
if nContourCnt > 1 then
|
||||
error( 'IsFaceRectangular : too many loops')
|
||||
error( 'IsFaceRectangle : too many loops')
|
||||
end
|
||||
|
||||
local bIsRectangular = EgtCurveIsARectangle( nContourId)
|
||||
|
||||
-- elimino curve create
|
||||
for i = 1, nContourCnt do
|
||||
EgtErase( nContourId + i - 1)
|
||||
end
|
||||
|
||||
return bIsRectangular
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.IsFaceRhomboid( Proc, idFace)
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Proc.idPart)
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Proc.id, idFace, nAddGrpId)
|
||||
function FaceData.IsFaceParallelogram( Face)
|
||||
-- recupero gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup)
|
||||
if nContourCnt > 1 then
|
||||
error( 'IsFaceRectangular : too many loops')
|
||||
error( 'IsFaceParallelogram : too many loops')
|
||||
end
|
||||
|
||||
local bIsTrapezoid = EgtCurveIsATrapezoid( nContourId)
|
||||
local bIsRhomboid = false
|
||||
-- un parallelogramma è un trapezoide con i lati paralleli a due a due
|
||||
if bIsTrapezoid
|
||||
and AreOppositeVectorApprox( Proc.Faces[idFace + 1].Edges[1].vtN, Proc.Faces[idFace + 1].Edges[3].vtN)
|
||||
and AreOppositeVectorApprox( Proc.Faces[idFace + 1].Edges[2].vtN, Proc.Faces[idFace + 1].Edges[4].vtN) then
|
||||
and AreOppositeVectorApprox( Face.Edges[1].vtN, Face.Edges[3].vtN)
|
||||
and AreOppositeVectorApprox( Face.Edges[2].vtN, Face.Edges[4].vtN) then
|
||||
|
||||
bIsRhomboid = true
|
||||
end
|
||||
|
||||
-- elimino curve create
|
||||
for i = 1, nContourCnt do
|
||||
EgtErase( nContourId + i - 1)
|
||||
end
|
||||
|
||||
return bIsRhomboid
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareBottomFaces( FaceA, FaceB)
|
||||
local dMaxVolumeRelativeChange = 0.15
|
||||
-- si prende la faccia con volume lavorato maggiore
|
||||
if FaceA.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceB.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif FaceB.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceA.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se volume lavorato simile, si prende la faccia con minore elevazione
|
||||
else
|
||||
if FaceA.dElevation < FaceB.dElevation - 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif FaceB.dElevation < FaceA.dElevation - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdgesBottomFace( EdgeA, EdgeB)
|
||||
-- prima i lati con facce adiacenti
|
||||
@@ -365,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
|
||||
@@ -379,8 +417,8 @@ local function GetBottomFaces( Proc)
|
||||
end
|
||||
nCurrentFace = nCurrentFace + 1
|
||||
end
|
||||
-- la BottomFace 1 è sempre quella con minor elevazione
|
||||
table.sort( BottomFaces, function (a, b) return a.dElevation < b.dElevation end)
|
||||
-- la BottomFace 1 è quella che permette di asportare il volume maggiore; nei casi ambigui si sceglie quella a minor elevazione
|
||||
table.sort( BottomFaces, CompareBottomFaces)
|
||||
end
|
||||
|
||||
if #BottomFaces == 0 then
|
||||
@@ -429,6 +467,10 @@ local function GetBottomFaces( Proc)
|
||||
CurrentEdge.dElevation = BottomFaces[1].Edges[i].dElevation
|
||||
CurrentEdge.bIsStartOpen = BottomFaces[1].Edges[i].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = BottomFaces[1].Edges[i].bIsEndOpen
|
||||
CurrentEdge.ptStart = BottomFaces[1].Edges[i].ptStart
|
||||
CurrentEdge.ptEnd = BottomFaces[1].Edges[i].ptEnd
|
||||
CurrentEdge.vtEdge = BottomFaces[1].Edges[i].vtEdge
|
||||
CurrentEdge.id = BottomFaces[1].Edges[i].id
|
||||
|
||||
if nFirstLongEdgeIndex then
|
||||
if i == nFirstLongEdgeIndex then
|
||||
@@ -454,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 {}
|
||||
@@ -524,6 +566,10 @@ local function GetLongFaces( Proc, MainFaces)
|
||||
CurrentEdge.dElevation = LongFaces[i].Edges[j].dElevation
|
||||
CurrentEdge.bIsStartOpen = LongFaces[i].Edges[j].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = LongFaces[i].Edges[j].bIsEndOpen
|
||||
CurrentEdge.ptStart = LongFaces[i].Edges[j].ptStart
|
||||
CurrentEdge.ptEnd = LongFaces[i].Edges[j].ptEnd
|
||||
CurrentEdge.vtEdge = LongFaces[i].Edges[j].vtEdge
|
||||
CurrentEdge.id = LongFaces[i].Edges[j].id
|
||||
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
@@ -558,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 {}
|
||||
@@ -620,6 +666,10 @@ local function GetSideFaces( Proc, MainFaces)
|
||||
CurrentEdge.dElevation = SideFaces[i].Edges[j].dElevation
|
||||
CurrentEdge.bIsStartOpen = SideFaces[i].Edges[j].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = SideFaces[i].Edges[j].bIsEndOpen
|
||||
CurrentEdge.ptStart = SideFaces[i].Edges[j].ptStart
|
||||
CurrentEdge.ptEnd = SideFaces[i].Edges[j].ptEnd
|
||||
CurrentEdge.vtEdge = SideFaces[i].Edges[j].vtEdge
|
||||
CurrentEdge.id = SideFaces[i].Edges[j].id
|
||||
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
@@ -653,7 +703,6 @@ end
|
||||
-- TODO test iniziale replicato in GetTunnelFaces
|
||||
function FaceData.GetMainFaces( Proc, Part)
|
||||
|
||||
EgtOutLog( '---MainFaces START---')
|
||||
local MainFaces = {}
|
||||
|
||||
-- CASO 1 : Feature tipo LapJoint
|
||||
@@ -661,26 +710,26 @@ 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)
|
||||
|
||||
-- scrivo informazioni delle facce nel log
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
Logs.WriteMainFacesLog( 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
|
||||
EgtOutLog( '---MainFaces NOT NEEDED---')
|
||||
end
|
||||
|
||||
EgtOutLog( '---MainFaces END---')
|
||||
return MainFaces
|
||||
end
|
||||
|
||||
|
||||
+37
-37
@@ -6,7 +6,7 @@
|
||||
local FeatureLib = {}
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
@@ -32,6 +32,10 @@ function FeatureLib.GetProcFromTrimesh( idTrimesh, Part, ProcToCopyFrom)
|
||||
Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part)
|
||||
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
||||
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
||||
Proc.dVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
if ProcToCopyFrom and Proc.dVolume < 10 * GEO.EPS_SMALL then
|
||||
Proc.dVolume = ProcToCopyFrom.dVolume
|
||||
end
|
||||
-- TODO servono anche altri dati raccolti nel collect??
|
||||
|
||||
return Proc
|
||||
@@ -39,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
|
||||
|
||||
@@ -54,7 +58,7 @@ end
|
||||
-- restituisce vero se tutti i lati della faccia passata si trovano sul grezzo
|
||||
local function AreAllFaceEdgesOnRaw( Part, Proc, idFace)
|
||||
local bEdgeOnRaw = true
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
local idTempGroup = Part.idTempGroup
|
||||
local nLoopId, nLoopCnt = EgtExtractSurfTmFacetLoops( Proc.id, idFace, idTempGroup)
|
||||
if nLoopCnt > 1 then
|
||||
error( 'AreAllFaceEdgesOnRaw : too many loops')
|
||||
@@ -194,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
|
||||
@@ -222,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
|
||||
@@ -240,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
|
||||
@@ -255,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
|
||||
@@ -323,12 +331,15 @@ function FeatureLib.GetAdditionalInfo( Proc, Part)
|
||||
elseif ID.IsRidgeLap( Proc) then
|
||||
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
||||
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
||||
elseif ID.IsMarking( Proc) then
|
||||
elseif ID.IsMarking( Proc) or ID.IsText( Proc) then
|
||||
Proc.FeatureInfo = FeatureLib.GetMarkTextData( Proc)
|
||||
elseif ID.IsHipValleyRafterNotch( Proc) then
|
||||
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
|
||||
@@ -495,6 +506,7 @@ function FeatureLib.GetDTMortiseData( Proc)
|
||||
|
||||
-- distanza massima all'imbocco ortogonale all'asse
|
||||
local vtDiff = EgtEP( idAux, GDB_RT.GLOB) - EgtSP( idAux, GDB_RT.GLOB)
|
||||
|
||||
local vtOrtDiff = vtDiff - vtDiff * vtAx * vtAx
|
||||
local dMortiseMaxDist = min( vtOrtDiff:len(), dMortiseWidth)
|
||||
|
||||
@@ -505,6 +517,9 @@ function FeatureLib.GetDTMortiseData( Proc)
|
||||
FeatureExtraInfo.dMortiseDepth = dMortiseDepth
|
||||
FeatureExtraInfo.dMortiseMinRadius = dMortiseMinRadius
|
||||
FeatureExtraInfo.vtMortiseN = vtMortiseN
|
||||
vtDiff:normalize()
|
||||
FeatureExtraInfo.vtMortisePathStart = EgtSV( idAux, GDB_RT.GLOB) * vtDiff
|
||||
FeatureExtraInfo.vtMortisePathEnd = EgtEV( idAux, GDB_RT.GLOB) * vtDiff
|
||||
FeatureExtraInfo.idAddAuxGeom = idAux
|
||||
|
||||
return FeatureExtraInfo
|
||||
@@ -901,23 +916,16 @@ end
|
||||
function FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
local dProcVolume = 0
|
||||
|
||||
local idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
if not idAddGroup then
|
||||
-- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste?
|
||||
EgtOutLog( 'Error : missing AddGroup')
|
||||
return 0
|
||||
end
|
||||
local idTempGroup = Part.idTempGroup
|
||||
|
||||
local idProcCopy = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) or GDB_ID.NULL
|
||||
local b3PartCopy = BBox3d( Part.b3Part)
|
||||
b3PartCopy:expand( -100 * GEO.EPS_SMALL)
|
||||
local idPartCopy = EgtSurfTmBBox( idAddGroup, b3PartCopy , false, GDB_RT.GLOB)
|
||||
local idPartCopy = EgtSurfTmBBox( idTempGroup, b3PartCopy , false, GDB_RT.GLOB)
|
||||
|
||||
EgtSurfTmSubtract( idPartCopy, idProcCopy)
|
||||
dProcVolume = EgtSurfVolume( idPartCopy)
|
||||
|
||||
EgtErase( { idProcCopy, idPartCopy})
|
||||
|
||||
return dProcVolume
|
||||
end
|
||||
|
||||
@@ -925,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
|
||||
@@ -940,6 +949,7 @@ function FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part)
|
||||
local dNotClampableLengthTail = 0
|
||||
|
||||
-- se il grezzo non è definito, prendo il box del pezzo
|
||||
-- TODO 1- si sta passando b3part per riferimento, 2- non dovrebbe essre sempre definito?
|
||||
if not Part.b3Raw then
|
||||
Part.b3Raw = Part.b3Part
|
||||
end
|
||||
@@ -961,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
|
||||
|
||||
@@ -979,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
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
-- LeadInOutLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria stima collisioni per travi
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local LeadInOutLib = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FaceData = require( 'FaceData')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
EgtOutLog( ' LeadInOutLib started', 1)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetExtraAddLengthInclinedSides( Face, Edge)
|
||||
|
||||
-- se faccia rettangolare i lati sono tutti a 90deg, inutile fare conti
|
||||
if FaceData.IsFaceRectangle( Face) then
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
local nPreviousEdgeIndex = Edge.id + 1 - 1
|
||||
if nPreviousEdgeIndex < 1 then
|
||||
nPreviousEdgeIndex = #Face.Edges
|
||||
end
|
||||
local nNextEdgeIndex = Edge.id + 1 + 1
|
||||
if nNextEdgeIndex > #Face.Edges then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
local vtEdgePrevious = Face.Edges[nPreviousEdgeIndex].vtEdge
|
||||
local vtEdgeNext = Face.Edges[nNextEdgeIndex].vtEdge
|
||||
local dLengthEdgePrevious = Face.Edges[nPreviousEdgeIndex].dLength
|
||||
local dLengthEdgeNext = Face.Edges[nNextEdgeIndex].dLength
|
||||
|
||||
local dExtraPrevious = dLengthEdgePrevious * ( Edge.vtEdge * -vtEdgePrevious)
|
||||
local dExtraNext = dLengthEdgeNext * ( -Edge.vtEdge * vtEdgeNext)
|
||||
|
||||
return dExtraPrevious, dExtraNext
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetPerpendicularLeadInOutDirection( Face, Edge)
|
||||
|
||||
-- informazioni lati adiacenti
|
||||
local nCurrentEdgeIndex = Edge.id + 1
|
||||
local nPreviousEdgeIndex = ( nCurrentEdgeIndex == 1 and #Face.Edges) or nCurrentEdgeIndex - 1
|
||||
local nNextEdgeIndex = ( nCurrentEdgeIndex == #Face.Edges and 1) or nCurrentEdgeIndex + 1
|
||||
local EdgeNext = Face.Edges[nNextEdgeIndex]
|
||||
local EdgePrevious = Face.Edges[nPreviousEdgeIndex]
|
||||
|
||||
-- tra le direzioni dei due lati adiacenti, si sceglie la migliore da cui attaccare, ossia quella più vicina alla perpendicolare al lato di lavoro
|
||||
local dCosAngleStart = -EdgePrevious.vtEdge * Edge.vtN
|
||||
local dCosAngleEnd = EdgeNext.vtEdge * Edge.vtN
|
||||
local vtLeadInOut
|
||||
-- se le due direzioni sono entro i 5° scelgo quella a Z assoluta minore, altrimenti quella più vicino alla perpendicolare
|
||||
-- massima differenza scalare per variazione di 5deg: cos(0) - cos(0 + 5) = 1 - cos(5)
|
||||
local dScalarTolerance = 1 - 0.996
|
||||
if abs( dCosAngleStart - dCosAngleEnd) < dScalarTolerance then
|
||||
if abs( EdgePrevious.vtEdge:getZ()) < abs( EdgeNext.vtEdge:getZ()) then
|
||||
vtLeadInOut = Vector3d( -EdgePrevious.vtEdge)
|
||||
else
|
||||
vtLeadInOut = Vector3d( EdgeNext.vtEdge)
|
||||
end
|
||||
else
|
||||
if dCosAngleStart > dCosAngleEnd then
|
||||
vtLeadInOut = Vector3d( -EdgePrevious.vtEdge)
|
||||
else
|
||||
vtLeadInOut = Vector3d( EdgeNext.vtEdge)
|
||||
end
|
||||
end
|
||||
|
||||
return vtLeadInOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CalculateLeadInOutLength( ptToolCenter, vtNFace, b3Box, vtLeadInOut, Tool)
|
||||
|
||||
-- al momento gestita solo lama
|
||||
if not Tool.sFamily == 'SawBlade' then
|
||||
error(' Tool family not implemented')
|
||||
end
|
||||
|
||||
-- Box del pezzo espansi ortogonalmente alle tre direzioni canoniche X, Y e Z
|
||||
local b3BoxX = BBox3d( b3Box) ; b3BoxX:expand( 0, 1000, 1000)
|
||||
local b3BoxY = BBox3d( b3Box) ; b3BoxY:expand( 1000, 0, 1000)
|
||||
local b3BoxZ = BBox3d( b3Box) ; b3BoxZ:expand( 1000, 1000, 0)
|
||||
|
||||
-- si setta utensile lama per il controllo collisione
|
||||
EgtCAvSetSawTool( Tool.dThickness, Tool.dDiameter, Tool.dThickness, 0, 0)
|
||||
|
||||
-- calcolo distanza di cui retrarre con funzioni Tool Collision Avoidance
|
||||
local dLength = min( EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxX, vtLeadInOut),
|
||||
EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxY, vtLeadInOut),
|
||||
EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxZ, vtLeadInOut))
|
||||
|
||||
return dLength
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function LeadInOutLib.CalculateLeadInOut( sLeadInOutType, Parameters, OptionalParameters)
|
||||
|
||||
-- parametri obbligatori
|
||||
local Face = Parameters.Face
|
||||
local Edge = Parameters.Edge
|
||||
local Part = Parameters.Part
|
||||
local Tool = Parameters.Tool
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
|
||||
-- parametri opzionali
|
||||
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
|
||||
local LeadInOut = {}
|
||||
local bIsStartClosed = not Edge.bIsStartOpen
|
||||
local bIsEndClosed = not Edge.bIsEndOpen
|
||||
|
||||
-- accorciamento per lati chiusi
|
||||
LeadInOut.dToolMarkLength = sqrt( dDepthToMachine * Tool.dDiameter - dDepthToMachine * dDepthToMachine)
|
||||
LeadInOut.dExtraAddLengthStart, LeadInOut.dExtraAddLengthEnd = GetExtraAddLengthInclinedSides( Face, Edge)
|
||||
-- allungamento per faccia singola (aperta in tutte le direzioni)
|
||||
LeadInOut.dAddedLengthOpenFace = BeamData.CUT_EXTRA
|
||||
|
||||
local LeadIn = {}
|
||||
local LeadOut = {}
|
||||
LeadIn.dStartAddLength = 0
|
||||
LeadOut.dEndAddLength = 0
|
||||
LeadIn.nType = MCH_MILL_LI.LINEAR
|
||||
LeadOut.nType = MCH_MILL_LI.LINEAR
|
||||
LeadIn.dPerpDistance = 0
|
||||
LeadOut.dPerpDistance = 0
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dTangentDistance = 0
|
||||
LeadIn.dElevation = 0
|
||||
LeadOut.dElevation = 0
|
||||
LeadIn.dCompLength = 0
|
||||
LeadOut.dCompLength = 0
|
||||
|
||||
-- calcolo allungamenti / accorciamenti
|
||||
if bIsStartClosed and bIsEndClosed then
|
||||
LeadIn.dStartAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthStart
|
||||
LeadOut.dEndAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthEnd
|
||||
elseif bIsStartClosed then
|
||||
LeadIn.dStartAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthStart
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadOut.dEndAddLength = max( -LeadIn.dStartAddLength - Edge.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
elseif bIsEndClosed then
|
||||
LeadOut.dEndAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthEnd
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadIn.dStartAddLength = max( -LeadOut.dEndAddLength - Edge.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
else
|
||||
LeadIn.dStartAddLength = LeadInOut.dAddedLengthOpenFace
|
||||
LeadOut.dEndAddLength = LeadInOut.dAddedLengthOpenFace
|
||||
end
|
||||
|
||||
-- calcolo punti notevoli della lavorazione
|
||||
-- punti di inizio e fine lavorazione alla profondità di lavoro reale, considerando allungamenti/accorciamenti
|
||||
local ptStartAtDepth = Edge.ptStart - Edge.vtEdge * LeadIn.dStartAddLength + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptEndAtDepth = Edge.ptEnd + Edge.vtEdge * LeadOut.dEndAddLength + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
-- punti in centro lama
|
||||
local ptStartBladeCenter = ptStartAtDepth + Edge.vtN * Tool.dDiameter / 2
|
||||
local ptEndBladeCenter = ptEndAtDepth + Edge.vtN * Tool.dDiameter / 2
|
||||
|
||||
-- box per calcolo uscita lama
|
||||
-- se è un taglio di testa o coda va aggiunto il sovramateriale
|
||||
local b3BoxPartExpanded = BBox3d( Part.b3Part)
|
||||
if bCannotSplitRestLength then
|
||||
b3BoxPartExpanded = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation)
|
||||
end
|
||||
-- il box si espande in tutte le direzioni per contemplare la sicurezza CUT_SIC
|
||||
b3BoxPartExpanded:expand( BeamData.CUT_SIC)
|
||||
|
||||
-- calcolo attacco scelto
|
||||
if sLeadInOutType == 'Perpendicular' then
|
||||
|
||||
-- scelta direzione migliore per l'attacco
|
||||
local vtLeadInOut = GetPerpendicularLeadInOutDirection( Face, Edge)
|
||||
|
||||
-- frame solidale al lato di lavoro (X lungo il lato, Y normale al lato)
|
||||
local frEdge = Frame3d( Edge.ptStart, Face.vtN, Edge.vtEdge)
|
||||
|
||||
-- direzione nel frame solidale al lato di lavoro
|
||||
local vtLeadInOuttLoc = Vector3d( vtLeadInOut)
|
||||
vtLeadInOuttLoc:toLoc( frEdge)
|
||||
|
||||
-- calcolo distanza per uscire dal box con questa lama nella direzione vtLeadInOut
|
||||
local dLeadInLength = CalculateLeadInOutLength( ptStartBladeCenter, Face.vtN, b3BoxPartExpanded, vtLeadInOut, Tool)
|
||||
local dLeadOutLength = CalculateLeadInOutLength( ptEndBladeCenter, Face.vtN, b3BoxPartExpanded, vtLeadInOut, Tool)
|
||||
|
||||
-- componenti dell'attacco
|
||||
LeadIn.dPerpDistance = dLeadInLength * vtLeadInOuttLoc:getY()
|
||||
LeadIn.dTangentDistance = dLeadInLength * -vtLeadInOuttLoc:getX()
|
||||
LeadOut.dPerpDistance = dLeadOutLength * vtLeadInOuttLoc:getY()
|
||||
LeadOut.dTangentDistance = dLeadOutLength * vtLeadInOuttLoc:getX()
|
||||
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = Point3d( ptStartAtDepth + vtLeadInOut * dLeadInLength)
|
||||
LeadOut.ptPoint = Point3d( ptEndAtDepth + vtLeadInOut * dLeadOutLength)
|
||||
|
||||
elseif sLeadInOutType == 'Tangent' then
|
||||
|
||||
-- calcolo distanza per uscire dal box con questa lama nella direzione tangenziale
|
||||
local dLeadInLength = CalculateLeadInOutLength( ptStartBladeCenter, Face.vtN, b3BoxPartExpanded, -Edge.vtEdge, Tool)
|
||||
local dLeadOutLength = CalculateLeadInOutLength( ptEndBladeCenter, Face.vtN, b3BoxPartExpanded, Edge.vtEdge, Tool)
|
||||
|
||||
-- componenti dell'attacco
|
||||
LeadIn.dPerpDistance = 0
|
||||
LeadIn.dTangentDistance = dLeadInLength
|
||||
LeadOut.dPerpDistance = 0
|
||||
LeadOut.dTangentDistance = dLeadOutLength
|
||||
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = Point3d( ptStartAtDepth - Edge.vtEdge * dLeadInLength)
|
||||
LeadOut.ptPoint = Point3d( ptEndAtDepth + Edge.vtEdge * dLeadOutLength)
|
||||
end
|
||||
|
||||
-- lunghezza totale attacco
|
||||
LeadIn.dTotalLength = sqrt( LeadIn.dPerpDistance ^ 2 + LeadIn.dTangentDistance ^ 2)
|
||||
LeadOut.dTotalLength = sqrt( LeadOut.dPerpDistance ^ 2 + LeadOut.dTangentDistance ^ 2)
|
||||
|
||||
LeadInOut.dTotalLength = LeadIn.dTotalLength + LeadOut.dTotalLength
|
||||
LeadInOut.LeadIn = LeadIn
|
||||
LeadInOut.LeadOut = LeadOut
|
||||
|
||||
return LeadInOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function LeadInOutLib.InvertLeadInOut( LeadIn, LeadOut)
|
||||
|
||||
local dOriginalStartAddLength = LeadIn.dStartAddLength
|
||||
local dOriginalEndAddLength = LeadOut.dEndAddLength
|
||||
|
||||
LeadIn, LeadOut = LeadOut, LeadIn
|
||||
|
||||
LeadIn.dStartAddLength = dOriginalEndAddLength
|
||||
LeadOut.dEndAddLength = dOriginalStartAddLength
|
||||
LeadIn.dEndAddLength = nil
|
||||
LeadOut.dStartAddLength = nil
|
||||
|
||||
return LeadIn, LeadOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return LeadInOutLib
|
||||
+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
|
||||
|
||||
+545
-194
@@ -9,11 +9,12 @@ local MachiningLib = {}
|
||||
require( 'EgtBase')
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local BCS = require( 'BasicCustomerStrategies')
|
||||
local FaceData = require ( 'FaceData')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
local LeadInOutLib = require( 'LeadInOutLib')
|
||||
|
||||
EgtOutLog( ' MachiningLib started', 1)
|
||||
|
||||
@@ -96,15 +97,29 @@ function MachiningLib.CanExtendAfterTail( sCanDamageNextPiece, Part)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function MachiningLib.GetMachiningSteps( dMachiningDepth, dStep)
|
||||
function MachiningLib.IsFeatureHinderingClamping( Proc, Part)
|
||||
local bFeatureHindersClamping
|
||||
|
||||
local dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail = FeatureLib.GetFeatureMaxNotClampableLengths( Proc, Part)
|
||||
bFeatureHindersClamping = FeatureLib.IsMachiningLong( max( dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
|
||||
return bFeatureHindersClamping
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function MachiningLib.GetMachiningSteps( bIsSlot, dMachiningDepth, dStep)
|
||||
local MachiningSteps = {}
|
||||
MachiningSteps.dStep = 0
|
||||
MachiningSteps.nCount = ceil( ( dMachiningDepth - 50 * GEO.EPS_SMALL) / dStep)
|
||||
if MachiningSteps.nCount > 1 then
|
||||
MachiningSteps.dStep = ( dMachiningDepth - dStep) / ( MachiningSteps.nCount - 1)
|
||||
-- se è una slot, dMachiningDepth è l'altezza della tasca e nel calcolo step si deve considerare lo spessore dell'utensile
|
||||
if bIsSlot then
|
||||
if MachiningSteps.nCount > 1 then
|
||||
MachiningSteps.dStep = ( dMachiningDepth - dStep) / ( MachiningSteps.nCount - 1)
|
||||
else
|
||||
MachiningSteps.dStep = dMachiningDepth
|
||||
MachiningSteps.nCount = 1
|
||||
end
|
||||
else
|
||||
MachiningSteps.dStep = dMachiningDepth
|
||||
MachiningSteps.nCount = 1
|
||||
MachiningSteps.dStep = dStep
|
||||
end
|
||||
|
||||
return MachiningSteps
|
||||
@@ -267,12 +282,203 @@ local function IsToolInAvailableToolList( AvailableToolList, sTool)
|
||||
return bToolFound
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- in base a tipo testa e angolo soglia, verifica se la faccia è troppo inclinata per la lavorazione scelta (per DownUp passare vtNFace opposta)
|
||||
function MachiningLib.IsFaceZOutOfRange( vtNFace, Tool)
|
||||
|
||||
-- lama sopra: angolo negativo troppo basso
|
||||
if Tool.SetupInfo.HeadType.bTop and vtNFace:getZ() < Tool.SetupInfo.GetMinNz( vtNFace, Tool) - GEO.EPS_ZERO then
|
||||
return true
|
||||
end
|
||||
-- lama sotto: angolo positivo troppo elevato
|
||||
if Tool.SetupInfo.HeadType.bBottom and vtNFace:getZ() > Tool.SetupInfo.GetMaxNz( vtNFace, Tool) + GEO.EPS_ZERO then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function TestEngagement( sBladeEngagement, Parameters, OptionalParameters)
|
||||
|
||||
-- parametri obbligatori (parametri opzionali transitano solamente)
|
||||
local Face = Parameters.Face
|
||||
local Edge = Parameters.Edge
|
||||
local Part = Parameters.Part
|
||||
local Tool = Parameters.Tool
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
|
||||
-- il lato della testa cambia in base all'Engagement
|
||||
local vtHead
|
||||
if sBladeEngagement == 'Standard' then
|
||||
vtHead = Face.vtN
|
||||
elseif sBladeEngagement == 'DownUp' then
|
||||
vtHead = -Face.vtN
|
||||
else
|
||||
error( 'TestEngagement : unknown engagement')
|
||||
end
|
||||
|
||||
-- se l'angolo non può essere raggiunto dall'utensile la lavorazione non è fattibile
|
||||
if MachiningLib.IsFaceZOutOfRange( vtHead, Tool) then
|
||||
return false
|
||||
end
|
||||
|
||||
local CheckCollisionParameters = {
|
||||
Edge = Edge,
|
||||
vtNFace = Face.vtN,
|
||||
vtHead = vtHead,
|
||||
Part = Part,
|
||||
Tool = Tool,
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
|
||||
local CheckCollisionOptionalParameters = BeamLib.TableCopyDeep( OptionalParameters or {})
|
||||
|
||||
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, Face.vtN)
|
||||
|
||||
-- check punti lavorazione
|
||||
-- lavorazione oltre le corse: non fattibile
|
||||
local PointsOnToolTipCenter = {
|
||||
PreSimulationLib.GetPointOnToolTipCenter( Edge.ptStart + Edge.vtN * ( Edge.dElevation - dDepthToMachine), vtHead, Face.vtN, Edge.vtN, Tool),
|
||||
PreSimulationLib.GetPointOnToolTipCenter( Edge.ptEnd + Edge.vtN * ( Edge.dElevation - dDepthToMachine), vtHead, Face.vtN, Edge.vtN, Tool)
|
||||
}
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
if bOutOfStroke then
|
||||
return false
|
||||
end
|
||||
-- lavorazione in collisione con il pezzo: non fattibile
|
||||
local bCollisionFound, bMoveAfterSplit = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters)
|
||||
if bCollisionFound then
|
||||
return false
|
||||
end
|
||||
|
||||
-- calcolo e check attacchi
|
||||
local LeadInOut = {}
|
||||
local LeadInOutOptionalParameters = {
|
||||
sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength,
|
||||
bMoveAfterSplit = bMoveAfterSplit
|
||||
}
|
||||
|
||||
-- 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)
|
||||
-- attacco perpendicolare non in extracorsa: si verifica se è in collisione
|
||||
if not bOutOfStrokePerpendicular then
|
||||
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
|
||||
if bOutOfStrokePerpendicular then
|
||||
return false
|
||||
else
|
||||
LeadInOut.sChosen = 'Perpendicular'
|
||||
return true, bMoveAfterSplit, LeadInOut
|
||||
end
|
||||
end
|
||||
|
||||
-- attacco tangenziale
|
||||
local TangentLeadInOut = LeadInOutLib.CalculateLeadInOut( 'Tangent', Parameters, LeadInOutOptionalParameters)
|
||||
-- check extracorsa nei punti di attacco
|
||||
PointsOnToolTipCenter = {
|
||||
PreSimulationLib.GetPointOnToolTipCenter( TangentLeadInOut.LeadIn.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool),
|
||||
PreSimulationLib.GetPointOnToolTipCenter( TangentLeadInOut.LeadOut.ptPoint, vtHead, Face.vtN, Edge.vtN, Tool)
|
||||
}
|
||||
local bOutOfStrokeTangent = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool)
|
||||
-- attacco tangenziale non in extracorsa: si verifica se è in collisione
|
||||
if not bOutOfStrokeTangent then
|
||||
CheckCollisionOptionalParameters.PointsToCheck = {}
|
||||
table.insert( CheckCollisionOptionalParameters.PointsToCheck, TangentLeadInOut.LeadIn.ptPoint)
|
||||
table.insert( CheckCollisionOptionalParameters.PointsToCheck, TangentLeadInOut.LeadOut.ptPoint)
|
||||
local bCollisionFoundTangent, bMoveAfterSplitTangent = PreSimulationLib.CheckCollision( sBladeEngagement, CheckCollisionParameters, CheckCollisionOptionalParameters)
|
||||
-- attacco tangenziale possibile
|
||||
if not bCollisionFoundTangent then
|
||||
LeadInOut.Tangent = TangentLeadInOut
|
||||
LeadInOut.Tangent.bMoveAfterSplit = bMoveAfterSplitTangent
|
||||
end
|
||||
end
|
||||
|
||||
-- se disponibili più attacchi si sceglie il più corto, altrimenti quello possibile
|
||||
if LeadInOut.Perpendicular and LeadInOut.Tangent then
|
||||
if LeadInOut.Perpendicular.dTotalLength > LeadInOut.Tangent.dTotalLength + 10 then
|
||||
LeadInOut.sChosen = 'Tangent'
|
||||
else
|
||||
LeadInOut.sChosen = 'Perpendicular'
|
||||
end
|
||||
elseif LeadInOut.Perpendicular and not LeadInOut.Tangent then
|
||||
LeadInOut.sChosen = 'Perpendicular'
|
||||
elseif LeadInOut.Tangent and not LeadInOut.Perpendicular then
|
||||
LeadInOut.sChosen = 'Tangent'
|
||||
-- nessun attacco possibile
|
||||
-- TODO qui invece di uscire si dovranno provare i due attacchi SpecialTangent e SpecialTangentInverted
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
return true, bMoveAfterSplit, LeadInOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- ritorna se la faccia e il lato sono lavorabili e, se sì, il modo di lavorare (standard/DownUp) e i tipi di attacco disponibili
|
||||
-- TODO si dovrà decidere come tagliare anche se pezzo corto (il motore non deve ingombrare con il pinzaggio)
|
||||
-- TODO da gestire riduzione percorso
|
||||
function MachiningLib.GetBladeEngagement( Parameters, OptionalParameters)
|
||||
|
||||
local Engagement
|
||||
|
||||
-- test lavorazione faccia in modo standard (no DownUp)
|
||||
local bIsEngagementOk, bMoveAfterSplit, LeadInOut = TestEngagement( 'Standard', Parameters, OptionalParameters)
|
||||
|
||||
if bIsEngagementOk then
|
||||
|
||||
Engagement = {
|
||||
sBladeEngagement = 'Standard',
|
||||
bMoveAfterSplit = bMoveAfterSplit,
|
||||
LeadInOut = LeadInOut
|
||||
}
|
||||
return true, Engagement
|
||||
end
|
||||
|
||||
-- faccia non lavorabile in modo standard: si verifica se il DownUp è fattibile
|
||||
bIsEngagementOk, bMoveAfterSplit, LeadInOut = TestEngagement( 'DownUp', Parameters, OptionalParameters)
|
||||
|
||||
if bIsEngagementOk then
|
||||
|
||||
Engagement = {
|
||||
sBladeEngagement = 'DownUp',
|
||||
bMoveAfterSplit = bMoveAfterSplit,
|
||||
LeadInOut = LeadInOut
|
||||
}
|
||||
return true, Engagement
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione per cercare utensile tipo FRESA con certe caratteristiche
|
||||
-- TODO qui vtToolDirection è in realtà vtN
|
||||
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
|
||||
@@ -316,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
|
||||
@@ -383,14 +601,14 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione per cercare utensile tipo LAMA con certe caratteristiche
|
||||
-- TODO da completare
|
||||
-- TODO il FindBlade dovrà restituire di utilizzare sempre la lama sopra se l'angolo lo permette, ma avendo un'altezza massima (da macchina) oltre cui il DownUp non sarà fattibile (evita collisioni tra asse e pezzo)
|
||||
-- TODO da rivedere/completare
|
||||
-- TODO per Engagement serviranno (opzionali) sBlockedAxis e vtAux
|
||||
function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
local ToolInfo = {}
|
||||
|
||||
-- parametri obbligatori
|
||||
if type( ToolSearchParameters.vtN) ~= 'table' then
|
||||
error( 'FindBlade : missing tool direction')
|
||||
if type( ToolSearchParameters.FaceToMachine) ~= 'table' then
|
||||
error( 'FindBlade : missing face info')
|
||||
end
|
||||
if type( ToolSearchParameters.bAllowTopHead) ~= 'boolean' then
|
||||
error( 'FindBlade : missing top head info')
|
||||
@@ -401,32 +619,69 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
if not ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
||||
error( 'FindBlade : wrong head info')
|
||||
end
|
||||
local FaceToMachine = ToolSearchParameters.FaceToMachine
|
||||
local bAllowTopHead = ToolSearchParameters.bAllowTopHead
|
||||
local bAllowBottomHead = ToolSearchParameters.bAllowBottomHead
|
||||
|
||||
-- parametri opzionali
|
||||
ToolSearchParameters.dElevation = ToolSearchParameters.dElevation or 0
|
||||
ToolSearchParameters.bForceLongcutBlade = ToolSearchParameters.bForceLongcutBlade or false
|
||||
local dElevation = ToolSearchParameters.dElevation
|
||||
local bForceLongcutBlade = ToolSearchParameters.bForceLongcutBlade or false
|
||||
local EdgeToMachine = ToolSearchParameters.EdgeToMachine
|
||||
local Part = ToolSearchParameters.Part
|
||||
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
|
||||
local CurrentEngagement
|
||||
local BestEngagement
|
||||
for i = 1, #TOOLS do
|
||||
local bIsToolCompatible = false
|
||||
|
||||
if TOOLS[i].sFamily == 'SAWBLADE' then
|
||||
if ToolSearchParameters.bAllowTopHead and not ToolSearchParameters.bAllowBottomHead then
|
||||
if bAllowTopHead and not bAllowBottomHead then
|
||||
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bTop
|
||||
elseif ToolSearchParameters.bAllowBottomHead and not ToolSearchParameters.bAllowTopHead then
|
||||
elseif bAllowBottomHead and not bAllowTopHead then
|
||||
bIsToolCompatible = TOOLS[i].SetupInfo.HeadType.bBottom
|
||||
else
|
||||
bIsToolCompatible = true
|
||||
end
|
||||
end
|
||||
|
||||
-- check angolo limite lama
|
||||
if TOOLS[i].SetupInfo.HeadType.bTop and ToolSearchParameters.vtN:getZ() < TOOLS[i].SetupInfo.GetMinNz( ToolSearchParameters.vtN, TOOLS[i]) - GEO.EPS_ZERO then
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
if TOOLS[i].SetupInfo.HeadType.bBottom and ToolSearchParameters.vtN:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtN, TOOLS[i]) + GEO.EPS_ZERO then
|
||||
bIsToolCompatible = false
|
||||
-- se dati sufficienti, si determina se con questo utensile il taglio è fattibile e il modo di lavorare della lama
|
||||
-- TODO corretto il calcolo della dDepthToMachine? è comunque inutile calcolare per una profondità che so già andrà in collisione
|
||||
if bIsToolCompatible then
|
||||
if FaceToMachine and EdgeToMachine and Part and dElevation then
|
||||
local bIsBladeOk = false
|
||||
local BladeEngagementParameters = {
|
||||
Face = FaceToMachine,
|
||||
Edge = EdgeToMachine,
|
||||
Part = Part,
|
||||
Tool = TOOLS[i],
|
||||
dDepthToMachine = min( dElevation, TOOLS[i].dMaxDepth)
|
||||
}
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
bIsBladeOk, CurrentEngagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
||||
TIMER:stopElapsed( 'GetBladeEngagement')
|
||||
-- orientamento non raggiungibile
|
||||
if not bIsBladeOk then
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
|
||||
-- se si ha solo la faccia si può verificare se questa è orientata correttamente
|
||||
elseif FaceToMachine then
|
||||
if MachiningLib.IsFaceZOutOfRange( FaceToMachine.vtN, TOOLS[i]) then
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se c'è una lista di utensili disponibili, si verifica che l'utensile attuale sia tra quelli
|
||||
@@ -436,15 +691,17 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
|
||||
if bIsToolCompatible then
|
||||
-- TODO gestire accorciamento massimo materiale per inclinazione
|
||||
local dCurrentResidualDepth = ToolSearchParameters.dElevation - TOOLS[i].dMaxDepth
|
||||
local dCurrentResidualDepth = ( dElevation or 0) - TOOLS[i].dMaxDepth
|
||||
if not nBestToolIndex or ( dBestToolResidualDepth > 0 and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL) then
|
||||
nBestToolIndex = i
|
||||
dBestToolResidualDepth = dCurrentResidualDepth
|
||||
BestEngagement = CurrentEngagement
|
||||
else
|
||||
-- prediligo utensile per tagli lunghi, se richiesto
|
||||
if ToolSearchParameters.bForceLongcutBlade and not TOOLS[nBestToolIndex].bIsUsedForLongCut and TOOLS[i].bIsUsedForLongCut then
|
||||
-- prediligo utensile per tagli lungo vena, se richiesto
|
||||
if bForceLongcutBlade and not TOOLS[nBestToolIndex].bIsUsedForLongCut and TOOLS[i].bIsUsedForLongCut then
|
||||
nBestToolIndex = i
|
||||
dBestToolResidualDepth = dCurrentResidualDepth
|
||||
BestEngagement = CurrentEngagement
|
||||
else
|
||||
-- entrambi completi
|
||||
if dBestToolResidualDepth <= 10 * GEO.EPS_SMALL and dCurrentResidualDepth <= 10 * GEO.EPS_SMALL then
|
||||
@@ -455,11 +712,13 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
GetIndexToolInAvailableToolList( ToolSearchParameters.AvailableToolList, TOOLS[nBestToolIndex].sName) then
|
||||
nBestToolIndex = i
|
||||
dBestToolResidualDepth = dCurrentResidualDepth
|
||||
BestEngagement = CurrentEngagement
|
||||
end
|
||||
-- si sceglie quello con le performance migliori
|
||||
elseif TOOLS[i].dPerformanceIndex > TOOLS[nBestToolIndex].dPerformanceIndex + 10 * GEO.EPS_SMALL then
|
||||
nBestToolIndex = i
|
||||
dBestToolResidualDepth = dCurrentResidualDepth
|
||||
BestEngagement = CurrentEngagement
|
||||
end
|
||||
-- entrambi incompleti
|
||||
elseif dBestToolResidualDepth > 10 * GEO.EPS_SMALL and dCurrentResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
@@ -467,6 +726,7 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
if dCurrentResidualDepth > dBestToolResidualDepth then
|
||||
nBestToolIndex = i
|
||||
dBestToolResidualDepth = dCurrentResidualDepth
|
||||
BestEngagement = CurrentEngagement
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -476,6 +736,7 @@ function MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
|
||||
ToolInfo.nToolIndex = nBestToolIndex
|
||||
ToolInfo.dResidualDepth = dBestToolResidualDepth
|
||||
ToolInfo.Engagement = BestEngagement
|
||||
|
||||
return ToolInfo
|
||||
end
|
||||
@@ -492,10 +753,10 @@ function MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam or 0
|
||||
end
|
||||
if not ToolSearchParameters.dMaxToolDiameter then
|
||||
ToolSearchParameters.dMaxToolDiameter = ToolSearchParameters.dToolDiameter + ( ToolSearchParameters.dDiameterTolerance or ( 100 * GEO.EPS_SMALL))
|
||||
ToolSearchParameters.dMaxToolDiameter = ToolSearchParameters.dToolDiameter + ( ToolSearchParameters.dDiameterTolerance or 0) + ( 10 * GEO.EPS_SMALL)
|
||||
end
|
||||
if not ToolSearchParameters.dMinToolDiameter then
|
||||
ToolSearchParameters.dMinToolDiameter = ToolSearchParameters.dToolDiameter - ( ToolSearchParameters.dDiameterTolerance or ( 100 * GEO.EPS_SMALL))
|
||||
ToolSearchParameters.dMinToolDiameter = ToolSearchParameters.dToolDiameter - ( ToolSearchParameters.dDiameterTolerance or 0) - ( 10 * GEO.EPS_SMALL)
|
||||
end
|
||||
|
||||
for i = 1, #TOOLS do
|
||||
@@ -521,6 +782,8 @@ function MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
elseif TOOLS[i].SetupInfo.HeadType.bBottom and
|
||||
ToolSearchParameters.vtToolDirection:getZ() > TOOLS[i].SetupInfo.GetMaxNz( ToolSearchParameters.vtToolDirection, TOOLS[i]) + GEO.EPS_ZERO then
|
||||
bIsToolCompatible = false
|
||||
elseif PreSimulationLib.CheckOutOfStrokeFromPoints( ToolSearchParameters.ptCheckOutStroke, ToolSearchParameters.vtToolDirection, 0, TOOLS[i]) then
|
||||
bIsToolCompatible = false
|
||||
end
|
||||
|
||||
-- scelgo il migliore
|
||||
@@ -843,7 +1106,7 @@ local function AddNewMachining( ProcToAdd, MachiningToAdd, AuxiliaryDataToAdd)
|
||||
nHeadCutRotation = 3
|
||||
elseif ProcToAdd.bSide then
|
||||
nHeadCutRotation = 2
|
||||
else
|
||||
else -- ProcToAdd.bStd
|
||||
nHeadCutRotation = 1
|
||||
end
|
||||
MACHININGS.Info.nHeadCutRotation = max( MACHININGS.Info.nHeadCutRotation or 0, nHeadCutRotation)
|
||||
@@ -853,7 +1116,7 @@ local function AddNewMachining( ProcToAdd, MachiningToAdd, AuxiliaryDataToAdd)
|
||||
nSplitCutRotation = 3
|
||||
elseif ProcToAdd.bSide and MachiningToAdd.sStage == 'AfterTail' then
|
||||
nSplitCutRotation = 2
|
||||
else
|
||||
else -- ProcToAdd.bStd
|
||||
nSplitCutRotation = 1
|
||||
end
|
||||
MACHININGS.Info.nSplitCutRotation = max( MACHININGS.Info.nSplitCutRotation or 0, nSplitCutRotation)
|
||||
@@ -904,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 = {
|
||||
@@ -983,17 +1262,20 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
|
||||
for i = 1, #MACHININGS do
|
||||
-- si aggiungono solo quelle della fase richiesta
|
||||
if ( sRotation == 'STD' and not MACHININGS[i].Proc.bDown and not MACHININGS[i].Proc.bSide) or
|
||||
if ( MACHININGS[i].Proc.bStd and sRotation == 'STD') or
|
||||
( MACHININGS[i].Proc.bDown and sRotation == 'DOWN') or
|
||||
( MACHININGS[i].Proc.bSide and sRotation == 'SIDE') then
|
||||
local nClonesToAdd = 1
|
||||
if MACHININGS[i].AuxiliaryData.Clones then
|
||||
nClonesToAdd = #MACHININGS[i].AuxiliaryData.Clones
|
||||
end
|
||||
-- dati da salvare dopo applicazione della lavorazione
|
||||
MACHININGS[i].Machining.MachStartAxesPos = {}
|
||||
MACHININGS[i].Machining.MachEndAxesPos = {}
|
||||
MACHININGS[i].Machining.nOperationId = {}
|
||||
for j = 1, nClonesToAdd do
|
||||
-- creazione lavorazione
|
||||
local nOperationId = EgtCreateMachining( MACHININGS[i].Machining.sOperationName, MACHININGS[i].Machining.nType, MACHININGS[i].Machining.sToolName)
|
||||
|
||||
if nOperationId then
|
||||
-- impostazione geometria
|
||||
local Geometry
|
||||
@@ -1091,45 +1373,74 @@ function MachiningLib.AddOperations( vProc, Part, sRotation)
|
||||
end
|
||||
|
||||
local bIsApplyOk = MachiningLib.ApplyMachining( true, false)
|
||||
|
||||
-- si salva sulla lista info lavorazione applicata
|
||||
local MachExtraInfo = { sType = 'MACH',
|
||||
nIndexInMachinings = i,
|
||||
nOperationId = nOperationId,
|
||||
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'
|
||||
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.sApplyInfo = sErr
|
||||
RESULT[MACHININGS[i].Proc.nIndexInResult].ChosenStrategy.nApplyError = nErr
|
||||
-- se non deve essere igniorato, si salva ingombro lavorazione attuale e fasi successive
|
||||
elseif not MACHININGS[i].AuxiliaryData.bIgnoreNotClampableLength then
|
||||
-- salvo ingombro non pinzabile testa/coda
|
||||
local nCurrRotation = MACHININGS[i].Proc.nIndexRotation
|
||||
local dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nCurrRotation)
|
||||
Part.NotClampableLength[sRotation].dHead = max( Part.NotClampableLength[sRotation].dHead, dNotClampHead)
|
||||
Part.NotClampableLength[sRotation].dTail = max( Part.NotClampableLength[sRotation].dTail, dNotClampTail)
|
||||
-- se applicazione andata a buon fine
|
||||
else
|
||||
|
||||
if sRotation == 'DOWN' then
|
||||
-- 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
|
||||
local dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nCurrRotation)
|
||||
Part.NotClampableLength[sRotation].dHead = max( Part.NotClampableLength[sRotation].dHead, dNotClampHead)
|
||||
Part.NotClampableLength[sRotation].dTail = max( Part.NotClampableLength[sRotation].dTail, dNotClampTail)
|
||||
|
||||
if sRotation == 'DOWN' then
|
||||
local nNextRotation = EgtIf( nCurrRotation - 1 < 1, nCurrRotation - 1 + 4, nCurrRotation - 1)
|
||||
-- se rotazione attiva (SIDE)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['SIDE'].dHead = max( Part.NotClampableLength['SIDE'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['SIDE'].dTail = max( Part.NotClampableLength['SIDE'].dTail, dNotClampTail)
|
||||
end
|
||||
nNextRotation = EgtIf( nNextRotation - 1 < 1, nNextRotation - 1 + 4, nNextRotation - 1)
|
||||
-- se rotazione attiva (STD)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
||||
end
|
||||
elseif sRotation == 'SIDE' then
|
||||
local nNextRotation = EgtIf( nCurrRotation - 1 < 1, nCurrRotation - 1 + 4, nCurrRotation - 1)
|
||||
-- se rotazione attiva (SIDE)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['SIDE'].dHead = max( Part.NotClampableLength['SIDE'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['SIDE'].dTail = max( Part.NotClampableLength['SIDE'].dTail, dNotClampTail)
|
||||
end
|
||||
nNextRotation = EgtIf( nNextRotation - 1 < 1, nNextRotation - 1 + 4, nNextRotation - 1)
|
||||
-- se rotazione attiva (STD)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
||||
end
|
||||
elseif sRotation == 'SIDE' then
|
||||
local nNextRotation = EgtIf( nCurrRotation - 1 < 1, nCurrRotation - 1 + 4, nCurrRotation - 1)
|
||||
-- se rotazione attiva (STD)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
||||
-- se rotazione attiva (STD)
|
||||
if string.sub( Part.ChosenCombination, nNextRotation, nNextRotation) == '1' then
|
||||
dNotClampHead, dNotClampTail = FeatureLib.GetFeatureRotationNotClampableLengths( MACHININGS[i].Proc, Part, nNextRotation)
|
||||
Part.NotClampableLength['STD'].dHead = max( Part.NotClampableLength['STD'].dHead, dNotClampHead)
|
||||
Part.NotClampableLength['STD'].dTail = max( Part.NotClampableLength['STD'].dTail, dNotClampTail)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1141,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
|
||||
@@ -1157,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
|
||||
@@ -1192,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
|
||||
|
||||
@@ -1234,7 +1547,19 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
local dToolEndFeed = TOOLS[Machining.nToolIndex].Feeds.dEndFeed
|
||||
local dToolFeed = TOOLS[Machining.nToolIndex].Feeds.dFeed
|
||||
|
||||
if Machining.nType == MCH_MY.MILLING then
|
||||
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 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 = ( ( 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
|
||||
if not Machining.LeadIn.dTotalEstimatedDistance then
|
||||
Machining.LeadIn.dTotalEstimatedDistance = sqrt( Machining.LeadIn.dPerpDistance ^ 2 + Machining.LeadIn.dTangentDistance ^ 2) + Machining.dStartSafetyLength
|
||||
@@ -1284,9 +1609,9 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
local ProcTm = FeatureLib.GetProcFromTrimesh( Machining.Geometry[1][1], Part)
|
||||
local dDepthToMachine = min( ProcTm.Faces[Machining.Geometry[1][2] + 1].dElevation, ( Machining.dMaxElev or ProcTm.Faces[Machining.Geometry[1][2] + 1].dElevation)) - ( max( 0, Machining.dResidualDepth or 0))
|
||||
local nSteps = max( ceil( ( dDepthToMachine - 50 * GEO.EPS_SMALL) / TOOLS[Machining.nToolIndex].dStep), 1)
|
||||
local nAddGroupId = BeamLib.GetAddGroup( Part.id)
|
||||
local idTempGroup = Part.idTempGroup
|
||||
-- TODO in futuro creare flatregion (se ci fossero isole il calcolo del percorso non sarebbe corretto)
|
||||
local idFaceContour = EgtExtractSurfTmFacetLoops( ProcTm.id, Machining.Geometry[1][2], nAddGroupId)
|
||||
local idFaceContour = EgtExtractSurfTmFacetLoops( ProcTm.id, Machining.Geometry[1][2], idTempGroup)
|
||||
-- si settano i lati aperti della curva derivata dalla superficie
|
||||
for i = 1, #ProcTm.Faces[Machining.Geometry[1][2] + 1].Edges do
|
||||
if ProcTm.Faces[Machining.Geometry[1][2] + 1].Edges[i].bIsOpen then
|
||||
@@ -1294,7 +1619,7 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
end
|
||||
end
|
||||
-- dal momento che la funzione EgtPocketing non considera il grezzo, nei casi ottimizzati si deve correggere l'offset
|
||||
local idTestCurve = EgtCopyGlob( idFaceContour, nAddGroupId )
|
||||
local idTestCurve = EgtCopyGlob( idFaceContour, idTempGroup )
|
||||
local bIsOptimizedPocketing = ( TOOLS[Machining.nToolIndex].dDiameter > TOOLS[Machining.nToolIndex].dSideStep - 10 * GEO.EPS_SMALL)
|
||||
and EgtOffsetCurve( idTestCurve, -TOOLS[Machining.nToolIndex].dDiameter / 2 - 10 * GEO.EPS_SMALL)
|
||||
if not bIsOptimizedPocketing then
|
||||
@@ -1310,7 +1635,7 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
end
|
||||
end
|
||||
-- calcolo percorso di svuotatura replicando il calcolo che fa la svuotatura
|
||||
local idPocketingPath = EgtPocketing( idFaceContour, TOOLS[Machining.nToolIndex].dDiameter / 2, TOOLS[Machining.nToolIndex].dSideStep, 0, Machining.nSubType, true, nAddGroupId)
|
||||
local idPocketingPath = EgtPocketing( idFaceContour, TOOLS[Machining.nToolIndex].dDiameter / 2, TOOLS[Machining.nToolIndex].dSideStep, 0, Machining.nSubType, true, idTempGroup)
|
||||
local dPocketingPathLength = EgtCurveLength( idPocketingPath)
|
||||
-- calcolo lunghezze e tempi totali
|
||||
if dPocketingPathLength then
|
||||
@@ -1322,10 +1647,6 @@ function MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
dLengthToMachineAllStepsWithLeadInOut = 99999 * nSteps
|
||||
dTimeToMachineTotal = dLengthToMachineAllStepsWithLeadInOut / dToolFeed
|
||||
end
|
||||
-- le geometrie create si settano da cancellare
|
||||
EgtSetLevel( idFaceContour, GDB_LV.TEMP)
|
||||
EgtSetLevel( idPocketingPath, GDB_LV.TEMP)
|
||||
EgtSetLevel( idTestCurve, GDB_LV.TEMP)
|
||||
else
|
||||
error( 'GetTimeToMachineAllStepsWithLeadInOut : unknown machining type')
|
||||
end
|
||||
@@ -1429,19 +1750,6 @@ end
|
||||
-- TODO libreria Sorting??
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local SortingComparisonRules = {
|
||||
-- ordine interno alla feature
|
||||
function( MachiningA, MachiningB)
|
||||
if MachiningA.Proc.id == MachiningB.Proc.id then
|
||||
if MachiningA.Machining.nFeatureInternalIndex < MachiningB.Machining.nFeatureInternalIndex then
|
||||
return 1
|
||||
elseif MachiningA.Machining.nFeatureInternalIndex > MachiningB.Machining.nFeatureInternalIndex then
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end,
|
||||
|
||||
-- dipendenze solo spostamento stage 2->4
|
||||
-- TODO da fare
|
||||
|
||||
@@ -1455,110 +1763,6 @@ local SortingComparisonRules = {
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- dipendenze
|
||||
-- TODO da fare
|
||||
|
||||
-- segment
|
||||
function ( MachiningA, MachiningB)
|
||||
if MachiningA.Machining.nPartSegment < MachiningB.Machining.nPartSegment then
|
||||
return 1
|
||||
elseif MachiningA.Machining.nPartSegment > MachiningB.Machining.nPartSegment then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- testa
|
||||
-- TODO da fare
|
||||
|
||||
-- famiglia utensile
|
||||
function ( MachiningA, MachiningB)
|
||||
-- TODO tirare fuori da qua??
|
||||
local ToolFamilyOrder = {
|
||||
SAWBLADE = 1,
|
||||
DRILLBIT = 2,
|
||||
MILL = 3,
|
||||
MORTISE = 4
|
||||
}
|
||||
local nToolFamilyOrderA = ToolFamilyOrder[ TOOLS[ MachiningA.Machining.nToolIndex].sFamily]
|
||||
local nToolFamilyOrderB = ToolFamilyOrder[ TOOLS[ MachiningB.Machining.nToolIndex].sFamily]
|
||||
|
||||
if nToolFamilyOrderA < nToolFamilyOrderB then
|
||||
return 1
|
||||
elseif nToolFamilyOrderA > nToolFamilyOrderB then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- performance utensile
|
||||
function( MachiningA, MachiningB)
|
||||
local dToolPerformanceIndexA = TOOLS[MachiningA.Machining.nToolIndex].dPerformanceIndex
|
||||
local dToolPerformanceIndexB = TOOLS[MachiningB.Machining.nToolIndex].dPerformanceIndex
|
||||
|
||||
if dToolPerformanceIndexA > dToolPerformanceIndexB then
|
||||
return 1
|
||||
elseif dToolPerformanceIndexA < dToolPerformanceIndexB then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- probabilmente arrivati qui significa che gli utensili A e B sono gli stessi
|
||||
-- se così non fosse e tutte le caratteristiche sopra sono uguali, ordine alfabetico
|
||||
function( MachiningA, MachiningB)
|
||||
local sToolNameA = TOOLS[MachiningA.Machining.nToolIndex].sName
|
||||
local sToolNameB = TOOLS[MachiningB.Machining.nToolIndex].sName
|
||||
|
||||
if sToolNameA < sToolNameB then
|
||||
return 1
|
||||
elseif sToolNameA > sToolNameB then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- lato di lavoro
|
||||
-- TODO questo, insieme all'ordinamento X, andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
||||
function( MachiningA, MachiningB)
|
||||
if MachiningA.Machining.vtToolDirection:getY() < -0.174 and MachiningB.Machining.vtToolDirection:getY() >= 0.174 then
|
||||
return 1
|
||||
elseif MachiningA.Machining.vtToolDirection:getY() >= 0.174 and MachiningB.Machining.vtToolDirection:getY() < -0.174 then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
-- ordinamento X
|
||||
-- TODO questo andrà sostituito dallo shortest path pesato sulla quantità di rotazione della testa
|
||||
function( MachiningA, MachiningB)
|
||||
local bIsMachiningOnFront = MachiningA.Machining.vtToolDirection:getY() < 10 * GEO.EPS_SMALL
|
||||
local nResult = 0
|
||||
|
||||
-- se lavorazione davanti ordine testa->coda
|
||||
if bIsMachiningOnFront then
|
||||
if MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
||||
nResult = 1
|
||||
elseif MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
||||
nResult = -1
|
||||
end
|
||||
-- se lavorazione dietro ordine coda->testa
|
||||
else
|
||||
if MachiningA.Machining.ptCenter:getX() < MachiningB.Machining.ptCenter:getX() - 10 * GEO.EPS_SMALL then
|
||||
nResult = 1
|
||||
elseif MachiningA.Machining.ptCenter:getX() > MachiningB.Machining.ptCenter:getX() + 10 * GEO.EPS_SMALL then
|
||||
nResult = -1
|
||||
end
|
||||
end
|
||||
|
||||
return nResult
|
||||
end
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
@@ -1575,5 +1779,152 @@ function MachiningLib.CompareMachinings( MachiningA, MachiningB)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function OrderMachining( MachiningOptList)
|
||||
-- Recupero l'identificativo del gruppo di lavoro corrente
|
||||
for i = 1, #MachiningOptList - 1 do
|
||||
local idSource = DB_MACH_APPLIED[MachiningOptList[i+1]].nOperationId
|
||||
local idRef = DB_MACH_APPLIED[MachiningOptList[i]].nOperationId
|
||||
EgtRelocateGlob( idSource, idRef, GDB_IN.AFTER)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function MachiningLib.ShortestPathSorting()
|
||||
local i = 1
|
||||
while i <= #DB_MACH_APPLIED do
|
||||
local nMachInDisp = 0
|
||||
local MachiningOptList = {}
|
||||
local GroupInfo = {}
|
||||
|
||||
-- se è una lavorazione
|
||||
if DB_MACH_APPLIED[i].sType ~= 'DISP' then
|
||||
-- inizio
|
||||
EgtOptMachInit()
|
||||
|
||||
-- feed dalla macchina
|
||||
-- TODO abbassare per considere accelerazioni??
|
||||
SetupInfo = BeamData.GetSetupInfo()
|
||||
EgtOptMachSetFeeds( SetupInfo.dFeedLinearAxesAverage or 10000, SetupInfo.dFeedRotativeAxesAverage or 1000)
|
||||
|
||||
-- tra gruppi (stage) non si può ottimizzare
|
||||
EgtOptMachSetAllGroupsDependencesAsMandatory( true)
|
||||
EgtOptMachSetOptimizationForGroups( true)
|
||||
|
||||
-- se è una lavorazione
|
||||
while DB_MACH_APPLIED[i] and DB_MACH_APPLIED[i].sType ~= 'DISP' do
|
||||
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
|
||||
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
|
||||
|
||||
-- cliclo su tutte le lavorazioni
|
||||
for k = 1, #MachiningOptList do
|
||||
if not DB_MACH_APPLIED[MachiningOptList[k]].Dependances then
|
||||
DB_MACH_APPLIED[MachiningOptList[k]].Dependances = {}
|
||||
end
|
||||
for j = 1, #MachiningOptList do
|
||||
-- se non è stessa lavorazione, imposto dati e dipendenze
|
||||
if k ~= j then
|
||||
local MachiningK = MACHININGS[DB_MACH_APPLIED[MachiningOptList[k]].nIndexInMachinings]
|
||||
local MachiningJ = MACHININGS[DB_MACH_APPLIED[MachiningOptList[j]].nIndexInMachinings]
|
||||
-- se stessa Proc
|
||||
if MachiningK.Proc.id == MachiningJ.Proc.id then
|
||||
-- se lavorazioni della stessa feature, obbligatorio rispettare ordine
|
||||
if MachiningK.Machining.nFeatureInternalIndex < MachiningJ.Machining.nFeatureInternalIndex then
|
||||
local bOk = EgtOptMachAddDependence( MachiningOptList[k], MachiningOptList[j])
|
||||
if not bOk then
|
||||
error( 'Machining sorting : error in dependencies')
|
||||
end
|
||||
table.insert( DB_MACH_APPLIED[MachiningOptList[k]].Dependances, MachiningOptList[j])
|
||||
-- se l'indice interno è uguale, sono cloni: si ordinano in base all'ordine in tabella
|
||||
elseif MachiningK.Machining.nFeatureInternalIndex == MachiningJ.Machining.nFeatureInternalIndex then
|
||||
if k < j then
|
||||
local bOk = EgtOptMachAddDependence( MachiningOptList[k], MachiningOptList[j])
|
||||
if not bOk then
|
||||
error( 'Machining sorting : error in dependencies')
|
||||
end
|
||||
table.insert( DB_MACH_APPLIED[MachiningOptList[k]].Dependances, MachiningOptList[j])
|
||||
end
|
||||
end
|
||||
-- se tra due Proc diverse
|
||||
else
|
||||
-- TODO :
|
||||
-- se ci sono dipendenze tra due feature diverse, la dipendenza è obbligatoria! ATTENZIONE A DIPENDENZE INCROCIATE A->B, B->C, C->A
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- definisco gruppo per gruppo la direzione preferita di ottimizzazione
|
||||
for t = 1, #GroupInfo do
|
||||
-- se gruppo "Taglio di coda" l'ordinamento è al contrario
|
||||
if GroupInfo[t].nStage == 3 then
|
||||
-- start point
|
||||
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, true, SHP_OB.NEAR_PNT, GroupInfo[t].ptMin[1], GroupInfo[t].ptMin[2], GroupInfo[t].ptMin[3])
|
||||
-- end point
|
||||
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, false, SHP_OB.NEAR_PNT, GroupInfo[t].ptMax[1], GroupInfo[t].ptMax[2], GroupInfo[t].ptMax[3])
|
||||
-- in tutti gli altri gruppi si ordina sempre dalla testa alla coda
|
||||
else
|
||||
-- start point
|
||||
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, true, SHP_OB.NEAR_PNT, GroupInfo[t].ptMax[1], GroupInfo[t].ptMax[2], GroupInfo[t].ptMax[3])
|
||||
-- end point
|
||||
EgtOptMachSetOpenBoundForGroups( GroupInfo[t].nGroup, false, SHP_OB.NEAR_PNT, GroupInfo[t].ptMin[1], GroupInfo[t].ptMin[2], GroupInfo[t].ptMin[3])
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo ordine lavorazioni
|
||||
MachiningOptList = EgtOptMachCalculate( MachiningOptList)
|
||||
|
||||
OrderMachining( MachiningOptList)
|
||||
|
||||
-- fine
|
||||
EgtOptMachTerminate()
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return MachiningLib
|
||||
|
||||
@@ -0,0 +1,547 @@
|
||||
-- PreSimulationLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria stima collisioni per travi
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local PreSimulationLib = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
EgtOutLog( ' PreSimulationLib started', 1)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetMachineAxes()
|
||||
|
||||
local LinearAxes = {}
|
||||
local RotativeAxes = {}
|
||||
|
||||
-- si recuperano tutti gli assi, lineari e rotativi
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
for i = 1, #AxesNames do
|
||||
-- EgtGetAxisType restituisce vero se asse lineare, false se asse rotativo
|
||||
if EgtGetAxisType( AxesNames[i]) then
|
||||
LinearAxes[#LinearAxes + 1] = {}
|
||||
LinearAxes[#LinearAxes].sName = AxesNames[i]
|
||||
else
|
||||
RotativeAxes[#RotativeAxes + 1] = {}
|
||||
RotativeAxes[#RotativeAxes].sName = AxesNames[i]
|
||||
end
|
||||
end
|
||||
|
||||
return LinearAxes, RotativeAxes
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function LogOutstroke( sToolName, ptOnToolTipCenter, vtHead, OptionalParameters)
|
||||
|
||||
-- parametri opzionali
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
local LinearAxesValues = OptionalParameters.LinearAxesValues
|
||||
local RotativeAxesValues = OptionalParameters.RotativeAxesValues
|
||||
|
||||
-- gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
-- si disegnano punto e vettore
|
||||
local idPoint = EgtPoint( idTempGroup, ptOnToolTipCenter, GDB_RT.GLOB)
|
||||
local idVector = EgtVector( idTempGroup, vtHead, ptOnToolTipCenter, GDB_RT.GLOB)
|
||||
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 LinearAxesValues then
|
||||
EgtOutLog( ' ' .. 'Lin1' .. ' = ' .. tostring( LinearAxesValues[1]) .. ', ' .. 'Lin2' .. ' = ' .. tostring( LinearAxesValues[2]) .. ', ' .. 'Lin3' .. ' = ' .. tostring( LinearAxesValues[3]))
|
||||
end
|
||||
if RotativeAxesValues then
|
||||
EgtOutLog( ' ' .. 'Rot1' .. ' = ' .. tostring( RotativeAxesValues[1]) .. ', ' .. 'Rot2' .. ' = ' .. tostring( RotativeAxesValues[2]) .. ', ' .. 'Rot3' .. ' = ' .. tostring( RotativeAxesValues[3]))
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- costruzione trimesh del grezzo restante in testa o in coda
|
||||
local function GetRestlengthSurfTm( Part, sSide)
|
||||
|
||||
-- si costruisce il box in globale
|
||||
local b3RestLength
|
||||
if sSide == 'Head' then
|
||||
local b3PartWithOvermaterial = BeamLib.GetPartBoxWithHeadTail( Part, sSide)
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMax():getX(), Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithOvermaterial:getMax():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3RestLength = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
elseif sSide == 'Tail' then
|
||||
local b3PartWithOvermaterial = BeamLib.GetPartBoxWithHeadTail( Part, sSide)
|
||||
local dXMin = b3PartWithOvermaterial:getMin():getX()
|
||||
-- si evita sempre di lavorare col motore dietro la coda della barra (potrebbe succedere con barra restante molto corta): in quel caso si deve sempre separare prima
|
||||
dXMin = min( dXMin, Part.b3Part:getMin():getX() - 2000)
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMin():getX(), Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( dXMin, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3RestLength = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
-- caso non testato, non dovrebbe mai finire qui (il default che arriva da fuori è Tail)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- si crea la trimesh dal box
|
||||
local idRestLengthBoxTm = EgtSurfTmBBox( Part.idTempGroup, b3RestLength , false, GDB_RT.GLOB)
|
||||
|
||||
return idRestLengthBoxTm
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function PreSimulationLib.GetPointOnToolTipCenter( ptPointAtDepth, vtHead, vtNFace, vtToolOffset, Tool)
|
||||
|
||||
return ptPointAtDepth + vtToolOffset * Tool.dDiameter / 2 + vtNFace * EgtIf( AreSameVectorApprox( vtHead, vtNFace), 0, Tool.dThickness)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- calcolo punto sull'uscita testa a partire dal punto di lavorazione o di attacco sul diametro utensile
|
||||
local function GetToolExitPoint( ptMachining, vtNEdge, vtHead, Tool, bIsDownUp)
|
||||
|
||||
local ptToolExitPoint = Point3d( ptMachining + vtNEdge * Tool.dDiameter / 2) + vtHead * EgtIf( bIsDownUp, ( Tool.dLength - Tool.dThickness), Tool.dLength)
|
||||
|
||||
return ptToolExitPoint
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- 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)
|
||||
local frTool = Frame3d( ptToolExit, vtHead, vtC)
|
||||
local vtMovePivotGlob = Vector3d( vtMovePivot)
|
||||
vtMovePivotGlob:toGlob( frTool)
|
||||
local ptPivot = ptToolExit + vtMovePivotGlob
|
||||
|
||||
return ptPivot
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- restituisce i punti notevoli della lavorazioni in cui fare il controllo
|
||||
local function GetCollisionPointsToCheck( Edge, dDepthToMachine)
|
||||
|
||||
local PointsToCheck = {}
|
||||
|
||||
-- punti notevoli
|
||||
local ptStart = Edge.ptStart + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptEnd = Edge.ptEnd + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptMid = Point3d( ( ptStart + ptEnd) / 2)
|
||||
|
||||
-- caso ottimizzato: lato parallelo ad una direzione principale
|
||||
local bIsEdgeParallelToMainDirection =
|
||||
AreSameOrOppositeVectorApprox( Edge.vtEdge, X_AX())
|
||||
or AreSameOrOppositeVectorApprox( Edge.vtEdge, Y_AX())
|
||||
or AreSameOrOppositeVectorApprox( Edge.vtEdge, Z_AX())
|
||||
|
||||
-- aggiunta punti
|
||||
table.insert( PointsToCheck, ptStart)
|
||||
if not bIsEdgeParallelToMainDirection then
|
||||
table.insert( PointsToCheck, ptMid)
|
||||
end
|
||||
table.insert( PointsToCheck, ptEnd)
|
||||
|
||||
return PointsToCheck
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckOutOfStrokePoint( ptOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- impostazione utensile
|
||||
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)
|
||||
|
||||
-- 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, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
if not bOkAngles then
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
end
|
||||
|
||||
-- se nessuna soluzione dagli assi rotativi, è in extracorsa
|
||||
if nSolutionsAngles == 0 then
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
LogOutstroke( Tool.sName, ptOnToolTipCenter, vtHead, { RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- calcolo assi lineari
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, dRotative1, dRotative2, dRotative3)
|
||||
|
||||
if not bOkPositions then
|
||||
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
end
|
||||
|
||||
-- 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( Tool.sName, ptOnToolTipCenter, vtHead, { LinearAxesValues = { dLinear1, dLinear2, dLinear3}, RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- EgtSetAxisPos( 'T', dT)
|
||||
-- EgtSetAxisPos( 'Y', dY)
|
||||
-- EgtSetAxisPos( 'Z', dZ)
|
||||
-- EgtSetAxisPos( 'C', dC1)
|
||||
-- EgtSetAxisPos( 'A', dA1)
|
||||
|
||||
-- se si arriva qui, il punto non è in finecorsa
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da punti sul tip dell'utensile
|
||||
function PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
for i = 1, #PointsOnToolTipCenter do
|
||||
|
||||
local bOutOfStroke = CheckOutOfStrokePoint( PointsOnToolTipCenter[i], vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- se trovato extracorsa inutile procedere con gli altri punti
|
||||
if bOutOfStroke then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- se arrivati qui, nessun extracorsa
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da geometria
|
||||
-- TODO da considerare anche gli attacchi
|
||||
function PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeometry, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
local b3GeomMaxOffset = EgtGetBBoxGlob( idGeometry, GDB_BB.STANDARD)
|
||||
local ptBoxCenter = b3GeomMaxOffset:getCenter()
|
||||
local dBoxDimX = b3GeomMaxOffset:getDimX()
|
||||
local dBoxDimY = b3GeomMaxOffset:getDimY()
|
||||
local dBoxDimZ = b3GeomMaxOffset:getDimZ()
|
||||
|
||||
-- si controlla il finecorsa nei punti al centro delle 6 facce del box
|
||||
local PointsOnToolTipCenter = {}
|
||||
-- X+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimX / 2 * X_AX()))
|
||||
-- X-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimX / 2 * X_AX()))
|
||||
-- Y+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimY / 2 * Y_AX()))
|
||||
-- Y-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimY / 2 * Y_AX()))
|
||||
-- Z+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimZ / 2 * Z_AX()))
|
||||
-- Z-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimZ / 2 * Z_AX()))
|
||||
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
return bOutOfStroke
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MoveMachineAxesToPosition( ptOnToolTipCenter, vtHead, vtAux)
|
||||
|
||||
-- calcolo assi rotativi
|
||||
local bOkAngles, nSolutionsAngles, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
if not bOkAngles then
|
||||
error( ' MoveMachineAxesToPosition : error')
|
||||
end
|
||||
|
||||
-- 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
|
||||
local bCollisionFoundPiece = false
|
||||
if not bCheckOnlyRestlength then
|
||||
local idCheckCollisionTm = Part.idBoxTm
|
||||
-- se testa o coda attaccate, si considerano nella superficie di collisione
|
||||
if bCannotSplitRestLength then
|
||||
local b3CheckCollision = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation)
|
||||
idCheckCollisionTm = EgtSurfTmBBox( Part.idTempGroup, b3CheckCollision, false, GDB_RT.GLOB)
|
||||
end
|
||||
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
|
||||
|
||||
-- check collisione con grezzo restante, se con il pezzo non c'è collisione e non è un taglio di testa o coda
|
||||
local bCollisionFoundRestLength = false
|
||||
if not ( bCollisionFoundPiece or bCannotSplitRestLength) then
|
||||
local idRestLengthSurfFr = GetRestlengthSurfTm( Part, sRestLengthSideForPreSimulation)
|
||||
if idRestLengthSurfFr then
|
||||
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
|
||||
|
||||
return false, bCollisionFoundRestLength
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- controllo collisione con verifica intersezione trimesh e geometrie da macchina
|
||||
local function CheckCollisionWithAxis( sAxis, MachiningParameters, OptionalParameters)
|
||||
|
||||
-- parametri obbligatori
|
||||
local Edge = MachiningParameters.Edge
|
||||
local vtNFace = MachiningParameters.vtNFace
|
||||
local vtHead = MachiningParameters.vtHead
|
||||
local Part = MachiningParameters.Part
|
||||
local Tool = MachiningParameters.Tool
|
||||
local dDepthToMachine = MachiningParameters.dDepthToMachine
|
||||
|
||||
-- parametri opzionali
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
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 sul tip dell'utensile, in centro
|
||||
local PointsOnToolTipCenter = {}
|
||||
for i = 1, #PointsToCheck do
|
||||
PointsOnToolTipCenter[i] = PreSimulationLib.GetPointOnToolTipCenter( PointsToCheck[i], vtHead, vtNFace, Edge.vtN, Tool)
|
||||
end
|
||||
|
||||
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, #PointsOnToolTipCenter do
|
||||
|
||||
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
|
||||
|
||||
return true
|
||||
|
||||
-- se trovata collisione con grezzo si setta che la lavorazione è da fare dopo separazione e si prosegue con gli altri punti
|
||||
elseif bCollisionFoundRestLength then
|
||||
|
||||
bMoveAfterSplit = true
|
||||
end
|
||||
end
|
||||
|
||||
-- se si arriva qui significa che non è stata trovata alcuna collisione con pezzo
|
||||
return false, bMoveAfterSplit
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, OptionalParameters)
|
||||
|
||||
local bCollisionFound
|
||||
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 {}
|
||||
|
||||
local OptionalParametersCheckCollisionWithAxis = {}
|
||||
OptionalParametersCheckCollisionWithAxis.bCheckOnlyRestlength = false
|
||||
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)
|
||||
if bIsDicing and ( sBladeEngagement == 'Standard') then
|
||||
bCheckOnlyRestlengthForAxisABC = true
|
||||
-- se l'elevazione reale (rispetto al pezzo + eventuale materiale in testa/coda) è maggiore del massimo materiale è sempre collisione
|
||||
-- TODO rifare con funzione
|
||||
elseif not bDisableRealElevationCheck then
|
||||
local Edge = Parameters.Edge
|
||||
local vtNFace = Parameters.vtNFace
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
local b3BoxForElevationCheck = BBox3d( Parameters.Part.b3Part)
|
||||
-- se è un taglio di testa o coda va aggiunto il sovramateriale
|
||||
if OptionalParametersCheckCollisionWithAxis.bCannotSplitRestLength then
|
||||
b3BoxForElevationCheck = BeamLib.GetPartBoxWithHeadTail( Parameters.Part, OptionalParametersCheckCollisionWithAxis.sRestLengthSideForPreSimulation)
|
||||
end
|
||||
-- trimesh rettangolare con un lato corrispondente al lato da lavorare e larghezza come spessore utensile
|
||||
local idTrimesh = EgtSurfTmRectangle( Parameters.Part.idTempGroup, Edge.ptStart, Edge.ptEnd, Edge.ptEnd + vtNFace * Parameters.Tool.dThickness, GDB_RT.GLOB)
|
||||
local vtNTrimesh = EgtSurfTmFacetNormVersor( idTrimesh, 0, GDB_ID.ROOT)
|
||||
-- se trimesh con normale opposta a quella del lato, si inverte (non si sa a priori che verso avrà)
|
||||
if not AreSameVectorApprox( Edge.vtN, vtNTrimesh) then
|
||||
EgtInvertSurf( idTrimesh)
|
||||
end
|
||||
local dRealElevation = EgtSurfTmFacetElevationInBBox( idTrimesh, 0, b3BoxForElevationCheck, true, GDB_ID.ROOT)
|
||||
local dRealDepthToMachine = ( dRealElevation - Parameters.Edge.dElevation + dDepthToMachine)
|
||||
if dRealDepthToMachine > Parameters.Tool.dMaxDepth + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- SCC
|
||||
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, vtNFace)
|
||||
|
||||
-- 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 sR3 and not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR3 = CheckCollisionWithAxis( sR3, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR2 = CheckCollisionWithAxis( sR2, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR1 = CheckCollisionWithAxis( sR1, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
local bMoveAfterSplit = bMoveAfterSplitL3 or bMoveAfterSplitR3 or bMoveAfterSplitR2 or bMoveAfterSplitR1
|
||||
|
||||
return bCollisionFound, bMoveAfterSplit
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return PreSimulationLib
|
||||
@@ -0,0 +1,122 @@
|
||||
-- BeamLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria calcolo tempo automatismo
|
||||
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local TimeLib = {}
|
||||
|
||||
|
||||
EgtOutLog( ' TimeLib started', 1)
|
||||
|
||||
|
||||
TimeLib.__index = TimeLib
|
||||
|
||||
function TimeLib.new()
|
||||
local TimeLibInstance = setmetatable({}, TimeLib)
|
||||
TimeLibInstance.dStartTime = os.clock()
|
||||
TimeLibInstance.Measurements = {}
|
||||
return TimeLibInstance
|
||||
end
|
||||
|
||||
-- reset entire timer
|
||||
function TimeLib:start()
|
||||
self.dStartTime = os.clock()
|
||||
self.Measurements = {}
|
||||
end
|
||||
|
||||
-- start elapsed measurement for a specific name
|
||||
function TimeLib:startElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
local dNow = os.clock()
|
||||
|
||||
if not self.Measurements[sMeasurementName] then
|
||||
self.Measurements[sMeasurementName] = {
|
||||
dStart = dNow,
|
||||
dLast = 0,
|
||||
dCumulative = 0,
|
||||
dRecent = 0,
|
||||
nCount = 0
|
||||
}
|
||||
else
|
||||
self.Measurements[sMeasurementName].dStart = dNow
|
||||
end
|
||||
end
|
||||
|
||||
-- stop elapsed measurement (increments count and updates cumulative)
|
||||
function TimeLib:stopElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
local dNow = os.clock()
|
||||
local Measurement = self.Measurements[sMeasurementName]
|
||||
|
||||
if Measurement and Measurement.dStart then
|
||||
local dDuration = dNow - Measurement.dStart
|
||||
Measurement.dRecent = dDuration
|
||||
Measurement.dCumulative = Measurement.dCumulative + dDuration
|
||||
Measurement.dLast = dNow
|
||||
Measurement.nCount = Measurement.nCount + 1
|
||||
Measurement.dStart = nil
|
||||
else
|
||||
-- if stop called without start, initialize with zero
|
||||
self.Measurements[sMeasurementName] = {
|
||||
dStart = nil,
|
||||
dLast = dNow,
|
||||
dCumulative = 0,
|
||||
dRecent = 0,
|
||||
nCount = 0
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- reset elapsed for a specific measurement
|
||||
function TimeLib:resetElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
self.Measurements[sMeasurementName] = nil
|
||||
end
|
||||
|
||||
-- return elapsed times: total, cumulative, recent, count
|
||||
function TimeLib:getElapsed(sName)
|
||||
local dTotal = os.clock() - self.dStartTime
|
||||
local sMeasurementName = sName or "Default"
|
||||
local Measurement = self.Measurements[sMeasurementName]
|
||||
|
||||
if Measurement then
|
||||
return dTotal, Measurement.dCumulative, Measurement.dRecent, Measurement.nCount
|
||||
else
|
||||
return dTotal, nil, nil, 0
|
||||
end
|
||||
end
|
||||
|
||||
-- log elapsed times for one measurement
|
||||
function TimeLib:logElapsed(sName)
|
||||
local dTotal, dCumulative, dRecent, nCount = self:getElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
|
||||
if dCumulative then
|
||||
EgtOutLog(string.format(
|
||||
"%s(#%d): recent %.3f, cumulative %.3f, total %.3f",
|
||||
sMeasurementName, nCount, dRecent, dCumulative, dTotal))
|
||||
else
|
||||
EgtOutLog(string.format("Total %.3f (no '%s' measurement started)",
|
||||
dTotal, sMeasurementName))
|
||||
end
|
||||
end
|
||||
|
||||
-- log elapsed times for all measurements
|
||||
function TimeLib:logAllElapsed()
|
||||
local dTotal = os.clock() - self.dStartTime
|
||||
if next(self.Measurements) == nil then
|
||||
EgtOutLog(string.format("Total %.3f (no measurements started)", dTotal))
|
||||
return
|
||||
end
|
||||
|
||||
for sMeasurementName, Measurement in pairs(self.Measurements) do
|
||||
local dCumulative = Measurement.dCumulative
|
||||
local dRecent = Measurement.dRecent
|
||||
local nCount = Measurement.nCount
|
||||
EgtOutLog(string.format(
|
||||
"%s(#%d): recent %.3f, cumulative %.3f, total %.3f",
|
||||
sMeasurementName, nCount, dRecent, dCumulative, dTotal))
|
||||
end
|
||||
end
|
||||
|
||||
return TimeLib
|
||||
+74
-457
@@ -1,479 +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
|
||||
--EgtStartCounter()
|
||||
EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType)
|
||||
--local dTime = EgtStopCounter()
|
||||
-- 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,556 @@
|
||||
-- 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
|
||||
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')
|
||||
|
||||
-- recupero cartella macchine
|
||||
local sIniFilePath = EgtGetIniFile()
|
||||
local MachineDirPath = EgtGetStringFromIni( 'Mach', 'MachinesDir', '', sIniFilePath)
|
||||
-- Verifico che tutte le macchine siano abilitate per la lavorazione delle Travi
|
||||
for MachineIndex = 1, #NEST.MACHINELIST do
|
||||
local sMachDir = MachineDirPath .. '\\' .. NEST.MACHINELIST[MachineIndex]
|
||||
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
|
||||
end
|
||||
|
||||
---- 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 = {}
|
||||
for nRawIndex = 1, #RAWLIST do
|
||||
local Raw = RAWLIST[nRawIndex]
|
||||
table.insert( Raws, {LenToFill = Raw.Len, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1, Count = Raw.Qty})
|
||||
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( PARTLIST) 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
|
||||
|
||||
-- se esiste un MachGorup precedente
|
||||
local nPreviousNestIndex = 0
|
||||
local nLastMachGroupId = EgtGetLastMachGroup()
|
||||
if nLastMachGroupId then
|
||||
nPreviousNestIndex = EgtGetInfo( nLastMachGroupId, "NestIndex", 'i')
|
||||
end
|
||||
for nMachineIndex = 1, #NEST.MACHINELIST do
|
||||
local sMachineName = NEST.MACHINELIST[nMachineIndex]
|
||||
-- imposto macchina corrente
|
||||
EgtSetCurrMachine( sMachineName)
|
||||
-- elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
-- creo gruppi di lavorazione per risultato
|
||||
for nMachGroupIndex = 1, #BestResult do
|
||||
local CurrMachGroup = BestResult[nMachGroupIndex]
|
||||
-- creo gruppo di lavorazione
|
||||
local MachGroupName = NewMachGroupName()
|
||||
nMachGroup = EgtAddMachGroup( MachGroupName)
|
||||
EgtSetInfo( nMachGroup, "NestIndex", nPreviousNestIndex + nMachGroupIndex)
|
||||
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)
|
||||
-- se esiste lista etichette
|
||||
local sTagList = ''
|
||||
if #NEST.MACHINELIST == 1 then
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList')
|
||||
else
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex)
|
||||
if not sTagList or #sTagList <= 0 then
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList')
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex, sTagList)
|
||||
end
|
||||
end
|
||||
if sTagList and #sTagList then
|
||||
-- elimino eventuali liste etichette da duplo
|
||||
EgtRemoveInfo( nPartDuploId, 'LuxTagList')
|
||||
for nRemoveTagMachineIndex = 1, nMachineIndex - 1 do
|
||||
EgtRemoveInfo( nPartDuploId, 'LuxTagList' .. nRemoveTagMachineIndex)
|
||||
end
|
||||
-- recupero liste etichette usate e non
|
||||
local TagTypeList = EgtSplitString( sTagList, ';')
|
||||
local UnusedTagList = {}
|
||||
local UsedTagList = {}
|
||||
if #TagTypeList == 1 then
|
||||
UnusedTagList = EgtSplitString( sTagList, ',')
|
||||
else
|
||||
if TagTypeList[1] and #TagTypeList[1] > 0 then
|
||||
UnusedTagList = EgtSplitString( TagTypeList[1], ',')
|
||||
end
|
||||
if TagTypeList[2] and #TagTypeList[2] > 0 then
|
||||
UsedTagList = EgtSplitString( TagTypeList[2], ',')
|
||||
end
|
||||
end
|
||||
local nAssignedTagIndex = #UnusedTagList
|
||||
local sAssignedTag = UnusedTagList[nAssignedTagIndex]
|
||||
-- creo stringa per info etichette aggiornata
|
||||
local sNewTagList = ''
|
||||
for nUnusedTagIndex = 1, nAssignedTagIndex - 1 do
|
||||
sNewTagList = sNewTagList .. UnusedTagList[nUnusedTagIndex] .. EgtIf( nUnusedTagIndex < nAssignedTagIndex - 1, ',', '')
|
||||
end
|
||||
sNewTagList = sNewTagList .. ';' .. UnusedTagList[nAssignedTagIndex] .. EgtIf( #UsedTagList > 0, ',', '')
|
||||
for nUsedTagIndex = 1, #UsedTagList do
|
||||
sNewTagList = sNewTagList .. UsedTagList[nUsedTagIndex] .. EgtIf( nUsedTagIndex < #UsedTagList, ',', '')
|
||||
end
|
||||
-- assegno etichetta a nuovo duplo
|
||||
EgtSetInfo( nPartDuploId, 'LuxTag', sAssignedTag)
|
||||
if #NEST.MACHINELIST == 1 then
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList', sNewTagList)
|
||||
else
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex, sNewTagList)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
EgtResetCurrMachGroup()
|
||||
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')
|
||||
@@ -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')
|
||||
+31
-15
@@ -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,16 +15,13 @@ 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
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
@@ -46,11 +43,15 @@ _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.BeamData = nil
|
||||
_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.
|
||||
@@ -76,7 +77,7 @@ end
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
@@ -286,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')
|
||||
@@ -300,12 +301,10 @@ end
|
||||
-- *** Inserimento delle lavorazioni nelle travi ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessFeatures()
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
local idTempGroup = BeamLib.CreateTempGroup()
|
||||
|
||||
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 = ''
|
||||
@@ -320,7 +319,7 @@ local function MyProcessFeatures()
|
||||
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
|
||||
-- nulla da segnalare
|
||||
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'
|
||||
@@ -348,6 +347,7 @@ local function MyProcessFeatures()
|
||||
end
|
||||
|
||||
-- cancello gruppo temporaneo
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
if #sOutput > 0 then EgtOutLog( sOutput) end
|
||||
@@ -365,11 +365,21 @@ 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
|
||||
@@ -377,4 +387,10 @@ if not GetDataConfig() then return end
|
||||
-- Abilito Vmill
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
||||
|
||||
if not MyProcessFeatures() then return end
|
||||
MyProcessFeatures()
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Bevel-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"sImage": "ConfigStrategy\\Bevel-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
}
|
||||
]
|
||||
@@ -227,6 +227,10 @@
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "DoubleBevel-2-Through",
|
||||
"sImage": "ConfigStrategy\\DoubleBevel-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -684,7 +688,7 @@
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ScarfJoint.png",
|
||||
"StrategyList" : [ ]
|
||||
"StrategyList" : [ { "sStrategyId": "STR0009" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -837,8 +841,8 @@
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
"sImage": "ConfigStrategy\\ProfileHead.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
@@ -106,7 +139,7 @@
|
||||
"sName": "GEN_dMaxWasteLength",
|
||||
"sNameNge": "GEN_MAX_WASTE_LENGTH",
|
||||
"sValue": "300",
|
||||
"sDescriptionShort": "Maximum Waste Length for Dice-cut",
|
||||
"sDescriptionShort": "Maximum length for dropped waste",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
@@ -117,7 +150,18 @@
|
||||
"sName": "GEN_dMaxWasteVolume",
|
||||
"sNameNge": "GEN_MAX_WASTE_VOLUME",
|
||||
"sValue": "6000000",
|
||||
"sDescriptionShort": "Maximum Waste Volume for Dice-cut",
|
||||
"sDescriptionShort": "Maximum volume for dropped waste",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_dMaxDimDice",
|
||||
"sNameNge": "GEN_MAX_DIM_DICE",
|
||||
"sValue": "150",
|
||||
"sDescriptionShort": "Maximum dice dimension",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local SPLITCUT = require( 'SPLITCUT')
|
||||
@@ -34,17 +34,28 @@ function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Result.sInfo = ''
|
||||
local OptionalParameters = { bForceChainSaw = Strategy.Parameters.bForceChainSaw, bReduceBladePath = Strategy.Parameters.bReduceBladePath,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength, dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume }
|
||||
OptionalParameters.sRestLengthSideForPreSimulation = 'Head'
|
||||
OptionalParameters.bCannotSplitRestLength = true
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- si setta che è taglio di coda
|
||||
-- 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
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
-- se non faccio tagli PRECUT, imposto tabella Result direttamente. Non serve verificare che riesca a rimuovere il materiale extra
|
||||
if not Strategy.SplitStrategy or #Strategy.SplitStrategy == 0 then
|
||||
Strategy.Result.sInfo = 'PreCut on head not possible'
|
||||
-- if not Strategy.SplitStrategy or #Strategy.SplitStrategy == 0 then
|
||||
-- Strategy.Result.sInfo = 'PreCut on head not possible'
|
||||
-- end
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Precut Head not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,22 +65,24 @@ function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- TODO di quale utensile si deve impostare la qualità qui?
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SAWBLADE')
|
||||
|
||||
-- se coincide con inizio grezzo, non va fatto
|
||||
if abs( Proc.b3Box:getCenter():getX() - Part.b3Raw:getMax():getX()) < 10 * GEO.EPS_SMALL then
|
||||
return true, Strategy.Result
|
||||
end
|
||||
|
||||
-- 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()
|
||||
end
|
||||
|
||||
local MachiningsToAdd = {}
|
||||
local bExecutePrecutOnly = Part.dHeadOverMaterial < 20
|
||||
local bExecutePrecutOnly = false
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
|
||||
bExecutePrecutOnly = Part.dHeadOverMaterial < 20
|
||||
|
||||
if Strategy.SplitStrategy and #Strategy.SplitStrategy > 0 then
|
||||
for i = 1, #Strategy.SplitStrategy do
|
||||
local TempList = {}
|
||||
@@ -87,25 +100,35 @@ function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
if not bExecutePrecutOnly then
|
||||
local OptionalParameters = {}
|
||||
-- si parte dal box della feature e si aggiunge il punto estremo del grezzo
|
||||
-- ATTENZIONE : Proc.b3Box viene modificata dato che il tipo Box è come se fosse una tabella, ma da qui passa solo 1 volta per pezzo quindi non dovrebbero esserci problemi
|
||||
local b3BoxDicing = Proc.b3Box
|
||||
b3BoxDicing:Add( Part.b3Raw:getMax())
|
||||
b3BoxDicing:expand( 1000 * GEO.EPS_SMALL)
|
||||
OptionalParameters.b3BoxDicing = b3BoxDicing
|
||||
|
||||
OptionalParameters.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParameters.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParameters.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
-- si recuperano gli estremi del box del materiale di testa da togliere
|
||||
local b3PartWithHead = BeamLib.GetPartBoxWithHeadTail( Part, 'Head')
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMax():getX() - 1, Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithHead:getMax():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParameters)
|
||||
local OptionalParametersBladeToWaste = {}
|
||||
OptionalParametersBladeToWaste.b3BoxDicing = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
OptionalParametersBladeToWaste.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParametersBladeToWaste.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
OptionalParametersBladeToWaste.sRestLengthSideForPreSimulation = 'Head'
|
||||
OptionalParametersBladeToWaste.bCannotSplitRestLength = true
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
-- se taglio non riuscito, si riprova con il riduci percorso forzato (collisione possibile in separazione pezzi alti)
|
||||
if ( not Strategy.Machining) or ( #Strategy.Machining == 0) then
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = true
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
end
|
||||
if Strategy.Machining and #Strategy.Machining > 0 then
|
||||
for i = 1, #Strategy.Machining do
|
||||
local TempList = {}
|
||||
TempList = Strategy.Machining[i]
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Head machining not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
@@ -183,6 +184,23 @@ local function GetTenonStrategy( Proc, Part)
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
-- TODO sostituire con applicazione della lavorazione?
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local vtCurveStart = EgtSV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local vtCurveEnd = EgtEV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local ptCurveStart = EgtSP( idGeomMaxOffset, GDB_ID.ROOT) + -vtCurveStart * Machining.Milling.LeadIn.dTangentDistance + ( Proc.FeatureInfo.vtTenonN ^ -vtCurveStart) * Machining.Milling.LeadIn.dPerpDistance
|
||||
local ptCurveEnd = EgtEP( idGeomMaxOffset, GDB_ID.ROOT) + vtCurveEnd * Machining.Milling.LeadOut.dTangentDistance + ( vtCurveEnd ^ Proc.FeatureInfo.vtTenonN) * Machining.Milling.LeadOut.dPerpDistance
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveStart, false, GDB_RT.GLOB)
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveEnd, true, GDB_RT.GLOB)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtTenonN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- tempo di svuotatura
|
||||
Result.Milling.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Milling, Part)
|
||||
else
|
||||
|
||||
@@ -22,10 +22,20 @@
|
||||
"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",
|
||||
"sValue": "40",
|
||||
"sValue": "10",
|
||||
"sDescriptionShort": "Minimum approach distance on open sides",
|
||||
"sDescriptionLong": "Minimum approach distance on open sides",
|
||||
"sType": "d",
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0002 = {}
|
||||
@@ -101,13 +102,13 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO va gestita meglio la decisione delle facce da lavorare
|
||||
local function GetBestPocketingStrategy( Proc)
|
||||
local function GetBestPocketingStrategy( Proc, Part)
|
||||
-- imposto parametri di ricerca utensile in base a topologia
|
||||
local Machining = {}
|
||||
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,16 +171,33 @@ local function GetBestPocketingStrategy( Proc)
|
||||
-- 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
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
-- se faccia singola e feature lavorata in unica lavorazione si può sempre affondare
|
||||
if Proc.Topology.sName == 'Cut-1-Through'
|
||||
or Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
if #FeatureSplittingPoints > 0 then
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
if not bIsSplitFeature then
|
||||
Milling.ToolInfo.dResidualDepth = 0
|
||||
end
|
||||
end
|
||||
Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
@@ -191,13 +209,14 @@ local function GetBestPocketingStrategy( Proc)
|
||||
-- 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 = {}
|
||||
@@ -225,12 +244,21 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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)
|
||||
@@ -241,6 +269,8 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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 = {}
|
||||
@@ -250,6 +280,19 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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)
|
||||
@@ -281,6 +324,8 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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 = {}
|
||||
@@ -290,13 +335,60 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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)
|
||||
@@ -308,10 +400,10 @@ local function GetBestPocketingStrategy( Proc)
|
||||
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
|
||||
@@ -428,7 +520,12 @@ end
|
||||
local function GetSplitSurfaces( Proc, Part, bAddMachining)
|
||||
local vAddId = {}
|
||||
local vAddIdTunnel = {}
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
local idAddGroup
|
||||
if bAddMachining then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
local nOriginalTmIdTunnel = GDB_ID.NULL
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
nOriginalTmIdTunnel = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.id
|
||||
@@ -438,18 +535,14 @@ local function GetSplitSurfaces( Proc, Part, bAddMachining)
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
|
||||
if #FeatureSplittingPoints == 0 then
|
||||
local nAddId = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, nAddGrpId) or GDB_ID.NULL
|
||||
if not bAddMachining then
|
||||
EgtSetLevel( nAddId, GDB_LV.TEMP)
|
||||
EgtSetLevel( nAddIdTunnel, GDB_LV.TEMP)
|
||||
end
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
else
|
||||
for i = 1, #FeatureSplittingPoints do
|
||||
local nAddId = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, nAddGrpId) or GDB_ID.NULL
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
if i == 1 then
|
||||
-- prima superficie, va tagliata solo a sinistra
|
||||
local ptSplit = FeatureSplittingPoints[i] + Vector3d( -BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
@@ -465,23 +558,15 @@ local function GetSplitSurfaces( Proc, Part, bAddMachining)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
end
|
||||
if not bAddMachining then
|
||||
EgtSetLevel( nAddId, GDB_LV.TEMP)
|
||||
EgtSetLevel( nAddIdTunnel, GDB_LV.TEMP)
|
||||
end
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
end
|
||||
-- taglio ultima superficie, va tagliata solo a destra
|
||||
local nAddId = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, nAddGrpId) or GDB_ID.NULL
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
local ptSplit = FeatureSplittingPoints[#FeatureSplittingPoints] + Vector3d( BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
if not bAddMachining then
|
||||
EgtSetLevel( nAddId, GDB_LV.TEMP)
|
||||
EgtSetLevel( nAddIdTunnel, GDB_LV.TEMP)
|
||||
end
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
end
|
||||
@@ -501,19 +586,27 @@ function STR0002.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla, serve una lavorazioen che lasci il testimone
|
||||
if MachiningLib.IsFeatureHinderingClamping( Proc, Part) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable ( Feature hinders clamping)'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
local ToolInfo = {}
|
||||
local Pocketing = {}
|
||||
|
||||
Strategy.Machining = GetBestPocketingStrategy( Proc)
|
||||
Strategy.Machining = GetBestPocketingStrategy( Proc, Part)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
local vAddId = {}
|
||||
@@ -535,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
|
||||
@@ -545,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
|
||||
@@ -579,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"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -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)
|
||||
@@ -210,7 +230,7 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
@@ -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
|
||||
@@ -236,6 +261,7 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local BottomEdge = LongFace.MainEdges.BottomEdge
|
||||
|
||||
-- TODO funzione separata
|
||||
-- TODO è meglio cercare la lama qui e passarla alla FACEBYBLADE, la scelta è più precisa
|
||||
-- lama - calcolo lavorazioni
|
||||
local Cutting = {}
|
||||
-- parametri comuni a tutte le lavorazioni cutting
|
||||
@@ -243,8 +269,7 @@ function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
bForceLongcutBlade = Strategy.Parameters.bForceLongcutBlade,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dPocketHeight = dPocketHeight,
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dMinNzDownUp = 0
|
||||
bIsSplitFeature = bIsSplitFeature
|
||||
}
|
||||
|
||||
-- primo lato del tunnel o lato di fondo
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -112,20 +112,10 @@ 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
|
||||
|
||||
-- se tasca su faccia sotto la strategia non è applicabile (la sega a catena in generale non può lavorare 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
|
||||
end
|
||||
|
||||
-- calcolo estensione oltre la coda
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
@@ -133,7 +123,7 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
@@ -142,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
|
||||
@@ -167,6 +172,7 @@ function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
bIsSplitFeature = bIsSplitFeature
|
||||
}
|
||||
|
||||
-- TODO aggiungere verifica finecorsa e nel caso cambio lato
|
||||
if Proc.Topology.sName == 'Groove-4-Blind' or Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
|
||||
-- si lavora tutto il fondo
|
||||
@@ -179,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)
|
||||
@@ -242,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"
|
||||
@@ -110,26 +110,6 @@
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMinZAngleTopBlade",
|
||||
"sNameNge": "MIN_Z_ANGLE_TOP_BLADE",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Min Z angle top blade",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxYAngleTopBlade",
|
||||
"sNameNge": "MAX_Y_ANGLE_TOP_BLADE",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Max Y angle top blade",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "ALLOW_FINISH_MILL",
|
||||
@@ -160,6 +140,11 @@
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxDimDice",
|
||||
"sSource": "GEN_dMaxDimDice",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -36,7 +36,7 @@ local function IsTwoFacesCommonEdgeTooLong( Proc, Part)
|
||||
end
|
||||
|
||||
-- se due facce, cubetti troppo lunghi in X non si possono fare
|
||||
local ptEdge1, _, ptEdge2 = EgtSurfTmFacetOppositeSide( Proc.id, Proc.Faces[1].id, -Proc.Faces[1].Edges[nCommonEdge].vtN, GDB_ID.ROOT)
|
||||
local ptEdge1, ptEdge2 = Proc.Faces[1].Edges[nCommonEdge].ptStart, Proc.Faces[1].Edges[nCommonEdge].ptEnd
|
||||
local b3BoxEdge = BBox3d( ptEdge1, ptEdge2)
|
||||
local dEdgeLengthOnX = b3BoxEdge:getDimX()
|
||||
if FeatureLib.IsMachiningLong( dEdgeLengthOnX, Part) then
|
||||
@@ -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
|
||||
|
||||
@@ -80,9 +80,9 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local idAddedTmFace
|
||||
local nAddedFace
|
||||
if Proc.nFct == 3 and not Proc.Topology.sName == 'Groove-3-Through' then
|
||||
if Proc.AdjacencyMatrix[1][2] > 10 * GEO.EPS_ANG_SMALL and Proc.AdjacencyMatrix[2][3] < 10 * GEO.EPS_ANG_SMALL then
|
||||
if Proc.AdjacencyMatrix[2][3] < 0 then
|
||||
nAddedFace = 1 - 1
|
||||
elseif Proc.AdjacencyMatrix[2][3] > 10 * GEO.EPS_ANG_SMALL and Proc.AdjacencyMatrix[3][1] < 10 * GEO.EPS_ANG_SMALL then
|
||||
elseif Proc.AdjacencyMatrix[1][3] < 0 then
|
||||
nAddedFace = 2 - 1
|
||||
else
|
||||
nAddedFace = 3 - 1
|
||||
@@ -100,8 +100,9 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- considerazioni necessarie a determinare se lavorare con codolo oppure no
|
||||
local bKeepWasteAttached = ( Strategy.Parameters.sCuttingStrategy == 'KEEP_WASTE_ATTACHED')
|
||||
local bDropWaste = ( Strategy.Parameters.sCuttingStrategy == 'DROP_WASTE')
|
||||
local dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail = FeatureLib.GetFeatureMaxNotClampableLengths( Proc, Part)
|
||||
local bFeatureHindersClamping = FeatureLib.IsMachiningLong( max( dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
|
||||
local bFeatureHindersClamping = MachiningLib.IsFeatureHinderingClamping( Proc, Part)
|
||||
|
||||
local bIsFeatureLong = FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
local bIsTwoFacesCommonEdgeTooLong = ( ( Proc.Topology and ( Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind')) and IsTwoFacesCommonEdgeTooLong( Proc, Part))
|
||||
|
||||
@@ -111,13 +112,14 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
or bKeepWasteAttached then
|
||||
|
||||
local BladeKeepWasteResult
|
||||
local OptionalParameters = { dExtendAfterTail = dExtendAfterTail, dStripWidth = Strategy.Parameters.dStripWidth}
|
||||
local OptionalParameters = { dExtendAfterTail = dExtendAfterTail, dStripWidth = Strategy.Parameters.dStripWidth, bForced = bKeepWasteAttached}
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
Blade.Result, BladeKeepWasteResult = BladeKeepWaste.Make( Proc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeKeepWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeKeepWasteResult.dMRR
|
||||
dCompletionPercentage = BladeKeepWasteResult.dCompletionPercentage
|
||||
dQuality = BladeKeepWasteResult.dQuality
|
||||
Strategy.Result.sInfo = BladeKeepWasteResult.sInfo or ''
|
||||
end
|
||||
|
||||
-- lavorazione a cubetti / taglio singolo
|
||||
@@ -127,20 +129,9 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
and not bIsTwoFacesCommonEdgeTooLong then
|
||||
|
||||
AuxiliaryData.bIgnoreNotClampableLength = false
|
||||
local dMinZTopBlade
|
||||
local dMaxNyTopBlade
|
||||
local BladeToWasteResult
|
||||
if Strategy.Parameters.dMinZAngleTopBlade then
|
||||
dMinZTopBlade = sin( Strategy.Parameters.dMinZAngleTopBlade)
|
||||
end
|
||||
if Strategy.Parameters.dMaxYAngleTopBlade then
|
||||
dMaxNyTopBlade = sin( Strategy.Parameters.dMaxYAngleTopBlade)
|
||||
end
|
||||
-- TODO rimuovere dMinNzTopBlade e dMaxNyTopBlade opzionali? non sono gestiti ovunque e probabilmente hanno utilizzo limitato
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
dMinNzTopBlade = dMinZTopBlade,
|
||||
dMaxNyTopBlade = dMaxNyTopBlade,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bAllowFastCuts = Strategy.Parameters.bAllowFastCuts,
|
||||
@@ -172,19 +163,9 @@ function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- TODO da completare
|
||||
-- TODO va messa per prima????????
|
||||
if idAddedTmFace then
|
||||
local dMinZTopBlade
|
||||
local dMaxNyTopBlade
|
||||
local BladeToWasteResult
|
||||
if Strategy.Parameters.dMinZAngleTopBlade then
|
||||
dMinZTopBlade = sin( Strategy.Parameters.dMinZAngleTopBlade)
|
||||
end
|
||||
if Strategy.Parameters.dMaxYAngleTopBlade then
|
||||
dMaxNyTopBlade = sin( Strategy.Parameters.dMaxYAngleTopBlade)
|
||||
end
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
dMinNzTopBlade = dMinZTopBlade,
|
||||
dMaxNyTopBlade = dMaxNyTopBlade,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
|
||||
@@ -74,6 +75,7 @@ local function GetTenonStrategy( Proc, Part)
|
||||
local bMachIsOk = true
|
||||
if ( Proc.FeatureInfo.vtTenonN:getZ() < 0 and TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop) or
|
||||
( Proc.FeatureInfo.vtTenonN:getZ() > 0 and TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom) then
|
||||
-- TODO questo test va sostituito con check collisione asse Z (PreCollision)
|
||||
local dTotalLen = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dLength + TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.dPivot
|
||||
local dHorizSpace = dTotalLen * sqrt( 1 - ( Proc.FeatureInfo.vtTenonN:getZ() * Proc.FeatureInfo.vtTenonN:getZ()))
|
||||
if dHorizSpace - ( TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.dCAxisSideEncumbrance / 2) < Proc.b3Box:getDimX() then
|
||||
@@ -158,6 +160,23 @@ local function GetTenonStrategy( Proc, Part)
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
-- TODO sostituire con applicazione della lavorazione?
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local vtCurveStart = EgtSV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local vtCurveEnd = EgtEV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local ptCurveStart = EgtSP( idGeomMaxOffset, GDB_ID.ROOT) + -vtCurveStart * Machining.Milling.LeadIn.dTangentDistance + ( Proc.FeatureInfo.vtTenonN ^ -vtCurveStart) * Machining.Milling.LeadIn.dPerpDistance
|
||||
local ptCurveEnd = EgtEP( idGeomMaxOffset, GDB_ID.ROOT) + vtCurveEnd * Machining.Milling.LeadOut.dTangentDistance + ( vtCurveEnd ^ Proc.FeatureInfo.vtTenonN) * Machining.Milling.LeadOut.dPerpDistance
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveStart, false, GDB_RT.GLOB)
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveEnd, true, GDB_RT.GLOB)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtTenonN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- tempo di svuotatura
|
||||
Result.Milling.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Milling, Part)
|
||||
end
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
@@ -15,6 +16,19 @@ local BladeToWaste = require('BLADETOWASTE')
|
||||
local STR0007 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSCC( Machining)
|
||||
local nSCC
|
||||
|
||||
if Machining.vtToolDirection:getX() > 0 then
|
||||
nSCC = MCH_SCC.ADIR_XP
|
||||
else
|
||||
nSCC = MCH_SCC.ADIR_XM
|
||||
end
|
||||
|
||||
return nSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function GetMortiseStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
@@ -94,11 +108,16 @@ function GetMortiseStrategy( Proc, Part)
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Machining.Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Milling.ToolInfo.nToolIndex then
|
||||
Machining.Milling.bIsApplicable = true
|
||||
local dToolDiam = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter
|
||||
|
||||
-- se richiesta passata antischeggia
|
||||
if Strategy.Parameters.bAntiSplint then
|
||||
Machining.AntiSplint = GetMortiseAntiSplint( Proc, Part, Machining.Milling.ToolInfo)
|
||||
end
|
||||
|
||||
Machining.Milling.bIsApplicable = true
|
||||
-- calcolo numero passate necessarie
|
||||
if Proc.FeatureInfo.dMortiseMaxDist > TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter * 1.9 then
|
||||
local dToolDiam = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter
|
||||
if Proc.FeatureInfo.dMortiseMaxDist > dToolDiam * 1.9 then
|
||||
local sSideStep = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.nMillingPathsNeeded = 1 + ceil( ( Proc.FeatureInfo.dMortiseMaxDist - dToolDiam * 1.9) / ( sSideStep * 2))
|
||||
-- suddivido step in base al numero passate da fare
|
||||
@@ -107,6 +126,55 @@ function GetMortiseStrategy( Proc, Part)
|
||||
Machining.nMillingPathsNeeded = 1
|
||||
end
|
||||
|
||||
-- aggiungo geometria
|
||||
Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Machining.Milling.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Machining.Milling.nType = MCH_MY.MILLING
|
||||
Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
Machining.Milling.sDepth = Strategy.Parameters.dOverMatOnLength
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Machining.Milling.LeadIn = {}
|
||||
Machining.Milling.LeadOut = {}
|
||||
Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
|
||||
local dDeltaAngledEntry = Proc.FeatureInfo.vtMortisePathStart * dToolDiam / 2
|
||||
local dDeltaAngledExit = Proc.FeatureInfo.vtMortisePathEnd * dToolDiam / 2
|
||||
|
||||
Machining.Milling.LeadIn.dTangentDistance = dToolDiam / 2 + dDeltaAngledEntry + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadIn.dPerpDistance = 0
|
||||
Machining.Milling.LeadOut.dTangentDistance = dToolDiam / 2 + dDeltaAngledExit + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadOut.dPerpDistance = 0
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Milling.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
Machining.Milling.bInvert = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Machining.Milling.nWorkside = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
|
||||
Machining.Milling.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
|
||||
Machining.Milling.nSCC = GetSCC( Machining.Milling)
|
||||
|
||||
-- passate con sovramateriale
|
||||
Machining.Milling.AuxiliaryData = { Clones = {}}
|
||||
for i = Machining.nMillingPathsNeeded, 1, -1 do
|
||||
-- il primo è il passaggio più esterno
|
||||
local nIndexClones = Machining.nMillingPathsNeeded - i + 1
|
||||
-- cambia solo sovrmateriale radiale
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones] = {}
|
||||
-- ultima passata con sovramateriale impostato
|
||||
if i == 1 then
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
else
|
||||
-- suddivido step in base al numero passate da fare
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * Machining.Milling.dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Result.Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
@@ -116,6 +184,17 @@ function GetMortiseStrategy( Proc, Part)
|
||||
else
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
EgtAddCurveCompoLineTg( idGeomMaxOffset, Machining.Milling.LeadIn.dTangentDistance, false)
|
||||
EgtAddCurveCompoLineTg( idGeomMaxOffset, Machining.Milling.LeadOut.dTangentDistance, true)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtMortiseN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -161,9 +240,9 @@ function GetMortiseMachiningResult( Proc, Result)
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = ( Result.Milling.dMRR + Result.Cutting.dMRR) / 2
|
||||
local sQuality
|
||||
if not Strategy.Machining.bCuttingWithMill and Strategy.Machining.bAntiSplint then
|
||||
if not Strategy.Machining.bCuttingWithMill and Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
sQuality = 'BEST'
|
||||
elseif Strategy.Machining.bAntiSplint then
|
||||
elseif Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
sQuality = 'FINE'
|
||||
else
|
||||
sQuality = 'STD'
|
||||
@@ -176,7 +255,7 @@ function GetMortiseMachiningResult( Proc, Result)
|
||||
TotalResult.sStatus = Result.Milling.sStatus
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = Result.Milling.dMRR
|
||||
local sQuality = EgtIf( Strategy.Parameters.bAntiSplint, 'BEST', 'STD')
|
||||
local sQuality = EgtIf( Strategy.Machining.AntiSplint.bIsApplicable, 'BEST', 'STD')
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( sQuality)
|
||||
TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc)
|
||||
TotalResult.sInfo = ''
|
||||
@@ -233,14 +312,15 @@ local function CalcTopPath( nProcId, AuxId, nAddGrpId, dAltMort, dSideAng, b3Sol
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function ApplyMortiseAntiSplint( Proc, Part)
|
||||
function GetMortiseAntiSplint( Proc, Part, ToolInfo)
|
||||
local AntiSplint = { bIsApplicable = false}
|
||||
-- se il percorso non è chiuso, aggiungo percorso e lavorazione antischeggia
|
||||
if not EgtCurveIsClosed( Proc.FeatureInfo.idAddAuxGeom) then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- calcolo il percorso top mortise
|
||||
local dSideAng = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dSideAngle
|
||||
local dToolDiam = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter
|
||||
local dSideAng = TOOLS[ToolInfo.nToolIndex].dSideAngle
|
||||
local dToolDiam = TOOLS[ToolInfo.nToolIndex].dDiameter
|
||||
local vtExtr = Proc.FeatureInfo.vtMortiseN
|
||||
local nAuxId1 = CalcTopPath( Proc.id, Proc.FeatureInfo.idAddAuxGeom, nAddGrpId, Proc.FeatureInfo.dMortiseDepth, dSideAng, Part.b3Part)
|
||||
-- se esiste il percorso
|
||||
@@ -275,48 +355,62 @@ function ApplyMortiseAntiSplint( Proc, Part)
|
||||
if not nId1 then
|
||||
local sErr = 'Wrong geometry : Error on DtMortise '
|
||||
EgtOutLog( sErr)
|
||||
return false, sErr
|
||||
return AntiSplint
|
||||
end
|
||||
EgtModifyCurveExtrusion( nId1, vtExtr, GDB_RT.GLOB)
|
||||
|
||||
local Machining = {}
|
||||
Machining.nToolIndex = Strategy.Machining.Milling.ToolInfo.nToolIndex
|
||||
Machining.nType = MCH_MY.MILLING
|
||||
Machining.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
AntiSplint.nToolIndex = ToolInfo.nToolIndex
|
||||
AntiSplint.nType = MCH_MY.MILLING
|
||||
AntiSplint.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Machining.LeadIn = {}
|
||||
Machining.LeadOut = {}
|
||||
Machining.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.LeadIn.dPerpDistance = 0
|
||||
Machining.LeadOut.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.LeadOut.dPerpDistance = 0
|
||||
AntiSplint.LeadIn = {}
|
||||
AntiSplint.LeadOut = {}
|
||||
AntiSplint.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
AntiSplint.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
AntiSplint.LeadIn.dTangentDistance = TOOLS[ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
AntiSplint.LeadIn.dPerpDistance = 0
|
||||
AntiSplint.LeadOut.dTangentDistance = TOOLS[ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
AntiSplint.LeadOut.dPerpDistance = 0
|
||||
|
||||
Machining.dRadialOffset = dToolRadDelta - 1
|
||||
Machining.sDepth = Proc.FeatureInfo.dMortiseDepth - Strategy.Parameters.dOverMatOnLength
|
||||
Machining.Geometry = {{ nId1, -1}}
|
||||
Machining.bInvert = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Machining.nWorkside = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
Machining.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
AntiSplint.dRadialOffset = dToolRadDelta - 1
|
||||
AntiSplint.sDepth = Proc.FeatureInfo.dMortiseDepth - Strategy.Parameters.dOverMatOnLength
|
||||
AntiSplint.Geometry = {{ nId1, -1}}
|
||||
AntiSplint.bInvert = EgtIf( TOOLS[ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
AntiSplint.nWorkside = EgtIf( TOOLS[ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
AntiSplint.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
AntiSplint.nSCC = GetSCC( AntiSplint)
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.sStage = 'AfterTail'
|
||||
AntiSplint.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
local idGeomOffset = EgtCopyGlob( nId1, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomOffset, EgtIf( AntiSplint.bInvert, -TOOLS[ToolInfo.nToolIndex].dDiameter / 2, TOOLS[ToolInfo.nToolIndex].dDiameter / 2), Part.idTempGroup)
|
||||
-- trasformo arco in una curva compo per poi allungarla in direzione tangente
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
idGeomOffset = EgtCurveCompo( Part.idTempGroup, idGeomOffset)
|
||||
EgtAddCurveCompoLineTg( idGeomOffset, AntiSplint.LeadIn.dTangentDistance, false)
|
||||
EgtAddCurveCompoLineTg( idGeomOffset, AntiSplint.LeadOut.dTangentDistance, true)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomOffset, Proc.FeatureInfo.vtMortiseN, AntiSplint.nSCC, TOOLS[ToolInfo.nToolIndex])
|
||||
-- se soddisfa tutti i requisiti, posso applicare
|
||||
if bOutOfStroke then
|
||||
AntiSplint.bIsApplicable = false
|
||||
else
|
||||
AntiSplint.bIsApplicable = true
|
||||
end
|
||||
MachiningLib.AddMachinings( Proc, Machining)
|
||||
|
||||
else
|
||||
local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id)
|
||||
EgtOutLog( sErr)
|
||||
return false, sErr
|
||||
end
|
||||
else
|
||||
local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id)
|
||||
EgtOutLog( sErr)
|
||||
return false, sErr
|
||||
end
|
||||
end
|
||||
return AntiSplint
|
||||
end
|
||||
|
||||
|
||||
@@ -400,65 +494,19 @@ function STR0007.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
-- se richiesta passata antischeggia
|
||||
if Strategy.Parameters.bAntiSplint then
|
||||
ApplyMortiseAntiSplint( Proc, Part)
|
||||
if Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Strategy.Machining.AntiSplint)
|
||||
end
|
||||
|
||||
-- passaggio sul profilo
|
||||
if Strategy.Machining.Milling.bIsApplicable then
|
||||
local AuxiliaryData = {}
|
||||
-- se molti passaggi richiesti, si fa svuotatura
|
||||
-- TODO in attesa delle svuotature, si fanno passaggi senza limiti sul numero massimo. Poi togliere il FALSE nella condizione.
|
||||
if false and Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then
|
||||
-- TODO. SERVONO NUOVE SVUOTATURE!!!!
|
||||
else
|
||||
-- aggiungo geometria
|
||||
Strategy.Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Strategy.Machining.Milling.nToolIndex = Strategy.Machining.Milling.ToolInfo.nToolIndex
|
||||
Strategy.Machining.Milling.nType = MCH_MY.MILLING
|
||||
Strategy.Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
Strategy.Machining.Milling.sDepth = Strategy.Parameters.dOverMatOnLength
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Strategy.Machining.Milling.LeadIn = {}
|
||||
Strategy.Machining.Milling.LeadOut = {}
|
||||
Strategy.Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Machining.Milling.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Machining.Milling.LeadIn.dPerpDistance = 0
|
||||
Strategy.Machining.Milling.LeadOut.dTangentDistance = TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Machining.Milling.LeadOut.dPerpDistance = 0
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Milling.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
Strategy.Machining.Milling.bInvert = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Strategy.Machining.Milling.nWorkside = EgtIf( TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
|
||||
Strategy.Machining.Milling.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
|
||||
-- TODO calcolare SCC
|
||||
|
||||
-- passate con sovramateriale
|
||||
AuxiliaryData.Clones = {}
|
||||
for i = Strategy.Machining.nMillingPathsNeeded, 1, -1 do
|
||||
-- il primo è il passaggio più esterno
|
||||
local nIndexClones = Strategy.Machining.nMillingPathsNeeded - i + 1
|
||||
-- cambia solo sovrmateriale radiale
|
||||
AuxiliaryData.Clones[nIndexClones] = {}
|
||||
-- ultima passata con sovramateriale impostato
|
||||
if i == 1 then
|
||||
AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
else
|
||||
-- suddivido step in base al numero passate da fare
|
||||
AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * Strategy.Machining.Milling.dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
-- aggiunge lavorazione
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, AuxiliaryData)
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, Strategy.Machining.Milling.AuxiliaryData)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -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,165 +1,190 @@
|
||||
-- Strategia: STR0009
|
||||
-- Descrizione
|
||||
-- Fresatura di contorno
|
||||
-- Feature tipo Arco
|
||||
-- Feature tipo ScarfJoint
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
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,80 +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.dStep = TOOLS[Strategy.Machinings[i].ToolInfo.nToolIndex].dStep
|
||||
Strategy.Machinings[i].Steps = MachiningLib.GetMachiningSteps( 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"
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
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
|
||||
@@ -83,7 +103,8 @@ end
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.sFamily == 'Bevel' or Proc.Topology.sFamily == 'DoubleBevel' or
|
||||
Proc.Topology.sName == 'VGroove-2-Through' or Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Proc.Topology.sName == 'VGroove-2-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or
|
||||
Proc.Topology.sName == 'Cut-1-Through' then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -92,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
|
||||
@@ -111,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
|
||||
@@ -147,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
|
||||
@@ -171,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
|
||||
@@ -178,16 +206,24 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- controllo dimensioni
|
||||
if not IsPositionOK( Proc, Part) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Feature not machinable in this position')
|
||||
-- controllo dimensioni solo se non è forzata
|
||||
if not CustomParameters.bForcedStrategy then
|
||||
if not IsPositionOk( Proc, Part) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Feature not machinable in this position')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla, serve una lavorazioen che lasci il testimone
|
||||
if MachiningLib.IsFeatureHinderingClamping( Proc, Part) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable ( Feature hinders clamping)'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
|
||||
-- TODO taglio su eventuali facce di chiusura
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
@@ -201,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
|
||||
@@ -253,7 +411,12 @@ function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #Strategy.Machinings do
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j])
|
||||
local AuxiliaryData = {}
|
||||
-- se strategia forzata non considero area non pinzabile
|
||||
if CustomParameters.bForcedStrategy then
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j], AuxiliaryData)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -20,224 +20,159 @@ local Strategy = {}
|
||||
local function GetDrillingStrategy( Proc, Part)
|
||||
local ToolSearchParameters = {}
|
||||
local Machining = {}
|
||||
local sQuality
|
||||
|
||||
-- se lavorazione orizzontale
|
||||
if Proc.FeatureInfo.bIsDrillHorizontal then
|
||||
local bDouble = false
|
||||
local Drilling = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
Drilling.bIsApplicable = false
|
||||
-- si cerca utensile 1
|
||||
local Drilling = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
ToolSearchParameters.ptCheckOutStroke = { Proc.FeatureInfo.ptDrillCenter + ( EgtMdbGetGeneralParam( MCH_GP.SAFEZ) * ToolSearchParameters.vtToolDirection)}
|
||||
|
||||
Drilling.ToolInfo = {}
|
||||
Drilling.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
-- se trovato utensile si settano i parametri comuni
|
||||
if Drilling.ToolInfo.nToolIndex then
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.dStep = TOOLS[Drilling.nToolIndex].dStep
|
||||
end
|
||||
|
||||
-- TODO se utensile 2 che si torverà è il gemello da usare nelle lavorazioni in doppio, allora gestire di conseguenza l'applicazione delle lavorazioni in doppio
|
||||
-- si cerca utensile 2
|
||||
local Drilling2 = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
Drilling2.ToolInfo = {}
|
||||
if Proc.FeatureInfo.bIsDrillOpen then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
Drilling.ToolInfo = {}
|
||||
Drilling.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
if Drilling.ToolInfo.nToolIndex then
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.dStep = TOOLS[Drilling.ToolInfo.nToolIndex].dStep
|
||||
-- se lavorazione non completa o se si deve forare dai due lati
|
||||
if Proc.FeatureInfo.bIsDrillOpen and
|
||||
( Drilling.ToolInfo.dResidualDepth > 10 * GEO.EPS_SMALL or Strategy.Parameters.sDrillingMode == 'FORCE_TWO' or Strategy.Parameters.sDrillingMode == 'AUTO') then
|
||||
bDouble = true
|
||||
local dHalfDrill = ( Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP) / 2
|
||||
Drilling.sDepth = min( dHalfDrill, Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth)
|
||||
Drilling.vtFaceNormal = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.bInvert = false
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
table.insert( Machining, Drilling)
|
||||
local Drilling2 = BeamLib.TableCopyDeep( Drilling)
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
table.insert( Machining, Drilling2)
|
||||
else
|
||||
Drilling.sDepth = 'TH'
|
||||
Drilling.vtFaceNormal = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.bInvert = false
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
table.insert( Machining, Drilling)
|
||||
end
|
||||
ToolSearchParameters.ptCheckOutStroke = { Proc.FeatureInfo.ptDrillCenter + ( ( Proc.FeatureInfo.dDrillLen + EgtMdbGetGeneralParam( MCH_GP.SAFEZ)) * ToolSearchParameters.vtToolDirection)}
|
||||
|
||||
-- voto
|
||||
if Drilling.ToolInfo.dResidualDepth < 0 or ( Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP) / 2 > Drilling.ToolInfo.dResidualDepth then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo or Machining[2].ToolInfo)
|
||||
if bDouble or not Proc.FeatureInfo.bIsDrillOpen then
|
||||
sQuality = 'FINE'
|
||||
else
|
||||
sQuality = 'ROUGH'
|
||||
end
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( sQuality)
|
||||
Strategy.Result.sInfo = ''
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = EgtIf( bDouble, Machining[1].sDepth * 2, Proc.FeatureInfo.dDrillLen)
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo or Machining[2].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE') -- se non completo, anche se fosse foro singolo, comunque non esce dall'altra parte, quindi non scheggia
|
||||
end
|
||||
else
|
||||
local sMessage = 'Drillbit not found'
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
end
|
||||
-- se lavorazione verticale
|
||||
else
|
||||
-- si cerca utensile 1
|
||||
local Drilling = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
Drilling.ToolInfo = {}
|
||||
Drilling.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
-- si cerca utensile 2
|
||||
local Drilling2 = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
Drilling2.ToolInfo = {}
|
||||
if Proc.FeatureInfo.bIsDrillOpen then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
Drilling2.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
end
|
||||
|
||||
-- se possono lavorare entrambi e si deve fare lavorazione doppia e si riesce a completare
|
||||
if Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex and
|
||||
( Strategy.Parameters.sDrillingMode == 'FORCE_TWO' or Strategy.Parameters.sDrillingMode == 'AUTO') and
|
||||
Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
|
||||
local dExtraDrill = ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP - ( Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth)) / 2
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
-- se trovato utensile si settano i parametri comuni
|
||||
if Drilling2.ToolInfo.nToolIndex then
|
||||
Drilling2.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling2)
|
||||
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
|
||||
-- se utensile 1 esegue completamente
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO') or not Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = 'TH'
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- se utensile 2 esegue completamente
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Drilling2.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO')) then
|
||||
Drilling2.sDepth = 'TH'
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- se possono lavorare entrambi
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex then
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
if Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth + Machining[2].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
end
|
||||
-- voto
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- se utensile 1 non completo
|
||||
elseif Drilling.ToolInfo.nToolIndex and ( Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' or Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- se utensile 2 non completo
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' then
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining[1].ToolInfo)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
else
|
||||
local sMessage
|
||||
-- se non sono state trovate punte
|
||||
if not Drilling.ToolInfo.nToolIndex and not Drilling2.ToolInfo.nToolIndex then
|
||||
sMessage = 'Drillbit not found'
|
||||
-- se son state trovate delle punte, ma non è stato possibile forare da entrambe le parti
|
||||
elseif Strategy.Parameters.sDrillingMode == 'FORCE_TWO' then
|
||||
sMessage = "Not possible to force machining from both sides. Please change drilling mode to AUTO"
|
||||
end
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
Drilling2.dStep = TOOLS[Drilling2.nToolIndex].dStep
|
||||
end
|
||||
end
|
||||
|
||||
-- se possono lavorare entrambi e si deve fare lavorazione doppia e si riesce a completare
|
||||
if Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex and
|
||||
( Strategy.Parameters.sDrillingMode == 'FORCE_TWO' or Strategy.Parameters.sDrillingMode == 'AUTO') and
|
||||
Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
|
||||
local dExtraDrill = ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP - ( Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth)) / 2
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling2)
|
||||
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
|
||||
-- se utensile 1 esegue completamente
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO') or not Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- annullo altra lavorazione
|
||||
Drilling2.ToolInfo.nToolIndex = nil
|
||||
-- se utensile 2 esegue completamente
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Drilling2.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO')) then
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- annullo altra lavorazione
|
||||
Drilling.ToolInfo.nToolIndex = nil
|
||||
-- se possono lavorare entrambi
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
if Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth + Machining[2].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
end
|
||||
-- voto
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- se utensile 1 non completo
|
||||
elseif Drilling.ToolInfo.nToolIndex and ( Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' or Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- annullo altra lavorazione
|
||||
Drilling2.ToolInfo.nToolIndex = nil
|
||||
-- se utensile 2 non completo
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' then
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- annullo altra lavorazione
|
||||
Drilling.ToolInfo.nToolIndex = nil
|
||||
else
|
||||
local sMessage
|
||||
-- se non sono state trovate punte
|
||||
if not Drilling.ToolInfo.nToolIndex and not Drilling2.ToolInfo.nToolIndex then
|
||||
sMessage = 'Drillbit not found'
|
||||
-- se son state trovate delle punte, ma non è stato possibile forare da entrambe le parti
|
||||
elseif Strategy.Parameters.sDrillingMode == 'FORCE_TWO' then
|
||||
sMessage = "Not possible to force machining from both sides. Please change drilling mode to AUTO"
|
||||
end
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
end
|
||||
|
||||
-- calcolo tempo di lavorazione
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
if Drilling.ToolInfo.nToolIndex then
|
||||
Strategy.Result.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Drilling, Part)
|
||||
end
|
||||
if Drilling2.ToolInfo.nToolIndex then
|
||||
Strategy.Result.dTimeToMachine = Strategy.Result.dTimeToMachine + MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Drilling2, Part)
|
||||
end
|
||||
|
||||
return Machining, Strategy.Result
|
||||
end
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -70,26 +70,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "dMinZAngleTopBlade",
|
||||
"sNameNge": "MIN_Z_ANGLE_TOP_BLADE",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Min Z angle top blade",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxYAngleTopBlade",
|
||||
"sNameNge": "MAX_Y_ANGLE_TOP_BLADE",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Max Y angle top blade",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -59,9 +59,9 @@ function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- separazione della terza faccia
|
||||
local idAddedTmFace
|
||||
local nAddedFace
|
||||
if Proc.AdjacencyMatrix[1][2] > 10 * GEO.EPS_ANG_SMALL and Proc.AdjacencyMatrix[2][3] < 10 * GEO.EPS_ANG_SMALL then
|
||||
if Proc.AdjacencyMatrix[2][3] < 0 then
|
||||
nAddedFace = 1 - 1
|
||||
elseif Proc.AdjacencyMatrix[2][3] > 10 * GEO.EPS_ANG_SMALL and Proc.AdjacencyMatrix[3][1] < 10 * GEO.EPS_ANG_SMALL then
|
||||
elseif Proc.AdjacencyMatrix[1][3] < 0 then
|
||||
nAddedFace = 2 - 1
|
||||
else
|
||||
nAddedFace = 3 - 1
|
||||
@@ -73,8 +73,14 @@ function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
if not( AreSameVectorApprox( Proc.Faces[nAddedFace + 1].vtN, X_AX()) and abs( Proc.Faces[nAddedFace + 1].ptCenter:getX() - Part.b3Part:getMax():getX()) < 10 * GEO.EPS_SMALL)
|
||||
and not( AreSameVectorApprox( Proc.Faces[nAddedFace + 1].vtN, -X_AX()) and abs( Proc.Faces[nAddedFace + 1].ptCenter:getX() - Part.b3Part:getMin():getX()) < 10 * GEO.EPS_SMALL) then
|
||||
|
||||
-- faccia aggiuntiva da lavorare
|
||||
idAddedTmFace = EgtCopySurfTmFacet( Proc.id, nAddedFace, nAddGrpId)
|
||||
-- faccia aggiuntiva da lavorare: si estende fino al box della parte
|
||||
local idAddGroup
|
||||
if bAddMachining then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
idAddedTmFace = EgtSurfTmPlaneInBBox( idAddGroup, Proc.Faces[nAddedFace + 1].ptCenter, Proc.Faces[nAddedFace + 1].vtN, Part.b3Part, GDB_ID.ROOT)
|
||||
end
|
||||
|
||||
-- rimozione della terza faccia dalla Proc
|
||||
@@ -85,17 +91,13 @@ function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
NewProc.NotClampableLength = FeatureLib.CalculateFeatureNotClampableLengths( NewProc, Part)
|
||||
NewProc.bHindersLaserMeasure = FeatureLib.CalculateFeatureHindersLaserMeasure( NewProc, Part)
|
||||
|
||||
-- TODO rimuovere??? codolo da implementare o no??
|
||||
-- considerazioni necessarie a determinare se lavorare con codolo oppure no
|
||||
local bKeepWasteAttached = ( Strategy.Parameters.sCuttingStrategy == 'KEEP_WASTE_ATTACHED')
|
||||
local bDropWaste = ( Strategy.Parameters.sCuttingStrategy == 'DROP_WASTE')
|
||||
local dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail = FeatureLib.GetFeatureMaxNotClampableLengths( NewProc, Part)
|
||||
local bFeatureHindersClamping = FeatureLib.IsMachiningLong( max( dFeatureMaxNotClampableLengthHead, dFeatureMaxNotClampableLengthTail), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
local bIsFeatureLong = FeatureLib.IsMachiningLong( NewProc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
local bFeatureHindersClamping = MachiningLib.IsFeatureHinderingClamping( Proc, Part)
|
||||
|
||||
-- lavorazione con codolo
|
||||
if ( bIsFeatureLong)
|
||||
or ( bFeatureHindersClamping and not bDropWaste)
|
||||
if ( bFeatureHindersClamping and not bDropWaste)
|
||||
or bKeepWasteAttached then
|
||||
|
||||
local BladeKeepWasteResult
|
||||
@@ -109,19 +111,9 @@ function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
-- lavorazione a cubetti facce concave
|
||||
else
|
||||
local dMinZTopBlade
|
||||
local dMaxNyTopBlade
|
||||
local BladeToWasteResult
|
||||
if Strategy.Parameters.dMinZAngleTopBlade then
|
||||
dMinZTopBlade = sin( Strategy.Parameters.dMinZAngleTopBlade)
|
||||
end
|
||||
if Strategy.Parameters.dMaxYAngleTopBlade then
|
||||
dMaxNyTopBlade = sin( Strategy.Parameters.dMaxYAngleTopBlade)
|
||||
end
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
dMinNzTopBlade = dMinZTopBlade,
|
||||
dMaxNyTopBlade = dMaxNyTopBlade,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
@@ -138,19 +130,9 @@ function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- TODO da completare
|
||||
-- TODO va messa per prima????????
|
||||
if idAddedTmFace then
|
||||
local dMinZTopBlade
|
||||
local dMaxNyTopBlade
|
||||
local BladeToWasteResult
|
||||
if Strategy.Parameters.dMinZAngleTopBlade then
|
||||
dMinZTopBlade = sin( Strategy.Parameters.dMinZAngleTopBlade)
|
||||
end
|
||||
if Strategy.Parameters.dMaxYAngleTopBlade then
|
||||
dMaxNyTopBlade = sin( Strategy.Parameters.dMaxYAngleTopBlade)
|
||||
end
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
dMinNzTopBlade = dMinZTopBlade,
|
||||
dMaxNyTopBlade = dMaxNyTopBlade,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
@@ -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
|
||||
@@ -198,6 +198,10 @@ function STR0013.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
MachiningToAdd.nToolIndex = nIndexTool
|
||||
MachiningToAdd.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
|
||||
if Proc.AffectedFaces.bLeft and not Proc.FeatureInfo.bIsDrillOpen then
|
||||
MachiningToAdd.sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, MachiningToAdd)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local ID = require( 'Identity')
|
||||
@@ -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)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local FaceData = require( 'FaceData')
|
||||
@@ -108,15 +108,17 @@ local function GetRoughStrategy( Proc, Part, bSaveAddedGeometries)
|
||||
local nMidFacet = Proc.nFct // 2 -- faccia a metà circa
|
||||
local vtN = EgtSurfTmFacetNormVersor( Proc.id, nMidFacet, GDB_ID.ROOT)
|
||||
|
||||
local nAddGroupId = BeamLib.GetAddGroup( Part.id)
|
||||
local idAddGroup
|
||||
if bSaveAddedGeometries then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
-- aggiungo piano di sgrossatura e lo lavoro
|
||||
local ptStart, vtNP = GetSawCutData( Proc, Proc.idAddAuxGeom, vtNF, vtN)
|
||||
local AddId = EgtSurfTmPlaneInBBox( nAddGroupId, ptStart, vtNP, Part.b3Part, GDB_RT.GLOB)
|
||||
local AddId = EgtSurfTmPlaneInBBox( idAddGroup, ptStart, vtNP, Part.b3Part, GDB_RT.GLOB)
|
||||
-- se la faccia è stata creata
|
||||
if AddId then
|
||||
if not bSaveAddedGeometries then
|
||||
EgtSetLevel( AddId, GDB_LV.TEMP)
|
||||
end
|
||||
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
@@ -209,7 +211,7 @@ local function GetEdgeWithCornerStrategy( Proc, Part)
|
||||
-- direzioni di lavorazione
|
||||
local vtCutDir1
|
||||
-- se è diretta verso alto o basso
|
||||
if vtN:getZ() > vtN:getY() then
|
||||
if abs( vtN:getZ()) > abs( vtN:getY()) then
|
||||
if vtN:getZ() > 0 then
|
||||
vtCutDir1 = Z_AX()
|
||||
else
|
||||
@@ -231,81 +233,99 @@ local function GetEdgeWithCornerStrategy( Proc, Part)
|
||||
vtCutDir2 = -X_AX()
|
||||
end
|
||||
|
||||
local nMachiningsToAdd
|
||||
|
||||
-- AUTO = preferisce lama. Se non è possibile prende fresa
|
||||
-- BLADE_FORCED = solo lama, altriemnti non applica nulla (potrebbe essere necessario un ribaltamento)
|
||||
-- MILL_FORCED = solo fresa, altriemnti non applica nulla (potrebbe essere necessario un ribaltamento)
|
||||
if Strategy.Parameters.sConcaveFaceStrategy == 'AUTO' or Strategy.Parameters.sConcaveFaceStrategy == 'BLADE_FORCED' then
|
||||
|
||||
nMachiningsToAdd = 0
|
||||
|
||||
-- TODO c'è una funzione che ritorni l'edge di connessione tra una faccia e un'altra?
|
||||
-- lavorazione faccia 1 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet+1, vtCutDir1)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nLastFacet+1], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
if Cutting then
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 1 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+2, vtCutDir1)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nFirstFacet+2], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
if Cutting then
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet, vtCutDir2)
|
||||
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nLastFacet], EdgeToMachine)
|
||||
if Cutting then
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+1, vtCutDir2)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nFirstFacet+1], EdgeToMachine)
|
||||
if Cutting then
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono lavorazioni provo a pulire spigoli con fresa, a patto che non sia stato forzato con lama
|
||||
if #Machining == 0 and Strategy.Parameters.sConcaveFaceStrategy ~= 'BLADE_FORCED' then
|
||||
if ( not nMachiningsToAdd or ( #Machining < nMachiningsToAdd)) and Strategy.Parameters.sConcaveFaceStrategy ~= 'BLADE_FORCED' then
|
||||
|
||||
Machining = {}
|
||||
nMachiningsToAdd = 0
|
||||
|
||||
-- TODO c'è una funzione che ritorni l'edge di connessione tra una faccia e un'altra?
|
||||
-- lavorazione faccia 1 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+2, vtCutDir1)
|
||||
local Milling = FaceByMill.Make( Proc, Part, Proc.Faces[nFirstFacet+2], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Milling.sStage = 'AfterTail'
|
||||
end
|
||||
if Milling then
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet, vtCutDir2)
|
||||
local Milling = FaceByMill.Make( Proc, Part, Proc.Faces[nLastFacet], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Milling.sStage = 'AfterTail'
|
||||
end
|
||||
if Milling then
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if nMachiningsToAdd and ( #Machining < nMachiningsToAdd) then
|
||||
Result = { dCompletionPercentage = ( #Machining / nMachiningsToAdd)}
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
@@ -439,7 +459,7 @@ local function GetArcStrategy( Proc, Part)
|
||||
|
||||
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 ID.IsRoundArch( Proc) and ( bIsFeatureDown or bIsFeatureBack or bForceStrip) then
|
||||
if bIsFeatureDown or bIsFeatureBack then
|
||||
dDimStrip = dDimStrip or max( BeamData.DIM_STRIP or 5, 5)
|
||||
else
|
||||
@@ -637,7 +657,7 @@ local function GetFeatureResult( Proc)
|
||||
-- se richieste anche le altre lavorazioni
|
||||
if not Strategy.Parameters.bOnlyChamfer then
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) then
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- se sgrossatura da eseguire
|
||||
if Strategy.Parameters.bExecRough then
|
||||
if not Strategy.RoughCut.Machinings or #Strategy.RoughCut.Machinings == 0 then
|
||||
@@ -698,7 +718,7 @@ function STR0015.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- calcolo se la lavorazione del tenone può essere spostata dopo taglio di coda
|
||||
-- verifico se la lavorazione può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
@@ -718,7 +738,7 @@ function STR0015.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- se non bisogna fare solo gli smussi, si calcolano le altre lavorazioni
|
||||
if not Strategy.Parameters.bOnlyChamfer then
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) then
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- lavorazione taglio per sgrossare
|
||||
if Strategy.Parameters.bExecRough then
|
||||
Strategy.RoughCut = {}
|
||||
@@ -760,7 +780,7 @@ function STR0015.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) then
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- lavorazione di sgrezzatura di lama
|
||||
if Strategy.Parameters.bExecRough and Strategy.RoughCut.Machinings then
|
||||
-- se cutting da fare come svuotatura
|
||||
@@ -797,10 +817,7 @@ function STR0015.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Profile.Machinings[i].Geometry = {{ Proc.idAddAuxGeom, -1}}
|
||||
Strategy.Profile.Machinings[i].nToolIndex = Strategy.Profile.Machinings[i].ToolInfo.nToolIndex
|
||||
Strategy.Profile.Machinings[i].nType = MCH_MY.MILLING
|
||||
Strategy.Profile.Machinings[i].Steps = {}
|
||||
|
||||
Strategy.Profile.Machinings[i].Steps.dStep = TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].dStep
|
||||
Strategy.Profile.Machinings[i].Steps = MachiningLib.GetMachiningSteps( tonumber( Strategy.Profile.Machinings[i].sDepth), TOOLS[Strategy.Profile.Machinings[i].nToolIndex].dStep)
|
||||
Strategy.Profile.Machinings[i].Steps = MachiningLib.GetMachiningSteps( false, tonumber( Strategy.Profile.Machinings[i].sDepth), TOOLS[Strategy.Profile.Machinings[i].nToolIndex].dStep)
|
||||
Strategy.Profile.Machinings[i].Steps.nStepType = MCH_MILL_ST.ONEWAY
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local SPLITCUT = require( 'SPLITCUT')
|
||||
@@ -34,11 +34,18 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
Strategy.Result.sInfo = ''
|
||||
local OptionalParameters = { bForceChainSaw = Strategy.Parameters.bForceChainSaw, bReduceBladePath = Strategy.Parameters.bReduceBladePath,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength, dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume }
|
||||
OptionalParameters.sRestLengthSideForPreSimulation = 'Tail'
|
||||
OptionalParameters.bCannotSplitRestLength = true
|
||||
local bAreAllMachiningsAdded = true
|
||||
local bExecutePrecutOnly = false
|
||||
|
||||
-- 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
|
||||
@@ -49,6 +56,11 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
OptionalParameters.bDisableDicing = true
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Split not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se devo rimuovere tutto il restante
|
||||
else
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
@@ -58,10 +70,18 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
OptionalParameters.dOffset = 0
|
||||
else
|
||||
Strategy.bIsPreCut = true
|
||||
-- TODO questo dOffset è errato, va creata una nuova faccia oppure usare dLongitudinalOffset e farlo transitare per tutti, anche Engagement
|
||||
-- TODO a dRestLength va anche aggiunto lo spessore lama se c'è a fine grezzo?
|
||||
OptionalParameters.dOffset = Part.dRestLength
|
||||
end
|
||||
OptionalParameters.bDisableDicing = true
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Precut Tail not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se non faccio tagli PRECUT, imposto tabella Result direttamente. Non serve verificare che riesca a rimuovere il materiale extra
|
||||
else
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
@@ -74,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()
|
||||
@@ -122,21 +139,26 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
|
||||
if not bExecutePrecutOnly then
|
||||
OptionalParameters = {}
|
||||
|
||||
-- eventuale grezzo custom per dicing (grezzo attuale + grezzo di coda)
|
||||
local nNextRawId = EgtGetNextRawPart( Part.idRaw)
|
||||
if nNextRawId then
|
||||
local b3BoxDicing = EgtGetRawPartBBox( nNextRawId)
|
||||
b3BoxDicing:Add( Part.b3Raw)
|
||||
OptionalParameters.b3BoxDicing = b3BoxDicing
|
||||
-- si recuperano gli estremi del box del materiale di coda da rimuovere
|
||||
local b3PartWithTail = BeamLib.GetPartBoxWithHeadTail( Part, 'Tail')
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMin():getX() + 1, Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithTail:getMin():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
|
||||
local OptionalParametersBladeToWaste = {}
|
||||
OptionalParametersBladeToWaste.b3BoxDicing = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
OptionalParametersBladeToWaste.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParametersBladeToWaste.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
OptionalParametersBladeToWaste.sRestLengthSideForPreSimulation = 'Tail'
|
||||
OptionalParametersBladeToWaste.bCannotSplitRestLength = true
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
-- se taglio non riuscito, si riprova con il riduci percorso forzato (collisione possibile in separazione pezzi alti)
|
||||
if ( not Strategy.Machining) or ( #Strategy.Machining == 0) then
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = true
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
end
|
||||
|
||||
OptionalParameters.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParameters.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParameters.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParameters)
|
||||
if Strategy.Machining and #Strategy.Machining > 0 then
|
||||
for i = 1, #Strategy.Machining do
|
||||
local TempList = {}
|
||||
@@ -149,6 +171,9 @@ function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
end
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Tail machining not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
+262
-92
@@ -11,47 +11,66 @@ require( 'EgtBase')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local FaceData = require( 'FaceData')
|
||||
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
|
||||
@@ -104,7 +123,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
|
||||
@@ -117,31 +136,95 @@ 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
|
||||
-- attenzione perchè se l'inclinazione della faccia la fa finire oltre lo spigolo questo riduce il massimo (come calcolare????)
|
||||
-- il FindBlade dovrà restituire di utilizzare sempre la lama sopra se l'angolo lo permette, ma avendo un'altezza massima (da macchina) oltre cui il DownUp non sarà fattibile (evita collisioni tra asse e pezzo)
|
||||
-- TODO scelta utensile è corretto lasciarla a FaceByBlade?
|
||||
-- TODO aggiungere accorciamento se angolo < 90
|
||||
|
||||
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
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( 'BladeKeepWaste : angle between faces must be concave and >= 90deg')
|
||||
return Machinings, Result
|
||||
end
|
||||
-- Rabbet lungo X non gestito
|
||||
if Proc.Topology.sName == 'Rabbet-2-Through' and Proc.AffectedFaces.bLeft and Proc.AffectedFaces.bRight then
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( 'BladeKeepWaste : Rabbet along X not managed')
|
||||
return Machinings, Result
|
||||
end
|
||||
elseif Proc.nFct == 3 then
|
||||
-- caso speciale RidgeLap - 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
|
||||
@@ -164,39 +247,34 @@ 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
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
||||
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)
|
||||
@@ -205,44 +283,129 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
-- calcolo lavorazioni
|
||||
-- taglio eventuali facce di chiusura
|
||||
for i = 1, #LongFaces do
|
||||
local Cutting = {}
|
||||
local OptionalParametersFaceByBlade = { bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = 9999, 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)
|
||||
-- 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
|
||||
-- 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
|
||||
|
||||
-- taglio con codolo faccia di fondo
|
||||
local dDepthToMachine = BottomEdgeToMachine.dElevation - OptionalParameters.dStripWidth
|
||||
local OptionalParametersFaceByBlade = { dDepthToMachine = dDepthToMachine, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail, nToolIndex = nToolIndex}
|
||||
-- primo lato
|
||||
Cutting1 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade)
|
||||
Cutting1.nInternalSortingPriority = 3
|
||||
Cutting1.dResultWeight = 0.3
|
||||
table.insert( CalculatedMachinings, Cutting1)
|
||||
-- secondo lato
|
||||
OptionalParametersFaceByBlade.OppositeToolDirectionMode = 'Enabled'
|
||||
Cutting2 = FaceByBlade.Make( Proc, Part, BottomFace, BottomEdgeToMachine, OptionalParametersFaceByBlade)
|
||||
Cutting2.nInternalSortingPriority = 3
|
||||
Cutting2.dResultWeight = 0.3
|
||||
--table.insert( CalculatedMachinings, Cutting2)
|
||||
|
||||
-- fresatura eventuali facce di chiusura
|
||||
-- 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
|
||||
end
|
||||
|
||||
-- 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
|
||||
local dDepthToMachineMill = BottomFace.MainEdges.LongEdges[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = max( Cutting1.dToolMarkLength, Cutting2.dToolMarkLength)
|
||||
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
|
||||
Milling.dResultWeight = 0.05
|
||||
table.insert( CalculatedMachinings, Milling)
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
@@ -253,8 +416,10 @@ function BLADEKEEPWASTE.Make( Proc, Part, OptionalParameters)
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo completamento, serve la lista di lavorazioni che comprende le non applicabili
|
||||
Result.dCompletionPercentage = GetStrategyCompletionPercentage( CalculatedMachinings)
|
||||
-- calcolo completamento (non applicabili devono essere incluse)
|
||||
-- se codolo non forzato si ritorna completa max al 94% (completion index 4)
|
||||
local dCalculatedCompletionPercentage = GetStrategyCompletionPercentage( CalculatedMachinings)
|
||||
Result.dCompletionPercentage = bForced and dCalculatedCompletionPercentage or min( 94, dCalculatedCompletionPercentage)
|
||||
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
|
||||
|
||||
-- aggiunta eventuali lavorazioni splittate
|
||||
@@ -266,12 +431,17 @@ 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)
|
||||
if Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Result.sStatus = 'Completed'
|
||||
if bForced then
|
||||
Result.sInfo = 'Waste attached. Remove manually.'
|
||||
end
|
||||
else
|
||||
Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
|
||||
+439
-276
File diff suppressed because it is too large
Load Diff
+301
-206
@@ -4,142 +4,90 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FaceData = require( 'FaceData')
|
||||
local LeadInOutLib = require( 'LeadInOutLib')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local FACEBYBLADE = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetLeadInOutType( Machining)
|
||||
local sLeadInOutType = ''
|
||||
-- i parametri si leggono da LeadInOut (engagement) e si modificano solo se necessario
|
||||
local function GetLeadInOut( Machining, EdgeToMachine, bIsSplitFeature)
|
||||
|
||||
if Machining.bIsStartClosed or Machining.bIsEndClosed
|
||||
or Machining.sCutType == 'Guillotine'
|
||||
or Machining.sCutType == 'Reduced' then
|
||||
|
||||
sLeadInOutType = 'Perpendicular'
|
||||
else
|
||||
-- testa sopra
|
||||
if TOOLS[Machining.nToolIndex].SetupInfo.HeadType.bTop then
|
||||
if abs( Machining.vtToolDirection:getX()) < 0.7 then
|
||||
if Machining.vtToolDirection:getZ() > -0.087
|
||||
or ( abs( Machining.vtToolDirection:getX()) < 0.34202 and abs( Machining.vtToolDirection:getZ()) < 0.7) then
|
||||
sLeadInOutType = 'Perpendicular'
|
||||
else
|
||||
sLeadInOutType = 'Tangent'
|
||||
end
|
||||
elseif abs( Machining.vtEdgeDirection:getZ()) > 0.7 then
|
||||
sLeadInOutType = 'Perpendicular'
|
||||
else
|
||||
-- TODO qui attacco tangenziale speciale tutto da un lato
|
||||
sLeadInOutType = 'Tangent'
|
||||
end
|
||||
-- testa sotto
|
||||
elseif TOOLS[Machining.nToolIndex].SetupInfo.HeadType.bBottom then
|
||||
if abs( Machining.vtToolDirection:getX()) < 0.7 then
|
||||
if Machining.vtToolDirection:getZ() < -GEO.EPS_SMALL
|
||||
or ( abs( Machining.vtToolDirection:getX()) < 0.34202 and abs( Machining.vtToolDirection:getZ()) < 0.7) then
|
||||
sLeadInOutType = 'Perpendicular'
|
||||
else
|
||||
sLeadInOutType = 'Tangent'
|
||||
end
|
||||
elseif abs( Machining.vtEdgeDirection:getZ()) > 0.7 then
|
||||
sLeadInOutType = 'Perpendicular'
|
||||
else
|
||||
-- TODO qui attacco tangenziale speciale tutto da un lato
|
||||
sLeadInOutType = 'Tangent'
|
||||
end
|
||||
-- se testa senza preferenza Top e Bottom si fa sempre attacco tangenziale
|
||||
else
|
||||
sLeadInOutType = 'Tangent'
|
||||
end
|
||||
end
|
||||
local LeadIn
|
||||
local LeadOut
|
||||
|
||||
return sLeadInOutType
|
||||
end
|
||||
|
||||
|
||||
local function CalculateLeadInOut( Machining, EdgeToMachine, bIsSplitFeature)
|
||||
-- TODO implementare le funzioni di Tool Collision Avoidance (vedi wiki e FacesBysaw -> CalcLeadInOutPerpGeom)
|
||||
|
||||
-- accorciamento per lati chiusi (è sempre l'impronta utensile)
|
||||
local dToolMarkLength = sqrt( Machining.dDepthToMachine * TOOLS[Machining.nToolIndex].dDiameter - Machining.dDepthToMachine * Machining.dDepthToMachine)
|
||||
-- allungamento per faccia singola (aperta in tutte le direzioni)
|
||||
local dAddedLengthOpenFace = BeamData.CUT_EXTRA
|
||||
if Machining.sCutType == 'Guillotine' then
|
||||
local dGuillotineLengthToMachine = 1
|
||||
dAddedLengthOpenFace = ( - EdgeToMachine.dLength + dGuillotineLengthToMachine) / 2
|
||||
elseif Machining.sCutType == 'Reduced' then
|
||||
dAddedLengthOpenFace = - FACEBYBLADE.GetPathReductionLength( Machining.nToolIndex, Machining.dMaxRadialOffset)
|
||||
end
|
||||
|
||||
if Machining.bInvert then
|
||||
Machining.bIsStartClosed, Machining.bIsEndClosed = Machining.bIsEndClosed, Machining.bIsStartClosed
|
||||
end
|
||||
|
||||
local LeadIn = {}
|
||||
local LeadOut = {}
|
||||
Machining.sLeadInOutType = ''
|
||||
LeadIn.dStartAddLength = 0
|
||||
LeadOut.dEndAddLength = 0
|
||||
LeadIn.nType = MCH_MILL_LI.LINEAR
|
||||
LeadOut.nType = MCH_MILL_LI.LINEAR
|
||||
LeadIn.dPerpDistance = 0
|
||||
LeadOut.dPerpDistance = 0
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dTangentDistance = 0
|
||||
-- in certe condizioni si deve forzare attacco perpendicolare
|
||||
if Machining.bIsStartClosed
|
||||
or Machining.bIsEndClosed
|
||||
or Machining.CloneStepsRadial.nCount > 1
|
||||
or Machining.Steps.nCount > 1
|
||||
or bIsSplitFeature then
|
||||
|
||||
Machining.sLeadInOutType = 'Perpendicular'
|
||||
if AreSameVectorApprox( Machining.vtToolDirection, EdgeToMachine.vtN) then
|
||||
LeadIn.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadOut.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
|
||||
if Machining.LeadInOut.Perpendicular then
|
||||
|
||||
Machining.sLeadInOutType = 'Perpendicular'
|
||||
|
||||
-- se attacco perpendicolare richiesto ma non disponibile, la lavorazione non è fattibile
|
||||
else
|
||||
LeadIn.dPerpDistance = BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadOut.dPerpDistance = BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
|
||||
return
|
||||
end
|
||||
else
|
||||
Machining.sLeadInOutType = GetLeadInOutType( Machining)
|
||||
if Machining.sLeadInOutType == 'Perpendicular' then
|
||||
LeadIn.dPerpDistance = 1
|
||||
LeadOut.dPerpDistance = 1
|
||||
else
|
||||
-- TODO da rimuovere, già inserito in GetLeadInOutType
|
||||
if abs( Machining.vtEdgeDirection:getZ()) > 0.707 then
|
||||
LeadIn.dPerpDistance = 1
|
||||
LeadOut.dPerpDistance = 1
|
||||
else
|
||||
LeadIn.dTangentDistance = TOOLS[Machining.nToolIndex].dDiameter / 2 + BeamData.CUT_SIC
|
||||
LeadOut.dTangentDistance = TOOLS[Machining.nToolIndex].dDiameter / 2 + BeamData.CUT_SIC
|
||||
end
|
||||
end
|
||||
|
||||
Machining.sLeadInOutType = Machining.LeadInOut.sChosen
|
||||
end
|
||||
LeadIn.dElevation = 0
|
||||
LeadOut.dElevation = 0
|
||||
LeadIn.dCompLength = 0
|
||||
LeadOut.dCompLength = 0
|
||||
if Machining.bIsStartClosed and Machining.bIsEndClosed then
|
||||
LeadIn.dStartAddLength = -dToolMarkLength
|
||||
LeadOut.dEndAddLength = -dToolMarkLength
|
||||
elseif Machining.bIsStartClosed then
|
||||
LeadIn.dStartAddLength = -dToolMarkLength
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadOut.dEndAddLength = max( -LeadIn.dStartAddLength - EdgeToMachine.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
elseif Machining.bIsEndClosed then
|
||||
LeadOut.dEndAddLength = -dToolMarkLength
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadIn.dStartAddLength = max( -LeadOut.dEndAddLength - EdgeToMachine.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
else
|
||||
LeadIn.dStartAddLength = dAddedLengthOpenFace
|
||||
LeadOut.dEndAddLength = dAddedLengthOpenFace
|
||||
|
||||
-- si prendono i valori che arrivano da LeadInOut (engagement)
|
||||
LeadIn = BeamLib.TableCopyDeep( Machining.LeadInOut[Machining.sLeadInOutType].LeadIn)
|
||||
LeadOut = BeamLib.TableCopyDeep( Machining.LeadInOut[Machining.sLeadInOutType].LeadOut)
|
||||
|
||||
-- se senso di percorrenza invertito si invertono anche gli attacchi
|
||||
if Machining.bInvert then
|
||||
Machining.bIsStartClosed, Machining.bIsEndClosed = Machining.bIsEndClosed, Machining.bIsStartClosed
|
||||
LeadIn, LeadOut = LeadInOutLib.InvertLeadInOut( LeadIn, LeadOut)
|
||||
end
|
||||
|
||||
-- in caso di percorso ridotto gli attacchi vanno adeguati
|
||||
if Machining.sEdgeUsage == 'Guillotine' then
|
||||
local dGuillotineLengthToMachine = 1
|
||||
LeadIn.dStartAddLength = ( - EdgeToMachine.dLength + dGuillotineLengthToMachine) / 2
|
||||
LeadOut.dEndAddLength = ( - EdgeToMachine.dLength + dGuillotineLengthToMachine) / 2
|
||||
LeadIn.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadOut.dTangentDistance = 0
|
||||
LeadIn.dTotalLength = sqrt( LeadIn.dPerpDistance ^ 2 + LeadIn.dTangentDistance ^ 2)
|
||||
LeadOut.dTotalLength = sqrt( LeadOut.dPerpDistance ^ 2 + LeadOut.dTangentDistance ^ 2)
|
||||
elseif Machining.sEdgeUsage == 'Reduced' then
|
||||
LeadIn.dStartAddLength = - FACEBYBLADE.GetPathReductionLength( Machining.nToolIndex, Machining.dMaxRadialOffset)
|
||||
LeadOut.dEndAddLength = - FACEBYBLADE.GetPathReductionLength( Machining.nToolIndex, Machining.dMaxRadialOffset)
|
||||
LeadIn.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dPerpDistance = EdgeToMachine.dElevation + BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadOut.dTangentDistance = 0
|
||||
LeadIn.dTotalLength = sqrt( LeadIn.dPerpDistance ^ 2 + LeadIn.dTangentDistance ^ 2)
|
||||
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
|
||||
LeadOut.dPerpDistance = BeamData.CUT_SIC - Machining.dRadialOffset
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dTangentDistance = 0
|
||||
end
|
||||
|
||||
-- stima lunghezza reale attacchi per calcolo lunghezza lavorata
|
||||
-- TODO sistemare per nuovi attacchi
|
||||
local dEstimatedLeadInPerpDistance = 0
|
||||
local dEstimatedLeadInTangentDistance = 0
|
||||
local dEstimatedLeadOutPerpDistance = 0
|
||||
@@ -163,8 +111,8 @@ local function CalculateLeadInOut( Machining, EdgeToMachine, bIsSplitFeature)
|
||||
end
|
||||
|
||||
|
||||
-- TODO implementare SCC in funzione macchina
|
||||
local function GetSCC( vtMachiningDirection, vtEdgeDirection, vtNFace)
|
||||
-- TODO da eliminare, sostituita da funzione macchina
|
||||
function FACEBYBLADE.GetSCC( vtMachiningDirection, vtEdgeDirection, vtNFace)
|
||||
local nSCC = MCH_SCC.NONE
|
||||
|
||||
if abs( vtMachiningDirection:getX()) > abs( vtMachiningDirection:getY()) - GEO.EPS_SMALL then
|
||||
@@ -259,60 +207,84 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
dLongitudinalOffset = 0
|
||||
end
|
||||
local dRadialStepSpan = OptionalParameters.dRadialStepSpan
|
||||
local dMinNzDownUp = OptionalParameters.dMinNzDownUp
|
||||
local sUserNotes = OptionalParameters.sUserNotes or ''
|
||||
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
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
Cutting.vtToolDirection = -EdgeToMachine.vtN
|
||||
else
|
||||
Cutting.vtToolDirection = EdgeToMachine.vtN
|
||||
end
|
||||
Cutting.vtEdgeDirection = EdgeToMachine.vtN ^ FaceToMachine.vtN
|
||||
-- TODO conviene spostare questi calcoli nel FaceData?
|
||||
Cutting.ptEdge1, _, Cutting.ptEdge2 = EgtSurfTmFacetOppositeSide( Proc.id, FaceToMachine.id, -Cutting.vtToolDirection, GDB_ID.ROOT)
|
||||
-- TODO gestire lama da sotto
|
||||
-- se si conosce il limite downUp (utensile forzato o downUp forzato) si decide se invertire (ToolInvert)
|
||||
-- TODO esiste un limite downUp massimo per la lama da sopra??
|
||||
if nToolIndex and not dMinNzDownUp then
|
||||
dMinNzDownUp = TOOLS[nToolIndex].SetupInfo.GetMinNzDownUp( Part.b3Raw, FaceToMachine.vtN, Cutting.vtToolDirection, TOOLS[nToolIndex])
|
||||
end
|
||||
if dMinNzDownUp and FaceToMachine.vtN:getZ() < dMinNzDownUp then
|
||||
Cutting.bToolInvert = true
|
||||
else
|
||||
Cutting.bToolInvert = false
|
||||
end
|
||||
-- TODO questa deve essere ptEnd - ptStart
|
||||
Cutting.vtEdgeDirection = Vector3d( EdgeToMachine.vtEdge)
|
||||
Cutting.vtToolDirection = EdgeToMachine.vtN
|
||||
Cutting.ptEdge1, Cutting.ptEdge2 = EdgeToMachine.ptStart, EdgeToMachine.ptEnd
|
||||
local EdgeToMachineOpposite = BeamLib.FindEdgeBestOrientedAsDirection( FaceToMachine.Edges, -EdgeToMachine.vtN)
|
||||
|
||||
-- ricerca utensile
|
||||
-- l'utensile arriva da fuori: si determina se il taglio è fattibile e il modo di lavorare della lama
|
||||
if nToolIndex then
|
||||
|
||||
Cutting.nToolIndex = nToolIndex
|
||||
local BladeEngagementParameters = {
|
||||
Face = FaceToMachine,
|
||||
Edge = EdgeToMachine,
|
||||
Part = Part,
|
||||
Tool = TOOLS[Cutting.nToolIndex],
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
BladeEngagementParameters.Edge = EdgeToMachineOpposite
|
||||
end
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
local Engagement
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
Cutting.bIsApplicable, Engagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
||||
TIMER:stopElapsed( 'GetBladeEngagement')
|
||||
if Cutting.bIsApplicable then
|
||||
Cutting.sBladeEngagement = Engagement.sBladeEngagement
|
||||
Cutting.bMoveAfterSplit = Engagement.bMoveAfterSplit
|
||||
Cutting.LeadInOut = Engagement.LeadInOut
|
||||
end
|
||||
|
||||
-- utensile da cercare: si prende la lama migliore che può effettuare questo taglio, senza particolari analisi
|
||||
else
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = dDepthToMachine
|
||||
if Cutting.bToolInvert then
|
||||
ToolSearchParameters.vtN = -FaceToMachine.vtN
|
||||
else
|
||||
ToolSearchParameters.vtN = FaceToMachine.vtN
|
||||
end
|
||||
ToolSearchParameters.bAllowTopHead = true
|
||||
-- TODO bisognerà implementare anche la lama da sotto
|
||||
ToolSearchParameters.bAllowBottomHead = false
|
||||
ToolSearchParameters.bAllowBottomHead = true
|
||||
ToolSearchParameters.bForceLongcutBlade = bForceLongcutBlade
|
||||
ToolSearchParameters.FaceToMachine = FaceToMachine
|
||||
ToolSearchParameters.EdgeToMachine = EdgeToMachine
|
||||
ToolSearchParameters.Part = Part
|
||||
ToolSearchParameters.sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation
|
||||
ToolSearchParameters.bCannotSplitRestLength = bCannotSplitRestLength
|
||||
ToolSearchParameters.bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
|
||||
local ToolInfo = MachiningLib.FindBlade( Proc, ToolSearchParameters)
|
||||
-- ora che l'utensile è scelto, se non era definito l'angolo di DownUp lo verifico per decidere se invertire
|
||||
if ToolInfo.nToolIndex and not dMinNzDownUp then
|
||||
dMinNzDownUp = TOOLS[ToolInfo.nToolIndex].SetupInfo.GetMinNzDownUp( Part.b3Raw, FaceToMachine.vtN, Cutting.vtToolDirection, TOOLS[ToolInfo.nToolIndex])
|
||||
if FaceToMachine.vtN:getZ() < dMinNzDownUp then
|
||||
Cutting.bToolInvert = true
|
||||
end
|
||||
end
|
||||
Cutting.nToolIndex = ToolInfo.nToolIndex
|
||||
if Cutting.nToolIndex then
|
||||
Cutting.sBladeEngagement = ToolInfo.Engagement.sBladeEngagement
|
||||
Cutting.bMoveAfterSplit = ToolInfo.Engagement.bMoveAfterSplit
|
||||
Cutting.LeadInOut = ToolInfo.Engagement.LeadInOut
|
||||
end
|
||||
|
||||
-- se non trovato utensile, la lavorazione non è applicabile
|
||||
if not Cutting.nToolIndex then
|
||||
Cutting.bIsApplicable = false
|
||||
end
|
||||
end
|
||||
if not TOOLS[Cutting.nToolIndex] or not TOOLS[Cutting.nToolIndex].sName then
|
||||
|
||||
-- orientamento non raggiungibile o lama non trovata: non applicabile
|
||||
if not Cutting.bIsApplicable then
|
||||
Cutting.sMessage = 'Blade not found'
|
||||
Cutting.bIsApplicable = false
|
||||
EgtOutLog( Cutting.sMessage)
|
||||
|
||||
return Cutting, EdgeToMachine.dElevation
|
||||
end
|
||||
|
||||
@@ -322,25 +294,32 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
Cutting.sMessage = 'Pocket too narrow for blade thickness'
|
||||
Cutting.bIsApplicable = false
|
||||
EgtOutLog( Cutting.sMessage)
|
||||
|
||||
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)
|
||||
return Cutting, EdgeToMachine.dElevation
|
||||
end
|
||||
end
|
||||
-- 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
|
||||
|
||||
-- parametri della lavorazione
|
||||
|
||||
-- profondità (parametro DEPTH)
|
||||
Cutting.sDepth = sDepth
|
||||
Cutting.sDepth = sDepth
|
||||
|
||||
-- inizio e fine aperti o chiusi
|
||||
Cutting.bIsStartClosed = not EdgeToMachine.bIsStartOpen
|
||||
Cutting.bIsEndClosed = not EdgeToMachine.bIsEndOpen
|
||||
-- lato di lavoro e inversione per avere taglio concorde
|
||||
Cutting.bIsStartClosed = not EdgeToMachine.bIsStartOpen
|
||||
Cutting.bIsEndClosed = not EdgeToMachine.bIsEndOpen
|
||||
|
||||
-- si settano lato di lavoro e inversione per avere concordanza
|
||||
if TOOLS[Cutting.nToolIndex].bIsCCW then
|
||||
Cutting.nWorkside = MCH_MILL_WS.RIGHT
|
||||
Cutting.bInvert = true
|
||||
@@ -348,37 +327,95 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
Cutting.nWorkside = MCH_MILL_WS.LEFT
|
||||
Cutting.bInvert = false
|
||||
end
|
||||
-- se OppositeToolDirectionMode è Optimized, se possibile e necessario, si attiva per garantire taglio concorde e verso l'alto (massima qualità)
|
||||
if ( OppositeToolDirectionMode == 'Optimized') and ( Proc.nFct == 1) and ( FaceData.IsFaceRhomboid( Proc, FaceToMachine.id)) then
|
||||
OppositeToolDirectionMode = 'Disabled'
|
||||
-- la direzione di percorrenza del lato deve essere verso l'alto; bInvert va considerata perchè inverte la direzione di percorrenza.
|
||||
if ( Cutting.bInvert and Cutting.vtEdgeDirection:getZ() > 100 * GEO.EPS_SMALL)
|
||||
or ( ( not Cutting.bInvert) and Cutting.vtEdgeDirection:getZ() < -100 * GEO.EPS_SMALL) then
|
||||
|
||||
-- si attiva OppositeToolDirection solo se non cambiano le condizioni di taglio downUp
|
||||
local dNewMinNzDownUp = TOOLS[nToolIndex].SetupInfo.GetMinNzDownUp( Part.b3Raw, FaceToMachine.vtN, -Cutting.vtToolDirection, TOOLS[nToolIndex])
|
||||
if ( FaceToMachine.vtN:getZ() < dMinNzDownUp) == ( FaceToMachine.vtN:getZ() < dNewMinNzDownUp) then
|
||||
OppositeToolDirectionMode = 'Enabled'
|
||||
Cutting.vtToolDirection = -EdgeToMachine.vtN
|
||||
Cutting.ptEdge1, _, Cutting.ptEdge2 = EgtSurfTmFacetOppositeSide( Proc.id, FaceToMachine.id, -Cutting.vtToolDirection, GDB_ID.ROOT)
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
-- se le condizioni downUp cambiano, si setta per tagliare verso l'alto
|
||||
else
|
||||
if Cutting.nWorkside == MCH_MILL_WS.RIGHT then
|
||||
Cutting.nWorkside = MCH_MILL_WS.LEFT
|
||||
Cutting.bInvert = false
|
||||
else
|
||||
Cutting.nWorkside = MCH_MILL_WS.RIGHT
|
||||
Cutting.bInvert = true
|
||||
end
|
||||
-- ToolInvert
|
||||
if Cutting.sBladeEngagement == 'DownUp' then
|
||||
Cutting.bToolInvert = true
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
end
|
||||
|
||||
-- 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)
|
||||
or ( ( not Cutting.bInvert) and Cutting.vtEdgeDirection:getZ() < -100 * GEO.EPS_SMALL) then
|
||||
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
if Cutting.nWorkside == MCH_MILL_WS.LEFT then
|
||||
Cutting.nWorkside = MCH_MILL_WS.RIGHT
|
||||
else
|
||||
Cutting.nWorkside = MCH_MILL_WS.LEFT
|
||||
end
|
||||
end
|
||||
|
||||
-- analisi fattibilità lavorazione dal lato opposto
|
||||
if OppositeToolDirectionMode ~= 'Disabled' then
|
||||
|
||||
-- lavorando dalla direzione opposta si verifica come se si lavorasse il lato opposto
|
||||
local BladeEngagementParameters = {
|
||||
Face = FaceToMachine,
|
||||
Edge = EdgeToMachineOpposite,
|
||||
Part = Part,
|
||||
Tool = TOOLS[Cutting.nToolIndex],
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
local bIsApplicableOpposite, EngagementOpposite = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters)
|
||||
TIMER:stopElapsed( 'GetBladeEngagement')
|
||||
|
||||
-- taglio opposto non fattibile
|
||||
if not bIsApplicableOpposite then
|
||||
-- se richiesto, si ritorna non applicabile
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
|
||||
Cutting.sMessage = 'Orientation not reachable'
|
||||
Cutting.bIsApplicable = false
|
||||
|
||||
return Cutting, EdgeToMachine.dElevation
|
||||
|
||||
-- se opzionale, si disabilita
|
||||
elseif OppositeToolDirectionMode == 'Optimized' then
|
||||
OppositeToolDirectionMode = 'Disabled'
|
||||
end
|
||||
end
|
||||
|
||||
-- se OppositeToolDirectionMode è Optimized, se possibile e necessario, si attiva la lavorazione dal lato opposto per garantire taglio concorde e verso l'alto (massima qualità)
|
||||
if ( OppositeToolDirectionMode == 'Optimized') and ( Proc.nFct == 1) and ( FaceData.IsFaceRectangle( FaceToMachine)) then
|
||||
|
||||
OppositeToolDirectionMode = 'Disabled'
|
||||
|
||||
-- la direzione di percorrenza del lato deve essere verso l'alto; bInvert va considerata perchè inverte la direzione di percorrenza
|
||||
-- il BladeEngagement non deve cambiare, altrimenti è inutile invertire la direzione
|
||||
if ( EngagementOpposite.sBladeEngagement == Cutting.sBladeEngagement)
|
||||
and ( EngagementOpposite.bMoveAfterSplit == Cutting.bMoveAfterSplit)
|
||||
and ( Cutting.bInvert and Cutting.vtEdgeDirection:getZ() > 100 * GEO.EPS_SMALL)
|
||||
or ( ( not Cutting.bInvert) and Cutting.vtEdgeDirection:getZ() < -100 * GEO.EPS_SMALL) then
|
||||
|
||||
OppositeToolDirectionMode = 'Enabled'
|
||||
end
|
||||
end
|
||||
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
Cutting.vtToolDirection = EdgeToMachineOpposite.vtN
|
||||
Cutting.ptEdge1, Cutting.ptEdge2 = EdgeToMachineOpposite.ptStart, EdgeToMachineOpposite.ptEnd
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
-- TODO da migliorare!!!!!!!!!
|
||||
if not EngagementOpposite.LeadInOut.Perpendicular then
|
||||
Cutting.LeadInOut.Perpendicular = nil
|
||||
end
|
||||
if not EngagementOpposite.LeadInOut.Tangent then
|
||||
Cutting.LeadInOut.Tangent = nil
|
||||
end
|
||||
end
|
||||
elseif OppositeToolDirectionMode == 'Enabled' then
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
end
|
||||
if Cutting.bToolInvert then
|
||||
Cutting.bInvert = not Cutting.bInvert
|
||||
end
|
||||
|
||||
-- TODO implementare lavorazione in DownUp se non è già DownUp e non si è riusciti a mantenere verso l'alto e concorde (testare solo DownUp))
|
||||
|
||||
-- profondità da lavorare e offset radiale
|
||||
if OptionalParameters.dPocketHeight then
|
||||
if TOOLS[Cutting.nToolIndex].dMaxDepth > dDepthToMachine - 10 * GEO.EPS_SMALL then
|
||||
@@ -402,36 +439,73 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
else
|
||||
Cutting.dDepthToMachine = dDepthToMachine
|
||||
Cutting.dResidualDepth = 0
|
||||
Cutting.sCutType = 'Standard'
|
||||
Cutting.sEdgeUsage = 'Standard'
|
||||
if bReduceBladePath
|
||||
and ( Proc.nFct == 1)
|
||||
and FaceData.IsFaceRectangular( Proc, FaceToMachine.id) then
|
||||
and FaceData.IsFaceRectangle( FaceToMachine) then
|
||||
|
||||
local bIsTopBlade = TOOLS[nToolIndex].SetupInfo.HeadType.bTop
|
||||
Cutting.dMaxRadialOffset = TOOLS[nToolIndex].dMaxMaterial - Cutting.dDepthToMachine - BeamData.CUT_SIC
|
||||
Cutting.dRadialOffsetGuillotine = FACEBYBLADE.GetRadialOffsetForGuillotine( nToolIndex, EdgeToMachine.dLength)
|
||||
-- TODO la lama sotto deve poter ridurre. Ghigliottina sì o no?
|
||||
local bIsTopBlade = TOOLS[Cutting.nToolIndex].SetupInfo.HeadType.bTop
|
||||
Cutting.dMaxRadialOffset = TOOLS[Cutting.nToolIndex].dMaxMaterial - Cutting.dDepthToMachine - BeamData.CUT_SIC
|
||||
Cutting.dRadialOffsetGuillotine = FACEBYBLADE.GetRadialOffsetForGuillotine( Cutting.nToolIndex, EdgeToMachine.dLength)
|
||||
if Cutting.dMaxRadialOffset > 10 * GEO.EPS_SMALL then
|
||||
-- taglio a ghigliottina
|
||||
if bIsTopBlade and ( Cutting.dRadialOffsetGuillotine < Cutting.dMaxRadialOffset - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
dDepthToMachine = Cutting.dDepthToMachine + Cutting.dRadialOffsetGuillotine
|
||||
Cutting.sCutType = 'Guillotine'
|
||||
Cutting.sEdgeUsage = 'Guillotine'
|
||||
|
||||
-- taglio ridotto
|
||||
else
|
||||
dDepthToMachine = Cutting.dDepthToMachine + Cutting.dMaxRadialOffset
|
||||
Cutting.sCutType = 'Reduced'
|
||||
Cutting.sEdgeUsage = 'Reduced'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se cambiata la profondità dDepthToMachine, si ritesta la fattibilità del taglio
|
||||
if Cutting.sEdgeUsage ~= 'Standard' then
|
||||
local EdgeToMachineForEngagement = EdgeToMachine
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
EdgeToMachineForEngagement = EdgeToMachineOpposite
|
||||
end
|
||||
local BladeEngagementParameters = {
|
||||
Face = FaceToMachine,
|
||||
Edge = EdgeToMachineForEngagement,
|
||||
Part = Part,
|
||||
Tool = TOOLS[Cutting.nToolIndex],
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local BladeEngagementOptionalParameters = {
|
||||
bIsDicing = bIsDicing,
|
||||
sRestLengthSideForPreSimulation = sRestLengthSideForPreSimulation,
|
||||
bCannotSplitRestLength = bCannotSplitRestLength,
|
||||
bDisableRealElevationCheck = bDisableRealElevationCheck
|
||||
}
|
||||
TIMER:startElapsed( 'GetBladeEngagement')
|
||||
local bIsApplicable, CurrentEngagement = MachiningLib.GetBladeEngagement( BladeEngagementParameters, BladeEngagementOptionalParameters )
|
||||
TIMER:stopElapsed( 'GetBladeEngagement')
|
||||
|
||||
-- se non fattibile o cambiano le condizioni BladeEngagement, non si riduce
|
||||
if not ( bIsApplicable and ( CurrentEngagement.sBladeEngagement == Cutting.sBladeEngagement) and ( CurrentEngagement.bMoveAfterSplit == Cutting.bMoveAfterSplit)) then
|
||||
Cutting.sEdgeUsage = 'Standard'
|
||||
dDepthToMachine = Cutting.dDepthToMachine
|
||||
end
|
||||
end
|
||||
|
||||
-- offset radiale (cambia se taglio opposto)
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
Cutting.dRadialOffset = -dDepthToMachine
|
||||
else
|
||||
Cutting.dRadialOffset = EdgeToMachine.dElevation - dDepthToMachine
|
||||
end
|
||||
end
|
||||
|
||||
-- completamento
|
||||
Cutting.dCompletionPercentage = ( 1 - Cutting.dResidualDepth / Cutting.dDepthToMachine) * 100
|
||||
|
||||
-- step verticale e offset longitudinale
|
||||
Cutting.Steps = MachiningLib.GetMachiningSteps( dPocketHeight, TOOLS[Cutting.nToolIndex].dThickness)
|
||||
Cutting.Steps = MachiningLib.GetMachiningSteps( true, dPocketHeight, TOOLS[Cutting.nToolIndex].dThickness)
|
||||
Cutting.Steps.nStepType = MCH_MILL_ST.ONEWAY
|
||||
Cutting.dMaxElev = Cutting.Steps.dStep * Cutting.Steps.nCount - 10 * GEO.EPS_SMALL
|
||||
if Cutting.bToolInvert then
|
||||
@@ -443,10 +517,13 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
else
|
||||
Cutting.dLongitudinalOffset = dLongitudinalOffset
|
||||
end
|
||||
|
||||
-- distanza di sicurezza
|
||||
Cutting.dStartSafetyLength = BeamData.CUT_SIC
|
||||
|
||||
-- overlap
|
||||
Cutting.dOverlap = 0
|
||||
|
||||
-- EdgeUse e frame lavorazione
|
||||
if OppositeToolDirectionMode == 'Enabled' then
|
||||
Cutting.nFaceuse = BeamLib.GetNearestOrthoOpposite( -Cutting.vtToolDirection)
|
||||
@@ -457,23 +534,37 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
--Cutting.vtFaceUse = Cutting.vtToolDirection
|
||||
Cutting.nEdgesFaceUse = EdgeToMachine.id
|
||||
end
|
||||
|
||||
-- SCC
|
||||
Cutting.nSCC = GetSCC( Cutting.vtToolDirection, Cutting.vtEdgeDirection, FaceToMachine.vtN)
|
||||
Cutting.nSCC = TOOLS[Cutting.nToolIndex].SetupInfo.GetSCC( Cutting.vtToolDirection, Cutting.vtEdgeDirection, FaceToMachine.vtN)
|
||||
|
||||
-- asse bloccato
|
||||
Cutting.sBlockedAxis = BeamLib.GetBlockedAxis( Cutting.nToolIndex, 'perpendicular', Part.b3Raw, FaceToMachine.vtN, EgtIf( FaceToMachine.vtN:getX() > 0, X_AX(), -X_AX()))
|
||||
|
||||
-- eventuale step orizzontale
|
||||
Cutting.CloneStepsRadial = {}
|
||||
if not dRadialStepSpan then
|
||||
dRadialStepSpan = Cutting.dDepthToMachine
|
||||
end
|
||||
if dRadialStepSpan > 10 * GEO.EPS_SMALL and TOOLS[Cutting.nToolIndex].dSideStep then
|
||||
Cutting.CloneStepsRadial = MachiningLib.GetMachiningSteps( dRadialStepSpan, TOOLS[Cutting.nToolIndex].dSideStep)
|
||||
Cutting.CloneStepsRadial = MachiningLib.GetMachiningSteps( true, dRadialStepSpan, TOOLS[Cutting.nToolIndex].dSideStep)
|
||||
else
|
||||
Cutting.CloneStepsRadial.nCount = 1
|
||||
Cutting.CloneStepsRadial.dStep = Cutting.dDepthToMachine
|
||||
end
|
||||
|
||||
-- approccio e retrazione
|
||||
Cutting.LeadIn, Cutting.LeadOut = CalculateLeadInOut( Cutting, EdgeToMachine, bIsSplitFeature)
|
||||
Cutting.LeadIn, Cutting.LeadOut = GetLeadInOut( Cutting, EdgeToMachine, bIsSplitFeature)
|
||||
-- se il calcolo attacchi fallisce, la lavorazione non è fattibile
|
||||
if not Cutting.LeadIn or not Cutting.LeadOut then
|
||||
|
||||
Cutting.bIsApplicable = false
|
||||
return Cutting
|
||||
end
|
||||
|
||||
-- solo per debug
|
||||
--Cutting.nOutRaw = 3
|
||||
|
||||
-- lunghezza lavorata
|
||||
-- TODO per il calcolo del dLengthOnX si deve correggere con allungamento / accorciamento percorso
|
||||
Cutting.dLengthToMachine = EdgeToMachine.dLength + Cutting.LeadIn.dStartAddLength + Cutting.LeadOut.dEndAddLength
|
||||
@@ -481,6 +572,7 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
Cutting.dLengthOnX = b3BoxEdge:getDimX()
|
||||
Cutting.dTimeToMachine, Cutting.dLengthToMachineAllStepsWithLeadInOut = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Cutting, Part)
|
||||
-- lunghezza impronta lama
|
||||
-- TODO rimpiazzare con LeadInOut.dToolMarkLength
|
||||
if Cutting.bIsStartClosed and Cutting.bIsEndClosed then
|
||||
Cutting.dToolMarkLength = abs( min( Cutting.LeadIn.dStartAddLength, Cutting.LeadOut.dEndAddLength))
|
||||
elseif Cutting.bIsStartClosed then
|
||||
@@ -499,8 +591,9 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
|
||||
-- se lavorazione aperta sulla coda, eventuali aggiustamenti
|
||||
-- TODO valutare se fare funzione a parte
|
||||
local bIsTruncatingCutOnTail = Proc.Topology and ( Proc.Topology.sName == 'Cut-1-Through' or Proc.Topology.sName == 'TailCut') and Proc.AffectedFaces.bLeft
|
||||
if bIsTruncatingCutOnTail then
|
||||
Cutting.bMoveAfterSplit = Cutting.bMoveAfterSplit or Cutting.LeadIn.bMoveAfterSplit or Cutting.LeadOut.bMoveAfterSplit
|
||||
local bIsTruncatingCutOnTail = Proc.Topology and ( Proc.Topology.sName == 'Cut-1-Through' or Proc.Topology.sName == 'TailCut') and Proc.AffectedFaces.bLeft
|
||||
if Cutting.bMoveAfterSplit or bIsTruncatingCutOnTail then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
elseif Proc.AffectedFaces.bLeft and ( EdgeToMachine.sType == 'Bottom' or ( Cutting.vtToolDirection:getX() < 0.707)) then
|
||||
local dLengthOnX = Cutting.dLengthOnX
|
||||
@@ -517,12 +610,14 @@ function FACEBYBLADE.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPar
|
||||
if not AreSameOrOppositeVectorApprox( EdgeToMachine.vtN, Y_AX()) then
|
||||
if MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part) then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
Cutting.bMoveAfterSplit = true
|
||||
else
|
||||
Cutting.bIsApplicable = false
|
||||
end
|
||||
elseif dAddLengthLeftSide + dAddLengthToReduce > dExtendAfterTail then
|
||||
if MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part) then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
Cutting.bMoveAfterSplit = true
|
||||
else
|
||||
if bStartLeft then
|
||||
Cutting.LeadIn.dStartAddLength = - dAddLengthToReduce + dExtendAfterTail
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
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
|
||||
|
||||
@@ -82,8 +87,8 @@ function FACEBYCHAINSAW.Make( Proc, Part, FaceToMachine, EdgeToMachine, Optional
|
||||
else
|
||||
Mortising.vtToolDirection = EdgeToMachine.vtN
|
||||
end
|
||||
Mortising.vtEdgeDirection = EdgeToMachine.vtN ^ FaceToMachine.vtN
|
||||
Mortising.ptEdge1, _, Mortising.ptEdge2 = EgtSurfTmFacetOppositeSide( Proc.id, FaceToMachine.id, -Mortising.vtToolDirection, GDB_ID.ROOT)
|
||||
Mortising.vtEdgeDirection = Vector3d( EdgeToMachine.vtEdge)
|
||||
Mortising.ptEdge1, Mortising.ptEdge2 = EdgeToMachine.ptStart, EdgeToMachine.ptEnd
|
||||
|
||||
-- ricerca utensile
|
||||
local ToolSearchParameters = {}
|
||||
@@ -196,22 +201,41 @@ 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
|
||||
dLongitudinalStepSpan = dPocketHeight
|
||||
end
|
||||
if dLongitudinalStepSpan > 10 * GEO.EPS_SMALL then
|
||||
Mortising.CloneStepsLongitudinal = MachiningLib.GetMachiningSteps( dLongitudinalStepSpan, TOOLS[Mortising.nToolIndex].dThickness)
|
||||
Mortising.CloneStepsLongitudinal = MachiningLib.GetMachiningSteps( true, dLongitudinalStepSpan, TOOLS[Mortising.nToolIndex].dThickness)
|
||||
else
|
||||
Mortising.CloneStepsLongitudinal.nCount = 1
|
||||
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())
|
||||
|
||||
+25
-12
@@ -4,8 +4,9 @@
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamData')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local PreSimulationLib = require('PreSimulationLib')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local FACEBYMILL = {}
|
||||
@@ -119,6 +120,10 @@ local function CalculateLeadInOut( Machining, EdgeToMachine, bIsSplitFeature)
|
||||
LeadIn.dStartAddLength = BeamData.CUT_EXTRA
|
||||
LeadOut.dEndAddLength = BeamData.CUT_EXTRA
|
||||
end
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = EdgeToMachine.ptStart - EdgeToMachine.vtEdge * ( LeadIn.dStartAddLength + LeadIn.dTangentDistance) + EdgeToMachine.vtN * ( EdgeToMachine.dElevation - Machining.dDepthToMachine + LeadIn.dPerpDistance)
|
||||
LeadOut.ptPoint = EdgeToMachine.ptEnd + EdgeToMachine.vtEdge * ( LeadOut.dEndAddLength + LeadOut.dTangentDistance) + EdgeToMachine.vtN * ( EdgeToMachine.dElevation - Machining.dDepthToMachine + LeadOut.dPerpDistance)
|
||||
|
||||
-- stima lunghezza reale attacchi per calcolo lunghezza lavorata
|
||||
local dEstimatedLeadInPerpDistance = 0
|
||||
local dEstimatedLeadInTangentDistance = 0
|
||||
@@ -203,9 +208,8 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
else
|
||||
Milling.vtToolDirection = EdgeToMachine.vtN
|
||||
end
|
||||
Milling.vtEdgeDirection = EdgeToMachine.vtN ^ FaceToMachine.vtN
|
||||
-- TODO conviene spostare questi calcoli nel FaceData?
|
||||
Milling.ptEdge1, _, Milling.ptEdge2 = EgtSurfTmFacetOppositeSide( Proc.id, FaceToMachine.id, -Milling.vtToolDirection, GDB_ID.ROOT)
|
||||
Milling.vtEdgeDirection = Vector3d( EdgeToMachine.vtEdge)
|
||||
Milling.ptEdge1, Milling.ptEdge2 = EdgeToMachine.ptStart, EdgeToMachine.ptEnd
|
||||
|
||||
-- se si conosce il limite downUp (utensile forzato o downUp forzato) si decide se invertire (ToolInvert)
|
||||
if nToolIndex and not dMinNzDownUp then
|
||||
@@ -251,7 +255,7 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
Milling.sMessage = 'Mill not found'
|
||||
Milling.bIsApplicable = false
|
||||
EgtOutLog( Milling.sMessage)
|
||||
return Milling, EdgeToMachine.dElevation
|
||||
return Milling
|
||||
end
|
||||
|
||||
-- verifica dimensioni tasca compatibili
|
||||
@@ -260,7 +264,7 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
Milling.sMessage = 'Pocket too narrow for blade thickness'
|
||||
Milling.bIsApplicable = false
|
||||
EgtOutLog( Milling.sMessage)
|
||||
return Milling, EdgeToMachine.dElevation
|
||||
return Milling
|
||||
end
|
||||
-- se tasca chiusa da entrambi i lati e più stretta della fresa la lavorazione non è applicabile
|
||||
if not ( EdgeToMachine.bIsStartOpen or EdgeToMachine.bIsEndOpen) then
|
||||
@@ -268,7 +272,7 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
Milling.sMessage = 'Pocket too narrow for blade diameter'
|
||||
Milling.bIsApplicable = false
|
||||
EgtOutLog( Milling.sMessage)
|
||||
return Milling, EdgeToMachine.dElevation
|
||||
return Milling
|
||||
end
|
||||
end
|
||||
|
||||
@@ -325,13 +329,11 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
Milling.dCompletionPercentage = ( 1 - Milling.dResidualDepth / Milling.dDepthToMachine) * 100
|
||||
-- step verticale e offset longitudinale
|
||||
if OptionalParameters.dPocketHeight then
|
||||
Milling.Steps = MachiningLib.GetMachiningSteps( dPocketHeight, TOOLS[Milling.nToolIndex].dMaxMaterial)
|
||||
Milling.Steps = MachiningLib.GetMachiningSteps( true, dPocketHeight, TOOLS[Milling.nToolIndex].dMaxMaterial)
|
||||
Milling.Steps.nStepType = OptionalParameters.nStepType or MCH_MILL_ST.ONEWAY
|
||||
Milling.dMaxElev = Milling.Steps.dStep * Milling.Steps.nCount - 10 * GEO.EPS_SMALL
|
||||
else
|
||||
Milling.Steps = {}
|
||||
Milling.Steps.dStep = TOOLS[Milling.nToolIndex].dStep
|
||||
Milling.Steps.nCount = ceil( ( FaceToMachine.dElevation - 50 * GEO.EPS_SMALL) / Milling.Steps.dStep)
|
||||
Milling.Steps = MachiningLib.GetMachiningSteps( false, FaceToMachine.dElevation, TOOLS[Milling.nToolIndex].dStep)
|
||||
Milling.Steps.nStepType = OptionalParameters.nStepType or MCH_MILL_ST.ZIGZAG
|
||||
Milling.dMaxElev = FaceToMachine.dElevation
|
||||
end
|
||||
@@ -368,13 +370,24 @@ function FACEBYMILL.Make( Proc, Part, FaceToMachine, EdgeToMachine, OptionalPara
|
||||
dRadialStepSpan = Milling.dDepthToMachine
|
||||
end
|
||||
if dRadialStepSpan > 10 * GEO.EPS_SMALL and TOOLS[Milling.nToolIndex].dSideStep then
|
||||
Milling.CloneStepsRadial = MachiningLib.GetMachiningSteps( dRadialStepSpan, TOOLS[Milling.nToolIndex].dSideStep)
|
||||
Milling.CloneStepsRadial = MachiningLib.GetMachiningSteps( true, dRadialStepSpan, TOOLS[Milling.nToolIndex].dSideStep)
|
||||
else
|
||||
Milling.CloneStepsRadial.nCount = 1
|
||||
Milling.CloneStepsRadial.dStep = 0
|
||||
end
|
||||
-- approccio e retrazione
|
||||
Milling.LeadIn, Milling.LeadOut = CalculateLeadInOut( Milling, EdgeToMachine, bIsSplitFeature)
|
||||
-- check finecorsa nei punti di attacco
|
||||
PointsOnToolTipCenter = {
|
||||
PreSimulationLib.GetPointOnToolTipCenter( Milling.LeadIn.ptPoint, FaceToMachine.vtN, FaceToMachine.vtN, EdgeToMachine.vtN, TOOLS[Milling.nToolIndex]),
|
||||
PreSimulationLib.GetPointOnToolTipCenter( Milling.LeadOut.ptPoint, FaceToMachine.vtN, FaceToMachine.vtN, EdgeToMachine.vtN, TOOLS[Milling.nToolIndex])
|
||||
}
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, FaceToMachine.vtN, Milling.nSCC, TOOLS[Milling.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Milling.sMessage = 'Out of stroke'
|
||||
Milling.bIsApplicable = false
|
||||
return Milling
|
||||
end
|
||||
-- lunghezza lavorata
|
||||
-- TODO per il calcolo del dLengthOnX si deve correggere con allungamento / accorciamento percorso
|
||||
Milling.dLengthToMachine = EdgeToMachine.dLength + Milling.LeadIn.dStartAddLength + Milling.LeadOut.dEndAddLength
|
||||
|
||||
@@ -9,6 +9,7 @@ require( 'EgtBase')
|
||||
|
||||
-- Carico i dati globali
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
@@ -31,7 +32,13 @@ function SPLITCUT.GetMachining( Proc, Part, ParametersFromStrategy)
|
||||
else
|
||||
-- Blade
|
||||
Machining, Result = BladeToWaste.Make( Proc, Part, ParametersFromStrategy)
|
||||
if Machining and #Machining > 0 then
|
||||
-- se taglio non riuscito, si riprova con il riduci percorso forzato (collisione possibile in separazione pezzi alti)
|
||||
if ( not Machining) or ( #Machining == 0) then
|
||||
local NewParametersFromStrategy = BeamLib.TableCopyDeep( ParametersFromStrategy)
|
||||
NewParametersFromStrategy.bReduceBladePath = true
|
||||
Machining, Result = BladeToWaste.Make( Proc, Part, NewParametersFromStrategy)
|
||||
end
|
||||
if Machining and ( #Machining > 0) then
|
||||
Machining.sTypeMachining = 'Blade'
|
||||
end
|
||||
-- TODO : casi con motosega da completare
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@
|
||||
-- Gestione della versione di Beam
|
||||
|
||||
NAME = 'Beam'
|
||||
VERSION = '2.6d1'
|
||||
MIN_EXE = '2.6g1'
|
||||
VERSION = '2.8a1'
|
||||
MIN_EXE = '2.7j2'
|
||||
|
||||
Reference in New Issue
Block a user