-- NestFlipAndRotate.lua by Egaltech s.r.l. 2022/05/09 -- Flip e rotazione ottimali per il nesting in base all'analisi delle features -- Intestazioni require( 'EgtBase') _ENV = EgtProtectGlobal() EgtEnableDebug( false) -- NFAR.PARTID = NFAR.RAW_GRAIN_DIR_X = true local sLog = 'Flip And Rotate Part ' .. tostring( NFAR.PARTID) EgtOutLog( sLog) -- Imposto direttorio libreria specializzata per Travi EgtAddToPackagePath( NFAR.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 NFAR.ERR = 12 NFAR.MSG = 'Error not configured for walls machine : ' .. sMachine WriteErrToLogFile( NFAR.ERR, NFAR.MSG) PostErrView( NFAR.ERR, NFAR.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.WProcessLapJoint = nil local LapJoint = require( 'WProcessLapJoint') _G.package.loaded.WProcessDrill = nil local Drill = require( 'WProcessDrill') _G.package.loaded.WProcessCut = nil local Cut = require( 'WProcessCut') _G.package.loaded.WProcessDoubleCut = nil local DoubleCut = require( 'WProcessDoubleCut') _G.package.loaded.WProcessSawCut = nil local SawCut = require( 'WProcessSawCut') _G.package.loaded.WProcessFreeContour = nil local FreeContour = require( 'WProcessFreeContour') _G.package.loaded.WProcessMortise = nil local Mortise = require( 'WProcessMortise') _G.package.loaded.WProcessDtMortise = nil local DtMortise = require( 'WProcessDtMortise') _G.package.loaded.WProcessMark = nil local Mark = require( 'WProcessMark') _G.package.loaded.WProcessText = nil local Text = require( 'WProcessText') -- Carico i dati globali local WD = require( 'WallData') ------------------------------------------------------------------- local function ClassifyFlip( vPartProc, b3Part) local FlipFeatureStates = {} local bLapJoints = false for nInd = 1, #vPartProc do if LapJoint.Identify( vPartProc[nInd]) then -- setto parametro Q if vPartProc[nInd].Prc == 30 then EgtSetInfo( vPartProc[nInd].Id, "Q08", 1) EgtSetInfo( vPartProc[nInd].Id, "Q08A", 1) else EgtSetInfo( vPartProc[nInd].Id, "Q03", 1) EgtSetInfo( vPartProc[nInd].Id, "Q03A", 1) end bLapJoints = true local nFlip0, nFlip1 = LapJoint.FlipClassify(vPartProc[nInd]) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif Drill.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = Drill.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif Cut.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = Cut.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif DoubleCut.Identify( vPartProc[nInd]) then -- setto parametro Q if vPartProc[nInd].Prc == 12 then EgtSetInfo( vPartProc[nInd].Id, "Q02", 1) EgtSetInfo( vPartProc[nInd].Id, "Q02A", 1) end local nFlip0, nFlip1 = DoubleCut.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif SawCut.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = SawCut.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif FreeContour.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = FreeContour.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif Mortise.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = Mortise.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif DtMortise.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = DtMortise.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif Mark.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = Mark.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end elseif Text.Identify( vPartProc[nInd]) then local nFlip0, nFlip1 = Text.FlipClassify(vPartProc[nInd], b3Part) if nFlip0 and nFlip1 and nFlip0 ~= nFlip1 then table.insert( FlipFeatureStates, { Flip0 = nFlip0, Flip1 = nFlip1}) end end end return FlipFeatureStates, bLapJoints end ------------------------------------------------------------------- local function ClassifyRotation( vPartProc) local RotateFeatureStates = {} for nInd = 1, #vPartProc do if Drill.Identify( vPartProc[nInd]) then local nRot0, nRot90, nRot180, nRot270 = Drill.RotateClassify(vPartProc[nInd], ValidRotations) if nRot0 and nRot0 >= 0 then table.insert( RotateFeatureStates, { Rot0 = nRot0, Rot90 = nRot90, Rot180 = nRot180, Rot270 = nRot270}) end end end return RotateFeatureStates end ------------------------------------------------------------------- ------------------------------------------------------------------- local vPartProc = WE.CollectFeatures( NFAR.PARTID) local b3Part = EgtGetBBoxGlob( NFAR.PARTID, GDB_BB.STANDARD) local bManualFlip = EgtGetInfo( NFAR.PARTID, "MANUALFLIP", 'b') local bManualRot = EgtGetInfo( NFAR.PARTID, "MANUALROT", 'b') -- FLIP local FlipFeatureStates, bLapJoints = ClassifyFlip( vPartProc, b3Part) local bFlip if not bManualFlip then -- analizzo stati flip delle feature local nFlip0Min = 100 local nFlip0Cnt = 0 local nFlip1Min = 100 local nFlip1Cnt = 0 -- calcolo punteggio minimo e sua molteplicita' per entrambi i lati for nInd = 1, #FlipFeatureStates do if FlipFeatureStates[nInd].Flip0 < nFlip0Min then nFlip0Min = FlipFeatureStates[nInd].Flip0 nFlip0Cnt = 1 elseif FlipFeatureStates[nInd].Flip0 == nFlip0Min then nFlip0Cnt = nFlip0Cnt + 1 end if FlipFeatureStates[nInd].Flip1 < nFlip1Min then nFlip1Min = FlipFeatureStates[nInd].Flip1 nFlip1Cnt = 1 elseif FlipFeatureStates[nInd].Flip1 == nFlip1Min then nFlip1Cnt = nFlip1Cnt + 1 end end -- calcolo lato con punteggio minore o molteplicita' piu' alta if nFlip0Min == nFlip1Min then if nFlip0Cnt > nFlip1Cnt then bFlip = true elseif nFlip0Cnt < nFlip1Cnt then bFlip = false elseif bLapJoints then -- se equivalenti ma ci sono lap joints, fisso il flip per non avere problemi con le aree di lavorazione nel nesting bFlip = false end elseif nFlip0Min < nFlip1Min then bFlip = true else bFlip = false end if bFlip ~= nil then -- se una posizione è più conveniente dell'altra setto info nel pezzo EgtSetInfo( NFAR.PARTID, "NestAllowFlip", false) EgtSetInfo( NFAR.PARTID, "NestFlip", bFlip) else EgtSetInfo( NFAR.PARTID, "NestAllowFlip", true) end if bFlip then -- flip pezzo EgtRotate( NFAR.PARTID, b3Part:getCenter(), X_AX(), 180, GDB_RT.GLOB) -- modifico le info del pezzo local nPartFlip = EgtGetInfo( NFAR.PARTID, "INVERTED", 'i') or 0 local nTotFlip = EgtIf( nPartFlip == 180, 0, 180) EgtSetInfo( NFAR.PARTID, "INVERTED", nTotFlip) EgtSetInfo( NFAR.PARTID, "FLIPROTMODIFIED", 1) end end -- rimuovo parametri Q local b3PartInside = BBox3d( b3Part) b3PartInside:expand( - ( WD.INSIDE_RAW_TOL or 30)) for nInd = 1, #vPartProc do local Proc = vPartProc[nInd] 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 ptCen = EgtSurfTmFacetCenter( Proc.Id, nFaceInd, GDB_ID.ROOT) -- se all'interno rimuovo info Q if EnclosesPointXY( b3PartInside, ptCen) 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( b3PartInside, ptCen) then -- resetto parametro Q if Proc.Prc == 12 then EgtRemoveInfo( Proc.Id, "Q02") EgtRemoveInfo( Proc.Id, "Q02A") end end end end end end -- ROTATION nRotate = 0 -- venatura EgtRemoveInfo( NFAR.PARTID, "HasGrainDirection") local bGrain = false local sGrainInfo = EgtGetInfo( NFAR.PARTID, "GRAINDIRECTION", 's') if sGrainInfo then local sGrainAlign = string.sub( sGrainInfo, 7) local sGrainDir = string.sub( sGrainInfo, 1, 5) if sGrainAlign == "1" and ( sGrainDir == "1,0,0" or sGrainDir == "0,1,0") then EgtSetInfo( NFAR.PARTID, "HasGrainDirection", 1) bGrain = true -- trovo la rotazione ( a meno di 180°) che deve avere il pezzo per essere allineato con la venatura del grezzo local nGrainRot = 0 if ( sGrainDir == "1,0,0" and not NFAR.RAW_GRAIN_DIR_X) or ( sGrainDir == "0,1,0" and NFAR.RAW_GRAIN_DIR_X) then nGrainRot = 90 end local nPartRot = EgtGetInfo( NFAR.PARTID, "ROTATED", 'i') or 0 if ( nGrainRot == 0 and ( nPartRot == 90 or nPartRot == 270)) or ( nGrainRot == 90 and ( nPartRot == 0 or nPartRot == 180)) then local b3Part = EgtGetBBoxGlob( NFAR.PARTID, GDB_BB.STANDARD) EgtRotate( NFAR.PARTID, b3Part:getCenter(), Z_AX(), 90, GDB_RT.GLOB) nRotate = 90 end end end if not bManualRot then local RotateFeatureStates = ClassifyRotation( vPartProc) -- analizzo stati rotazione delle feature local nRot0Min = 100 local nRot0Cnt = 0 local nRot90Min = 100 local nRot90Cnt = 0 local nRot180Min = 100 local nRot180Cnt = 0 local nRot270Min = 100 local nRot270Cnt = 0 -- calcolo punteggio minimo e sua molteplicita' per tutte le rotazioni for nInd = 1, #RotateFeatureStates do if RotateFeatureStates[nInd].Rot0 < nRot0Min then nRot0Min = RotateFeatureStates[nInd].Rot0 nRot0Cnt = 1 elseif RotateFeatureStates[nInd].Rot0 == nRot0Min then nRot0Cnt = nRot0Cnt + 1 end if RotateFeatureStates[nInd].Rot90 < nRot90Min then nRot90Min = RotateFeatureStates[nInd].Rot90 nRot90Cnt = 1 elseif RotateFeatureStates[nInd].Rot90 == nRot90Min then nRot90Cnt = nRot90Cnt + 1 end if RotateFeatureStates[nInd].Rot180 < nRot180Min then nRot180Min = RotateFeatureStates[nInd].Rot180 nRot180Cnt = 1 elseif RotateFeatureStates[nInd].Rot180 == nRot180Min then nRot180Cnt = nRot180Cnt + 1 end if RotateFeatureStates[nInd].Rot270 < nRot270Min then nRot270Min = RotateFeatureStates[nInd].Rot270 nRot270Cnt = 1 elseif RotateFeatureStates[nInd].Rot270 == nRot270Min then nRot270Cnt = nRot270Cnt + 1 end end -- se c'e' qualche stato di rotazione local MinList = { { Rot = 0, Score = nRot0Min, ScoreCnt = nRot0Cnt}, { Rot = 90, Score = nRot90Min, ScoreCnt = nRot90Cnt}, { Rot = 180, Score = nRot180Min, ScoreCnt = nRot180Cnt}, { Rot = 270, Score = nRot270Min, ScoreCnt = nRot270Cnt}} local nRotateOpt = 0 if #RotateFeatureStates > 0 then -- calcolo lato con punteggio minore o molteplicita' piu' alta local nRotMax = MinList[1].Rot local nScoreMax = MinList[1].Score local nScoreCnt = MinList[1].ScoreCnt for nInd = 2, #MinList do if MinList[nInd].Score > nScoreMax then nRotMax = MinList[nInd].Rot nScoreMax = MinList[nInd].Score nScoreCnt = MinList[nInd].ScoreCnt elseif MinList[nInd].Score == nScoreMax then -- se punteggio > 0 conservo quello con molteplicità più alta, se punteggio = 0 conservo quello con molteplicità più bassa if ( nScoreMax ~= 0 and MinList[nInd].ScoreCnt > nScoreCnt) or ( nScoreMax == 0 and MinList[nInd].ScoreCnt < nScoreCnt) then nRotMax = MinList[nInd].Rot nScoreMax = MinList[nInd].Score nScoreCnt = MinList[nInd].ScoreCnt end end end nRotateOpt = nRotMax else nRotateOpt = 0 end local bRotNest = false local nStepRotNest = 0 -- se calcolate limitazioni su rotazioni if MinList and #MinList > 0 then -- verifico condizioni da permettere al nesting if MinList[1].Score >= 50 and MinList[2].Score >= 50 and MinList[3].Score >= 50 and MinList[4].Score >= 50 then bRotNest = true nStepRotNest = 90 elseif (nRotateOpt == 0 and MinList[3].Score >= 50) or ( nRotateOpt == 90 and MinList[4].Score >= 50) then bRotNest = true nStepRotNest = 180 end else -- altrimenti permetto tutto bRotNest = true nStepRotNest = 90 end -- verifico se ci sono fori lungo Y che bloccano la rotazione local bDrillOnY = ( nStepRotNest == 180) local b3Part = EgtGetBBoxGlob( NFAR.PARTID, GDB_BB.STANDARD) if bGrain then -- se venatura eseguo rotazione solo se è di 180° if nRotateOpt == 180 then EgtRotate( NFAR.PARTID, b3Part:getCenter(), Z_AX(), nRotateOpt, GDB_RT.GLOB) nRotate = nRotate + nRotateOpt end nStepRotNest = 180 else -- eseguo rotazione EgtRotate( NFAR.PARTID, b3Part:getCenter(), Z_AX(), nRotateOpt, GDB_RT.GLOB) nRotate = nRotate + nRotateOpt end -- verifico se rotazione è valida ( pezzo contenuto nel grezzo) solo se no venatura if not bGrain then b3Part = EgtGetBBoxGlob( NFAR.PARTID, GDB_BB.STANDARD) local bValidRotationForRaw = b3Part:getDimX() < WD.MAX_LENGTH and b3Part:getDimY() < WD.MAX_WIDTH local bRotatedIsValid = b3Part:getDimY() < WD.MAX_LENGTH and b3Part:getDimX() < WD.MAX_WIDTH if not bValidRotationForRaw and bRotatedIsValid then EgtRotate( NFAR.PARTID, b3Part:getCenter(), Z_AX(), 90, GDB_RT.GLOB) nRotate = nRotate + 90 nStepRotNest = 180 end end -- se no venatura e non ci sono fori verifico se il pezzo cade if not bGrain and not bDrillOnY then b3Part = EgtGetBBoxGlob( NFAR.PARTID, GDB_BB.STANDARD) local bValidRotation = b3Part:getDimX() > ( WD.INTRULLI or 1200) -- verifico se ruotata resta valida local bRotatedIsValid = b3Part:getDimY() > ( WD.INTRULLI or 1200) -- se non è valida ma ruotato lo sarebbe, ruoto if not bValidRotation and bRotatedIsValid and nStepRotNest ~= 180 then EgtRotate( NFAR.PARTID, b3Part:getCenter(), Z_AX(), 90, GDB_RT.GLOB) nRotate = nRotate + 90 nStepRotNest = 180 elseif bValidRotation and not bRotatedIsValid then -- se fosse valida ma la sua ruotata no, allora blocco lo step nella rotazione del nesting nStepRotNest = 180 end end -- setto info nel pezzo if nRotate > 0 then local nPartRot = EgtGetInfo( NFAR.PARTID, "ROTATED", 'i') or 0 local nTotRot = nPartRot - EgtIf( bFlip, -nRotate, nRotate) nTotRot = EgtIf( nTotRot < 0, nTotRot + 360, nTotRot) EgtSetInfo( NFAR.PARTID, "ROTATED", nTotRot) EgtSetInfo( NFAR.PARTID, "FLIPROTMODIFIED", 1) end EgtSetInfo( NFAR.PARTID, "NestStepRot", nStepRotNest) EgtSetInfo( NFAR.PARTID, "NestRot", nRotate) EgtSetInfo( NFAR.PARTID, "NestAllowRot", bRotNest) end NFAR.ERR = 0