943ccea2a8
- varie modifiche per cliente belga.
887 lines
36 KiB
Lua
887 lines
36 KiB
Lua
-- NestProcess.lua by Egaltech s.r.l. 2021/05/25
|
|
-- 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.DRILL_MACH_AREA = 1
|
|
|
|
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)
|
|
|
|
-- Imposto direttorio libreria specializzata per Travi
|
|
local sBaseDir = EgtGetSourceDir()
|
|
EgtAddToPackagePath( sBaseDir .. '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')
|
|
|
|
-- Carico i dati globali
|
|
local WD = require( 'WallData')
|
|
|
|
-- 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, ptP2, vtFace, nOutlineGrp)
|
|
local dExtra = 1000 * GEO.EPS_SMALL
|
|
local vtX = ptP2 - ptP1
|
|
vtX:normalize()
|
|
-- creo il rettangolo della lavorazione
|
|
ptP1 = ptP1 - vtX * 9000
|
|
ptP2 = ptP2 + vtX * ( WD.SIDEMILL_DIAM_DOWN / 2 + dExtra)
|
|
ptP2 = ptP2 + vtFace * ( WD.SIDEMILL_DIAM_DOWN + dExtra)
|
|
local nId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX(), ptP2:getY(), 0), Point3d( ptP1:getX(), ptP1:getY(), 0))
|
|
EgtSetColor( nId, EgtStdColor("RED"))
|
|
return nId
|
|
end
|
|
|
|
-- Funzione che crea le regioni occupate dalle lavorazioni
|
|
local function ComputeToolOutlines( nPartId)
|
|
|
|
local ToolOutlineId = {}
|
|
|
|
-- 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
|
|
Proc = vPartProc[nInd]
|
|
|
|
-- lap joint
|
|
if LapJoint.Identify( vPartProc[nInd]) then
|
|
|
|
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() <= - 0.95 or vtN[2]:getZ() <= - 0.95) then
|
|
local vtFace = EgtIf( vtN[1]:getZ() <= -0.95, vtN[2], vtN[1])
|
|
local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT)
|
|
-- creo il rettangolo della lavorazione
|
|
local nId = CreateToolRectangle( ptP1, ptP2, vtFace, nOutlineGrp)
|
|
if nId ~= GDB_ID.NULL then table.insert(ToolOutlineId, nId) end
|
|
|
|
-- se rivolto verso l'alto
|
|
elseif ( vtN[1]:getZ() >= 0.95 or vtN[2]:getZ() >= 0.95 and WD.SIDEMILL_DIAM_UP > 0) then
|
|
local vtFace = EgtIf( vtN[1]:getZ() >= 0.95, vtN[2], vtN[1])
|
|
local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT)
|
|
local b3Face = EgtSurfTmGetFacetBBoxGlob( Proc.Id, EgtIf( vtN[1]:getZ() >= 0.95, 0, 1), GDB_BB.STANDARD)
|
|
local dDim = 0
|
|
if AreSameOrOppositeVectorApprox( vtFace, X_AX()) then
|
|
dDim = b3Face:getDimX()
|
|
elseif AreSameOrOppositeVectorApprox( vtFace, Y_AX()) then
|
|
dDim = b3Face:getDimY()
|
|
end
|
|
|
|
-- creo il rettangolo della lavorazione
|
|
local dExtra = 1000 * GEO.EPS_SMALL
|
|
local vtX = ptP2 - ptP1
|
|
vtX:normalize()
|
|
-- creo il rettangolo della lavorazione
|
|
ptP1 = ptP1 - vtX * ( WD.SIDEMILL_DIAM_UP / 2 + dExtra)
|
|
ptP2 = ptP2 + vtX * ( WD.SIDEMILL_DIAM_UP / 2 + dExtra)
|
|
local dVal = max( dDim + WD.SIDEMILL_DIAM_UP / 2, WD.SIDEMILL_DIAM_UP)
|
|
ptP2 = ptP2 + vtFace * ( dVal + dExtra)
|
|
local nId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX(), ptP2:getY(), 0), Point3d( ptP1:getX(), ptP1:getY(), 0))
|
|
EgtSetColor( nId, EgtStdColor("RED"))
|
|
local nPrId = EgtGetInfo( Proc.Id, "PRID", 'i')
|
|
EgtSetInfo( nId, "PRID", nPrId)
|
|
if nId ~= GDB_ID.NULL then table.insert(ToolOutlineId, nId) end
|
|
end
|
|
end
|
|
|
|
-- lap joint 3 facce nel mezzo di una faccia
|
|
if Proc.Fct == 3 then
|
|
local nFacInd, dElev = WL.GetFaceWithMostAdj( Proc.Id, Proc.PartId)
|
|
if nFacInd ~= -2 then
|
|
local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT)
|
|
if not AreSameOrOppositeVectorApprox( vtN, Z_AX()) 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
|
|
local nId = CreateToolRectangle( ptP1, ptP2, vtN, nOutlineGrp)
|
|
if nId ~= GDB_ID.NULL then table.insert(ToolOutlineId, nId) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- fori
|
|
if NEST.DRILL_MACH_AREA 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)
|
|
-- verifico se la lunghezza del foro è maggiore della lunghezza della punta
|
|
if bOpen and AreSameOrOppositeVectorApprox( vtExtr, Y_AX()) and dLen > WD.HOR_DRILL_LEN - 10 then
|
|
local ptP1 = Proc.Box:getMin()
|
|
local ptP2 = Proc.Box:getMax()
|
|
ptP1 = ptP1 - 2000 * Y_AX()
|
|
ptP2 = ptP2 + 2000 * Y_AX()
|
|
local nId = EgtRectangle2P( nOutlineGrp, Point3d(ptP2:getX(), ptP2:getY(), 0), Point3d( ptP1:getX(), ptP1:getY(), 0))
|
|
EgtSetColor( nId, EgtStdColor("RED"))
|
|
if nId ~= GDB_ID.NULL then table.insert(ToolOutlineId, nId) end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return ToolOutlineId
|
|
end
|
|
|
|
-- Funzione che sposta e aggiunge pezzi per nesting
|
|
local function AddRawParts(RawParts)
|
|
-- creo tabella dei grezzi
|
|
for nIndex, nLen in pairs( LEN) do
|
|
table.insert(RawParts, {Len = nLen})
|
|
end
|
|
for nIndex, nWidth in pairs( WIDTH) do
|
|
RawParts[tonumber(nIndex)].Width = nWidth
|
|
end
|
|
for nIndex, nQty in pairs( QTY) do
|
|
RawParts[tonumber(nIndex)].Qty = nQty
|
|
end
|
|
for nIndex, nMaterial in pairs( MATERIAL) do
|
|
RawParts[tonumber(nIndex)].Material = nMaterial
|
|
end
|
|
|
|
local OUTLINE = "Outline"
|
|
for nIndex = 1, #RawParts do
|
|
-- creo pannello del materiale
|
|
local SheetPartId = EgtGroup(GDB_ID.ROOT)
|
|
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, 0, RawParts[nIndex].Qty) -- EgtAutoNestAddSheet( SheetId, OutlineId, dKerf, nPriority, nCount)
|
|
end
|
|
end
|
|
|
|
local function AddParts(RawParts)
|
|
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
|
|
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')
|
|
nRotate = EgtGetInfo( nPartId, "NestRot", 'i')
|
|
bRotNest = EgtGetInfo( nPartId, "NestAllowRot", 'b')
|
|
-- verifico se rotazione è valida
|
|
local bValidRotation = b3Part:getDimX() < RawParts[1].Len and b3Part:getDimY() < RawParts[1].Width
|
|
if not bValidRotation then
|
|
bRotNest = true
|
|
nStepRotNest = 90
|
|
end
|
|
end
|
|
|
|
-- aggiungo stato a lista stati del pezzo
|
|
-- table.insert( PartStates, { PartId = tonumber(nPartId), Flip = bFlip, Rotate = nRotate})
|
|
|
|
|
|
-- local bFtDown = false
|
|
-- local vPartProc = WE.CollectFeatures( nPartId, b3Raw)
|
|
-- for nInd = 1, #vPartProc do
|
|
-- if LapJoint.Identify( vPartProc[nInd]) then
|
|
-- local nFacOpt, dMinElev, nFacOpt2, dMinElev2 = WL.GetFaceWithMostAdj( vPartProc[nInd].Id, vPartProc[nInd].PartId)
|
|
-- if nFacOpt >= 0 then
|
|
-- local vtN = EgtSurfTmFacetNormVersor( vPartProc[nInd].Id, nFacOpt, GDB_ID.ROOT)
|
|
-- if vtN:getZ() < -0.09 then
|
|
-- bFtDown = true
|
|
-- break
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- LapJoint.FlipClassify(vPartProc[nInd])
|
|
-- end
|
|
-- -- ruoto se necessario
|
|
-- if bFtDown then
|
|
-- local b3Solid = EgtGetBBoxGlob(nPartId, GDB_BB.IGNORE_TEXT)
|
|
-- local ptRotCen = b3Solid:getCenter()
|
|
-- EgtRotate( nPartId, ptRotCen, X_AX(), 180, GDB_RT.GLOB)
|
|
-- end
|
|
|
|
-- -- recupero le feature di lavorazione della parete
|
|
-- local bFtDown = false
|
|
-- local vPartProc = WE.CollectFeatures( nPartId, b3Raw)
|
|
-- for nInd = 1, #vPartProc do
|
|
-- if LapJoint.Identify( vPartProc[nInd]) then
|
|
-- local nFacOpt, dMinElev, nFacOpt2, dMinElev2 = WL.GetFaceWithMostAdj( vPartProc[nInd].Id, vPartProc[nInd].PartId)
|
|
-- if nFacOpt >= 0 then
|
|
-- local vtN = EgtSurfTmFacetNormVersor( vPartProc[nInd].Id, nFacOpt, GDB_ID.ROOT)
|
|
-- if vtN:getZ() < -0.09 then
|
|
-- bFtDown = true
|
|
-- break
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- -- ruoto se necessario
|
|
-- if bFtDown then
|
|
-- local b3Solid = EgtGetBBoxGlob(nPartId, GDB_BB.IGNORE_TEXT)
|
|
-- local ptRotCen = b3Solid:getCenter()
|
|
-- EgtRotate( nPartId, ptRotCen, X_AX(), 180, GDB_RT.GLOB)
|
|
-- 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 vCrvRef = EgtCurveArea( nOutline)
|
|
for nInd = 1, nCnt - 1 do
|
|
local vCrv = EgtCurveArea( nOutline + nInd)
|
|
-- se trovo più loop esterni uso come contorno quello del box (quindi forzo nCurrOutline a nil)
|
|
if abs( vCrv * vCrvRef - 1) < GEO.EPS_SMALL then
|
|
nCurrOutline = nil
|
|
for nInd2 = 0, nCnt - 1 do
|
|
EgtErase( nOutline + nInd2)
|
|
end
|
|
nCnt = 1
|
|
break
|
|
end
|
|
end
|
|
|
|
--local frSum = EgtSurfFlatRegion(nOutlineLayer, nOutline)
|
|
--EgtSaveFile("c:\\Temp\\ProvaNesting.nge")
|
|
-- -- per ogni contorno creo flat region e le sommo
|
|
-- for nIndex = 0, nCnt - 1 do
|
|
-- EgtScale( nOutline + nIndex, GLOB_FRM(), 1, 1, 0, GDB_RT.GLOB)
|
|
-- EgtModifyCurveExtrusion( nOutline + nIndex, Z_AX(), GDB_RT.GLOB)
|
|
-- local frCurr = EgtSurfFlatRegion(nOutlineLayer, nOutline + nIndex)
|
|
-- if frCurr then
|
|
-- if frSum then
|
|
-- EgtSurfFrAdd(frSum, frCurr)
|
|
-- else
|
|
-- frSum = frCurr
|
|
-- end
|
|
-- end
|
|
-- EgtErase(frCurr)
|
|
-- end
|
|
-- --EgtSaveFile("c:/Temp/ProvaNesting.nge")
|
|
-- -- calcolo contorno della flat region somma
|
|
-- nCurrOutline = EgtExtractSurfFrChunkLoops(frSum, 0, nOutlineLayer)
|
|
-- EgtErase(frSum)
|
|
-- -- cancello contorni
|
|
-- for nIndex = 0, nCnt do
|
|
-- EgtErase(nOutline + nIndex)
|
|
-- 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
|
|
--if nCnt == 0 then
|
|
-- -- 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))
|
|
--else
|
|
-- --EgtScale( nOutline, GLOB_FRM(), 1, 1, 0, GDB_RT.GLOB)
|
|
-- --EgtModifyCurveExtrusion( nOutline, Z_AX(), GDB_RT.GLOB)
|
|
-- --EgtSaveFile("c:/Temp/ProvaNesting.nge")
|
|
-- EgtScale( nOutline, GLOB_FRM(), 1, 1, 0, GDB_RT.GLOB)
|
|
-- EgtModifyCurveExtrusion( nOutline, Z_AX(), GDB_RT.GLOB)
|
|
-- local frSum = EgtSurfFlatRegion(nOutlineLayer, nOutline)
|
|
-- EgtSaveFile("c:\\Temp\\ProvaNesting.nge")
|
|
-- -- per ogni contorno creo flat region e le sommo
|
|
-- for nIndex = 1, nCnt - 1 do
|
|
-- EgtScale( nOutline + nIndex, GLOB_FRM(), 1, 1, 0, GDB_RT.GLOB)
|
|
-- EgtModifyCurveExtrusion( nOutline + nIndex, Z_AX(), GDB_RT.GLOB)
|
|
-- local frCurr = EgtSurfFlatRegion(nOutlineLayer, nOutline + nIndex)
|
|
-- if frCurr then
|
|
-- EgtSurfFrAdd(frSum, frCurr)
|
|
-- end
|
|
-- end
|
|
-- -- calcolo contorno della flat region somma
|
|
-- nOutline = EgtExtractSurfFrChunkLoops(frSum, 0, nOutlineLayer)
|
|
-- -- cancello contorni successivi
|
|
-- for nIndex = 1, nCnt do
|
|
-- EgtErase(nOutline + nIndex)
|
|
-- end
|
|
--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
|
|
|
|
|
|
--[[ local nOutline
|
|
local nTrimesh
|
|
local bFirst = true
|
|
local bSecond = false
|
|
local bUseBox = false
|
|
nTrimesh = EgtGetFirstNameInGroup( nOutlineLayer, "1-Out")
|
|
if not nTrimesh then
|
|
nTrimesh = EgtGetFirstNameInGroup( nOutlineLayer, "2-Out")
|
|
end
|
|
if not nTrimesh then
|
|
nTrimesh = EgtGetFirstNameInGroup( nOutlineLayer, "3-Out")
|
|
end
|
|
if not nTrimesh then
|
|
nTrimesh = EgtGetFirstNameInGroup( nOutlineLayer, "4-Out")
|
|
end
|
|
-- se trovato contorno
|
|
if nTrimesh then
|
|
-- recupero la curva associata
|
|
local nAuxId = EgtGetInfo(nTrimesh, "AUXID", 'i')
|
|
nOutline = nTrimesh + nAuxId
|
|
-- verifico che il contorno sia verticale
|
|
local nFacetCount = EgtSurfTmFacetCount(nTrimesh)
|
|
for nIndex = 0, nFacetCount - 1 do
|
|
local vtNorm = EgtSurfTmFacetNormVersor(nTrimesh, nIndex, GDB_ID.ROOT)
|
|
if abs( vtNorm:getZ()) > 10 * GEO.EPS_SMALL then
|
|
bUseBox = true
|
|
break
|
|
end
|
|
end
|
|
-- se due compo o una e lati inclinati
|
|
if bUseBox then
|
|
-- calcolo box della trimesh
|
|
local b3Outline = EgtGetBBoxGlob(nTrimesh, GDB_BB.IGNORE_TEXT)
|
|
local ptP1 = Point3d( b3Outline:getMin():getX(), b3Outline:getMin():getY(), 0)
|
|
local ptP2 = Point3d( b3Outline:getMax():getX(), b3Outline:getMax():getY(), 0)
|
|
-- creo outline del box
|
|
nOutline = EgtRectangle2P(nOutlineLayer, ptP1, ptP2, GDB_RT.GLOB)
|
|
EgtSetStatus(nOutline, GDB_ST.OFF)
|
|
end
|
|
-- altrimenti cerco la regione sopra
|
|
else
|
|
-- cancello precedenti contorni calcolati
|
|
local nOldONId = EgtGetFirstNameInGroup( nOutlineLayer, 'ON_TMP')
|
|
if nOldONId then
|
|
EgtErase( nOldONId)
|
|
end
|
|
-- cerco la regione sopra
|
|
local nReg
|
|
for i = 1, 4 do
|
|
local sRegName = string.format( '%d-Top', i)
|
|
nReg = EgtGetFirstNameInGroup( nOutlineLayer, sRegName)
|
|
if nReg then
|
|
local vtNorm = EgtSurfFrNormVersor( nReg, GDB_ID.ROOT)
|
|
if vtNorm:getZ() > 0.99 then break end
|
|
end
|
|
end
|
|
if not nReg then
|
|
EgtOutLog("Errore: regione superiore non trovata")
|
|
end
|
|
-- recupero contorno della regione
|
|
local OutId, nCnt = EgtExtractSurfFrChunkLoops( nReg, 0, nOutlineLayer)
|
|
if OutId and nCnt > 1 then
|
|
for i = 2, nCnt do
|
|
EgtErase( OutId + i - 1)
|
|
end
|
|
end
|
|
if OutId then
|
|
EgtSetName( OutId, 'ON_TMP')
|
|
nOutline = OutId
|
|
end
|
|
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 tmp1, tmp2, area = EgtCurveArea( nOutline + nInd)
|
|
if area > WD.NEST_HOLE_MIN_AREA then
|
|
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
|
|
|
|
-- verifico se anullato nesting
|
|
if EgtProcessEvents( 100 + ( nPartIndex / nTotParts * 100), 0) == 1 then
|
|
return false
|
|
end
|
|
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()
|
|
|
|
-- inizio nesting automatico
|
|
EgtAutoNestStart()
|
|
|
|
-- lista dei grezzi
|
|
local RawParts = {}
|
|
|
|
-- creo grezzi e li aggiungo al nesting
|
|
AddRawParts(RawParts)
|
|
|
|
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)
|
|
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)
|
|
|
|
-- 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
|
|
|
|
-- 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
|
|
if RawParts[nIndex].PartId == nId then
|
|
EgtSetInfo(nMachGroup, "PANELLEN", RawParts[nIndex].Len)
|
|
EgtSetInfo(nMachGroup, "PANELWIDTH", RawParts[nIndex].Width)
|
|
EgtSetInfo(nMachGroup, "MATERIAL", RawParts[nIndex].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
|
|
nPartCount = 0
|
|
-- 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)
|
|
-- applico flip e rotazioni fatte durante verifica posizionamento pezzo
|
|
local b3Part = EgtGetBBoxGlob( nPartDuploId, GDB_BB.STANDARD)
|
|
local nPartInd
|
|
-- for nInd = 1, #PartStates do
|
|
-- if PartStates[nInd].PartId == nId then
|
|
-- -- if PartStates[nInd].Flip then
|
|
-- -- EgtRotate( nPartDuploId, b3Part:getCenter(), X_AX(), 180, GDB_RT.GLOB)
|
|
-- -- end
|
|
-- -- if PartStates[nInd].Rotate and PartStates[nInd].Rotate > 0 then
|
|
-- -- EgtRotate( nPartDuploId, b3Part:getCenter(), Z_AX(), PartStates[nInd].Rotate, GDB_RT.GLOB)
|
|
-- -- end
|
|
-- nPartInd = nInd
|
|
-- end
|
|
-- end
|
|
|
|
local PartBBox = EgtGetBBoxGlob( nPartDuploId, GDB_BB.STANDARD)
|
|
|
|
-- 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.OFF)
|
|
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)
|
|
PartBBox:rotate( ORIG(), X_AX(), 180)
|
|
end
|
|
EgtRotate( nPartDuploId, ORIG(), Z_AX(), dAngRot, GDB_RT.GLOB)
|
|
PartBBox:rotate( ORIG(), Z_AX(), dAngRot)
|
|
EgtMove( nPartDuploId, Vector3d( dX, dY, 0), GDB_RT.GLOB)
|
|
PartBBox:move( Vector3d( dX, dY, 0))
|
|
local ptPos = Point3d( PartBBox:getMin():getX(), PartBBox:getMin():getY(), 0)
|
|
EgtSetInfo( nMachGroup, "PART" .. nPartCount, nPartDuploId .. "," .. EgtNumToString( ptPos:getX(), 3) .. "," .. EgtNumToString( ptPos:getY(), 3) .. "," .. 0 .."," .. 0)
|
|
EgtSetInfo( nPartDuploId, "POSX", ptPos:getX())
|
|
EgtSetInfo( nPartDuploId, "POSY", ptPos:getY())
|
|
|
|
local nPartRot = EgtGetInfo( nId, "ROTATED", 'i') or 0
|
|
local nTotRot = dAngRot + nPartRot
|
|
nTotRot = EgtIf( nTotRot < 360, nTotRot, nTotRot - 360)
|
|
EgtSetInfo( nPartDuploId, "ROT", nTotRot)
|
|
|
|
local nPartFlip = EgtGetInfo( nId, "INVERTED", 'i')
|
|
nPartFlip = EgtIf( nPartFlip == 180, 1, 0)
|
|
local nTotFlip = nPartFlip ~ nFlag
|
|
EgtSetInfo( nPartDuploId, "FLIP", nTotFlip)
|
|
|
|
end
|
|
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.FLAG = 6 -- CREATE_PANEL
|
|
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( EgtGetSourceDir() .. "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( -WD.INSIDE_RAW_TOL)
|
|
EgtOutLog( 'RawBox='..tostring( b3Raw))
|
|
local nPartDuploId = EgtGetFirstPartInRawPart( nRawPartId)
|
|
while nPartDuploId do
|
|
-- creo lista associazioni feature con tooloutline
|
|
local ToolOutlinesList = {}
|
|
local nToolOutlinesGrp = EgtGetFirstNameInGroup( nPartDuploId, "ToolOutlines")
|
|
if nToolOutlinesGrp and nToolOutlinesGrp ~= GDB_ID.NULL then
|
|
local nToolOutlineId = EgtGetFirstInGroup( nToolOutlinesGrp)
|
|
while nToolOutlineId and nToolOutlineId ~= GDB_ID.NULL do
|
|
-- recupero Id della feature dall'area di lavorazione
|
|
local nProcId = EgtGetInfo( nToolOutlineId, "PRID", 'i')
|
|
if nProcId and nFeatureId ~= GDB_ID.NULL then
|
|
table.insert( ToolOutlinesList, { ToolOutlineId = nToolOutlineId, ProcId = nProcId})
|
|
end
|
|
nToolOutlineId = EgtGetNext( nToolOutlineId)
|
|
end
|
|
end
|
|
-- ciclo su feature per associare Id geometrico a PRID
|
|
local vPartProc = WE.CollectFeatures( nPartDuploId)
|
|
for ProcIndex=1, #vPartProc do
|
|
local nFeatureId = vPartProc[ProcIndex].Id
|
|
-- recupero ProcId della feature
|
|
local nFeatureProcId = EgtGetInfo( nFeatureId, "PRID", 'i')
|
|
-- ciclo su lista
|
|
for i = 1, #ToolOutlinesList do
|
|
-- verifico se hanno lo stesso ProcId
|
|
if ToolOutlinesList[i].ProcId == nFeatureProcId then
|
|
ToolOutlinesList[i].FeatureId = nFeatureId
|
|
ToolOutlinesList[i].PartProc = vPartProc[ProcIndex]
|
|
end
|
|
end
|
|
end
|
|
-- ciclo su lista associazioni
|
|
for i = 1, #ToolOutlinesList do
|
|
-- verifico tipo feature
|
|
if LapJoint.Identify( ToolOutlinesList[i].PartProc) then
|
|
local b3ToolOutline = EgtGetBBoxGlob( ToolOutlinesList[i].ToolOutlineId, GDB_BB.STANDARD)
|
|
EgtOutLog( 'ToolOutlineBox='..tostring( b3ToolOutline))
|
|
-- se all'interno rimuovo info Q
|
|
if EnclosesXY( b3Raw, b3ToolOutline) then
|
|
-- resetto parametro Q
|
|
if ToolOutlinesList[i].PartProc.Prc == 30 then
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q08")
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q08A")
|
|
else
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q03")
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q03A")
|
|
end
|
|
end
|
|
elseif DoubleCut.Identify( ToolOutlinesList[i].PartProc) then
|
|
local b3ToolOutline = EgtGetBBoxGlob( ToolOutlinesList[i].ToolOutlineId, GDB_BB.STANDARD)
|
|
EgtOutLog( 'ToolOutlineBox='..tostring( b3ToolOutline))
|
|
-- se all'interno rimuovo info Q
|
|
if EnclosesXY( b3Raw, b3ToolOutline) then
|
|
-- resetto parametro Q
|
|
if ToolOutlinesList[i].PartProc.Prc == 12 then
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q02")
|
|
EgtRemoveInfo( ToolOutlinesList[i].PartProc.Id, "Q02A")
|
|
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
|
|
|
|
EgtOutLog( ' +++ NestProcess completed')
|