2200 lines
93 KiB
Lua
2200 lines
93 KiB
Lua
-- NestProcess.lua by Egaltech s.r.l. 2022/11/24
|
|
-- Gestione nesting automatico pareti
|
|
|
|
-- 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
|
|
--NEST.MIN_ANGLE_PNT = 60
|
|
--NEST.DRILL_MACH_AREA = 0
|
|
NEST.LAP_JOINT_U_MACH_AREA = 1 -- 0
|
|
NEST.MACH_AREA_USE_OTHER_DIAM = 1 -- 0
|
|
NEST.MACH_AREA_OTHER_DIAM = 200
|
|
NEST.MACH_AREA_IGNORE_3rdFACE = 1 -- 0
|
|
|
|
if NEST.FLAG ~= 11 then
|
|
local sLog = 'NestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1] .. ', ' .. WIDTH[1]
|
|
EgtOutLog( sLog)
|
|
|
|
-- Cancello file di log specifico
|
|
local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt')
|
|
EgtEraseFile( sLogFile)
|
|
end
|
|
|
|
-- Imposto direttorio libreria specializzata per Travi
|
|
EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua')
|
|
|
|
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Pareti
|
|
local sMachDir = EgtGetCurrMachineDir()
|
|
if not EgtExistsFile( sMachDir .. '\\Wall\\WallData.lua') then
|
|
NEST.ERR = 12
|
|
NEST.MSG = 'Error not configured for walls 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 .. '\\Wall\\?.lua')
|
|
|
|
-- Carico le librerie
|
|
_G.package.loaded.WallExec = nil
|
|
local WE = require( 'WallExec')
|
|
_G.package.loaded.WallLib = nil
|
|
local WL = require( 'WallLib')
|
|
_G.package.loaded.WProcessLapJoint = nil
|
|
local LapJoint = require( 'WProcessLapJoint')
|
|
_G.package.loaded.WProcessDrill = nil
|
|
local Drill = require( 'WProcessDrill')
|
|
_G.package.loaded.WProcessDoubleCut = nil
|
|
local DoubleCut = require( 'WProcessDoubleCut')
|
|
_G.package.loaded.WProcessFreeContour = nil
|
|
local FreeContour = require( 'WProcessFreeContour')
|
|
_G.package.loaded.PanelSaw = nil
|
|
local PanelSaw = require( 'PanelSaw')
|
|
|
|
-- Carico i dati globali
|
|
local WD = require( 'WallData')
|
|
|
|
-- Recupero alcuni dati dal WallData o li setto a valori di default
|
|
local s_dSideMillDiamDown = WD.SIDEMILL_DIAM_DOWN or 350
|
|
local s_dSideMillDiamUp = WD.SIDEMILL_DIAM_UP or 65
|
|
local s_dHorDrillLen = WD.HOR_DRILL_LEN or 1780
|
|
local s_dHorDrillDiam = WD.HOR_DRILL_DIAM or 35
|
|
local s_dHorDrillDiam5Axes = WD.HOR_DRILL_DIAM_5AX or 0
|
|
local s_sOrigCorner = WD.ORIG_CORNER or 'TL'
|
|
local s_dIntRulli = WD.INTRULLI or 1200
|
|
local s_dMinRawYHorDrill = WD.MINRAWY_HOR_DRILL or 2800
|
|
local s_dNestHoleMinArea = WD.NEST_HOLE_MIN_AREA or 200000
|
|
local s_dInsideRawTol = WD.INSIDE_RAW_TOL or 30
|
|
|
|
-- lista dei pezzi con flip o rotazione
|
|
local PartStates = {}
|
|
|
|
------------------------------------------------------------------
|
|
-- 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
|
|
|
|
------------------------------------------------------------------
|
|
-- 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
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che crea il rettangolo della lavorazione
|
|
local function CreateToolRectangle( ptP1, dValP1, ptP2, dValP2, vtFace, dValFace, nOutlineGrp)
|
|
local dExtra = 5
|
|
local vtX = ptP2 - ptP1
|
|
vtX:normalize()
|
|
-- creo il rettangolo della lavorazione
|
|
ptP1 = ptP1 - vtX * ( dValP1 + dExtra)
|
|
ptP2 = ptP2 + vtX * ( dValP2 + dExtra)
|
|
ptP2 = ptP2 + vtFace * ( dValFace + dExtra)
|
|
--local nId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX(), ptP2:getY(), 0), Point3d( ptP1:getX(), ptP1:getY(), 0))
|
|
local nId = EgtRectangle2P( nOutlineGrp, ptP2, ptP1)
|
|
return nId
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che verifica se la lavorazione è lap joint dal basso ed eventualmente ne calcola l'area di lavorazione
|
|
local function IdentifyLJFromBottom( Proc, bCompute, nOutlineGrp)
|
|
|
|
local bLJFromBottom = false
|
|
local nRectId
|
|
local vtFace
|
|
|
|
local dMinCompZ = 0.95
|
|
if Proc.Fct == 2 then
|
|
local vtN = {}
|
|
vtN[1] = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT)
|
|
vtN[2] = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT)
|
|
|
|
-- se rivolto verso il basso
|
|
if ( vtN[1]:getZ() < - dMinCompZ or vtN[2]:getZ() < - dMinCompZ) then
|
|
vtFace = EgtIf( vtN[1]:getZ() < - dMinCompZ, vtN[2], vtN[1])
|
|
if not ( vtFace:getZ() > dMinCompZ or vtFace:getZ() < - dMinCompZ) then
|
|
bLJFromBottom = true
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT)
|
|
-- creo il rettangolo della lavorazione
|
|
nRectId = CreateToolRectangle( ptP1, s_dSideMillDiamDown / 2, ptP2, s_dSideMillDiamDown / 2, vtFace, s_dSideMillDiamDown, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif Proc.Fct == 3 then
|
|
local nFacInd, dElev, nFacInd2 = WL.GetFaceWithMostAdj( Proc.Id, Proc.PartId)
|
|
|
|
-- se nel mezzo di una faccia
|
|
if not nFacInd2 then
|
|
if nFacInd ~= -2 and nFacInd ~= GDB_ID.NULL then
|
|
vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT)
|
|
if not ( vtFace:getZ() > dMinCompZ or vtFace:getZ() < - dMinCompZ) then
|
|
local nOtherFace = EgtIf( nFacInd == 0, 1, 0)
|
|
local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nOtherFace, GDB_ID.ROOT)
|
|
if abs( ptP1:getZ() - ptP2:getZ()) < GEO.EPS_SMALL then
|
|
bLJFromBottom = true
|
|
if bCompute then
|
|
nRectId = CreateToolRectangle( ptP1, s_dSideMillDiamDown / 2, ptP2, s_dSideMillDiamDown / 2, vtFace, s_dSideMillDiamDown, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- se dal basso
|
|
else
|
|
local nFaceZ = -1
|
|
for nIdx = 0, 2 do
|
|
local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nIdx, GDB_ID.ROOT)
|
|
if vtN2:getZ() < - dMinCompZ then
|
|
nFaceZ = nIdx
|
|
break
|
|
end
|
|
end
|
|
if nFaceZ ~= -1 then
|
|
local nFace = EgtIf( nFaceZ == nFacInd, nFacInd2, nFacInd)
|
|
local nOtherFace = EgtIf( nFaceZ + nFace == 3, 0, EgtIf( nFaceZ + nFace == 2, 1, 2))
|
|
vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nFace, GDB_ID.ROOT)
|
|
--vtFace[2] = EgtSurfTmFacetNormVersor( Proc.Id, nOtherFace, GDB_ID.ROOT)
|
|
bLJFromBottom = true
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFace, nFaceZ, GDB_ID.ROOT)
|
|
local bAdj2, ptP3, ptP4 = EgtSurfTmFacetsContact( Proc.Id, nFace, nOtherFace, GDB_ID.ROOT)
|
|
if AreSamePointApprox( ptP2, ptP3) or AreSamePointApprox( ptP2, ptP4) then
|
|
ptP1, ptP2 = ptP2, ptP1
|
|
end
|
|
local dVal = EgtIf( NEST.MACH_AREA_IGNORE_3rdFACE == 1, s_dSideMillDiamDown / 2, 0)
|
|
nRectId = CreateToolRectangle( ptP1, dVal, ptP2, s_dSideMillDiamDown / 2, vtFace, s_dSideMillDiamDown, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif Proc.Fct == 4 then
|
|
local nFacInd, dElev, nFacInd2, dElev2 = WL.GetFaceWithMostAdj( Proc.Id, Proc.PartId)
|
|
if nFacInd ~= -2 and nFacInd ~= GDB_ID.NULL then
|
|
vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT)
|
|
|
|
if not ( vtFace:getZ() > dMinCompZ or vtFace:getZ() < - dMinCompZ) then
|
|
local nOtherFace = -1
|
|
for nIdx = 0, 3 do
|
|
local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nIdx, GDB_ID.ROOT)
|
|
if vtN2:getZ() > dMinCompZ or vtN2:getZ() < - dMinCompZ then
|
|
nOtherFace = nIdx
|
|
break
|
|
end
|
|
end
|
|
if nOtherFace ~= -1 and nOtherFace ~= nFacInd and nOtherFace ~= nFacInd2 then
|
|
bLJFromBottom = true
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nOtherFace, GDB_ID.ROOT)
|
|
local bAdj2, ptP3, ptP4 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nFacInd2, GDB_ID.ROOT)
|
|
if AreSamePointApprox( ptP2, ptP3) or AreSamePointApprox( ptP2, ptP4) then
|
|
ptP1, ptP2 = ptP2, ptP1
|
|
end
|
|
nRectId = CreateToolRectangle( ptP1, 0, ptP2, s_dSideMillDiamDown / 2, vtFace, s_dSideMillDiamDown, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
|
|
if nFacInd2 and nFacInd2 ~= GDB_ID.NULL then
|
|
local vtFace2 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd2, GDB_ID.ROOT)
|
|
if ( vtFace2:getZ() < - dMinCompZ or vtFace:getZ() < - dMinCompZ) then
|
|
bLJFromBottom = true
|
|
if vtFace:getZ() < -dMinCompZ then vtFace = vtFace2 end
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nFacInd2, GDB_ID.ROOT)
|
|
nRectId = CreateToolRectangle( ptP1, 0, ptP2, 0, vtFace, s_dSideMillDiamDown, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if bLJFromBottom then
|
|
return vtFace, nRectId
|
|
else
|
|
return
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che verifica se la lavorazione è lap joint da sopra ed eventualmente ne calcola l'area di lavorazione
|
|
local function IdentifyLJFromTop( Proc, bCompute, nOutlineGrp)
|
|
|
|
local bLJFromTop = false
|
|
local vtFace, nRectId
|
|
|
|
if s_dSideMillDiamUp < GEO.EPS_SMALL then return end
|
|
|
|
local dMinComp = 0.95
|
|
if Proc.Fct == 2 then
|
|
local vtN = {}
|
|
vtN[1] = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT)
|
|
vtN[2] = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT)
|
|
|
|
-- se rivolto verso l'alto
|
|
if (vtN[1]:getZ() > dMinComp or vtN[2]:getZ() > dMinComp) then
|
|
bLJFromTop = true
|
|
vtFace = EgtIf( vtN[1]:getZ() > dMinComp, vtN[2], vtN[1])
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT)
|
|
local b3Face = EgtSurfTmGetFacetBBoxGlob( Proc.Id, EgtIf( vtN[1]:getZ() > dMinComp, 0, 1), GDB_BB.STANDARD)
|
|
local dDim = 0
|
|
if vtFace:getX() > dMinComp or vtFace:getX() < - dMinComp then
|
|
dDim = b3Face:getDimX()
|
|
elseif vtFace:getY() > dMinComp or vtFace:getY() < - dMinComp then
|
|
dDim = b3Face:getDimY()
|
|
end
|
|
local dValFace = max( dDim + s_dSideMillDiamUp / 2, s_dSideMillDiamUp)
|
|
local dVal = s_dSideMillDiamUp / 2
|
|
if NEST.MACH_AREA_USE_OTHER_DIAM == 1 then
|
|
dVal = NEST.MACH_AREA_OTHER_DIAM / 2
|
|
end
|
|
nRectId = CreateToolRectangle( ptP1, dVal, ptP2, dVal, vtFace, dValFace, nOutlineGrp)
|
|
end
|
|
end
|
|
|
|
-- caso 3 facce
|
|
elseif Proc.Fct == 3 then
|
|
local nFacInd, dElev, nFacInd2 = WL.GetFaceWithMostAdj( Proc.Id, Proc.PartId)
|
|
|
|
-- forma ad U
|
|
if not nFacInd2 and nFacInd ~= GDB_ID.NULL and NEST.LAP_JOINT_U_MACH_AREA == 1 then
|
|
local vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT)
|
|
if vtFace:getZ() > dMinComp then
|
|
bLJFromTop = true
|
|
if bCompute then
|
|
local b3Face = EgtSurfTmGetFacetBBoxGlob( Proc.Id, nFacInd, GDB_BB.STANDARD)
|
|
local nOtherFace = EgtIf( nFacInd == 0, 1, 0)
|
|
local vtNOther = EgtSurfTmFacetNormVersor( Proc.Id, nOtherFace, GDB_ID.ROOT)
|
|
local vtDir = EgtIf( AreSameOrOppositeVectorApprox( vtNOther, X_AX()), Y_AX(), X_AX())
|
|
local dVal = s_dSideMillDiamUp / 2 + 5
|
|
local ptMin = b3Face:getMin() - dVal * vtDir
|
|
local ptMax = b3Face:getMax() + dVal * vtDir
|
|
-- nRectId = EgtRectangle2P( nOutlineGrp, Point3d(ptMax:getX(), ptMax:getY(), 0), Point3d( ptMin:getX(), ptMin:getY(), 0))
|
|
nRectId = EgtRectangle2P( nOutlineGrp, ptMax, ptMin)
|
|
end
|
|
end
|
|
|
|
elseif nFacInd2 then
|
|
local nFaceZ = -1
|
|
for nIdx = 0, 2 do
|
|
local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nIdx, GDB_ID.ROOT)
|
|
if vtN2:getZ() > dMinComp then
|
|
nFaceZ = nIdx
|
|
break
|
|
end
|
|
end
|
|
if nFaceZ ~= -1 then
|
|
local nFace = EgtIf( nFaceZ == nFacInd, nFacInd2, nFacInd)
|
|
local nOtherFace = EgtIf( nFaceZ + nFace == 3, 0, EgtIf( nFaceZ + nFace == 2, 1, 2))
|
|
local vtFace = {}
|
|
vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nFace, GDB_ID.ROOT)
|
|
--vtFace = EgtSurfTmFacetNormVersor( Proc.Id, nOtherFace, GDB_ID.ROOT)
|
|
bLJFromTop = true
|
|
if bCompute then
|
|
local bAdj, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFace, nFaceZ, GDB_ID.ROOT)
|
|
local bAdj2, ptP3, ptP4 = EgtSurfTmFacetsContact( Proc.Id, nFace, nOtherFace, GDB_ID.ROOT)
|
|
if AreSamePointApprox( ptP2, ptP3) or AreSamePointApprox( ptP2, ptP4) then
|
|
ptP1, ptP2 = ptP2, ptP1
|
|
end
|
|
|
|
local b3Face = EgtSurfTmGetFacetBBoxGlob( Proc.Id, nFaceZ, GDB_BB.STANDARD)
|
|
local dDim = 0
|
|
if vtFace:getX() > dMinComp or vtFace:getX() < - dMinComp then
|
|
dDim = b3Face:getDimX()
|
|
elseif vtFace:getY() > dMinComp or vtFace:getY() < - dMinComp then
|
|
dDim = b3Face:getDimY()
|
|
end
|
|
local dValFace = max( dDim + s_dSideMillDiamUp / 2, s_dSideMillDiamUp)
|
|
local dVal = s_dSideMillDiamUp / 2
|
|
if NEST.MACH_AREA_USE_OTHER_DIAM == 1 then
|
|
dVal = NEST.MACH_AREA_OTHER_DIAM / 2
|
|
end
|
|
nRectId = CreateToolRectangle( ptP1, 0, ptP2, dVal, vtFace, dValFace, nOutlineGrp)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if bLJFromTop then
|
|
return vtFace, nRectId
|
|
else
|
|
return
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che crea le regioni occupate dalle lavorazioni
|
|
local function ComputeToolOutlines( nPartId)
|
|
|
|
local ToolOutlineId = {}
|
|
EgtRemoveInfo( nPartId, "ToolOutlines")
|
|
|
|
-- recupero il gruppo con gli outlines degli utensili
|
|
local nOutlineGrp = EgtGetFirstNameInGroup(GDB_ID.ROOT, "ToolOutlines")
|
|
if not nOutlineGrp or nOutlineGrp == GDB_ID.NULL then
|
|
nOutlineGrp = EgtGroup( GDB_ID.ROOT)
|
|
EgtSetName( nOutlineGrp, "ToolOutlines")
|
|
EgtSetStatus( nOutlineGrp, GDB_ST.OFF)
|
|
end
|
|
|
|
local vPartProc = WE.CollectFeatures( nPartId, b3Raw)
|
|
for nInd = 1, #vPartProc do
|
|
|
|
local Proc = vPartProc[nInd]
|
|
|
|
-- lap joint
|
|
if LapJoint.Identify( Proc) then
|
|
-- verifico se dal basso
|
|
local _ , nRectId = IdentifyLJFromBottom( Proc, true, nOutlineGrp)
|
|
if nRectId then
|
|
EgtSetColor( nRectId, EgtStdColor("BLUE"))
|
|
table.insert( ToolOutlineId, nRectId)
|
|
else
|
|
-- verifico se dall'alto
|
|
local _ , nRectId = IdentifyLJFromTop( Proc, true, nOutlineGrp)
|
|
if nRectId then
|
|
EgtSetColor( nRectId, EgtStdColor("AQUA"))
|
|
local nPrId = EgtGetInfo( Proc.Id, "PRID", 'i')
|
|
EgtSetInfo( nRectId, "PRID", nPrId)
|
|
table.insert( ToolOutlineId, nRectId)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- fori
|
|
if NEST.DRILL_MACH_AREA == 1 and Drill.Identify( Proc) then
|
|
-- recupero dati del foro
|
|
local AuxId = EgtGetInfo( Proc.Id, 'AUXID', 'i') or 0
|
|
if AuxId then AuxId = AuxId + Proc.Id end
|
|
local dLen = abs( EgtCurveThickness( AuxId))
|
|
local vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB)
|
|
local bOpen = ( Proc.Fcs ~= 0 and Proc.Fce ~= 0)
|
|
local dDiam = 2 * EgtArcRadius( AuxId)
|
|
|
|
-- verifico se la lunghezza del foro è maggiore della lunghezza della punta
|
|
if bOpen and AreSameOrOppositeVectorApprox( vtExtr, Y_AX()) and dLen > s_dHorDrillLen - 1 then
|
|
local ptP1 = Proc.Box:getMin()
|
|
local ptP2 = Proc.Box:getMax()
|
|
local dExtra = 10
|
|
ptP1 = ptP1 - ( WD.MAX_WIDTH - dLen + dExtra) * Y_AX()
|
|
ptP2 = ptP2 + ( WD.MAX_WIDTH - dLen + dExtra) * Y_AX()
|
|
|
|
--local nId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX(), ptP2:getY(), 0), Point3d( ptP1:getX(), ptP1:getY(), 0))
|
|
local nId = EgtRectangle2P( nOutlineGrp, ptP2, ptP1)
|
|
EgtSetColor( nId, EgtStdColor("AQUA"))
|
|
if nId ~= GDB_ID.NULL then table.insert(ToolOutlineId, nId) end
|
|
end
|
|
end
|
|
|
|
-- lati inclinati free contour
|
|
if FreeContour.Identify( Proc) then
|
|
local bPocket = EgtGetInfo( Proc.Id, 'PCKT', 'b')
|
|
if not bPocket then
|
|
for nInd = 0, Proc.Fct - 1 do
|
|
local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nInd, GDB_ID.ROOT)
|
|
-- se inclinato
|
|
if abs( vtN:getZ()) > GEO.EPS_SMALL then
|
|
local bUnderCut = vtN:getZ() < - GEO.EPS_SMALL
|
|
|
|
local dCosAlpha = (vtN ^ Z_AX()):len()
|
|
local dVal
|
|
if bUnderCut then
|
|
dVal = ( NEST.OFFSET + 0.1) / dCosAlpha
|
|
else
|
|
dVal = ( NEST.OFFSET + 0.1) * dCosAlpha
|
|
end
|
|
|
|
local frLoc, dDimX, dDimY = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nInd, GDB_ID.ROOT)
|
|
local b3Face = EgtSurfTmGetFacetBBoxRef( Proc.Id, nInd, GDB_BB.STANDARD, frLoc)
|
|
local ptA = b3Face:getMin()
|
|
local ptC = b3Face:getMax()
|
|
local ptB = ptA + dDimY * Y_AX()
|
|
local ptD = ptA + dDimX * X_AX()
|
|
ptA:toGlob( frLoc)
|
|
ptB:toGlob( frLoc)
|
|
ptC:toGlob( frLoc)
|
|
ptD:toGlob( frLoc)
|
|
|
|
local ptP1, ptP2
|
|
if bUnderCut then
|
|
ptP1 = EgtIf( ptA:getZ() > ptC:getZ(), ptA, ptC)
|
|
ptP2 = EgtIf( ptB:getZ() > ptD:getZ(), ptB, ptD)
|
|
else
|
|
ptP1 = EgtIf( ptA:getZ() < ptC:getZ(), ptA, ptC)
|
|
ptP2 = EgtIf( ptB:getZ() < ptD:getZ(), ptB, ptD)
|
|
end
|
|
|
|
local vtDir = ptP2 - ptP1
|
|
vtDir:normalize()
|
|
ptP1 = ptP1 - vtDir * 0.5 * NEST.OFFSET
|
|
ptP2 = ptP2 + vtDir * 0.5 * NEST.OFFSET
|
|
local vtNxy = Vector3d( vtN:getX(), vtN:getY(), 0)
|
|
vtNxy:normalize()
|
|
local ptP4 = ptP2 + dVal * vtNxy
|
|
|
|
local nRectId = EgtRectangle3P( nOutlineGrp, ptP1, ptP4, ptP2)
|
|
EgtSetColor( nRectId, EgtStdColor("AQUA"))
|
|
if nRectId ~= GDB_ID.NULL then table.insert( ToolOutlineId, nRectId) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return ToolOutlineId
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function ClassifyDrillsOnLateralFaces( nPartId, dMinSheetWidth)
|
|
|
|
local dDeltaRaw = WD.MAX_WIDTH - dMinSheetWidth + NEST.KERF
|
|
local DrillClassif
|
|
local DrillOnFaces = { F = {nbr = 0, closed = false, long = false, OnlyOnRef = false}, B = {nbr = 0, closed = false, long = false, OnlyOnRef = false},
|
|
L = {nbr = 0, closed = false, long = false, OnlyOnRef = false}, R = {nbr = 0, closed = false, long = false, OnlyOnRef = false}}
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
local ptPartMin = b3Part:getMin()
|
|
local ptPartMax = b3Part:getMax()
|
|
|
|
local vPartProc = WE.CollectFeatures( nPartId)
|
|
for nInd = 1, #vPartProc do repeat
|
|
|
|
if Drill.Identify( vPartProc[nInd]) then
|
|
|
|
-- identifico su quali facce si trova il foro
|
|
local bOpen = ( vPartProc[nInd].Fcs ~= 0 and vPartProc[nInd].Fce ~= 0)
|
|
local AuxId = EgtGetInfo( vPartProc[nInd].Id, 'AUXID', 'i') or 0
|
|
if AuxId then AuxId = AuxId + vPartProc[nInd].Id end
|
|
if not AuxId or EgtGetType( AuxId) ~= GDB_TY.CRV_ARC then break end
|
|
-- verifico se diametro compatibile con la punta
|
|
local dDiam = 2 * EgtArcRadius( AuxId)
|
|
if ( abs( dDiam - s_dHorDrillDiam5Axes) < WD.DRILL_TOL + GEO.EPS_SMALL) or ( abs( dDiam - s_dHorDrillDiam) < WD.DRILL_TOL + GEO.EPS_SMALL) then
|
|
local ptDrill = EgtCP( AuxId, GDB_RT.GLOB)
|
|
local dLen = abs( EgtCurveThickness( AuxId))
|
|
local bLong = dLen > s_dHorDrillLen - 1
|
|
local bOnlyOnRef = dLen + dDeltaRaw > s_dHorDrillLen - GEO.EPS_SMALL and not bLong
|
|
|
|
-- faccia Front
|
|
local dTol = GEO.EPS_SMALL
|
|
if ( abs( ptDrill:getY() - ptPartMin:getY()) < dTol) then
|
|
DrillOnFaces.F.nbr = DrillOnFaces.F.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.F.OnlyOnRef = true end
|
|
if bOpen then
|
|
DrillOnFaces.B.nbr = DrillOnFaces.B.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.B.OnlyOnRef = true end
|
|
else
|
|
DrillOnFaces.F.closed = true
|
|
|
|
end
|
|
if bLong then
|
|
DrillOnFaces.F.long = true
|
|
if bOpen then DrillOnFaces.B.long = true end
|
|
end
|
|
|
|
-- faccia Back
|
|
elseif ( abs( ptDrill:getY() - ptPartMax:getY()) < dTol) then
|
|
DrillOnFaces.B.nbr = DrillOnFaces.B.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.B.OnlyOnRef = true end
|
|
if bOpen then
|
|
DrillOnFaces.F.nbr = DrillOnFaces.F.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.F.OnlyOnRef = true end
|
|
else
|
|
DrillOnFaces.B.closed = true
|
|
end
|
|
if bLong then
|
|
DrillOnFaces.B.long = true
|
|
if bOpen then DrillOnFaces.F.long = true end
|
|
end
|
|
|
|
-- faccia Left
|
|
elseif ( abs( ptDrill:getX() - ptPartMin:getX()) < dTol) then
|
|
DrillOnFaces.L.nbr = DrillOnFaces.L.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.L.OnlyOnRef = true end
|
|
if bOpen then
|
|
DrillOnFaces.R.nbr = DrillOnFaces.R.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.R.OnlyOnRef = true end
|
|
else
|
|
DrillOnFaces.L.closed = true
|
|
end
|
|
if bLong then
|
|
DrillOnFaces.L.long = true
|
|
if bOpen then DrillOnFaces.R.long = true end
|
|
end
|
|
|
|
-- faccia Right
|
|
elseif ( abs( ptDrill:getX() - ptPartMax:getX()) < dTol) then
|
|
DrillOnFaces.R.nbr = DrillOnFaces.R.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.R.OnlyOnRef = true end
|
|
if bOpen then
|
|
DrillOnFaces.L.nbr = DrillOnFaces.L.nbr + 1
|
|
if bOnlyOnRef then DrillOnFaces.L.OnlyOnRef = true end
|
|
else
|
|
DrillOnFaces.R.closed = true
|
|
end
|
|
if bLong then
|
|
DrillOnFaces.R.long = true
|
|
if bOpen then DrillOnFaces.L.long = true end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
until true
|
|
end
|
|
|
|
-- identifico la faccia da mettere sul lato del grezzo
|
|
local sDrillFace, nMax = '', -100
|
|
for k, v in pairs( DrillOnFaces) do
|
|
if v.nbr > nMax or ( v.nbr == nMax and not DrillOnFaces[sDrillFace].OnlyOnRef and v.OnlyOnRef) then
|
|
sDrillFace, nMax = k, v.nbr
|
|
end
|
|
end
|
|
|
|
local sDrillFace2
|
|
if nMax > 0 then
|
|
if sDrillFace == 'F' or sDrillFace == 'B' then
|
|
-- cerco chi vince tra faccia left e right
|
|
if DrillOnFaces.L.nbr > DrillOnFaces.R.nbr then
|
|
sDrillFace2 = 'L'
|
|
elseif DrillOnFaces.L.nbr < DrillOnFaces.R.nbr then
|
|
sDrillFace2 = 'R'
|
|
elseif DrillOnFaces.L.nbr == DrillOnFaces.R.nbr and DrillOnFaces.L.nbr > 0 then
|
|
if DrillOnFaces.L.OnlyOnRef then
|
|
sDrillFace2 = 'L'
|
|
else
|
|
sDrillFace2 = 'R'
|
|
end
|
|
end
|
|
|
|
else
|
|
-- cerco chi vince tra faccia front e back
|
|
if DrillOnFaces.F.nbr > DrillOnFaces.B.nbr then
|
|
sDrillFace2 = 'F'
|
|
elseif DrillOnFaces.F.nbr < DrillOnFaces.B.nbr then
|
|
sDrillFace2 = 'B'
|
|
elseif DrillOnFaces.F.nbr == DrillOnFaces.B.nbr and DrillOnFaces.F.nbr > 0 then
|
|
if DrillOnFaces.F.OnlyOnRef then
|
|
sDrillFace2 = 'F'
|
|
else
|
|
sDrillFace2 = 'B'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if NEST.DRILL_MACH_AREA == 0 then
|
|
DrillOnFaces[sDrillFace].long = false
|
|
end
|
|
|
|
if nMax > 0 then
|
|
DrillClassif = { sCase = sDrillFace, bClosed = DrillOnFaces[sDrillFace].closed, bLong = DrillOnFaces[sDrillFace].long, bOnlyOnRef = DrillOnFaces[sDrillFace].OnlyOnRef}
|
|
end
|
|
|
|
local DrillClassif2
|
|
if sDrillFace2 then
|
|
if NEST.DRILL_MACH_AREA == 0 then
|
|
DrillOnFaces[sDrillFace2].long = false
|
|
end
|
|
DrillClassif2 = { sCase = sDrillFace2, bClosed = DrillOnFaces[sDrillFace2].closed, bLong = DrillOnFaces[sDrillFace2].long, bOnlyOnRef = DrillOnFaces[sDrillFace2].OnlyOnRef}
|
|
end
|
|
|
|
|
|
return DrillClassif, DrillClassif2
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function ClassifyLapJointsFromBottom( nPartId)
|
|
|
|
local res = { Nbr = 0, sCase = '', bParall = false}
|
|
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local ptPartMin = b3Part:getMin()
|
|
local ptPartMax = b3Part:getMax()
|
|
|
|
local vtLapJoints = {}
|
|
local dMinComponentVal = 0.95
|
|
local vPartProc = WE.CollectFeatures( nPartId)
|
|
for nInd = 1, #vPartProc do
|
|
|
|
if LapJoint.Identify( vPartProc[nInd]) then
|
|
-- verifico se LJ da sotto
|
|
local vtFace = IdentifyLJFromBottom( vPartProc[nInd], false)
|
|
if vtFace then
|
|
if vtFace:getX() > dMinComponentVal then
|
|
vtLapJoints["R"] = 1
|
|
elseif vtFace:getX() < - dMinComponentVal then
|
|
vtLapJoints["L"] = 1
|
|
elseif vtFace:getY() > dMinComponentVal then
|
|
vtLapJoints["B"] = 1
|
|
elseif vtFace:getY() < - dMinComponentVal then
|
|
vtLapJoints["F"] = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local nCnt = 0
|
|
for _ in pairs(vtLapJoints) do nCnt = nCnt + 1 end
|
|
|
|
if nCnt == 1 then
|
|
res.Nbr = 1
|
|
for k, _ in pairs( vtLapJoints) do
|
|
res.sCase = k
|
|
end
|
|
|
|
elseif nCnt == 2 then
|
|
res.Nbr = 2
|
|
if vtLapJoints["F"] and vtLapJoints["B"] then
|
|
res.bParall = true
|
|
res.sCase = "F"
|
|
elseif vtLapJoints["R"] and vtLapJoints["L"] then
|
|
res.bParall = true
|
|
res.sCase = "R"
|
|
else
|
|
res.bParall = false
|
|
if vtLapJoints["B"] and vtLapJoints["R"] then
|
|
res.sCase = 'BR'
|
|
elseif vtLapJoints["B"] and vtLapJoints["L"] then
|
|
res.sCase = 'BL'
|
|
elseif vtLapJoints["F"] and vtLapJoints["R"] then
|
|
res.sCase = 'FR'
|
|
elseif vtLapJoints["F"] and vtLapJoints["L"] then
|
|
res.sCase = 'FL'
|
|
end
|
|
end
|
|
|
|
elseif nCnt == 3 then
|
|
res.Nbr = 3
|
|
if not vtLapJoints["F"] then
|
|
res.sCase = "F"
|
|
elseif not vtLapJoints["B"] then
|
|
res.sCase = "B"
|
|
elseif not vtLapJoints["R"] then
|
|
res.sCase = "R"
|
|
elseif not vtLapJoints["L"] then
|
|
res.sCase = "L"
|
|
end
|
|
|
|
elseif nCnt == 4 then
|
|
res.Nbr = 4
|
|
elseif nCnt ~= 0 then
|
|
return
|
|
end
|
|
|
|
return res
|
|
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function CreateDefectOnAngle( nPartId, RawPart, bDrillLong, bOnOppositeAng)
|
|
|
|
local PartTab = {}
|
|
-- recupero il gruppo dove salvo i defects
|
|
local nOutlineGrp = EgtGetFirstNameInGroup(GDB_ID.ROOT, "SheetDefects")
|
|
if not nOutlineGrp or nOutlineGrp == GDB_ID.NULL then
|
|
nOutlineGrp = EgtGroup( GDB_ID.ROOT)
|
|
EgtSetName( nOutlineGrp, "SheetDefects")
|
|
EgtSetStatus( nOutlineGrp, GDB_ST.OFF)
|
|
end
|
|
|
|
local dExtraMachArea = s_dSideMillDiamDown -- per tenere conto dell'area di lavorazione
|
|
local dExtra = NEST.KERF
|
|
|
|
-- local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
local b3PartX = b3Part:getDimX()
|
|
local b3PartY = b3Part:getDimY()
|
|
-- se ho fori lunghi devo riservare tutto lo spazio
|
|
if bDrillLong then
|
|
b3PartY = RawPart.Width
|
|
end
|
|
|
|
-- calcolo i punti che definiscono il rettangolo
|
|
local ptP1, ptP2
|
|
if ( s_sOrigCorner == 'TL' and not bOnOppositeAng) or ( s_sOrigCorner == 'BL' and bOnOppositeAng) then
|
|
-- angolo TL
|
|
ptP1 = Point3d( 0, RawPart.Width - b3PartY - dExtra, 0)
|
|
ptP2 = Point3d( b3PartX + dExtra, RawPart.Width, 0)
|
|
PartTab.posX = NEST.KERF
|
|
PartTab.posY = RawPart.Width - b3Part:getDimY() - NEST.KERF
|
|
elseif ( s_sOrigCorner == 'BL' and not bOnOppositeAng) or ( s_sOrigCorner == 'TL' and bOnOppositeAng) then
|
|
-- angolo BL
|
|
ptP1 = Point3d( 0, 0, 0)
|
|
ptP2 = Point3d( b3PartX + dExtra, b3PartY + dExtra, 0)
|
|
PartTab.posX = NEST.KERF
|
|
PartTab.posY = NEST.KERF
|
|
elseif ( s_sOrigCorner == 'TR' and not bOnOppositeAng) or ( s_sOrigCorner == 'BR' and bOnOppositeAng) then
|
|
-- angolo TR
|
|
ptP1 = Point3d( RawPart.Len - b3PartX - dExtra, RawPart.Width - b3PartY - dExtra, 0)
|
|
ptP2 = Point3d( RawPart.Len, RawPart.Width, 0)
|
|
PartTab.posX = RawPart.Len - b3Part:getDimX() - NEST.KERF
|
|
PartTab.posY = RawPart.Width - b3Part:getDimY() - NEST.KERF
|
|
elseif ( s_sOrigCorner == 'BR' and not bOnOppositeAng) or ( s_sOrigCorner == 'TR' and bOnOppositeAng) then
|
|
-- angolo BR
|
|
ptP1 = Point3d( RawPart.Len - b3PartX - dExtra, 0, 0)
|
|
ptP2 = Point3d( RawPart.Len, b3PartY + dExtra, 0)
|
|
PartTab.posX = RawPart.Len - b3Part:getDimX() - NEST.KERF
|
|
PartTab.posY = NEST.KERF
|
|
end
|
|
|
|
PartTab.Id = tonumber(nPartId)
|
|
PartTab.DefectId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX() + dExtraMachArea, ptP2:getY() + dExtraMachArea , 0), Point3d( ptP1:getX() - dExtraMachArea , ptP1:getY() - dExtraMachArea, 0))
|
|
EgtSetName( PartTab.DefectId, "Defect")
|
|
|
|
return PartTab
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function RotateOptimalCase( nPartId, nAngle, nAngleValidRot, RawPart, nPnt1, nPnt2)
|
|
|
|
local bOptimal = false
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), nAngle, GDB_RT.GLOB)
|
|
local nRotate = nAngle
|
|
local nAnglePnt
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
-- b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local bIsValidRotation = b3Part:getDimX() < RawPart.Len - 2 * NEST.KERF + GEO.EPS_SMALL and b3Part:getDimY() < RawPart.Width - 2 * NEST.KERF + GEO.EPS_SMALL
|
|
if bIsValidRotation then
|
|
bOptimal = true
|
|
nAnglePnt = nPnt1
|
|
else
|
|
bOptimal = false
|
|
-- ruoto nella migliore posizione ammissibile
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), nAngleValidRot, GDB_RT.GLOB)
|
|
nRotate = nRotate + nAngleValidRot
|
|
nAnglePnt = nPnt2
|
|
end
|
|
|
|
if nRotate >= 360 then
|
|
nRotate = nRotate - 360
|
|
end
|
|
|
|
return nAnglePnt, nRotate, bOptimal
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function RotateOptimalCaseDrill( nPartId, bCanRotate, nPnt1, nPnt2)
|
|
|
|
local nRotate = 0
|
|
local nAnglePnt
|
|
|
|
if bCanRotate then
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), 180, GDB_RT.GLOB)
|
|
nRotate = 180
|
|
nAnglePnt = nPnt1
|
|
else
|
|
nAnglePnt = nPnt2
|
|
end
|
|
|
|
return nAnglePnt, nRotate
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che classifica i pezzi in base alla loro necessità di stare negli angoli
|
|
local function ClassifyAngles( nPartId, RawPart, sRefOrig, bLockedRot, dMinSheetWidth)
|
|
|
|
-- elimino eventuali info
|
|
EgtSetInfo( nPartId, "NestOnEdge", 0)
|
|
EgtSetInfo( nPartId, "NestOnAngle", 0)
|
|
EgtSetInfo( nPartId, "OnlyOnRefSide", 0)
|
|
|
|
local nAngle
|
|
local nRotate = 0
|
|
local bOptimal
|
|
local bManual = false
|
|
local bOnly180Rot = EgtGetInfo( nPartId, "HasGrainDirection", 'b') or false
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
|
|
-- fori
|
|
local DrillClassif, DrillClassif2 = ClassifyDrillsOnLateralFaces( nPartId, dMinSheetWidth)
|
|
local bDrill = false
|
|
local bDrillOpen = false
|
|
local bLongDrill = false
|
|
|
|
if DrillClassif then
|
|
bDrill = true
|
|
bDrillOpen = not DrillClassif.bClosed
|
|
bLongDrill = DrillClassif.bLong
|
|
if DrillClassif.bOnlyOnRef then
|
|
EgtSetInfo( nPartId, "OnlyOnRefSide", 1)
|
|
end
|
|
end
|
|
|
|
-- oriento il pezzo in base al foro
|
|
if bDrill and not bLockedRot then
|
|
local RotationAngles
|
|
if sRefOrig == 'TL' or sRefOrig == 'TR' then
|
|
RotationAngles = { F = 180, B = 0, L = 270, R = 90}
|
|
else
|
|
RotationAngles = { F = 0, B = 180, L = 90, R = 270}
|
|
end
|
|
|
|
-- se rotazione è libera
|
|
if not bOnly180Rot then
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), RotationAngles[DrillClassif.sCase], GDB_RT.GLOB)
|
|
nRotate = nRotate + RotationAngles[DrillClassif.sCase]
|
|
|
|
-- verifico se la rotazione è valida
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
-- b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local bIsValidRotation = b3Part:getDimX() < RawPart.Len - 2 * NEST.KERF + GEO.EPS_SMALL and b3Part:getDimY() < RawPart.Width - 2 * NEST.KERF + GEO.EPS_SMALL
|
|
if not bIsValidRotation then
|
|
-- ritorno nella posizione originaria
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), - RotationAngles[DrillClassif.sCase], GDB_RT.GLOB)
|
|
nRotate = nRotate - RotationAngles[DrillClassif.sCase]
|
|
-- se ho un'altra posizione possibile ruoto in quella
|
|
if DrillClassif2 then
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), RotationAngles[DrillClassif2.sCase], GDB_RT.GLOB)
|
|
nRotate = nRotate + RotationAngles[DrillClassif2.sCase]
|
|
bDrillOpen = not DrillClassif2.bClosed
|
|
bLongDrill = DrillClassif2.bLong
|
|
if DrillClassif2.bOnlyOnRef then
|
|
EgtSetInfo( nPartId, "OnlyOnRefSide", 1)
|
|
end
|
|
else
|
|
-- dimentico di avere il foro
|
|
bDrill = false
|
|
end
|
|
end
|
|
|
|
-- se posso ruotare solo di 180° per venatura
|
|
else
|
|
if RotationAngles[DrillClassif.sCase] == 0 or RotationAngles[DrillClassif.sCase] == 180 then
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), RotationAngles[DrillClassif.sCase], GDB_RT.GLOB)
|
|
nRotate = nRotate + RotationAngles[DrillClassif.sCase]
|
|
else
|
|
-- vedo se ho un'altra posizione possibile
|
|
if DrillClassif2 and ( RotationAngles[DrillClassif2.sCase] == 0 or RotationAngles[DrillClassif2.sCase] == 180) then
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), RotationAngles[DrillClassif2.sCase], GDB_RT.GLOB)
|
|
nRotate = nRotate + RotationAngles[DrillClassif2.sCase]
|
|
bDrillOpen = not DrillClassif2.bClosed
|
|
bLongDrill = DrillClassif2.bLong
|
|
if DrillClassif2.bOnlyOnRef then
|
|
EgtSetInfo( nPartId, "OnlyOnRefSide", 1)
|
|
end
|
|
else
|
|
-- dimentico di avere il foro
|
|
bDrill = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- se non ho venature e fori scelgo una posizione che non faccia cadere il pezzo
|
|
if not bDrill and not bOnly180Rot and not bLockedRot then
|
|
b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local bIsValid = b3Part:getDimX() > s_dIntRulli
|
|
local bRotatedIsValid = b3Part:getDimY() > s_dIntRulli
|
|
if not bIsValid and not bRotatedIsValid then
|
|
EgtSetInfo( nPartId, "REDUCECUT", 1)
|
|
elseif not bIsValid or not bRotatedIsValid then
|
|
bOnly180Rot = true
|
|
EgtSetInfo( nPartId, "NestStepRot", 180)
|
|
end
|
|
if not bIsValid and bRotatedIsValid then
|
|
EgtRotate( nPartId, b3Part:getCenter(), Z_AX(), 90, GDB_RT.GLOB)
|
|
nRotate = nRotate + 90
|
|
end
|
|
end
|
|
|
|
-- lap joints
|
|
local ResLapJoints = ClassifyLapJointsFromBottom( nPartId)
|
|
b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local bAdd = true
|
|
|
|
if ResLapJoints.Nbr > 0 and bLockedRot then
|
|
b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
if b3Part:getDimX() > s_dIntRulli then
|
|
EgtSetInfo( nPartId, "REDUCECUT", 1)
|
|
end
|
|
local PartAngleClassification = { PartId = tostring( nPartId), Angle = 100, nRotate = 0, bDrill = true, bLongDrill = true}
|
|
return PartAngleClassification
|
|
end
|
|
|
|
-- se anche fori oppure possibile solo rotazione di 180° per non far cadere il pezzo
|
|
if bDrill or bOnly180Rot then
|
|
local bCanRotate = not bDrill or ( bDrill and bDrillOpen)
|
|
|
|
if ResLapJoints.Nbr == 0 then
|
|
nAngle = 0
|
|
if not bDrill then bAdd = false end
|
|
|
|
elseif ResLapJoints.Nbr == 1 then
|
|
if (( sRefOrig == 'TL' or sRefOrig == 'TR') and ResLapJoints.sCase == 'B' ) or
|
|
(( sRefOrig == 'BL' or sRefOrig == 'BR') and ResLapJoints.sCase == 'F' ) then
|
|
nAngle = 20
|
|
elseif (( sRefOrig == 'TL' or sRefOrig == 'TR') and ResLapJoints.sCase == 'F' ) or
|
|
(( sRefOrig == 'BL' or sRefOrig == 'BR') and ResLapJoints.sCase == 'B' ) then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 20, 100)
|
|
nRotate = nRotate + nRotate2
|
|
elseif ResLapJoints.sCase == 'R' then
|
|
if bCanRotate then bManual = true end
|
|
if sRefOrig == 'TL' or sRefOrig == 'BL'then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 40, 0)
|
|
nRotate = nRotate + nRotate2
|
|
else
|
|
nAngle = 40
|
|
end
|
|
elseif ResLapJoints.sCase == 'L' then
|
|
if bCanRotate then bManual = true end
|
|
if sRefOrig == 'TR' or sRefOrig == 'BR' then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 40, 0)
|
|
nRotate = nRotate + nRotate2
|
|
else
|
|
nAngle = 40
|
|
end
|
|
end
|
|
|
|
elseif ResLapJoints.Nbr == 2 then
|
|
if ResLapJoints.bParall then
|
|
if ResLapJoints.sCase == 'F' then
|
|
nAngle = 100
|
|
else
|
|
nAngle = 80
|
|
end
|
|
else
|
|
if (( sRefOrig == 'TL' or sRefOrig == 'TR') and (ResLapJoints.sCase == 'BL' or ResLapJoints.sCase == 'BR')) or
|
|
(( sRefOrig == 'BL' or sRefOrig == 'BR') and (ResLapJoints.sCase == 'FL' or ResLapJoints.sCase == 'FR')) then
|
|
nAngle = 40
|
|
else
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 40, 100)
|
|
nRotate = nRotate + nRotate2
|
|
end
|
|
end
|
|
|
|
elseif ResLapJoints.Nbr == 3 then
|
|
if (( sRefOrig == 'TL' or sRefOrig == 'TR') and ResLapJoints.sCase == 'F' ) or
|
|
(( sRefOrig == 'BL' or sRefOrig == 'BR') and ResLapJoints.sCase == 'B' ) then
|
|
nAngle = 80
|
|
elseif (( sRefOrig == 'TL' or sRefOrig == 'TR') and ResLapJoints.sCase == 'B' ) or
|
|
(( sRefOrig == 'BL' or sRefOrig == 'BR') and ResLapJoints.sCase == 'F' ) then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 80, 100)
|
|
nRotate = nRotate + nRotate2
|
|
elseif ResLapJoints.sCase == 'R' then
|
|
if bCanRotate then bManual = true end
|
|
if sRefOrig == 'TR' or sRefOrig == 'BR' then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 100, 100)
|
|
nRotate = nRotate + nRotate2
|
|
end
|
|
nAngle = 100
|
|
elseif ResLapJoints.sCase == 'L' then
|
|
if bCanRotate then bManual = true end
|
|
if sRefOrig == 'TL' or sRefOrig == 'BL' then
|
|
nAngle, nRotate2 = RotateOptimalCaseDrill( nPartId, bCanRotate, 100, 100)
|
|
nRotate = nRotate + nRotate2
|
|
end
|
|
nAngle = 100
|
|
end
|
|
|
|
elseif ResLapJoints.Nbr == 4 then
|
|
nAngle = 100
|
|
end
|
|
|
|
-- no fori
|
|
else
|
|
if ResLapJoints.Nbr == 0 then
|
|
bAdd = false
|
|
|
|
elseif ResLapJoints.Nbr == 1 then
|
|
if sRefOrig == 'TL' or sRefOrig == 'TR' then
|
|
RotationAngles = { F = 180, B = 0, R = 90, L = 270}
|
|
elseif sRefOrig == 'BL'or sRefOrig == 'BR' then
|
|
RotationAngles = { F = 0, B = 180, R = 270, L = 90}
|
|
end
|
|
local nAngleValidRot = EgtIf( sRefOrig == 'TL' or sRefOrig == 'BR', 90, 270)
|
|
nAngle, nRotate2, bOptimal = RotateOptimalCase( nPartId, RotationAngles[ResLapJoints.sCase], nAngleValidRot, RawPart, 20, 40)
|
|
nRotate = nRotate + nRotate2
|
|
if not bOptimal then bManual = true end
|
|
|
|
elseif ResLapJoints.Nbr == 2 then
|
|
if ResLapJoints.bParall then
|
|
-- se lap joints su lati paralleli
|
|
RotationAngles = { F = 90, R = 0}
|
|
nAngle, nRotate2 = RotateOptimalCase( nPartId, RotationAngles[ResLapJoints.sCase], 90, RawPart, 80, 100)
|
|
nRotate = nRotate + nRotate2
|
|
else
|
|
-- se lap joints su lati adiacenti
|
|
if sRefOrig == 'TR' then
|
|
RotationAngles = { FR = 90, BR = 0, BL = 270, FL = 180}
|
|
elseif sRefOrig == 'TL' then
|
|
RotationAngles = { FR = 180, BR = 90, BL = 0, FL = 270}
|
|
elseif sRefOrig == 'BR' then
|
|
RotationAngles = { FR = 0, BR = 270, BL = 180, FL = 90}
|
|
elseif sRefOrig == 'BL' then
|
|
RotationAngles = { FR = 270, BR = 180, BL = 90, FL = 0}
|
|
end
|
|
local nAngleValidRot = EgtIf( sRefOrig == 'TL' or sRefOrig == 'BR', 270, 90)
|
|
nAngle, nRotate2, bOptimal = RotateOptimalCase( nPartId, RotationAngles[ResLapJoints.sCase], nAngleValidRot, RawPart, 40, 40)
|
|
nRotate = nRotate + nRotate2
|
|
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local bCanRotate = b3Part:getDimX() < RawPart.Width
|
|
if bOptimal and bCanRotate then bManual = true end
|
|
end
|
|
|
|
elseif ResLapJoints.Nbr == 3 then
|
|
if sRefOrig == 'TL' or sRefOrig == 'TR' then
|
|
RotationAngles = { F = 0, B = 180, R = 270, L = 90}
|
|
elseif sRefOrig == 'BL' or sRefOrig == 'BR' then
|
|
RotationAngles = { F = 180, B = 0, R = 90, L = 270}
|
|
end
|
|
local nAngleValidRot = EgtIf( sRefOrig == 'TL' or sRefOrig == 'BR', 90, 270)
|
|
nAngle, nRotate2, bOptimal = RotateOptimalCase( nPartId, RotationAngles[ResLapJoints.sCase], nAngleValidRot, RawPart, 80, 100)
|
|
nRotate = nRotate + nRotate2
|
|
if not bOptimal then bManual = true end
|
|
|
|
elseif ResLapJoints.Nbr == 4 then
|
|
nAngle, nRotate2 = RotateOptimalCase( nPartId, 0, 90, RawPart, 100, 100)
|
|
nRotate = nRotate + nRotate2
|
|
end
|
|
end
|
|
|
|
-- aggiorno le info di rotazione del pezzo
|
|
if nRotate >= 360 then
|
|
nRotate = nRotate - 360
|
|
end
|
|
if nRotate > 0 then
|
|
local bPartFlip = ( ( EgtGetInfo( nPartId, "INVERTED", 'i') or 0) == 180)
|
|
local nPartRot = EgtGetInfo( nPartId, "ROTATED", 'i') or 0
|
|
local nTotRot = nPartRot - EgtIf( bPartFlip, -nRotate, nRotate)
|
|
nTotRot = EgtIf( nTotRot < 0, nTotRot + 360, nTotRot)
|
|
EgtSetInfo( nPartId, "ROTATED", nTotRot)
|
|
EgtSetInfo( nPartId, "MODIFIEDFORNEST", 1)
|
|
end
|
|
|
|
if not bAdd then
|
|
return
|
|
end
|
|
|
|
local PartAngleClassification = { PartId = tostring( nPartId), Angle = nAngle, nRotate = nRotate, bDrill = bDrill, bLongDrill = bLongDrill, bManual = bManual}
|
|
|
|
local bCanBeOnOtherEdge = not bDrill or ( bDrill and RawPart.Width > s_dMinRawYHorDrill - GEO.EPS_SMALL)
|
|
if bOnly180Rot then
|
|
if bCanBeOnOtherEdge then
|
|
EgtSetInfo( nPartId, "NestAllowRot", 1)
|
|
EgtSetInfo( nPartId, "NestStepRot", 180)
|
|
else
|
|
EgtSetInfo( nPartId, "NestAllowRot", 0)
|
|
EgtSetInfo( nPartId, "NestStepRot", 0)
|
|
end
|
|
end
|
|
|
|
-- verifico se il pezzo cade (caso di foro)
|
|
b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
if b3Part:getDimX() > s_dIntRulli then
|
|
EgtSetInfo( nPartId, "REDUCECUT", 1)
|
|
end
|
|
|
|
return PartAngleClassification
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function ComputeRestrictedZones( RawParts)
|
|
|
|
local dTotArea = 0
|
|
-- area totale dei pezzi
|
|
for nPartId, nCount in pairs( PART) do
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
local dPartArea = b3Part:getDimX() * b3Part:getDimY()
|
|
dTotArea = dTotArea + dPartArea * nCount
|
|
end
|
|
|
|
-- stimo il numero di angoli disponibili
|
|
local vSheetNbrEstimate = {}
|
|
local nSheetNbrEstimate = 0
|
|
local nSheetNbrCorrection = - 2
|
|
local nAnglesNbrEstimate = 0
|
|
local nAngelsNbrCorrection = 0
|
|
|
|
local vRawDistrib = {}
|
|
if #RawParts == 1 then
|
|
vRawDistrib = {1}
|
|
elseif #RawParts == 2 then
|
|
vRawDistrib = {0.7, 0.3}
|
|
else
|
|
for nInd = 1, #RawParts do
|
|
table.insert( vRawDistrib, 1 / #RawParts)
|
|
end
|
|
end
|
|
|
|
local dMaxSheetWidth = -100
|
|
local nMaxSheet = 1
|
|
local dMinSheetWidth = WD.MAX_WIDTH
|
|
for nInd = 1, #RawParts do
|
|
local dSheetArea = RawParts[nInd].Len * RawParts[nInd].Width
|
|
if RawParts[nInd].Width > dMaxSheetWidth + GEO.EPS_SMALL then
|
|
dMaxSheetWidth = RawParts[nInd].Width
|
|
nMaxSheet = nInd
|
|
elseif abs( RawParts[nInd].Width - dMaxSheetWidth) < GEO.EPS_SMALL then
|
|
if RawParts[nInd].Len > RawParts[nMaxSheet].Len then
|
|
nMaxSheet = nInd
|
|
end
|
|
end
|
|
if RawParts[nInd].Width < dMinSheetWidth then
|
|
dMinSheetWidth = RawParts[nInd].Width
|
|
end
|
|
|
|
vSheetNbrEstimate[nInd] = min( ceil( dTotArea * vRawDistrib[nInd] / dSheetArea) + nSheetNbrCorrection, RawParts[nInd].Qty)
|
|
if vSheetNbrEstimate[nInd] <= 0 then
|
|
vSheetNbrEstimate[nInd] = min( RawParts[nInd].Qty, 1)
|
|
end
|
|
|
|
nSheetNbrEstimate = nSheetNbrEstimate + vSheetNbrEstimate[nInd]
|
|
nAnglesNbrEstimate = nAnglesNbrEstimate + vSheetNbrEstimate[nInd] * 2
|
|
end
|
|
nAnglesNbrEstimate = nAnglesNbrEstimate + nAngelsNbrCorrection
|
|
|
|
-- classificazione dei pezzi in base alla loro necessità di stare negli angoli
|
|
local nTotParts = 0
|
|
for _ in pairs( PART) do nTotParts = nTotParts + 1 end
|
|
local nPartIndex = 0
|
|
local AngleClassification = {}
|
|
for nPartId, nCount in pairs( PART) do
|
|
nPartIndex = nPartIndex + 1
|
|
local bManualRot = EgtGetInfo( nPartId, "MANUALROT", 'b')
|
|
local PartClassif = ClassifyAngles(tonumber(nPartId), RawParts[nMaxSheet], s_sOrigCorner, bManualRot, dMinSheetWidth)
|
|
if PartClassif then
|
|
for nI = 1, nCount do
|
|
local newTab = {PartId = PartClassif.PartId, Angle = PartClassif.Angle, nRotate = PartClassif.nRotate, bDrill = PartClassif.bDrill, bLongDrill = PartClassif.bLongDrill, bManual = PartClassif.bManual}
|
|
table.insert( AngleClassification, newTab)
|
|
end
|
|
end
|
|
|
|
if EgtProcessEvents( nPartIndex / nTotParts * 100, 0) == 1 then
|
|
return false
|
|
end
|
|
end
|
|
|
|
table.sort( AngleClassification, function(a, b) return a.Angle > b.Angle end)
|
|
|
|
local vManuallyDone = {}
|
|
local vPartsManuallyDone = {}
|
|
for nInd = 1, #vSheetNbrEstimate do
|
|
for nInd2 = 1, vSheetNbrEstimate[nInd] do
|
|
table.insert( vManuallyDone, { RawPartId = nInd, Done = 0, Parts = {}})
|
|
end
|
|
end
|
|
local nSheetNbr = #vManuallyDone
|
|
local vFilledSheets = {}
|
|
for nInd = 1, #vSheetNbrEstimate do
|
|
for nInd2 = 1, vSheetNbrEstimate[nInd] do
|
|
table.insert( vFilledSheets, { Width = RawParts[nInd].Width, OrigWidth = RawParts[nInd].Width})
|
|
end
|
|
end
|
|
|
|
for nInd = 1, #AngleClassification do
|
|
|
|
if AngleClassification[nInd].Angle >= NEST.MIN_ANGLE_PNT and AngleClassification[nInd].Angle > 0 then
|
|
|
|
-- verifico di avere ancora angoli a disposizione secondo la stima dei grezzi
|
|
local bFound = false
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( AngleClassification[nInd].PartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
local dPartWidth = b3Part:getDimY() + NEST.KERF
|
|
for nInd2 = 1, #vFilledSheets do
|
|
if dPartWidth < vFilledSheets[nInd2].Width then
|
|
-- verifico se il grezzo aveva già un pezzo in un angolo
|
|
if abs( vFilledSheets[nInd2].Width - vFilledSheets[nInd2].OrigWidth) < GEO.EPS_SMALL then
|
|
vFilledSheets[nInd2].Width = vFilledSheets[nInd2].Width - dPartWidth - s_dSideMillDiamDown
|
|
else
|
|
-- se il grezzo aveva già un pezzo nell'angolo, dopo il pezzo corrente non ne posso mettere altri
|
|
vFilledSheets[nInd2].Width = 0
|
|
end
|
|
bFound = true
|
|
break
|
|
end
|
|
end
|
|
|
|
-- se ho ancora angoli a disposizione oppure il pezzo deve stare necessariamente sull'angolo per essere lavorato
|
|
if bFound or AngleClassification[nInd].Angle == 100 then
|
|
-- verifico se va nestato manualmente
|
|
if AngleClassification[nInd].bManual then
|
|
|
|
-- trovo il punto della lista dove inserirlo
|
|
local nIdx = -1
|
|
local bOnOppositeSide = false
|
|
for nInd2 = 1, #vManuallyDone do
|
|
-- verifico se il pezzo può stare sull'altro angolo
|
|
local bOnlyOnRef = EgtGetInfo( AngleClassification[nInd].PartId, "OnlyOnRefSide", 'b')
|
|
local bCanBeOnOtherAngle = not bOnlyOnRef and
|
|
( not AngleClassification[nInd].bDrill or
|
|
( AngleClassification[nInd].bDrill and not AngleClassification[nInd].bLongDrill and
|
|
RawParts[vManuallyDone[nInd2].RawPartId].Width > s_dMinRawYHorDrill - GEO.EPS_SMALL))
|
|
|
|
if #(vManuallyDone[nInd2].Parts) == 0 then
|
|
-- verifico che il pezzo stia in questo grezzo
|
|
local b3Part = EgtGetBBoxGlob( AngleClassification[nInd].PartId, GDB_BB.STANDARD)
|
|
if b3Part:getDimX() < RawParts[vManuallyDone[nInd2].RawPartId].Len and b3Part:getDimY() < RawParts[vManuallyDone[nInd2].RawPartId].Width then
|
|
nIdx = nInd2
|
|
break
|
|
end
|
|
|
|
elseif #(vManuallyDone[nInd2].Parts) == 1 and bCanBeOnOtherAngle then
|
|
-- verifico se il pezzo già posizionato nell'angolo non ha fori lunghi
|
|
if not vManuallyDone[nInd2].Parts[1].bLongDrill then
|
|
-- oriento il pezzo in modo ottimale per andare su quell'angolo
|
|
local sRefOrig
|
|
if s_sOrigCorner == 'TL' then sRefOrig = 'BL' end
|
|
if s_sOrigCorner == 'BL' then sRefOrig = 'TL' end
|
|
if s_sOrigCorner == 'TR' then sRefOrig = 'BR' end
|
|
if s_sOrigCorner == 'BR' then sRefOrig = 'TR' end
|
|
local bManTmp
|
|
local res = ClassifyAngles( AngleClassification[nInd].PartId, RawParts[vManuallyDone[nInd2].RawPartId], sRefOrig, bManTmp, dMinSheetWidth)
|
|
-- verifico sia compatibile con pezzo già inserito
|
|
local b3OtherPart = EgtGetBBoxGlob( vManuallyDone[nInd2].Parts[1].Id, GDB_BB.STANDARD)
|
|
local b3Part = EgtGetBBoxGlob( AngleClassification[nInd].PartId, GDB_BB.STANDARD)
|
|
local dExtra = 2 * NEST.KERF + s_dSideMillDiamDown + 1
|
|
-- se è compatibile assegno questa rotazione al pezzo
|
|
if b3Part:getDimY() + b3OtherPart:getDimY() + dExtra < RawParts[vManuallyDone[nInd2].RawPartId].Width then
|
|
nIdx = nInd2
|
|
bOnOppositeSide = true
|
|
-- aggiorno le info di rotazione
|
|
if res.nRotate > 0 then
|
|
local bPartFlip = ( ( EgtGetInfo( AngleClassification[nInd].PartId, "INVERTED", 'i') or 0) == 180)
|
|
local nPartRot = EgtGetInfo( AngleClassification[nInd].PartId, "ROTATED", 'i') or 0
|
|
local nTotRot = nPartRot - EgtIf( bPartFlip, -res.nRotate, res.nRotate)
|
|
nTotRot = EgtIf( nTotRot < 0, nTotRot + 360, nTotRot)
|
|
EgtSetInfo( AngleClassification[nInd].PartId, "ROTATED", nTotRot)
|
|
EgtSetInfo( AngleClassification[nInd].PartId, "MODIFIEDFORNEST", 1)
|
|
end
|
|
break
|
|
end
|
|
-- altrimenti lo riporto nella sua posizione originaria
|
|
EgtRotate( AngleClassification[nInd].PartId, b3Part:getCenter(), Z_AX(), - res.nRotate, GDB_RT.GLOB)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- nesto il pezzo a mano
|
|
if nIdx ~= -1 then
|
|
-- aree di lavorazione
|
|
local nToolOutlineIds = ComputeToolOutlines( AngleClassification[nInd].PartId)
|
|
local sInfo = ""
|
|
for nInd = 1, #nToolOutlineIds do
|
|
sInfo = sInfo .. tostring(nToolOutlineIds[nInd]) .. ","
|
|
end
|
|
-- salvo tra le info del pezzo gli id delle sue aree di lavorazione
|
|
if sInfo ~= "" then
|
|
EgtSetInfo( AngleClassification[nInd].PartId, "ToolOutlines", sInfo)
|
|
end
|
|
|
|
-- calcolo defect corrispondente al pezzo
|
|
local PartTab = CreateDefectOnAngle( AngleClassification[nInd].PartId, RawParts[vManuallyDone[nIdx].RawPartId], AngleClassification[nInd].bLongDrill, bOnOppositeSide)
|
|
PartTab.bLongDrill = AngleClassification[nInd].bLongDrill
|
|
table.insert( vManuallyDone[nIdx].Parts, PartTab)
|
|
table.insert( vPartsManuallyDone, tonumber( AngleClassification[nInd].PartId))
|
|
|
|
else
|
|
-- aggiungo info per il nesting per ricordare che andrà su angolo
|
|
EgtSetInfo( AngleClassification[nInd].PartId, "NestOnAngle", 1)
|
|
end
|
|
else
|
|
-- se non va nestato manualmente segno info per nesting
|
|
EgtSetInfo( AngleClassification[nInd].PartId, "NestOnAngle", 1)
|
|
end
|
|
|
|
else
|
|
-- se non ho più angoli a disposizione lo metto sul lato
|
|
EgtSetInfo(AngleClassification[nInd].PartId, "NestOnEdge", 1)
|
|
end
|
|
|
|
else
|
|
EgtSetInfo(AngleClassification[nInd].PartId, "NestOnEdge", 1)
|
|
end
|
|
|
|
end
|
|
|
|
local nInd = 1
|
|
while nInd <= #vManuallyDone do
|
|
if #(vManuallyDone[nInd].Parts) == 0 then
|
|
table.remove( vManuallyDone, nInd)
|
|
else
|
|
nInd = nInd + 1
|
|
end
|
|
end
|
|
|
|
return vManuallyDone, vPartsManuallyDone
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
-- Funzione che sposta e aggiunge pezzi per nesting
|
|
local function AddRawParts(RawParts, vDoneManually)
|
|
|
|
local OUTLINE = "Outline"
|
|
for nIndex = 1, #RawParts do
|
|
RawParts[nIndex].PartId = {}
|
|
|
|
-- pannelli con pezzi inseriti manualmente
|
|
local nTotSheetWithDefects = 0
|
|
for nInd = 1, #vDoneManually do
|
|
if vDoneManually[nInd].RawPartId == nIndex then
|
|
-- creo pannello del materiale
|
|
local SheetPartId = EgtGroup(GDB_ID.ROOT)
|
|
table.insert( RawParts[nIndex].PartId, SheetPartId)
|
|
EgtSetName(SheetPartId, "Sheet")
|
|
local SheetLayerId = EgtGroup(SheetPartId)
|
|
EgtSetName(SheetLayerId, OUTLINE)
|
|
local SheetOutlineId = EgtRectangle2P(SheetLayerId, Point3d(0,0,0), Point3d(RawParts[nIndex].Len + 0.1, RawParts[nIndex].Width + 0.1, 0), GDB_RT.GLOB)
|
|
EgtSetName(SheetOutlineId, OUTLINE)
|
|
-- creo foglio per nesting
|
|
EgtAutoNestAddSheet( SheetPartId, SheetOutlineId, NEST.KERF, 0, 1)
|
|
-- aggiungo defects
|
|
for nInd2 = 1, #(vDoneManually[nInd].Parts) do
|
|
EgtAutoNestAddDefectToSheet( SheetPartId, vDoneManually[nInd].Parts[nInd2].DefectId)
|
|
end
|
|
vDoneManually[nInd].SheetId = SheetPartId
|
|
nTotSheetWithDefects = nTotSheetWithDefects + 1
|
|
end
|
|
end
|
|
|
|
-- pannelli senza pezzi inseriti manualmente
|
|
local SheetPartId = EgtGroup(GDB_ID.ROOT)
|
|
table.insert( RawParts[nIndex].PartId, SheetPartId)
|
|
EgtSetName(SheetPartId, "Sheet")
|
|
local SheetLayerId = EgtGroup(SheetPartId)
|
|
EgtSetName(SheetLayerId, OUTLINE)
|
|
local SheetOutlineId = EgtRectangle2P(SheetLayerId, Point3d(0,0,0), Point3d(RawParts[nIndex].Len + 0.1, RawParts[nIndex].Width + 0.1, 0), GDB_RT.GLOB)
|
|
-- EgtModifyCurveThickness(SheetOutlineId, -Material.T_mm)
|
|
EgtSetName(SheetOutlineId, OUTLINE)
|
|
|
|
-- creo foglio per nesting
|
|
EgtAutoNestAddSheet( SheetPartId, SheetOutlineId, NEST.KERF, 1, RawParts[nIndex].Qty - nTotSheetWithDefects)
|
|
-- EgtAutoNestAddSheet( SheetId, OutlineId, dKerf, nPriority, nCount)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
local function AddParts(RawParts, vPartsDoneManually)
|
|
|
|
-- cerco la width massima dei grezzi
|
|
local dRawMaxWidth = - 100
|
|
for nIndex = 1, #RawParts do
|
|
if RawParts[nIndex].Width > dRawMaxWidth then
|
|
dRawMaxWidth = RawParts[nIndex].Width
|
|
end
|
|
end
|
|
|
|
-- valori correttivi per vincoli StripX e StripY
|
|
local dStripYCorr = GEO.EPS_SMALL
|
|
local dStripXCorr = GEO.EPS_SMALL
|
|
if NEST.CORNER == NST_CORNER.TL or NEST.CORNER == NST_CORNER.TR then
|
|
dStripYCorr = 0.1 - GEO.EPS_SMALL
|
|
end
|
|
if NEST.CORNER == NST_CORNER.BR or NEST.CORNER == NST_CORNER.TR then
|
|
dStripXCorr = 0.1 - GEO.EPS_SMALL
|
|
end
|
|
|
|
local nTotParts = 0
|
|
for _ in pairs( PART) do nTotParts = nTotParts + 1 end
|
|
local nPartIndex = 0
|
|
-- ciclo su pezzi per aggiungerli al nesting
|
|
for nPartId, nCount in pairs( PART) do repeat
|
|
|
|
-- conto quanti pezzi di questo tipo sono già stati posizionati a mano
|
|
nManuallyDone = 0
|
|
for nJ = 1, #vPartsDoneManually do
|
|
if vPartsDoneManually[nJ] == tonumber( nPartId) then
|
|
nManuallyDone = nManuallyDone + 1
|
|
end
|
|
end
|
|
|
|
if nManuallyDone == nCount then
|
|
-- se tutti posizionati passo al pezzo successivo
|
|
break
|
|
else
|
|
-- posiziono con il nesting solo quelli mancanti
|
|
nCount = nCount - nManuallyDone
|
|
end
|
|
|
|
nPartIndex = nPartIndex + 1
|
|
|
|
-- calcolo bbox pezzo per rotazioni
|
|
local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.STANDARD)
|
|
|
|
-- recupero eventuali stati di flip e rotazione dalle info del pezzo
|
|
local bFlipNest = true
|
|
local bFlip = false
|
|
local bRotNest = true
|
|
local nStepRotNest = 90
|
|
local nRotate = 0
|
|
|
|
-- flip
|
|
local bManualFlip = EgtGetInfo( nPartId, "MANUALFLIP", 'b')
|
|
if bManualFlip then
|
|
bFlipNest = false
|
|
elseif EgtExistsInfo( nPartId, "NestFlip") then
|
|
bFlipNest = EgtGetInfo( nPartId, "NestAllowFlip", 'b')
|
|
bFlip = EgtGetInfo( nPartId, "NestFlip", 'b')
|
|
end
|
|
|
|
-- rotation
|
|
local bManualRot = EgtGetInfo( nPartId, "MANUALROT", 'b')
|
|
if bManualRot then
|
|
bRotNest = false
|
|
elseif EgtExistsInfo( nPartId, "NestRot") then
|
|
nStepRotNest = EgtGetInfo( nPartId, "NestStepRot", 'i')
|
|
bRotNest = EgtGetInfo( nPartId, "NestAllowRot", 'b')
|
|
-- verifico se rotazione è valida (pezzo è contenuto nel grezzo)
|
|
local bValidRotationInRaw = b3Part:getDimX() < RawParts[1].Len - 2 * NEST.KERF + GEO.EPS_SMALL and b3Part:getDimY() < dRawMaxWidth - 2 * NEST.KERF + GEO.EPS_SMALL
|
|
if not bValidRotationInRaw then
|
|
bRotNest = true
|
|
nStepRotNest = 90
|
|
end
|
|
end
|
|
|
|
-- recupero vecchio contorno se già presente
|
|
local nOutlineLayer = EgtGetFirstNameInGroup(nPartId, "Outline")
|
|
local nOldOutline = EgtGetFirstNameInGroup(nOutlineLayer, 'ON_TMP')
|
|
local nOutline, nCnt
|
|
|
|
-- se l'outline non è stato calcolato oppure il pezzo è stato modificato, lo ricalcolo
|
|
local bPartIsModified = EgtGetInfo( nPartId, "MODIFIEDFORNEST", 'b')
|
|
if not nOldOutline or bPartIsModified then
|
|
|
|
-- elimino il vecchio contorno se pesente
|
|
while ( nOldOutline) do
|
|
EgtErase(nOldOutline or GDB_ID.NULL)
|
|
nOldOutline = EgtGetFirstNameInGroup( nOutlineLayer, 'ON_TMP')
|
|
end
|
|
|
|
-- Recupero o ricalcolo il solido
|
|
local SolidId = EgtBeamGetSolid( nPartId)
|
|
if not SolidId or not EgtGetInfo( SolidId, 'VALID') then
|
|
EgtBeamCalcSolid( nPartId, true)
|
|
SolidId = EgtBeamGetSolid( nPartId)
|
|
end
|
|
nOutline, nCnt = EgtGetSurfTmSilhouette( SolidId, Z_AX(), 10, nOutlineLayer, GDB_RT.GLOB)
|
|
EgtBeamShowSolid( nPartId, false)
|
|
|
|
for nInd = 0, nCnt - 1 do
|
|
EgtSetName( nOutline + nInd, 'ON_TMP')
|
|
EgtSetStatus( nOutline + nInd, 0)
|
|
end
|
|
|
|
local nCurrOutline = nOutline
|
|
if nCnt > 0 then
|
|
local frSum
|
|
EgtScale( nOutline, GLOB_FRM(), 1, 1, 0, GDB_RT.GLOB)
|
|
EgtModifyCurveExtrusion( nOutline, Z_AX(), GDB_RT.GLOB)
|
|
|
|
-- verifico che la prima curva sia l'unico loop esterno
|
|
local vtCrvRefN = EgtCurveArea( nOutline)
|
|
for nInd = 1, nCnt - 1 do
|
|
local vtCrvN = EgtCurveArea( nOutline + nInd)
|
|
-- se trovo più loop esterni uso come contorno quello del box (quindi forzo nCurrOutline a nil)
|
|
if vtCrvN and vtCrvRefN and AreSameVectorApprox( vtCrvN, vtCrvRefN) then
|
|
nCurrOutline = nil
|
|
for nInd2 = 0, nCnt - 1 do
|
|
EgtErase( nOutline + nInd2)
|
|
end
|
|
nCnt = 1
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if nCurrOutline and nCurrOutline ~= GDB_ID.NULL then
|
|
nOutline = nCurrOutline
|
|
else
|
|
-- se non ho trovato contorno, lo recupero dal Box
|
|
local nBoxLayer = EgtGetFirstNameInGroup(nPartId, "Box")
|
|
local nBox = EgtGetFirstNameInGroup(nBoxLayer, "Box")
|
|
local BBox = EgtGetBBoxGlob(nBox, GDB_BB.STANDARD)
|
|
nOutline = EgtRectangle2P(nOutlineLayer, Point3d( BBox:getMin():getX(), BBox:getMin():getY(), 0), Point3d( BBox:getMax():getX(), BBox:getMax():getY(), 0), GDB_RT.GLOB)
|
|
EgtOutLog("Impossible creating silhouette for part " .. tostring(nPartId))
|
|
nCnt = 1
|
|
end
|
|
|
|
EgtSetName( nOutline, 'ON_TMP')
|
|
EgtSetStatus( nOutline, 0)
|
|
|
|
else
|
|
-- altrimenti uso l'outline già calcolato
|
|
nOutline = nOldOutline
|
|
-- recupero il valore di nCnt
|
|
local vOutlinesIds = EgtGetNameInGroup( nOutlineLayer, 'ON_TMP')
|
|
nCnt = #vOutlinesIds
|
|
end
|
|
|
|
-- calcolo aree lavorazione
|
|
local nToolOutlineIds = ComputeToolOutlines( nPartId)
|
|
if bFlipNest and #nToolOutlineIds > 0 then
|
|
bFlipNest = false
|
|
end
|
|
|
|
if nOutline then
|
|
-- aggiungo pezzo al nesting
|
|
EgtAutoNestAddPart( nPartId, nOutline, bFlipNest, bRotNest, nStepRotNest, 0, nCount)
|
|
-- EgtAutoNestAddPart( PartId, OutlineId, bCanFlip, bCanRotate, dRotStep, nPriority, nCount)
|
|
end
|
|
-- aggiungo finestre
|
|
for nInd = 1, nCnt - 1 do
|
|
local _, _, dArea = EgtCurveArea( nOutline + nInd)
|
|
if dArea and dArea > s_dNestHoleMinArea then
|
|
EgtModifyCurveExtrusion( nOutline + nInd, Z_AX(), GDB_RT.GLOB)
|
|
EgtAutoNestAddHoleToPart( nPartId, nOutline + nInd)
|
|
end
|
|
end
|
|
|
|
-- aggiungo aree di lavorazione del pezzo
|
|
local sInfo = ""
|
|
for nInd = 1, #nToolOutlineIds do
|
|
EgtAutoNestAddToolOutlineToPart( nPartId, nToolOutlineIds[nInd])
|
|
sInfo = sInfo .. tostring(nToolOutlineIds[nInd]) .. ","
|
|
end
|
|
-- salvo tra le info del pezzo gli id delle sue aree di lavorazione
|
|
if sInfo ~= "" then
|
|
EgtSetInfo( nPartId, "ToolOutlines", sInfo)
|
|
end
|
|
|
|
-- Eventuali vincoli StripX e StripY
|
|
local bOnEdge = EgtGetInfo(nPartId, "NestOnEdge", 'b')
|
|
local bOnAngle = EgtGetInfo(nPartId, "NestOnAngle", 'b')
|
|
if bOnEdge or bOnAngle then
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
|
|
-- punto di riferimento sul pezzo
|
|
local ptRef
|
|
local dval = 10
|
|
if ( s_sOrigCorner == 'TL' or s_sOrigCorner == 'TR') then
|
|
ptRef = Point3d( b3Part:getMax():getX() - b3Part:getDimX() / 2, b3Part:getMax():getY() - dval, 0)
|
|
else
|
|
ptRef = Point3d( b3Part:getMin():getX() + b3Part:getDimX() / 2, b3Part:getMin():getY() + dval, 0)
|
|
end
|
|
|
|
-- vincolo StripY
|
|
local bOnlyOnRefSide = EgtGetInfo( nPartId, "OnlyOnRefSide", 'b')
|
|
if bOnlyOnRefSide then
|
|
if s_sOrigCorner == 'BL' or s_sOrigCorner == 'BR' then
|
|
EgtAutoNestSetStripYconstraintToPart( nPartId, ptRef, NEST.KERF + dval + dStripYCorr, 100000)
|
|
else
|
|
EgtAutoNestSetStripYconstraintToPart( nPartId, ptRef, - 1000, dRawMaxWidth + 1000 - ( NEST.KERF + dval - dStripYCorr))
|
|
end
|
|
else
|
|
EgtAutoNestSetStripYconstraintToPart( nPartId, ptRef, NEST.KERF + dval + dStripYCorr, dRawMaxWidth - 2 * ( NEST.KERF + dval))
|
|
end
|
|
|
|
-- se sull'angolo aggiungo anche vincolo StripX
|
|
if bOnAngle then
|
|
if s_sOrigCorner == 'TL' or s_sOrigCorner == 'BL' then
|
|
EgtAutoNestSetStripXconstraintToPart( nPartId, ptRef, NEST.KERF + b3Part:getDimX() / 2 + dStripXCorr, 100000)
|
|
else
|
|
EgtAutoNestSetStripXconstraintToPart( nPartId, ptRef, -100, RawParts[1].Len + 100 - NEST.KERF - b3Part:getDimX() / 2 + dStripXCorr)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- verifico se anullato nesting
|
|
if EgtProcessEvents( 100 + ( nPartIndex / nTotParts * 100), 0) == 1 then
|
|
return false
|
|
end
|
|
until true
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
------------------------------------------------------------------
|
|
------------------------------------------------------------------
|
|
-- Inizializzo contatori errori e avvisi
|
|
local nErrCnt = 0
|
|
local nWarnCnt = 0
|
|
local bOk = true
|
|
NEST.ERR = 0
|
|
|
|
-- resetto gruppo di lavorazione corrente
|
|
EgtResetCurrMachGroup()
|
|
|
|
-- modalità nesting utile per cabinet: un grezzo per ogni pezzo, pezzo centrato nel grezzo. Il grezzo non viene preso da magazzino ma creato ad hoc, con un dato sovramateriale.
|
|
-- il numero del MachGroup deve coincidere con il PDN del pezzo originale
|
|
if NEST.FLAG ~= 11 and WD.ENABLE_SIMPLE_NESTING then
|
|
|
|
-- sovramateriale richiesto
|
|
local dOverMaterial = max( 0, NEST.KERF or 2)
|
|
|
|
-- inizializzazione parametri per creazione grezzo tramite BatchProcessNew
|
|
_G.WALL = {}
|
|
WALL.FILE = NEST.FILE
|
|
WALL.MACHINE = NEST.MACHINE
|
|
WALL.BASEDIR = NEST.BASEDIR
|
|
WALL.FLAG = 6 -- CREATE_PANEL
|
|
WALL.NESTING_REF = 'BL'
|
|
|
|
-- si ricrea la lista pezzi ordinata
|
|
local PartList = {}
|
|
local nPartCounter = 0
|
|
for nPartId, nCount in pairs( PART) do
|
|
nPartCounter = nPartCounter + 1
|
|
PartList[nPartCounter] = {}
|
|
PartList[nPartCounter].nId = nPartId
|
|
PartList[nPartCounter].nCount = nCount
|
|
PartList[nPartCounter].nPdn = EgtGetInfo( nPartId, "PDN", 'i')
|
|
PartList[nPartCounter].bAddCounterToNaming = false
|
|
-- se presente un pezzo con multipli il PDN sarà seguito da un contatore
|
|
if nCount > 1 then
|
|
PartList[nPartCounter].bAddCounterToNaming = true
|
|
end
|
|
end
|
|
-- si riordina in base al PDN
|
|
table.sort( PartList, function(a, b) return tonumber( a.nPdn) < tonumber( b.nPdn) end)
|
|
|
|
-- per ogni singolo pezzo si chiama la fliprot per avere la migliore orientazione
|
|
-- si creano duplo e machgroup e si settano le note opportune per poi creare i grezzi richiamando la BatchProcessNew (flag 6)
|
|
for i = 1, #PartList do
|
|
|
|
local nPartId = PartList[i].nId
|
|
local nPartCount = PartList[i].nCount
|
|
local nPdn = PartList[i].nPdn
|
|
local bAddCounterToNaming = PartList[i].bAddCounterToNaming
|
|
|
|
-- si ruotano e invertono i pezzi per avere la migliore posizione di lavorazione
|
|
_G.NFAR = {}
|
|
NFAR.ERR = 0
|
|
NFAR.MSG = ''
|
|
NFAR.PARTID = nPartId
|
|
NFAR.BASEDIR = NEST.BASEDIR
|
|
dofile( NEST.BASEDIR .. "\\NestFlipAndRotate.lua")
|
|
|
|
-- informazioni dalla parte originale
|
|
-- box e relative dimensioni
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local b3Part = EgtGetBBoxGlob( nBoxId, GDB_BB.STANDARD)
|
|
-- inversione e rotazione
|
|
local nPartFlip = EgtGetInfo( nPartId, "INVERTED", 'i') or 0
|
|
local nPartRotation = EgtGetInfo( nPartId, "ROTATED", 'i') or 0
|
|
|
|
-- dimensioni grezzo, considerando sovramateriale
|
|
local dRawLength = b3Part:getDimX() + 2 * dOverMaterial
|
|
local dRawWidth = b3Part:getDimY() + 2 * dOverMaterial
|
|
|
|
for j = 1, nPartCount do
|
|
-- creazione gruppo di lavoro
|
|
local sMachGroupName = nPdn
|
|
if bAddCounterToNaming then
|
|
sMachGroupName = nPdn .. '_' .. string.format("%02d", j)
|
|
end
|
|
local nMachGroupId = EgtAddMachGroup( sMachGroupName)
|
|
if not nMachGroupId then
|
|
EgtOutLog( "Errore: MachGroup " .. nPdn .. " già presente")
|
|
EgtOutBox( 'Error : MachGroup ' .. nPdn .. ' already existing', 'Nesting failed')
|
|
NEST.ERR = 2
|
|
return
|
|
end
|
|
-- settaggio note in gruppo di lavoro
|
|
EgtSetInfo( nMachGroupId, "PANELLEN", dRawLength)
|
|
EgtSetInfo( nMachGroupId, "PANELWIDTH", dRawWidth)
|
|
EgtSetInfo( nMachGroupId, "MATERIAL", NEST.MATERIAL)
|
|
EgtSetInfo( nMachGroupId, "PRODID", NEST.PRODID)
|
|
EgtSetInfo( nMachGroupId, "PATTID", nMachGroupId)
|
|
|
|
-- creazione duplo
|
|
local nPartDuploId = EgtDuploNew( nPartId)
|
|
-- settaggio note in duplo
|
|
EgtSetInfo( nMachGroupId, "PART" .. 1, nPartDuploId .. "," .. EgtNumToString( dOverMaterial) .. "," .. EgtNumToString( dOverMaterial) .. "," .. 0 .."," .. 0)
|
|
EgtSetInfo( nPartDuploId, "POSY", dOverMaterial)
|
|
EgtSetInfo( nPartDuploId, "POSX", dOverMaterial)
|
|
EgtSetInfo( nPartDuploId, "FLIP", nPartFlip)
|
|
EgtSetInfo( nPartDuploId, "ROT", nPartRotation)
|
|
|
|
-- creazione grezzi tramite BatchProcessNew
|
|
EgtSetCurrMachGroup( nMachGroupId)
|
|
EgtSetInfo( nMachGroupId, "UPDATEUI", 1)
|
|
dofile( NEST.BASEDIR .. "\\BatchProcessNew.lua")
|
|
end
|
|
end
|
|
|
|
EgtProcessEvents( 200 + 100, 0)
|
|
EgtResetCurrMachGroup()
|
|
EgtOutLog( ' +++ NestProcess completed')
|
|
|
|
EgtOutLog( ' +++ Generating Cutting List')
|
|
|
|
return
|
|
|
|
elseif NEST.FLAG == 11 then
|
|
|
|
local vCuttingListType = EgtSplitString( WD.PANELSAW_TYPE)
|
|
for i = 1, #vCuttingListType do
|
|
local sCuttingListType = vCuttingListType[i]
|
|
PanelSaw.GenerateCuttingList( sCuttingListType)
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
-- inizio nesting automatico
|
|
EgtAutoNestStart()
|
|
|
|
-- lista dei grezzi
|
|
local RawParts = {}
|
|
-- creo tabella dei grezzi
|
|
for sIndex, dLen in pairs( LEN) do
|
|
RawParts[tonumber(sIndex)] = { Len = dLen}
|
|
end
|
|
for sIndex, dWidth in pairs( WIDTH) do
|
|
RawParts[tonumber(sIndex)].Width = dWidth
|
|
end
|
|
for sIndex, nQty in pairs( QTY) do
|
|
RawParts[tonumber(sIndex)].Qty = nQty
|
|
end
|
|
for sIndex, sMaterial in pairs( MATERIAL) do
|
|
RawParts[tonumber(sIndex)].Material = sMaterial
|
|
end
|
|
|
|
--
|
|
local vDoneManually, vPartsDoneManually = ComputeRestrictedZones( RawParts)
|
|
|
|
-- creo grezzi e li aggiungo al nesting
|
|
AddRawParts(RawParts, vDoneManually)
|
|
|
|
if not bOk then
|
|
EgtOutLog("Interruzione nesting")
|
|
NEST.ERR = 1
|
|
end
|
|
|
|
-- calcolo rotazioni e flip ed aggiungo pezzi al nesting
|
|
if bOk then
|
|
bOk = AddParts(RawParts, vPartsDoneManually)
|
|
end
|
|
|
|
if not bOk then
|
|
EgtOutLog("Interruzione nesting")
|
|
NEST.ERR = 1
|
|
end
|
|
|
|
if bOk then
|
|
-- aggiungo offset tra pezzi
|
|
EgtAutoNestSetInterpartGap( NEST.OFFSET)
|
|
|
|
-- Impostazione corner di inizio del nesting (NST_CORNER.BL, TL, BR, TR)
|
|
EgtAutoNestSetStartCorner( NEST.CORNER)
|
|
|
|
-- Report dei dati di nesting per debug
|
|
EgtAutoNestSetReportFile( EgtGetTempDir() .. '\\LastNest.json')
|
|
|
|
-- imposto tempo di nesting e lo avvio
|
|
EgtAutoNestCompute( true, NEST.TIME)
|
|
end
|
|
|
|
-- Variabili di calcolo
|
|
local nNestedParts, nParts, nSheets, nNestings, dTotFillRatio
|
|
local bNestingOk = bOk
|
|
-- Attesa fine calcolo
|
|
local nTime = 0
|
|
while bNestingOk do
|
|
bNestingOk, nStat = EgtAutoNestGetComputationStatus()
|
|
if nStat == 2 or nStat == 3 then
|
|
nNestedParts, nParts, nSheets, nNestings, dTotFillRatio = EgtAutoNestGetResults()
|
|
--EgtOutText( string.format( 'Parts : %d/%d Filling : %.2f%%', nNestedParts, nParts, 100 * dTotFillRatio))
|
|
end
|
|
if nStat == 3 then break end
|
|
nTime = nTime + 1
|
|
if EgtProcessEvents( nTime / NEST.TIME * 100, 995) == 1 then
|
|
bNestingOk = EgtAutoNestCancelComputation()
|
|
bOk = false
|
|
EgtOutLog("Interruzione nesting")
|
|
NEST.ERR = 1
|
|
break
|
|
end
|
|
end
|
|
|
|
|
|
local dXCorr = 0
|
|
local dYCorr = 0
|
|
if NEST.CORNER == NST_CORNER.TL then
|
|
dYCorr = - 0.1
|
|
elseif NEST.CORNER == NST_CORNER.TR then
|
|
dYCorr = - 0.1
|
|
dXCorr = - 0.1
|
|
elseif NEST.CORNER == NST_CORNER.BR then
|
|
dXCorr = - 0.1
|
|
end
|
|
|
|
|
|
-- se nesting andato bene
|
|
if bNestingOk then
|
|
|
|
-- disposizione sheet e parts
|
|
local SheetId = GDB_ID.NULL
|
|
local vtAdd = V_NULL()
|
|
local MachGroupList = {}
|
|
local nPartCount = 0
|
|
local Sheet = {PartList = {}}
|
|
local bFirstSheet = true
|
|
for i = 0, 999 do
|
|
local nType, nId, nFlag, dX, dY, dAngRot = EgtAutoNestGetOneResult( i)
|
|
if not nType then break end
|
|
-- se sheet
|
|
if nType > 0 then
|
|
MachGroupList = {}
|
|
for MGIndex = 1, nType do
|
|
-- creo gruppo di lavorazione
|
|
local MachGroupName = NewMachGroupName()
|
|
local nMachGroup = EgtAddMachGroup(MachGroupName, sCurrMachName)
|
|
table.insert( MachGroupList, { MGId = nMachGroup})
|
|
for nIndex = 1, #RawParts do
|
|
for nInd2 = 1, #(RawParts[nIndex].PartId) do
|
|
if RawParts[nIndex].PartId[nInd2] == nId then
|
|
EgtSetInfo(nMachGroup, "PANELLEN", RawParts[nIndex].Len)
|
|
EgtSetInfo(nMachGroup, "PANELWIDTH", RawParts[nIndex].Width)
|
|
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)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- aggiungo pezzi nestati a mano
|
|
nPartCount = 0
|
|
for nInd = 1, #vDoneManually do
|
|
if vDoneManually[nInd].SheetId == nId then
|
|
vDoneManually[nInd].Done = 1
|
|
for nInd2 = 1, #(vDoneManually[nInd].Parts) do
|
|
nPartCount = nPartCount + 1
|
|
local nPartDuploId = EgtDuploNew( vDoneManually[nInd].Parts[nInd2].Id)
|
|
|
|
-- aggiungo le curve corrispondenti alle aree di lavorazione del pezzo
|
|
local sToolOutlines = EgtGetInfo( vDoneManually[nInd].Parts[nInd2].Id, "ToolOutlines", 's')
|
|
if sToolOutlines then
|
|
-- recupero o creo il gruppo per gli outlines
|
|
local nToolOutlinesGrp = EgtGetFirstNameInGroup( nPartDuploId, "ToolOutlines")
|
|
if not nToolOutlinesGrp then
|
|
nToolOutlinesGrp = EgtGroup( nPartDuploId)
|
|
EgtSetName( nToolOutlinesGrp, "ToolOutlines")
|
|
EgtSetStatus( nToolOutlinesGrp, GDB_ST.ON)
|
|
end
|
|
|
|
for str in string.gmatch(sToolOutlines, "([^"..",".."]+)") do
|
|
EgtCopyGlob( tonumber(str), nToolOutlinesGrp)
|
|
end
|
|
end
|
|
|
|
-- applico flip, rotazione e traslazione pezzo e box da nesting
|
|
EgtSetInfo( nMachGroup, "PART" .. nPartCount, nPartDuploId .. "," .. EgtNumToString( vDoneManually[nInd].Parts[nInd2].posX, 3) .. "," .. EgtNumToString( vDoneManually[nInd].Parts[nInd2].posY, 3) .. "," .. 0 .."," .. 0)
|
|
EgtSetInfo( nPartDuploId, "POSX", vDoneManually[nInd].Parts[nInd2].posX)
|
|
EgtSetInfo( nPartDuploId, "POSY", vDoneManually[nInd].Parts[nInd2].posY)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- altrimenti pezzo
|
|
else
|
|
nPartCount = nPartCount + 1
|
|
for MGIndex = 1, #MachGroupList do
|
|
local nMachGroup = MachGroupList[MGIndex].MGId
|
|
--EgtSetCurrMachGroup(nMachGroup)
|
|
-- se c'e' un grezzo valido
|
|
if nMachGroup and nMachGroup ~= GDB_ID.NULL then
|
|
-- creo pezzo copia
|
|
local nPartDuploId = EgtDuploNew( nId)
|
|
local nPartInd
|
|
|
|
-- aggiungo le curve corrispondenti alle aree di lavorazione del pezzo
|
|
local sToolOutlines = EgtGetInfo( nId, "ToolOutlines", 's')
|
|
if sToolOutlines then
|
|
-- recupero o creo il gruppo per gli outlines
|
|
local nToolOutlinesGrp = EgtGetFirstNameInGroup( nPartDuploId, "ToolOutlines")
|
|
if not nToolOutlinesGrp then
|
|
nToolOutlinesGrp = EgtGroup( nPartDuploId)
|
|
EgtSetName( nToolOutlinesGrp, "ToolOutlines")
|
|
EgtSetStatus( nToolOutlinesGrp, GDB_ST.ON)
|
|
end
|
|
|
|
for str in string.gmatch(sToolOutlines, "([^"..",".."]+)") do
|
|
EgtCopyGlob( tonumber(str), nToolOutlinesGrp)
|
|
end
|
|
end
|
|
|
|
-- applico flip, rotazione e traslazione pezzo e box da nesting
|
|
if nFlag == 1 then
|
|
EgtRotate( nPartDuploId, ORIG(), X_AX(), 180, GDB_RT.GLOB)
|
|
end
|
|
EgtRotate( nPartDuploId, ORIG(), Z_AX(), dAngRot, GDB_RT.GLOB)
|
|
EgtMove( nPartDuploId, Vector3d( dX, dY, 0), GDB_RT.GLOB)
|
|
|
|
local nBoxLayerId = EgtGetFirstNameInGroup( nPartDuploId, "Box")
|
|
local nBoxId = EgtGetFirstNameInGroup( nBoxLayerId, "Box")
|
|
local PartBBox = EgtGetBBoxGlob(nBoxId, GDB_BB.STANDARD)
|
|
local ptPos = Point3d( PartBBox:getMin():getX(), PartBBox:getMin():getY(), 0)
|
|
EgtSetInfo( nMachGroup, "PART" .. nPartCount, nPartDuploId .. "," .. EgtNumToString( ptPos:getX() + dXCorr, 3) .. "," .. EgtNumToString( ptPos:getY() + dYCorr, 3) .. "," .. 0 .."," .. 0)
|
|
EgtSetInfo( nPartDuploId, "POSX", ptPos:getX() + dXCorr)
|
|
EgtSetInfo( nPartDuploId, "POSY", ptPos:getY() + dYCorr)
|
|
|
|
local nPartFlip = EgtGetInfo( nId, "INVERTED", 'i') or 0
|
|
nPartFlip = EgtIf( nPartFlip == 180, 1, 0)
|
|
local nTotFlip = EgtIf( nPartFlip ~= nFlag, 180, 0)
|
|
EgtSetInfo( nPartDuploId, "FLIP", nTotFlip)
|
|
|
|
local bPartFlip = ( nTotFlip == 180)
|
|
local nPartRot = EgtGetInfo( nId, "ROTATED", 'i') or 0
|
|
local nTotRot = nPartRot - EgtIf( bPartFlip, -dAngRot, dAngRot)
|
|
if nTotRot < 0 then
|
|
nTotRot = nTotRot + 360
|
|
elseif nTotRot >= 360 then
|
|
nTotRot = nTotRot - 360
|
|
end
|
|
EgtSetInfo( nPartDuploId, "ROT", nTotRot)
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- creo gruppi di lavorazione per fogli con pezzi nestati solo a mano
|
|
for nInd = 1, #vDoneManually do
|
|
if vDoneManually[nInd].Done == 0 then
|
|
-- creo gruppo di lavorazione
|
|
local MachGroupName = NewMachGroupName()
|
|
local nMachGroup = EgtAddMachGroup(MachGroupName, sCurrMachName)
|
|
table.insert( MachGroupList, { MGId = nMachGroup})
|
|
for nIndex = 1, #RawParts do
|
|
for nInd2 = 1, #(RawParts[nIndex].PartId) do
|
|
if RawParts[nIndex].PartId[nInd2] == vDoneManually[nInd].SheetId then
|
|
EgtSetInfo(nMachGroup, "PANELLEN", RawParts[nIndex].Len)
|
|
EgtSetInfo(nMachGroup, "PANELWIDTH", RawParts[nIndex].Width)
|
|
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)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- aggiungo pezzi nestati a mano
|
|
nPartCount = 0
|
|
for nInd2 = 1, #(vDoneManually[nInd].Parts) do
|
|
nPartCount = nPartCount + 1
|
|
local nPartDuploId = EgtDuploNew( vDoneManually[nInd].Parts[nInd2].Id)
|
|
|
|
-- aggiungo le curve corrispondenti alle aree di lavorazione del pezzo
|
|
local sToolOutlines = EgtGetInfo( vDoneManually[nInd].Parts[nInd2].Id, "ToolOutlines", 's')
|
|
if sToolOutlines then
|
|
-- recupero o creo il gruppo per gli outlines
|
|
local nToolOutlinesGrp = EgtGetFirstNameInGroup( nPartDuploId, "ToolOutlines")
|
|
if not nToolOutlinesGrp then
|
|
nToolOutlinesGrp = EgtGroup( nPartDuploId)
|
|
EgtSetName( nToolOutlinesGrp, "ToolOutlines")
|
|
EgtSetStatus( nToolOutlinesGrp, GDB_ST.ON)
|
|
end
|
|
|
|
for str in string.gmatch(sToolOutlines, "([^"..",".."]+)") do
|
|
EgtCopyGlob( tonumber(str), nToolOutlinesGrp)
|
|
end
|
|
end
|
|
|
|
-- applico flip, rotazione e traslazione pezzo e box da nesting
|
|
EgtSetInfo( nMachGroup, "PART" .. nPartCount, nPartDuploId .. "," .. EgtNumToString( vDoneManually[nInd].Parts[nInd2].posX, 3) .. "," .. EgtNumToString( vDoneManually[nInd].Parts[nInd2].posY, 3) .. "," .. 0 .."," .. 0)
|
|
EgtSetInfo( nPartDuploId, "POSX", vDoneManually[nInd].Parts[nInd2].posX)
|
|
EgtSetInfo( nPartDuploId, "POSY", vDoneManually[nInd].Parts[nInd2].posY)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- creo grezzi per ogni gruppo di lavorazione
|
|
local MachGroupToTCnt = EgtGetMachGroupCount()
|
|
local MachGroupIndex = 0
|
|
_G.WALL = {}
|
|
WALL.FILE = NEST.FILE
|
|
WALL.MACHINE = NEST.MACHINE
|
|
WALL.BASEDIR = NEST.BASEDIR
|
|
WALL.FLAG = 6 -- CREATE_PANEL
|
|
WALL.NESTING_REF = 'BL'
|
|
nMachGroup = EgtGetFirstMachGroup()
|
|
while nMachGroup do
|
|
EgtSetCurrMachGroup( nMachGroup)
|
|
if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then
|
|
MachGroupIndex = MachGroupIndex + 1
|
|
EgtRemoveInfo( nMachGroup, "AUTONEST")
|
|
EgtSetInfo( nMachGroup, "UPDATEUI", 1)
|
|
dofile( NEST.BASEDIR .. "\\BatchProcessNew.lua")
|
|
-- aggiorno interfaccia
|
|
EgtProcessEvents( 200 + ( MachGroupIndex / MachGroupToTCnt * 100), 0)
|
|
end
|
|
|
|
-- ciclo sui duplo per sistemare Q
|
|
local nRawPartId = EgtGetFirstRawPart()
|
|
-- recupero box grezzo ridotto della tolleranza
|
|
local b3Raw = EgtGetRawPartBBox( nRawPartId)
|
|
b3Raw:expand( - s_dInsideRawTol)
|
|
EgtOutLog( 'RawBox='..tostring( b3Raw))
|
|
|
|
local nPartDuploId = EgtGetFirstPartInRawPart( nRawPartId)
|
|
while nPartDuploId do
|
|
local vPartProc = WE.CollectFeatures( nPartDuploId)
|
|
for ProcIndex = 1, #vPartProc do
|
|
local Proc = vPartProc[ProcIndex]
|
|
|
|
if LapJoint.Identify( Proc) then
|
|
-- cerco la faccia rivolta verso l'alto e la faccia rivolta verso il basso
|
|
local nFaceInd = -1
|
|
local nFaceDownInd = -1
|
|
for nIdx = 0, Proc.Fct - 1 do
|
|
local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nIdx, GDB_ID.ROOT)
|
|
if vtN:getZ() > 0.95 then
|
|
nFaceInd = nIdx
|
|
elseif vtN:getZ() < - 0.95 then
|
|
nFaceDownInd = nIdx
|
|
end
|
|
end
|
|
-- se è lap joint dall'alto
|
|
if nFaceInd ~= -1 and nFaceDownInd == -1 then
|
|
local bResetQ = false
|
|
local ptCen = EgtSurfTmFacetCenter( Proc.Id, nFaceInd, GDB_ID.ROOT)
|
|
-- se all'interno rimuovo info Q
|
|
if EnclosesPointXY( b3Raw, ptCen) then
|
|
bResetQ = true
|
|
elseif Proc.Fct == 2 then
|
|
-- se non è interno ma ha 2 facce non ortogonali rimuovo info Q
|
|
local vtN1 = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT)
|
|
local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT)
|
|
if abs( vtN1 * vtN2) > GEO.EPS_SMALL then
|
|
bResetQ = true
|
|
end
|
|
end
|
|
|
|
if bResetQ then
|
|
-- resetto parametro Q
|
|
if Proc.Prc == 30 then
|
|
EgtRemoveInfo( Proc.Id, "Q08")
|
|
EgtRemoveInfo( Proc.Id, "Q08A")
|
|
else
|
|
EgtRemoveInfo( Proc.Id, "Q03")
|
|
EgtRemoveInfo( Proc.Id, "Q03A")
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif DoubleCut.Identify( Proc) then
|
|
-- verifico se due facce e rivolto verso l'alto
|
|
if Proc.Fct == 2 then
|
|
local vtN = {}
|
|
vtN[1] = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT)
|
|
vtN[2] = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT)
|
|
|
|
if ( vtN[1]:getZ() >= 0.95 or vtN[2]:getZ() >= 0.95) then
|
|
local nFaceInd = EgtIf( vtN[1]:getZ() >= 0.95, 0, 1)
|
|
local ptCen = EgtSurfTmFacetCenter( Proc.Id, nFaceInd, GDB_ID.ROOT)
|
|
-- se all'interno rimuovo info Q
|
|
if EnclosesPointXY( b3Raw, ptCen) then
|
|
-- resetto parametro Q
|
|
if Proc.Prc == 12 then
|
|
EgtRemoveInfo( Proc.Id, "Q02")
|
|
EgtRemoveInfo( Proc.Id, "Q02A")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
nPartDuploId = EgtGetNextPartInRawPart(nPartDuploId)
|
|
end
|
|
nMachGroup = EgtGetNextMachGroup(nMachGroup)
|
|
end
|
|
|
|
else
|
|
EgtOutLog("Errore: nesting fallito")
|
|
NEST.ERR = 2
|
|
end
|
|
|
|
EgtResetCurrMachGroup()
|
|
|
|
-- cancello rettangolo del materiale per nesting
|
|
for RawPartId = 1, #RawParts do
|
|
EgtErase(RawParts[RawPartId].PartId)
|
|
end
|
|
|
|
local nOutlineGrp = EgtGetFirstNameInGroup(GDB_ID.ROOT, "ToolOutlines")
|
|
if nOutlineGrp and nOutlineGrp ~= GDB_ID.NULL then EgtErase( nOutlineGrp) end
|
|
local nSheetDefectsGrp = EgtGetFirstNameInGroup(GDB_ID.ROOT, "SheetDefects")
|
|
if nSheetDefectsGrp and nSheetDefectsGrp ~= GDB_ID.NULL then EgtErase( nSheetDefectsGrp) end
|
|
|
|
-- EgtSaveFile( "C:\\EgtData\\EgtBEAMWALL\\Temp\\file.nge")
|
|
|
|
EgtOutLog( ' +++ NestProcess completed') |