-- BeamExec.lua by Egaltech s.r.l. 2021/12/20 -- Libreria esecuzione lavorazioni per Travi -- 2019/07/11 Aggiunta gestione stato rotazione di feature per TS3. -- 2019/09/04 Corretto controllo feature di testa e coda con sovramateriale di testa elevato. -- 2019/09/25 Aggiunta gestione StepJoint e StepJointNotch. -- 2020/01/21 Aggiunta gestione ScarfJoint. -- 2020/02/10 Aggiunta gestione FrenchRidgeLap. -- 2020/02/11 Aggiunta gestione BlockHausFront. -- 2020/04/02 Fori di testa dal basso non danno errore e fanno ribaltare la trave. -- 2020/04/07 Aggiunta gestione TyroleanDovetail. -- 2020/04/14 Aggiunta gestione Dovetail. -- 2020/05/16 Migliorie ordinamento fori. -- 2020/05/16 Gestione rotazione di 90deg. -- 2020/05/21 Correzione rotazione di 90deg (caso DY > DZ). -- 2020/05/25 Correzione rotazione di 90deg dopo scarico su carico. -- 2020/06/02 Per dati foro si chiama funzione GetData di ProcessDrill (per gestire variazioni di diametro da UserParams). -- 2020/07/25 Ricalcolati flag head e tail della prima parte del foro dopo lo split. -- 2020/07/27 Modifica a ordinamento fori. -- 2020/10/07 Aggiunta distanza libera dietro il pezzo (BDST) scritta nel suo grezzo. -- 2020/10/15 Per foro sdoppiato ricalcolo anche flag Head oltre a Tail . -- 2020/10/23 Corretto spostamento foro per tenone quando tenone nullo. -- 2020/12/29 Aggiunta gestione fori in doppio. -- 2021/02/25 Aggiunta gestione eventuale ricalcolo per macchine tipo PF. -- 2021/07/13 Aggiunta gestione posizionamento pezzo TR/BR per macchine con carico a destra e scarico a sinistra. -- 2021/11/27 House mortise sempre prima di (dt)mortise, house tenon sempre dopo (dt)tenon. -- 2021/12/15 Corretta CompareFeature (risultato deve essere simmetrico scambiando le feature). -- 2021/12/20 Ulteriore correzione a CompareFeature (caso con entrambe senza geometria). -- Tabella per definizione modulo local BeamExec = {} -- Include require( 'EgtBase') -- Carico i dati globali e libero tutti gli altri _G.package.loaded.BeamData = nil _G.package.loaded.CutData = nil _G.package.loaded.MillingData = nil _G.package.loaded.PocketingData = nil _G.package.loaded.DrillData = nil _G.package.loaded.SawingData = nil local BD = require( 'BeamData') -- Carico le librerie _G.package.loaded.MachiningLib = nil _G.package.loaded.BeamLib = nil _G.package.loaded.DiceCut = nil _G.package.loaded.FacesBySaw = nil _G.package.loaded.ProcessHeadCut = nil _G.package.loaded.ProcessSplit = nil _G.package.loaded.ProcessCut = nil _G.package.loaded.ProcessDoubleCut = nil _G.package.loaded.ProcessLongCut = nil _G.package.loaded.ProcessLongDoubleCut = nil _G.package.loaded.ProcessSawCut = nil _G.package.loaded.ProcessRidgeLap = nil _G.package.loaded.ProcessLapJoint = nil _G.package.loaded.ProcessChamfer = nil _G.package.loaded.ProcessDrill = nil _G.package.loaded.ProcessFrenchRidgeLap = nil _G.package.loaded.ProcessBlockHausFront = nil _G.package.loaded.ProcessTenon = nil _G.package.loaded.ProcessMortise = nil _G.package.loaded.ProcessDtTenon = nil _G.package.loaded.ProcessDtMortise = nil _G.package.loaded.ProcessMark = nil _G.package.loaded.ProcessText = nil _G.package.loaded.ProcessScarfJoint = nil _G.package.loaded.ProcessSimpleScarf = nil _G.package.loaded.ProcessStepJoint = nil _G.package.loaded.ProcessStepJointNotch = nil _G.package.loaded.ProcessProfFront = nil _G.package.loaded.ProcessProfConcave = nil _G.package.loaded.ProcessProfConvex = nil _G.package.loaded.ProcessProfCamb = nil _G.package.loaded.ProcessProfHead = nil _G.package.loaded.ProcessRoundArch = nil _G.package.loaded.ProcessTyroleanDovetail = nil _G.package.loaded.ProcessDovetail = nil _G.package.loaded.ProcessFreeContour = nil _G.package.loaded.ProcessDecor = nil local BM = require( 'MachiningLib') local BL = require( 'BeamLib') local DC = require( 'DiceCut') local Fbs = require( 'FacesBySaw') local Hcut= require( 'ProcessHeadCut') local Split = require( 'ProcessSplit') local Cut = require( 'ProcessCut') local DoubleCut = require( 'ProcessDoubleCut') local LongCut = require( 'ProcessLongCut') local Long2Cut = require( 'ProcessLongDoubleCut') local SawCut = require( 'ProcessSawCut') local RidgeLap = require( 'ProcessRidgeLap') local LapJoint = require( 'ProcessLapJoint') local Chamfer = require( 'ProcessChamfer') local Drill = require( 'ProcessDrill') local FrenchRidgeLap = require( 'ProcessFrenchRidgeLap') local BlockHausFront = require( 'ProcessBlockHausFront') local Tenon = require( 'ProcessTenon') local Mortise = require( 'ProcessMortise') local DtTenon = require( 'ProcessDtTenon') local DtMortise = require( 'ProcessDtMortise') local Mark = require( 'ProcessMark') local Text = require( 'ProcessText') local ScarfJoint = require( 'ProcessScarfJoint') local Scarf = require( 'ProcessSimpleScarf') local StepJoint = require( 'ProcessStepJoint') local StJoNotch = require( 'ProcessStepJointNotch') local ProfFront = require( 'ProcessProfFront') local ProfConcave = require( 'ProcessProfConcave') local ProfConvex = require( 'ProcessProfConvex') local ProfCamb = require( 'ProcessProfCamb') local ProfHead = require( 'ProcessProfHead') local RoundArch = require( 'ProcessRoundArch') local TyroleanDovetail = require( 'ProcessTyroleanDovetail') local Dovetail = require( 'ProcessDovetail') local FreeContour = require( 'ProcessFreeContour') local Decor = require( 'ProcessDecor') EgtOutLog( ' BeamExec started', 1) EgtMdbSetGeneralParam( MCH_GP.MAXDEPTHSAFE, BD.COLL_SIC) EgtMdbSave() ------------------------------------------------------------------------------------------------------------- -- *** Inserimento delle travi nel grezzo *** ------------------------------------------------------------------------------------------------------------- function BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, vBeam, bMachGroupOk) -- Determinazione minimo grezzo scaricabile BeamExec.CalcMinUnloadableRaw( dRawW, dRawH) -- Creazione nuovo gruppo di lavoro if not bMachGroupOk then local sMgName = EgtGetMachGroupNewName( 'Mach_1') local NewMgId = EgtAddMachGroup( sMgName) if not NewMgId then local sOut = 'Errore nella creazione del gruppo di lavoro ' .. sMgName return false, sOut end end -- Impostazione della tavola EgtSetTable( 'Tab') -- Area tavola local b3Tab = EgtGetTableArea() -- Calcolo posizione estremo TR/BR della tavola rispetto a sua origine in BL BD.OriXR = Point3d( b3Tab:getDimX(), EgtIf( BD.RIGHT_LOAD, 0, b3Tab:getDimY()), 0) BD.PosXR = EgtIf( BD.RIGHT_LOAD, MCH_CR.BR, MCH_CR.TR) -- Impostazione dell'attrezzaggio di default EgtImportSetup() -- Inserimento dei pezzi con il loro grezzo local Cnt = 0 local Len = dRawL local nPrevRaw, dPrevDelta local DeltaS = dOvmHead local DeltaE = BD.OVM_MID for i = 1, #vBeam do -- assegno identificativo pezzo local Pz = vBeam[i].Id -- dati del pezzo local b3Part = EgtGetBBoxGlob( Pz or GDB_ID.NULL, GDB_BB.EXACT) local b3Solid = vBeam[i].Box if b3Part:isEmpty() or b3Solid:isEmpty() then break end EgtOutLog( 'PartSez=' .. EgtNumToString( b3Part:getDimY(), 1) .. 'x' .. EgtNumToString( b3Part:getDimZ(), 1), 3) -- se sezione compatibile e lunghezza disponibile sufficiente local PartLen = b3Solid:getDimX() local PartWidth = b3Solid:getDimY() local PartHeight = b3Solid:getDimZ() local NextLen = Len - DeltaS - PartLen - DeltaE if (( abs( PartWidth - dRawW) < 10 * GEO.EPS_SMALL and abs( PartHeight - dRawH) < 10 * GEO.EPS_SMALL) or ( abs( PartHeight - dRawW) < 10 * GEO.EPS_SMALL and abs( PartWidth - dRawH) < 10 * GEO.EPS_SMALL)) and NextLen + DeltaE >= 0 then -- eventuale sovramateriale di testa if vBeam[i].PosX then DeltaS = max( vBeam[i].PosX - ( dRawL - Len), 0) end -- dimensioni del grezzo local CrawLen = min( PartLen + DeltaS + DeltaE, Len) local Delta = CrawLen - PartLen - DeltaS -- creo e posiziono il grezzo local nRaw = EgtAddRawPart( Point3d(0,0,0), CrawLen, dRawW, dRawH, BD.RAWCOL) EgtMoveToCornerRawPart( nRaw, BD.OriXR, BD.PosXR) EgtMoveRawPart( nRaw, Vector3d( Len - dRawL, 0, 0)) -- assegno ordine in lavorazione Cnt = Cnt + 1 EgtSetInfo( nRaw, 'ORD', Cnt) -- creo o pulisco gruppo geometrie aggiuntive if not BL.CreateOrEmptyAddGroup( Pz) then local sOut = 'Error creating Additional Group in Part ' .. tostring( Pz) return false, sOut end -- aggiungo faccia per taglio iniziale al pezzo BL.AddPartStartFace( Pz, b3Solid) -- se sovramateriale di testa, lo notifico if DeltaS > 0.09 then EgtSetInfo( nRaw, 'HOVM', DeltaS) if nPrevRaw then EgtSetInfo( nPrevRaw, 'BDST', DeltaS + dPrevDelta) end end -- aggiungo faccia per taglio finale al pezzo BL.AddPartEndFace( Pz, b3Solid) -- inserisco il pezzo nel grezzo EgtDeselectPartObjs( Pz) local ptPos = b3Part:getMin() - b3Solid:getMin() + Vector3d( Delta, ( dRawW - PartWidth) / 2, ( dRawH - PartHeight) / 2) EgtAddPartToRawPart( Pz, ptPos, nRaw) if abs( PartWidth - dRawW) > 10 * GEO.EPS_SMALL then -- rotazione attorno a centro geometria complessiva del pezzo EgtRotatePartInRawPart( Pz, X_AX(), 90) -- correggo per eccentricità solido rispetto a geometria complessiva del pezzo local vtEccOri = b3Solid:getCenter() - b3Part:getCenter() local vtEccRot = Vector3d( vtEccOri) vtEccRot:rotate( X_AX(), 90) EgtMovePartInRawPart( Pz, ( vtEccOri - vtEccRot)) end -- aggiorno la lunghezza residua della barra Len = Len - CrawLen -- aggiorno grezzo precedente nPrevRaw = nRaw dPrevDelta = Delta end -- se rimasto troppo poco grezzo, esco --if Len < BD.MinRaw then break end DeltaS = 0 end if nPrevRaw then EgtSetInfo( nPrevRaw, 'BDST', 10000) end -- Se rimasto materiale aggiungo grezzo dell'avanzo if Len > 10 then local nRaw = EgtAddRawPart( Point3d(0,0,0), Len, dRawW, dRawH, BD.RAWCOL) EgtMoveToCornerRawPart( nRaw, BD.OriXR, BD.PosXR) EgtMoveRawPart( nRaw, Vector3d( Len - dRawL, 0, 0)) -- assegno ordine in lavorazione Cnt = Cnt + 1 EgtSetInfo( nRaw, 'ORD', Cnt) end return true end ------------------------------------------------------------------------------------------------------------- function BeamExec.CalcMinUnloadableRaw( dRawW, dRawH) if BD.GetMinUnloadableRaw then BD.MinRaw = BD.GetMinUnloadableRaw( dRawW, dRawH) else local H_S = 200 local H_L = 400 -- Determinazione minimo grezzo scaricabile if dRawH <= H_S then BD.MinRaw = BD.MINRAW_S elseif dRawH <= H_L then local Coeff = ( dRawH - H_S) / ( H_L - H_S) BD.MinRaw = ( 1 - Coeff) * BD.MINRAW_S + Coeff * BD.MINRAW_L else BD.MinRaw = BD.MINRAW_L end end end ------------------------------------------------------------------------------------------------------------- -- *** Inserimento delle lavorazioni nelle travi *** ------------------------------------------------------------------------------------------------------------- local function Verify90DegRotation( nRawId) if not nRawId then return false end -- dimensioni sezione trave in posizione normale (rotazione 0°) local dRawW = EgtGetRawPartBBox( nRawId):getDimY() local dRawH = EgtGetRawPartBBox( nRawId):getDimZ() -- verifica dell'altezza rispetto alla massima larghezza return ( dRawH < BD.MAX_WIDTH + 10 * GEO.EPS_SMALL and dRawW < BD.MAX_HEIGHT + 10 * GEO.EPS_SMALL) or ( dRawH < BD.MAX_WIDTH2 + 10 * GEO.EPS_SMALL and dRawW < BD.MAX_HEIGHT2 + 10 * GEO.EPS_SMALL) end ------------------------------------------------------------------------------------------------------------- local function IsHeadFeature( Proc, b3Raw, dCurrOvmH) -- feature sempre di testa o coda per il gruppo if Proc.Grp == 1 or Proc.Grp == 2 then return ( Proc.Box:getCenter():getX() > b3Raw:getCenter():getX() - 0.5 * dCurrOvmH) end -- feature sempre di testa o coda nonostante il gruppo if ( Proc.Grp == 3 or Proc.Grp == 4) and ( Proc.Prc == 38 or Proc.Prc == 51 or Proc.Prc == 56 or Proc.Prc == 100 or Proc.Prc == 101 or Proc.Prc == 102 or Proc.Prc == 103 or Proc.Prc == 106) then return ( Proc.Box:getCenter():getX() > b3Raw:getCenter():getX() - 0.5 * dCurrOvmH) end -- gestioni speciali if LapJoint.Identify( Proc) then return LapJoint.IsHeadFeature( Proc, b3Raw, dCurrOvmH) end if Drill.Identify( Proc) then return Drill.IsHeadFeature( Proc, b3Raw, dCurrOvmH) end if RoundArch.Identify( Proc) then return RoundArch.IsHeadFeature( Proc, b3Raw, dCurrOvmH) end if Dovetail.Identify( Proc) then return Dovetail.IsHeadFeature( Proc, b3Raw, dCurrOvmH) end if FreeContour.Identify( Proc) then return FreeContour.IsHeadFeature( Proc, b3Raw, dCurrOvmH) end -- non è di testa return false end ------------------------------------------------------------------------------------------------------------- local function IsTailFeature( Proc, b3Raw, dCurrOvmH) -- feature sempre di testa o coda per il gruppo (se non troppo lunga) if Proc.Grp == 1 or Proc.Grp == 2 then return ( Proc.Box:getCenter():getX() < b3Raw:getCenter():getX() - 0.5 * dCurrOvmH and Proc.Box:getDimX() < BD.MAX_LEN_HTFEA) end -- feature sempre di testa o coda nonostante il gruppo if ( Proc.Grp == 3 or Proc.Grp == 4) and ( Proc.Prc == 38 or Proc.Prc == 51 or Proc.Prc == 56 or Proc.Prc == 100 or Proc.Prc == 101 or Proc.Prc == 102 or Proc.Prc == 103 or Proc.Prc == 106) then return ( Proc.Box:getCenter():getX() < b3Raw:getCenter():getX() - 0.5 * dCurrOvmH) end -- gestioni speciali if LapJoint.Identify( Proc) then return LapJoint.IsTailFeature( Proc, b3Raw) end if Drill.Identify( Proc) then return Drill.IsTailFeature( Proc, b3Raw) end if DtMortise.Identify( Proc) then return DtMortise.IsTailFeature( Proc, b3Raw) end if RoundArch.Identify( Proc) then return RoundArch.IsTailFeature( Proc, b3Raw) end if Dovetail.Identify( Proc) then return Dovetail.IsTailFeature( Proc, b3Raw) end if FreeContour.Identify( Proc) then return FreeContour.IsTailFeature( Proc, b3Raw) end -- non è di coda return false end ------------------------------------------------------------------------------------------------------------- local function PrintFeatures( vProc, b3Raw) EgtOutLog( ' RawBox=' .. tostring( b3Raw)) for i = 1, #vProc do local Proc = vProc[i] local sOut = string.format( ' Id=%3d Grp=%1d Prc=%3d TC=%2d/%d Flg=%2d Down=%s Side=%s Head=%s Tail=%s Fcse=%1d,%1d Diam=%.2f Fct=%2d Box=%s', Proc.Id, Proc.Grp, Proc.Prc, Proc.TaskId, Proc.CutId, Proc.Flg, EgtIf( Proc.Down, 'T', 'F'), EgtIf( Proc.Side, 'T', 'F'), EgtIf( Proc.Head, 'T', 'F'), EgtIf( Proc.Tail, 'T', 'F'), Proc.Fcs, Proc.Fce, Proc.Diam, Proc.Fct, tostring( Proc.Box)) -- info speciali per Block Haus Half Lap if Proc.Prc == 37 then local sSpec = string.format( ' N=%s Hd=%s', tostring( Proc.vtN or V_NULL()), EgtIf( Proc.HeadDir, 'T', 'F')) sOut = sOut .. sSpec end EgtOutLog( sOut) end end ------------------------------------------------------------------------------------------------------------- local function CollectFeatures( PartId, b3Raw, dCurrOvmH) -- recupero le feature local vProc = {} local LayerId = {} LayerId[1] = BL.GetAddGroup( PartId) LayerId[2] = EgtGetFirstNameInGroup( PartId or GDB_ID.NULL, 'Processings') for nInd = 1, 2 do local ProcId = EgtGetFirstInGroup( LayerId[nInd] or GDB_ID.NULL) while ProcId do local nEntType = EgtGetType( ProcId) if nEntType == GDB_TY.SRF_MESH or nEntType == GDB_TY.EXT_TEXT or nEntType == GDB_TY.CRV_LINE or nEntType == GDB_TY.CRV_ARC or nEntType == GDB_TY.CRV_BEZ or nEntType == GDB_TY.CRV_COMPO then local nGrp = EgtGetInfo( ProcId, 'GRP', 'i') local nPrc = EgtGetInfo( ProcId, 'PRC', 'i') local nDo = EgtGetInfo( ProcId, 'DO', 'i') or 1 local nCutId = EgtGetInfo( EgtGetParent( EgtGetParent( ProcId)), 'CUTID', 'i') or 0 local nTaskId = EgtGetInfo( ProcId, 'TASKID', 'i') or 0 if nGrp and nPrc and nDo == 1 then local Proc = {} Proc.Id = ProcId Proc.Grp = nGrp Proc.Prc = nPrc Proc.Flg = 1 Proc.Fct = EgtSurfTmFacetCount( ProcId) or 0 Proc.Diam = 0 Proc.Fcs = 0 Proc.Fce = 0 Proc.CutId = nCutId Proc.TaskId = nTaskId Proc.Box = EgtGetBBoxGlob( ProcId, GDB_BB.STANDARD) if Proc.Box and not Proc.Box:isEmpty() then Proc.Head = IsHeadFeature( Proc, b3Raw, dCurrOvmH) Proc.Tail = IsTailFeature( Proc, b3Raw, dCurrOvmH) table.insert( vProc, Proc) -- se foro if Drill.Identify( Proc) then -- assegno diametro e facce di ingresso e uscita (dati tabelle sempre per riferimento) Proc.Diam, Proc.Fcs, Proc.Fce = Drill.GetData( Proc, b3Raw) -- verifico se necessaria seconda lavorazione da parte opposta per foro più lungo della punta if Drill.Split( Proc, b3Raw) then -- aggiorno flags prima parte foro (dati tabelle sempre per riferimento) Proc.Flg = 2 Proc.Head = IsHeadFeature( Proc, b3Raw, dCurrOvmH) Proc.Tail = IsTailFeature( Proc, b3Raw, dCurrOvmH) -- definisco dati seconda parte local Proc2 = {} Proc2.Id = ProcId Proc2.Grp = nGrp Proc2.Prc = nPrc Proc2.Flg = -2 Proc2.Box = BBox3d( Proc.Box) Proc2.Fct = Proc.Fct Proc2.Diam = Proc.Diam Proc2.Head = Drill.IsHeadFeature( Proc2, b3Raw, dCurrOvmH) Proc2.Tail = Drill.IsTailFeature( Proc2, b3Raw) Proc2.Fcs = Proc.Fce Proc2.Fce = Proc.Fcs Proc2.CutId = Proc.CutId Proc2.TaskId = Proc.TaskId table.insert( vProc, Proc2) end -- se BlockHaus HalfLap elseif Proc.Prc == 37 then local nFacInd = BL.GetFaceWithMostAdj( Proc.Id, PartId) if nFacInd then local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) if vtN then Proc.vtN = Vector3d( vtN) end end end else Proc.Head = false Proc.Tail = false Proc.Flg = 0 table.insert( vProc, Proc) EgtOutLog( ' Feature ' .. tostring( Proc.Id) .. ' is empty (no geometry)') end end end ProcId = EgtGetNext( ProcId) end end return vProc end ------------------------------------------------------------------------------------------------------------- local function OrderFeatures( vProc, b3Raw) local dDrillPenalty = EgtIf( BD.PRESS_ROLLER, 200, 100) local dSmallDrillRange = EgtIf( b3Raw:getDimX() < BD.LEN_SHORT_PART, 200, 600) -- funzione di confronto -- secondo centro box in X (taglio di intestazione prima di altri tagli di testa e taglio di separazione però prima di altri tagli di coda) local function CompareFeatures( B1, B2) -- se primo disabilitato e secondo no va dopo if B1.Flg == 0 and B2.Flg ~= 0 then return false end -- se secondo disabilitato e primo no va lasciato dopo if B2.Flg == 0 and B1.Flg ~= 0 then return true end -- se entrambi disabilitati seguo l'Id if B1.Flg == 0 and B2.Flg == 0 then return ( B1.Id < B2.Id) end -- se primo è intestazione va sempre prima if Hcut.Identify( B1) then return true end -- se l'altro è intestazione va sempre prima if Hcut.Identify( B2) then return false end -- se uno di testa e non l'altro, privilegio quello di testa if B1.Head ~= B2.Head then return B1.Head end -- se entrambi tenoni e si intersecano, metto prima tenone vero e poi base tenone if ( Tenon.Identify( B1) or DtTenon.Identify( B1)) and ( Tenon.Identify( B2) or DtTenon.Identify( B2)) and B1.Box:getMin():getX() < B2.Box:getMax():getX() + 100 * GEO.EPS_SMALL and B2.Box:getMin():getX() < B1.Box:getMax():getX() + 100 * GEO.EPS_SMALL then return ( ( B1.Prc == 50 or B1.Prc == 55) and B2.Prc == 52) end -- se primo house mortise, secondo mortise e si intersecano, metto prima house mortise if Mortise.Identify( B1) and B1.Prc == 53 and ( Mortise.Identify( B2) or DtMortise.Identify( B2)) and B2.Prc ~= 53 and B1.Box:getMin():getX() < B2.Box:getMax():getX() + 100 * GEO.EPS_SMALL and B2.Box:getMin():getX() < B1.Box:getMax():getX() + 100 * GEO.EPS_SMALL then return true end -- se primo mortise, secondo house mortise e si intersecano, metto prima house mortise if ( Mortise.Identify( B1) or DtMortise.Identify( B1)) and B1.Prc ~= 53 and Mortise.Identify( B2) and B2.Prc == 53 and B1.Box:getMin():getX() < B2.Box:getMax():getX() + 100 * GEO.EPS_SMALL and B2.Box:getMin():getX() < B1.Box:getMax():getX() + 100 * GEO.EPS_SMALL then return false end -- se entrambi di testa e primo è scasso o mortasa e secondo no va messo dopo if B1.Head and B2.Head and ( LapJoint.Identify( B1) or Mortise.Identify( B1) or DtMortise.Identify( B1)) and not ( LapJoint.Identify( B2) or Mortise.Identify( B2) or DtMortise.Identify( B2)) then return false end -- se entrambi di testa e secondo è scasso o mortasa e primo no va lasciato dopo if B1.Head and B2.Head and ( LapJoint.Identify( B2) or Mortise.Identify( B2) or DtMortise.Identify( B2)) and not ( LapJoint.Identify( B1) or Mortise.Identify( B1) or DtMortise.Identify( B1)) then return true end -- se primo è feature di coda e l'altro è separazione o non è feature di coda if B1.Tail and ( Split.Identify( B2) or not B2.Tail) then return false end -- se secondo è feature di coda e l'altro è separazione o non è feature di coda if B2.Tail and ( Split.Identify( B1) or not B1.Tail) then return true end -- se primo è scasso o mortasa di coda e secondo no, sempre dopo if B1.Tail and ( LapJoint.Identify( B1) or Mortise.Identify( B1) or DtMortise.Identify( B1)) and not ( B2.Tail and ( LapJoint.Identify( B2) or Mortise.Identify( B2) or DtMortise.Identify( B2))) then return false end -- se secondo è scasso o mortasa di coda e primo no, va lasciato dopo if B2.Tail and ( LapJoint.Identify( B2) or Mortise.Identify( B2) or DtMortise.Identify( B2)) and not ( B1.Tail and ( LapJoint.Identify( B1) or Mortise.Identify( B1) or DtMortise.Identify( B1))) then return true end -- se primo è taglio longitudinale completo o altra lav. lunga, dopo tutte le altre feature non di coda if abs( B1.Box:getDimX() - b3Raw:getDimX()) < 0.2 * b3Raw:getDimX() then -- se anche l'altra è lunga, faccio prima quello a Zmax if abs( B2.Box:getDimX() - b3Raw:getDimX()) < 0.2 * b3Raw:getDimX() then return B1.Box:getMax():getZ() > B2.Box:getMax():getZ() else return B2.Tail or B1.Box:getMin():getX() + 20 > B2.Box:getCenter():getX() end end -- se secondo è taglio longitudinale completo o altra lav. lunga, dopo tutte le altre feature non di coda if abs( B2.Box:getDimX() - b3Raw:getDimX()) < 0.2 * b3Raw:getDimX() then return not ( B1.Tail or B2.Box:getMin():getX() + 20 > B1.Box:getCenter():getX()) end -- se primo è foro e l'altro no, lo penalizzo if B1.Prc == 40 and B2.Prc ~= 40 then return ( B1.Box:getCenter():getX() > B2.Box:getMax():getX() + dDrillPenalty) end -- se primo è altro e secondo è foro, lo premio if B1.Prc ~= 40 and B2.Prc == 40 then return ( B1.Box:getMax():getX() + dDrillPenalty > B2.Box:getCenter():getX()) end -- se entrambi fori con posizione praticamente uguale ordino secondo diametro e faccia di inizio (Fcs) if B1.Prc == 40 and B2.Prc == 40 and abs( B1.Box:getCenter():getX() - B2.Box:getCenter():getX()) < dSmallDrillRange then if abs( B1.Diam - B2.Diam) < 1.0 then if B1.Fcs == B2.Fcs then if abs( B1.Box:getCenter():getX() - B2.Box:getCenter():getX()) < 1.0 then if abs( B1.Box:getCenter():getY() - B2.Box:getCenter():getY()) < 1.0 then if abs( B1.Box:getCenter():getZ() - B2.Box:getCenter():getZ()) < 1.0 then return ( B1.Id < B2.Id) else return ( B1.Box:getCenter():getZ() > B2.Box:getCenter():getZ()) end else return ( B1.Box:getCenter():getY() > B2.Box:getCenter():getY()) end else return ( B1.Box:getCenter():getX() > B2.Box:getCenter():getX()) end else return ( B1.Fcs > B2.Fcs) end else return ( B1.Diam > B2.Diam) end end -- confronto standard if abs( B1.Box:getCenter():getX() - B2.Box:getCenter():getX()) > 0.4 * ( B1.Box:getDimX() + B2.Box:getDimX()) then return B1.Box:getCenter():getX() > B2.Box:getCenter():getX() elseif abs( B1.Box:getCenter():getY() - B2.Box:getCenter():getY()) > 0.2 * ( B1.Box:getDimY() + B2.Box:getDimY()) then return B1.Box:getCenter():getY() > B2.Box:getCenter():getY() elseif abs( B1.Box:getCenter():getZ() - B2.Box:getCenter():getZ()) > 0.1 * ( B1.Box:getDimZ() + B2.Box:getDimZ()) then return B1.Box:getCenter():getZ() > B2.Box:getCenter():getZ() else return ( B1.Id < B2.Id) end end -- test della funzione di ordinamento if EgtGetDebugLevel() >= 3 then EgtOutLog( ' CompareFeatures Test ') local bCompTest = true for i = 1, #vProc do for j = i + 1, #vProc do local bComp1 = CompareFeatures( vProc[i], vProc[j]) local bComp2 = CompareFeatures( vProc[j], vProc[i]) if bComp1 == bComp2 then bCompTest = false EgtOutLog( string.format( ' ProcId : %d vs %d --> ERROR', vProc[i].Id, vProc[j].Id)) end end end if bCompTest then EgtOutLog( ' ALL OK') end end -- eseguo ordinamento table.sort( vProc, CompareFeatures) -- riunisco fori con lo stesso diametro e non troppo lontani local dDrillRange = dSmallDrillRange if BD.GO_FAST == 2 then dDrillRange = 6000 elseif BD.PRESS_ROLLER then dDrillRange = 2000 end for i = 1, #vProc do local ProcI = vProc[i] if ProcI.Prc == 40 then for j = i + 1, #vProc do local ProcJ = vProc[j] if ProcJ.Prc == 40 and ProcJ.Head == ProcI.Head and ProcJ.Tail == ProcI.Tail and abs( ProcJ.Diam - ProcI.Diam) < 1.0 and abs( ProcJ.Box:getCenter():getX() - ProcI.Box:getCenter():getX()) < dDrillRange then if j > i + 1 then local ProcK = vProc[i+1] if ProcK.Prc ~= 40 or abs( ProcK.Diam - ProcJ.Diam) > 1.0 then table.insert( vProc, i + 1, table.remove( vProc, j)) end end end end end end -- riunisco fori da fare in doppio local i = 1 while i < #vProc do local ProcI = vProc[i] if ProcI.Prc == 40 then local DouId = EgtGetInfo( ProcI.Id, 'DOU', 'i') if DouId then for j = i + 1, #vProc do if vProc[j].Id == DouId then table.insert( vProc, i, table.remove( vProc, j)) i = i + 1 break end end end end i = i + 1 end -- riunisco marcature, testi e decori non troppo lontani local dMarkRange = 300 for i = 1, #vProc do local ProcI = vProc[i] if ProcI.Prc == 60 or ProcI.Prc == 61 or ProcI.Prc == 959 then for j = i + 1, #vProc do local ProcJ = vProc[j] if ( ProcJ.Prc == 60 or ProcJ.Prc == 61 or ProcJ.Prc == 959) and ProcJ.Head == ProcI.Head and ProcJ.Tail == ProcI.Tail and abs( ProcJ.Box:getCenter():getX() - ProcI.Box:getCenter():getX()) < dMarkRange then if j > i + 1 then table.insert( vProc, i + 1, table.remove( vProc, j)) end break end end end end -- ordino BlockHaus HalfLap vicini (davanti, sotto, dietro, sopra) local dBHHLRange = 100 for i = 1, #vProc do local ProcI = vProc[i] if ProcI.Prc == 37 then for j = i + 1, #vProc do local ProcJ = vProc[j] if ProcJ.Prc == 37 and abs( ProcI.Box:getCenter():getX() - ProcJ.Box:getCenter():getX()) < dBHHLRange then if ProcI.HeadDir then if ProcJ.vtN:getY() < -0.5 then table.insert( vProc, i, table.remove( vProc, j)) break elseif ProcJ.vtN:getZ() < -0.5 and ProcI.vtN:getY() > -0.5 then table.insert( vProc, i, table.remove( vProc, j)) ProcI = vProc[i] elseif ProcJ.vtN:getY() > 0.5 and ProcI.vtN:getY() > -0.5 and ProcI.vtN:getZ() > -0.5 then table.insert( vProc, i, table.remove( vProc, j)) ProcI = vProc[i] end else if ProcJ.vtN:getY() > 0.5 then table.insert( vProc, i, table.remove( vProc, j)) break elseif ProcJ.vtN:getZ() < -0.5 and ProcI.vtN:getY() < 0.5 then table.insert( vProc, i, table.remove( vProc, j)) ProcI = vProc[i] elseif ProcJ.vtN:getY() < -0.5 and ProcI.vtN:getY() < 0.5 and ProcI.vtN:getZ() > -0.5 then table.insert( vProc, i, table.remove( vProc, j)) ProcI = vProc[i] end end end end end end end ------------------------------------------------------------------------------------------------------------- local function ClassifyFeatures( vProc, b3Raw, Stats) local bAllOk = true local bSomeDown = false local bSomeSide = false local bSplitRot = false local nHeading local nSplitting for i = 1, #vProc do local Proc = vProc[i] local bOk = true local bDown = false local bSide = false local bDownSideOnHeadOk = false -- se senza geometria (già disabilitato if Proc.Flg == 0 then bOk = false -- se intestatura elseif Hcut.Identify( Proc) then nHeading = i -- se separazione elseif Split.Identify( Proc) then nSplitting = i -- se taglio elseif Cut.Identify( Proc) then bOk, bDown = Cut.Classify( Proc, b3Raw) -- se doppio taglio elseif DoubleCut.Identify( Proc) then bOk, bDown = DoubleCut.Classify( Proc, b3Raw) -- se taglio longitudinale elseif LongCut.Identify( Proc) then bOk, bDown = LongCut.Classify( Proc) -- se doppio taglio longitudinale elseif Long2Cut.Identify( Proc) then -- se due facce longitudinali, classifico doppio taglio longitudinale if Long2Cut.GetLongFacesCount( Proc) == 2 then bOk, bDown = Long2Cut.Classify( Proc) -- altrimenti eseguo singolo taglio longitudinale else bOk, bDown = LongCut.Classify( Proc) end -- se taglio con lama elseif SawCut.Identify( Proc) then bOk, bDown = SawCut.Classify( Proc) -- se mezzo-legno di testa elseif RidgeLap.Identify( Proc) then bOk, bDown = RidgeLap.Classify( Proc, b3Raw) -- se scanalatura, scanalatura frontale, tacca, tacca cantonale, mezzo-legno, scanalatura-battuta, -- mezzolegno tipo chalet-tavola di chiusura, rivestimento, mezzolegno chalet, tasca, taglio triangolato elseif LapJoint.Identify( Proc) then bOk, bDown = LapJoint.Classify( Proc, b3Raw) -- se foratura elseif Drill.Identify( Proc) then bOk, bDown, bSide = Drill.Classify( Proc, b3Raw) bDownSideOnHeadOk = true -- se tenone elseif Tenon.Identify( Proc) then bOk, bDown = Tenon.Classify( Proc, b3Raw) -- se giunzione francese elseif FrenchRidgeLap.Identify( Proc) then bOk, bDown = FrenchRidgeLap.Classify( Proc) -- se block house front elseif BlockHausFront.Identify( Proc) then bOk, bDown = BlockHausFront.Classify( Proc) -- se mortasa (anche frontale) elseif Mortise.Identify( Proc) then bOk, bDown = Mortise.Classify( Proc) -- se tenone a coda di rondine elseif DtTenon.Identify( Proc) then bOk, bDown = DtTenon.Classify( Proc, b3Raw) -- se mortasa a coda di rondine (anche frontale) elseif DtMortise.Identify( Proc) then bOk, bDown = DtMortise.Classify( Proc) -- se marcatura elseif Mark.Identify( Proc) then bOk, bDown = Mark.Classify( Proc) -- se testo elseif Text.Identify( Proc) then bOk, bDown = Text.Classify( Proc) -- se giunto Gerber elseif ScarfJoint.Identify( Proc) then bOk, bDown = ScarfJoint.Classify( Proc) -- se giunto Gerber elseif Scarf.Identify( Proc) then bOk, bDown = Scarf.Classify( Proc) -- se giunto a gradino elseif StepJoint.Identify( Proc) then bOk, bDown = StepJoint.Classify( Proc) -- se tacca a gradino elseif StJoNotch.Identify( Proc) then bOk, bDown = StJoNotch.Classify( Proc) -- se arco elseif RoundArch.Identify( Proc) then bOk, bDown = RoundArch.Classify( Proc) -- se incastro tirolo elseif TyroleanDovetail.Identify( Proc) then bOk, bDown = TyroleanDovetail.Classify( Proc, b3Raw) -- se giunto coda di rondine elseif Dovetail.Identify( Proc) then bOk, bDown = Dovetail.Classify( Proc, b3Raw) -- se profilo front elseif ProfFront.Identify( Proc) then bOk, bDown, bSide = ProfFront.Classify( Proc, b3Raw) -- se profilo concavo elseif ProfConcave.Identify( Proc) then bOk, bDown, bSide = ProfConcave.Classify( Proc, b3Raw) -- se profilo convesso elseif ProfConvex.Identify( Proc) then bOk, bDown, bSide = ProfConvex.Classify( Proc, b3Raw) -- se profilo caudato elseif ProfCamb.Identify( Proc) then bOk, bDown, bSide = ProfCamb.Classify( Proc, b3Raw) -- se profilo head elseif ProfHead.Identify( Proc) then bOk, bDown, bSide = ProfHead.Classify( Proc, b3Raw) -- se contorno libero elseif FreeContour.Identify( Proc) then bOk, bDown, bSide = FreeContour.Classify( Proc, b3Raw) -- se decorazione elseif Decor.Identify( Proc) then bOk, bDown = Decor.Classify( Proc) end -- assegno risultato if bOk then -- non ammessa feature di testa da lavorare ribaltata o ruotata if Proc.Head and ( bDown or bSide) and not bDownSideOnHeadOk then Proc.Flg = 0 Proc.Down = true bAllOk = false table.insert( Stats, {Err = 1, Msg='Error : impossible to machine by orientation', CutId=Proc.CutId, TaskId=Proc.TaskId}) -- gestione feature di coda da lavorare ribaltata elseif Proc.Tail and bDown then Proc.Down = true bSomeDown = true bSplitRot = true -- gestione feature di coda da lavorare ruotata elseif Proc.Tail and bSide then Proc.Side = true bSomeSide = true bSplitRot = true -- caso normale else Proc.Down = bDown Proc.Side = bSide if bDown then bSomeDown = true end if bSide then bSomeSide = true end end elseif Proc.Flg == 0 then bAllOk = false Proc.ErrMsg = 'Error : out of the part' table.insert( Stats, {Err = 1, Msg=Proc.ErrMsg, CutId=Proc.CutId, TaskId=Proc.TaskId}) else Proc.Flg = 0 bAllOk = false if not Proc.ErrMsg then Proc.ErrMsg = 'Error : impossible to machine' end table.insert( Stats, {Err = 1, Msg=Proc.ErrMsg, CutId=Proc.CutId, TaskId=Proc.TaskId}) end end -- se necessario ribaltamento, assegno intestatura alla fase ribaltata if bSomeDown and nHeading then vProc[nHeading].Down = true -- se altrimenti necessaria rotazione (senza ribaltamento), assegno intestatura alla fase ribaltata (creata ad hoc) elseif bSomeSide and nHeading then vProc[nHeading].Down = true bSomeDown = true end -- se necessaria separazione del ribaltato o ruotato, la assegno sempre alla fase ribaltata if bSplitRot and nSplitting then vProc[nSplitting].Down = true bSomeDown = true end return bAllOk, bSomeDown, bSomeSide, bSplitRot end ------------------------------------------------------------------------------------------------------------- local function AddFeatureMachining( Proc, nPhase, nRawId, nPartId, dCurrOvmH, bNeedHCut, b3Raw) local bOk = true local sErr = '' local bNewPhase = false EgtOutLog( ' * Process ' .. tostring( Proc.Id) .. ' *', 1) -- se intestatura ( 1-340-X ) if Hcut.Identify( Proc) then -- esecuzione taglio di testa bOk, sErr = Hcut.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH, bNeedHCut) -- se separazione ( 2-350-X ) elseif Split.Identify( Proc) then -- esecuzione separazione o eliminazione grezzo residuo bOk, sErr = Split.Make( Proc, nPhase, nRawId, nPartId) -- richiedo il passaggio alla seconda fase di lavorazione di questa trave bNewPhase = true -- se taglio ( 1/2-010-X) elseif Cut.Identify( Proc) then -- esecuzione taglio bOk, sErr = Cut.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se doppio taglio ( 1/2-011-X) elseif DoubleCut.Identify( Proc) then -- esecuzione doppio taglio bOk, sErr = DoubleCut.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se taglio longitudinale ( 0/3/4-010-X) elseif LongCut.Identify( Proc) then -- esecuzione taglio longitudinale bOk, sErr = LongCut.Make( Proc, nPhase, nRawId, nPartId) -- se doppio taglio longitudinale ( 0-012-X) elseif Long2Cut.Identify( Proc) then -- se due facce longitudinali, eseguo doppio taglio longitudinale if Long2Cut.GetLongFacesCount( Proc) == 2 then bOk, sErr = Long2Cut.Make( Proc, nPhase, nRawId, nPartId) -- altrimenti eseguo singolo taglio longitudinale else bOk, sErr = LongCut.Make( Proc, nPhase, nRawId, nPartId) end -- se taglio con lama ( 0/3/4-013-X) elseif SawCut.Identify( Proc) then -- esecuzione taglio bOk, sErr = SawCut.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se mezzo-legno di testa ( 1/2-030-X) elseif RidgeLap.Identify( Proc) then -- esecuzione mezzo-legno di testa bOk, sErr = RidgeLap.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se fessura ( 3/4-016-X) o se fessura frontale ( 3/4-017-X) o se tacca ( 3/4-020-X) o se tacca cantonale ( 3/4-025-X) -- o se mezzo-legno ( 3/4-030-X) o se scanalatura/battuta ( 3/4-032-X) o se mezzo legno tipo chalet/tavola di chiusura ( 3/4-033-X) -- o se rivestimento ( 3/4-034-X) o se mezzolegno chalet ( 4-037-X) o se tasca ( 4-039-X) o se taglio triangolato ( 4-120-X) elseif LapJoint.Identify( Proc) then -- esecuzione mezzo-legno o scanalatura bOk, sErr = LapJoint.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se smusso ( 3/4-036-X) elseif Chamfer.Identify( Proc) then -- esecuzione smusso bOk, sErr = Chamfer.Make( Proc, nPhase, nRawId, nPartId) -- se foratura ( 3/4-040-X) elseif Drill.Identify( Proc) then -- esecuzione foratura bOk, sErr = Drill.Make( Proc, nPhase, nRawId, nPartId) -- se giunzione francese ( 1/2-035-X) elseif FrenchRidgeLap.Identify( Proc) then -- esecuzione giunzione francese bOk, sErr = FrenchRidgeLap.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se block house front ( 3/4-038-X) elseif BlockHausFront.Identify( Proc) then -- esecuzione giunzione francese bOk, sErr = BlockHausFront.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se tenone ( 1/2-050-X) elseif Tenon.Identify( Proc) then -- esecuzione tenone bOk, sErr = Tenon.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se mortasa ( 3/4-050-X) anche frontale ( 3/4-051-X) elseif Mortise.Identify( Proc) then -- esecuzione mortasa bOk, sErr = Mortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se tenone a coda di rondine ( 1/2-055-X) elseif DtTenon.Identify( Proc) then -- esecuzione tenone bOk, sErr = DtTenon.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se mortasa a coda di rondine ( 3/4-055-X) anche frontale ( 3/4-056-X) elseif DtMortise.Identify( Proc) then -- esecuzione mortasa bOk, sErr = DtMortise.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se marcatura ( 3/4-060-X) elseif Mark.Identify( Proc) then -- esecuzione marcatura bOk, sErr = Mark.Make( Proc, nPhase, nRawId, nPartId) -- se testo ( 4-061-X) elseif Text.Identify( Proc) then -- esecuzione testo bOk, sErr = Text.Make( Proc, nPhase, nRawId, nPartId) -- se giunto Gerber ( 1/2-071-X) elseif ScarfJoint.Identify( Proc) then -- esecuzione giunto Gerber bOk, sErr = ScarfJoint.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se giunto Gerber ( 1/2-070-X) elseif Scarf.Identify( Proc) then -- esecuzione giunto Gerber bOk, sErr = Scarf.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se giunto a gradino ( 1/2-080-X) elseif StepJoint.Identify( Proc) then -- esecuzione giunto a gradino bOk, sErr = StepJoint.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se tacca a gradino ( 3/4-080-X) elseif StJoNotch.Identify( Proc) then -- esecuzione tacca a gradino bOk, sErr = StJoNotch.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se profilo Front ( 3/4-100-X) elseif ProfFront.Identify( Proc) then -- esecuzione profilo bOk, sErr = ProfFront.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se profilo concavo ( 3/4-101-X) elseif ProfConcave.Identify( Proc) then -- esecuzione profilo bOk, sErr = ProfConcave.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se profilo convesso ( 3/4-102-X) elseif ProfConvex.Identify( Proc) then -- esecuzione profilo bOk, sErr = ProfConvex.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se profilo caudato ( 3/4-103-X) elseif ProfCamb.Identify( Proc) then -- esecuzione profilo bOk, sErr = ProfCamb.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se arco ( 4-104-X) elseif RoundArch.Identify( Proc) then -- esecuzione arco bOk, sErr = RoundArch.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se profilo Head ( 3/4-106-X) elseif ProfHead.Identify( Proc) then -- esecuzione profilo bOk, sErr = ProfHead.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se incastro tirolo ( 1/2/3/4-136-X) elseif TyroleanDovetail.Identify( Proc) then bOk, sErr = TyroleanDovetail.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se giunto coda di rondine ( 1/2/3/4-138-X) elseif Dovetail.Identify( Proc) then bOk, sErr = Dovetail.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se contorno libero ( 0/3/4-250-X) elseif FreeContour.Identify( Proc) then -- esecuzione contorno bOk, sErr = FreeContour.Make( Proc, nPhase, nRawId, nPartId, dCurrOvmH) -- se decorazione ( 0/3/4-959-X) elseif Decor.Identify( Proc) then -- esecuzione decorazione bOk, sErr = Decor.Make( Proc, nPhase, nRawId, nPartId) -- altrimenti feature sconosciuta else sErr = 'Error on process ' .. tostring( Proc.Id) .. ' unknown type (' .. tonumber( Proc.Grp) .. '-' .. tonumber( Proc.Prc) .. ')' EgtOutLog( sErr) bOk = false end return bOk, sErr, bNewPhase end ------------------------------------------------------------------------------------------------------------- local function VerifyNeedForHeadCut( vProc, bSomeDown, bSomeSide) -- verifico se necessaria la rotazione di 90 gradi if not bSomeSide then return false end -- verifico se viene dopo un pezzo diviso quando ruotato (quindi con rimanenza scaricata sul carico) local nPrevPhase = EgtGetCurrPhase() - 1 local nPrevDispId = EgtGetPhaseDisposition( nPrevPhase) or GDB_ID.NULL local nPrevType = EgtGetInfo( nPrevDispId, 'TYPE') if nPrevType ~= 'MID2' and nPrevType ~= 'END2' then return false end -- verifico se c'è una sola lavorazione ribaltata (quindi è il taglio di testa) local nDownCnt = 0 for i = 1, #vProc do if vProc[i].Down then nDownCnt = nDownCnt + 1 end end return ( nDownCnt == 1) end ------------------------------------------------------------------------------------------------------------- local function SetCutsOnFrontMortises( vProc) -- ciclo sulle feature for i = 1, #vProc do if vProc[i].Fct > 0 and Cut.Identify( vProc[i]) then for j = 1, #vProc do if vProc[j].Fct > 0 and Mortise.FrontIdentify( vProc[j]) then -- se esiste intersezione tra le due features if vProc[i].Box:getMin():getX() < vProc[j].Box:getMax():getX() + 100 * GEO.EPS_SMALL and vProc[j].Box:getMin():getX() < vProc[i].Box:getMax():getX() + 100 * GEO.EPS_SMALL then -- recupero il piano del taglio local ptC1, vtN1 = Cut.GetCutPlane( vProc[i]) -- recupero il piano frontale della mortasa local ptC2, vtN2 = Mortise.GetCutPlane( vProc[j]) -- verifico se i piani coincidono local bSamePlane = ( ptC1 and vtN1 and ptC2 and vtN2 and AreSameVectorApprox( vtN1, vtN2) and ( ptC2 - ptC1) * vtN1 < 1.0) if bSamePlane then vProc[i].CutFront = vProc[j].Id end -- log local sMsg = string.format( 'Cut %d meet Mortise %d', vProc[i].Id, vProc[j].Id) .. EgtIf( bSamePlane, ' with same plane', '') EgtOutLog( sMsg, 3) end elseif vProc[j].Fct > 0 and DtMortise.FrontIdentify( vProc[j]) then -- se esiste intersezione tra le due features if vProc[i].Box:getMin():getX() < vProc[j].Box:getMax():getX() + 100 * GEO.EPS_SMALL and vProc[j].Box:getMin():getX() < vProc[i].Box:getMax():getX() + 100 * GEO.EPS_SMALL then -- recupero il piano del taglio local ptC1, vtN1 = Cut.GetCutPlane( vProc[i]) -- recupero il piano frontale della mortasa local ptC2, vtN2 = DtMortise.GetCutPlane( vProc[j]) -- verifico se i piani coincidono local bSamePlane = ( ptC1 and vtN1 and ptC2 and vtN2 and AreSameVectorApprox( vtN1, vtN2) and ( ptC2 - ptC1) * vtN1 < 1.0) if bSamePlane then vProc[i].CutFront = vProc[j].Id end -- log local sMsg = string.format( 'Cut %d meet DtMortise %d', vProc[i].Id, vProc[j].Id) .. EgtIf( bSamePlane, ' with same plane', '') EgtOutLog( sMsg, 3) end end end end end end ------------------------------------------------------------------------------------------------------------- local function MoveDrillsOnTenon( vProc) -- se non richiesto spostamento fori su tenone, esco if not BD.OFFSET_DRILL_TENON or abs( BD.OFFSET_DRILL_TENON) < 0.1 then return end -- ciclo sulle feature for i = 1, #vProc do if vProc[i].Flg ~= 0 and Tenon.Identify( vProc[i]) then for j = 1, #vProc do if Drill.Identify( vProc[j]) then -- se esiste intersezione tra tenone e foro if vProc[i].Box:getMin():getX() < vProc[j].Box:getMax():getX() + 100 * GEO.EPS_SMALL and vProc[j].Box:getMin():getX() < vProc[i].Box:getMax():getX() + 100 * GEO.EPS_SMALL then -- verifico se foro già spostato if not EgtExistsInfo( vProc[j].Id, 'MOV') then -- recupero curva ausiliaria del foro local AuxDriId = EgtGetInfo( vProc[j].Id, 'AUXID', 'i') AuxDriId = EgtIf( AuxDriId, AuxDriId + vProc[j].Id, nil) -- recupero versore normale del tenone local AuxTenId = EgtGetInfo( vProc[i].Id, 'AUXID', 'i') AuxTenId = EgtIf( AuxTenId, AuxTenId + vProc[i].Id, GDB_ID.NULL) local vtExtr = EgtCurveExtrusion( AuxTenId, GDB_RT.GLOB) -- se tutto ok, eseguo spostamento if AuxDriId and vtExtr then local vtMove = -vtExtr * BD.OFFSET_DRILL_TENON EgtMove( AuxDriId, vtMove, GDB_RT.GLOB) EgtSetInfo( vProc[j].Id, 'MOV', vtMove) end end end end end end end end ------------------------------------------------------------------------------------------------------------- function BeamExec.ProcessFeatures() -- verifica se possibile rotazione di 90 gradi BD.ROT90 = BD.ROT90 and Verify90DegRotation( EgtGetFirstRawPart()) -- ciclo sui pezzi local nTotErr = 0 local Stats = {} local nOrd = 1 local nRawId = EgtGetFirstRawPart() while nRawId do -- verifico che il grezzo contenga pezzi oppure sia abbastanza lungo da essere scaricato coi carrelli local nPartId = EgtGetFirstPartInRawPart( nRawId) if not nPartId and EgtGetRawPartBBox( nRawId):getDimX() < BD.MinRaw then break end -- aggiungo la fase, se non è la prima if nOrd == 1 then EgtSetCurrPhase( 1) else BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, 0) end local nPhase = EgtGetCurrPhase() local nDispId = EgtGetPhaseDisposition( nPhase) EgtSetInfo( nDispId, 'TYPE', EgtIf( nPartId, 'START', 'REST')) EgtSetInfo( nDispId, 'ORD', nOrd) EgtOutLog( ' *** Phase=' .. tostring( nPhase) .. ' Raw=' .. tostring( nRawId) .. ' Part=' .. tostring( nPartId) .. ' ***', 1) -- ingombro del grezzo e sovramateriale di testa local b3Raw = EgtGetRawPartBBox( nRawId) local dCurrOvmH = EgtGetInfo( nRawId, 'HOVM', 'd') or 0 -- recupero le feature di lavorazione della trave local vProc = CollectFeatures( nPartId, b3Raw, dCurrOvmH) -- le ordino lungo X OrderFeatures( vProc, b3Raw) -- le classifico local bAllOk, bSomeDown, bSomeSide, bSplitRot = ClassifyFeatures( vProc, b3Raw, Stats) if not bAllOk then nTotErr = nTotErr + 1 end -- debug if EgtGetDebugLevel() >= 1 then PrintFeatures( vProc, b3Raw) end EgtOutLog( ' *** AddMachinings ***', 1) -- verifico se comunque necessario taglio di testa local bNeedHCut = VerifyNeedForHeadCut( vProc, bSomeDown, bSomeSide) -- inserisco corrispondenze di tagli coincidenti con mortase normali o a coda di rondine di testa SetCutsOnFrontMortises( vProc) -- eventuale spostamento fori sui tenoni MoveDrillsOnTenon( vProc) -- se richiesto ribaltamento (oppure rotazione) if ( bSomeDown or bSomeSide) and not BD.DOWN_HEAD then -- ribalto le travi della fase corrente local nRId = nRawId while nRId do EgtRotateRawPart( nRId, X_AX(), 180) nRId = EgtGetNextRawPart( nRId) end EgtSetInfo( nDispId, 'ROT', -2) -- inserisco le lavorazioni da lavorare ribaltate for i = 1, #vProc do -- creo la lavorazione local Proc = vProc[i] if Proc.Flg ~= 0 and Proc.Down then local bOk, sMsg, bNewPhase = AddFeatureMachining( Proc, nPhase, nRawId, nPartId, dCurrOvmH, bNeedHCut, b3Raw) if not bOk then nTotErr = nTotErr + 1 table.insert( Stats, {Err=1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) elseif sMsg and #sMsg > 0 then table.insert( Stats, {Err=-1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) else table.insert( Stats, {Err=0, Msg='', Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) end -- se era taglio di separazione, aggiungo nuova fase if bNewPhase then BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, BD.RAW_OFFSET) EgtRotateRawPart( nRawId, X_AX(), 180) -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BD.MinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end nPhase = EgtGetCurrPhase() nDispId = EgtGetPhaseDisposition( nPhase) EgtSetInfo( nDispId, 'TYPE', 'MID2') EgtSetInfo( nDispId, 'ORD', nOrd) EgtSetInfo( nDispId, 'ROT', -2) end end end -- se separazione non ancora effettuata, aggiungo nuova fase con le travi in posizione standard if not bSplitRot then BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, 0) -- altrimenti else -- aggiungo nuova fase con le travi in posizione standard BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, BD.RAW_OFFSET) -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BD.MinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end end nPhase = EgtGetCurrPhase() nDispId = EgtGetPhaseDisposition( nPhase) local nType = 'MID' if bSplitRot then nType = EgtIf( bSomeSide, 'MID2', 'END2') end EgtSetInfo( nDispId, 'TYPE', nType) EgtSetInfo( nDispId, 'ORD', nOrd) end -- se richiesta rotazione if bSomeSide and not BD.DOWN_HEAD then -- vettore movimento grezzi per rotazione di 90deg local dDeltaYZ = EgtGetRawPartBBox( nRawId):getDimY() - EgtGetRawPartBBox( nRawId):getDimZ() local vtMove = Vector3d( 0, dDeltaYZ / 2, dDeltaYZ / 2) local bPreMove = ( dDeltaYZ < 0) -- ruoto le travi della fase corrente local nRId = nRawId while nRId do if bPreMove then EgtMoveRawPart( nRId, vtMove) end EgtRotateRawPart( nRId, X_AX(), EgtIf( BD.RIGHT_LOAD, -90, 90)) if not bPreMove then EgtMoveRawPart( nRId, vtMove) end nRId = EgtGetNextRawPart( nRId) end EgtSetInfo( nDispId, 'ROT', -1) -- inserisco le lavorazioni da lavorare ruotate local nSideMchOk = 0 for i = 1, #vProc do -- creo la lavorazione local Proc = vProc[i] if Proc.Flg ~= 0 and Proc.Side then local bOk, sMsg, bNewPhase = AddFeatureMachining( Proc, nPhase, nRawId, nPartId, dCurrOvmH, false, b3Raw) if not bOk then nTotErr = nTotErr + 1 table.insert( Stats, {Err=1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) elseif sMsg and #sMsg > 0 then table.insert( Stats, {Err=-1, Msg=sMsg, Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) else table.insert( Stats, {Err=0, Msg='', Rot=-2, CutId=Proc.CutId, TaskId=Proc.TaskId}) end if bOk then nSideMchOk = nSideMchOk + 1 end -- se era taglio di separazione, aggiungo nuova fase if bNewPhase then BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, BD.RAW_OFFSET) if bPreMove then EgtMoveRawPart( nRawId, vtMove) end EgtRotateRawPart( nRawId, X_AX(), EgtIf( BD.RIGHT_LOAD, -90, 90)) if not bPreMove then EgtMoveRawPart( nRawId, vtMove) end -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BD.MinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end nPhase = EgtGetCurrPhase() nDispId = EgtGetPhaseDisposition( nPhase) EgtSetInfo( nDispId, 'TYPE', 'MID2') EgtSetInfo( nDispId, 'ORD', nOrd) EgtSetInfo( nDispId, 'ROT', -1) end end end -- se non sono state inserite lavorazioni di fianco, elimino la fase perchè inutile e dannosa if nSideMchOk == 0 then EgtRemoveLastPhase() end -- se separazione non ancora effettuata, aggiungo nuova fase con le travi in posizione standard if not bSplitRot then BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, 0) -- altrimenti else BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, BD.RAW_OFFSET) -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BD.MinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end end nPhase = EgtGetCurrPhase() nDispId = EgtGetPhaseDisposition( nPhase) EgtSetInfo( nDispId, 'TYPE', EgtIf( not bSplitRot, 'MID', 'END2')) EgtSetInfo( nDispId, 'ORD', nOrd) end -- inserisco le lavorazioni non ribaltate della trave for i = 1, #vProc do -- creo la lavorazione local Proc = vProc[i] if Proc.Flg ~= 0 and ( not ( Proc.Down or Proc.Side) or BD.DOWN_HEAD) then local bOk, sMsg, bNewPhase = AddFeatureMachining( Proc, nPhase, nRawId, nPartId, dCurrOvmH, false, b3Raw) if not bOk then nTotErr = nTotErr + 1 table.insert( Stats, {Err=1, Msg=sMsg, Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) elseif sMsg and #sMsg > 0 then table.insert( Stats, {Err=-1, Msg=sMsg, Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) else table.insert( Stats, {Err=0, Msg='', Rot=0, CutId=Proc.CutId, TaskId=Proc.TaskId}) end -- se era taglio di separazione, aggiungo nuova fase if bNewPhase then BL.AddPhaseWithRawParts( nRawId, BD.OriXR, BD.PosXR, BD.RAW_OFFSET) -- se grezzo successivo senza pezzi e finale, va tolto local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) == 0 and EgtGetRawPartBBox( nNextRawId):getDimX() < BD.MinRaw then EgtRemoveRawPartFromCurrPhase( nNextRawId) end nPhase = EgtGetCurrPhase() nDispId = EgtGetPhaseDisposition( nPhase) EgtSetInfo( nDispId, 'TYPE', 'END') EgtSetInfo( nDispId, 'ORD', nOrd) end end end EgtOutLog( ' *** End AddMachinings ***', 1) -- passo al grezzo successivo nOrd = nOrd + 1 nRawId = EgtGetNextRawPart( nRawId) end -- Aggiornamento finale di tutto EgtSetCurrPhase( 1) local bApplOk, sApplErrors, sApplWarns = EgtApplyAllMachinings() -- eventuale ricalcolo per macchine tipo PF (ma tengo warning del primo calcolo) if EgtExistsInfo( EgtGetCurrMachGroup(), 'RECALC') then EgtOutLog( ' **** RECALC ****') bApplOk, sApplErrors, _ = EgtApplyAllMachinings() EgtRemoveInfo( EgtGetCurrMachGroup(), 'RECALC') end if not bApplOk then nTotErr = nTotErr + 1 table.insert( Stats, {Err = 1, Msg=sApplErrors, Rot=0, CutId=0, TaskId=0}) elseif sApplWarns and #sApplWarns > 0 then local vLine = EgtSplitString( sApplWarns, '\r\n') for i = 1, #vLine do local nPos = vLine[i]:find( '(WRN', 1, true) if nPos then local sData = vLine[i]:sub( nPos + 1, -2) local vVal = EgtSplitString( sData, ',') local nWarn = EgtGetVal( vVal[1] or '', 'WRN', 'i') local nCutId = EgtGetVal( vVal[2] or '', 'CUTID', 'i') if nWarn and nCutId then table.insert( Stats, { Err=-nWarn, Msg=vLine[i], Rot=0, CutId=nCutId, TaskId=0}) end end end end return ( nTotErr == 0), Stats end ------------------------------------------------------------------------------------------------------------- return BeamExec