-- ProcessLapJoint.lua by Egaltech s.r.l. 2024/03/15 -- Gestione calcolo mezzo-legno per Travi -- 2019/10/08 Agg. gestione OpenPocket. -- 2021/01/24 Con sega a catena ora sempre impostato asse A. -- 2021/02/03 Corretto riconoscimento feature di coda. -- 2021/02/04 Razionalizzata gestione forzatura lama. Corretta gestione diametro minimo utensile per svuotatura. -- 2021/03/04 Due facce con testa da sotto. -- 2021/03/20 Piccole correzioni. -- 2021/03/22 Modificata gestione caso due facce lunghe come la trave con trave corta. -- 2021/04/13 Modificata gestione fessura U con sega a catena (corta ora ok, lunga ancora da correggere). -- 2021/04/14 Correzioni ribasso a U con fresa da sotto. -- 2021/04/15 Aggiunta gestione massima lunghezza fresa da sotto su svuotature. -- 2021/04/21 Anche feature lunga con due facce con opzione lama ora si taglia con lama. -- 2021/04/23 Corretto caso con antischeggia non inseriti perchè inutili. -- 2021/04/27 Antischeggia solo se feature trasversali. -- 2021/05/12 Semplificata gestione diametro minimo utensile per svuotatura. -- 2021/06/04 Su U passante con faccia perpendicolare aggiunta si forza Pocket. -- 2021/06/11 Su U passante e profonda se non bastano due svuotature su faccia ortogonale si fa anche la faccia di fondo per quanto possibile. -- 2021/06/21 Nel caso precedente si fa la terza svuotatura anche se è possibile fare una sola delle prime due (altra da sotto). -- 2021/06/21 Gestione ripresa spigoli o contorno con fresa più piccola ( diametro < 3/4 utensile svuotatura) attivata da parametro Q. -- 2021/07/02 Migliorie e correzioni su svuotature e pulitura spigoli. -- 2021/07/15 Aggiunti antischeggia con fresa. -- 2021/09/08 Aggiunta gestione parametro Q04 per i tagli di lama lungo facce lunghe (con o senza facce di chiusura) -- 2021/09/21 Aggiunta lavorazione/opzione "lamello" con le feature 16, 30, 32, 39, -- che si attiva abilitando il check al tipo milling: SideMillAsBlade (SideMillAsBlade_2) -- 2021/09/23 Gestione migliorata lavorazioni BH (blockhaus) su macchina fast BH, -- migliorata applicazione lavorazioni BH su feature lunghe lavorte a passi -- 2021/10/06 Ad antischeggia con lama in presenza di testa da sotto aggiunta preferenza a testa da sopra. -- 2021/10/19 Corretta gestione inversione per Tunnel. OpenPocket anche se spezzato ma 1 o 2 facce. Introdotta lunghezza minima per lamello. -- 2021/10/21 Migliorato controllo affondamento utensile in U lavorato da 3 parti (anche da sotto). -- 2021/10/27 Migliorato calcolo asse tunnel o similare. -- 2021/11/02 In svuotatura con lati aperti diametro fresa non superiore al doppio del lato piccolo. -- 2021/11/15 Quando si usa sega a catena uso Q10 come massima elevazione. -- 2021/11/22 Corretta segnalazione warning su foro di L20 e L25. -- 2022/01/19 Cambiata % lunghezza pezzo per spezzatura. Tolta correzione spessore fresa a disco con superficie da lavorare verso Z-. -- 2022/01/26 Migliorato controllo uso testa da sotto nel caso due facce con lama. -- 2022/02/07 Corretto caso con due facce che non è un LongDoubleCut ma che veniva identificato come tale. -- 2022/02/14 Introdotto uso svuotature ZigZag ottimizzate. -- 2022/03/18 Corretta lavorazione BH. -- 2022/03/21 Quando si usa lama uso Q10 come massima elevazione. -- 2022/03/29 Aggiunta gestione antischeggia con Q06 anche su 3/4-033-X. -- 2022/04/28 Lavorazione BH forzata sempre OneWay. -- 2022/05/04 Corretta classificazione due facce sotto. Modificati criteri assegnazione due facce alla coda. -- 2022/05/24 Miglioramenti vari per BH, compreso controlli per lavorazione da sotto. -- 2022/06/13 Modifiche per feature lunga con due facce non equivalenti a taglio long. doppio o singolo con faccia terminale. -- 2022/06/15 Correzione calcolo normale alla faccia per sega catena di fianco. -- 2022/06/16 Implemento lavorazioni con fresatura di lato per L30 (al momento solo passanti) se parametro Q03=2. Modificate funzioni Make, MakeMoreFaces, Classify. -- 2022/06/21 Implemento di lavorazioni non passanti con fresatura di lato per L30 se parametro Q03=2. Modificate funzioni MakeMoreFaces, Classify. -- 2022/06/29 Migliorate lavorazioni con fresatura di lato per L30 se parametro Q03=2. Ora con 4 facce / 3 facce a L può entrare una fresa grande fino al doppio dell'altezza della tasca / doppio della dimensione minima. -- 2022/07/05 Modifiche per sega a catena di testa e relativa MaxElev. -- 2022/07/12 In MakeByChainOrSaw aggiunto check per feature L20 usata in modo improprio e, nel caso, si passa a una lavorazione tasca. -- 2022/08/11 Aggiunta lavorazione tunnel splittata con sega a catena per tutte le macchine ad esclusione della Fast. -- 2022/09/01 Spostate le funzioni GetTunnelDimension, CalcCollisionSafety, SetOpenSide in BeamLib. -- 2022/09/15 Implementata gestione feature Planing L090, gestita come LapJoint -- Implementata, in caso di fresatura di lato con altezza tasca molto bassa, la contornatura con unica passata -- Migliorata gestione AntiSplint (Mill e Saw) -- 2022/09/27 Aggiunta gestione SCC per svuotature con TURN (solo dopo applicazione lavorazione). -- 2022/10/20 In MakeByChainOrSaw modificato check per trovare la faccia adiacente sul lato più lungo. -- 2022/12/12 Default 1000 per BD.MIN_LEN_LAMELLO. In MachineByMill migliorata ricerca utensile e gestione inversione in funzione del lato di lavoro. -- 2022/12/16 Implementato parametro Q_SIDE_ROUGH_TOOL anche per L20 -- 2022/12/21 Sistemata gestione SideMillAsSaw. -- 2023/01/19 In MakeMoreFaces -> MakeBySideMill aggiunto controllo che lo step finale non superi lo spessore utensile. -- 2023/01/24 In MakeByPocket gestito caso il caso in cui veniva applicata una fresatura con percorso vuoto. Ora viene rimossa e la tasca viene fatta con lama. -- 2023/02/06 Alla MakeDrillOnCorner aggiunto controllo distanza di sicurezza minima. -- 2023/02/16 Piccola correzione alla scelta utensile di svuotatura. -- 2023/02/21 Piccola correzione alla MakeByPocket. -- 2023/03/31 Correzione al calcolo della distanza di collisione nel caso in cui il gambo sia più piccolo dell'utensile. -- 2023/06/06 Limiti su svuotature tasche a L 4 facce come per L 3 facce. In svuotatura aggiunto recupero UserNotes da libreria per MaxOptSize. -- 2023/16/12 Corretto il recupero dati utensile che, in alcune funzioni, puntava all'utensile errato. -- 2023/06/29 Se forzata lavorazione laterale permetto l'uso del truciolatore solo se non è una tasca chiusa. -- 2023/07/19 Correzioni e modifiche ad antischeggia con lama (#1351). -- 2023/08/01 Aggiunta gestione rinvio angolare solo per tasche 5 lati, da sotto e perfettamente verticali. -- 2023/08/02 Piccola correzione al calcolo della distanza di sicurezza in base al gambo dell'utensile. -- 2023/08/02 Corretto incremento della profondità pari al raggio utensile per tunnel con sega a catena. -- 2023/08/10 Modificata scelta SCC per tasche in Y+/- in coda o quasi (anche per relativi antischeggia con lama). -- 2023/09/12 In MakeByPockets gestito correttamente il ritorno nil di GetUShapeWidth. -- 2023/09/26 In MakeLongMoreFaces migliorata gestione spezzatura di Tunnel. -- 2023/09/26 Modificata chiamata a GetFaceWithMostAdj. -- 2023/09/27 In MakeMoreFaces e Classify refactoring della gestione scanalatura chiusa. -- 2023/09/27 In MakeLongMoreFaces aggiunto Topology.Classify alla Proc creata. -- 2023/10/03 In MakePocket aggiunto messaggio in caso si rovini il pezzo successivo. -- 2023/10/25 In LapJoint 2 facce longitudinali faccio di lama solo se taglio completamente. Altrimenti fresa. -- 2023/10/27 In Lapjoint 2 facce con angolo > 90 deg, se forzata fresa, si svuota la faccia principale e si lavora poi la faccia inclinata. -- 2023/11/03 Aggiunta MakeStaircaseStep per lavorazione con fresa + lama di gradini scala. Smusso opzionale. -- 2023/11/06 In MakeStaircaseStep gestito ritorno. -- 2023/11/06 Migliorie per lavorazione con AngularTransmission con FAST. -- 2023/11/30 Calcolo elevazione velocizzato e centralizzato tramite la funzione GetFaceElevation. -- 2023/12/01 In MakeMoreFaces, nelle OpenPocket, ammesso utensile con diametro fino a 3 volte la dimensione della tasca (era 2). -- 2023/12/06 In VerifySideMillAsSaw, se SIDEDEPTH non definita, viene calcolata. -- 2024/01/18 Implementata GetBlockedAxis che gestisce gli assi bloccati per tutti i tipi di utensile. -- 2024/01/22 Implementata gestione seghe a catena multiple. -- 2024/01/31 In tagli con sega a catena ora si considera l'ingombro della testa per il calcolo della massima profondità. -- Aggiunta funzione GetToolEntryAngle per determinare l'angolo di ingresso dell'utensile nella faccia. -- 2024/02/08 Ora i rabbet lungo X che guardano in basso sono sempre fatti con fresatura di lato per evitare di ruotare. -- 2024/02/13 In MakeMoreFaces escluse le Groove 2 facce dalla gestione Special3faces. -- 2024/02/22 Migliorato calcolo area non pinzabile in testa HCING e coda TCING -- Rimosso un caso di controllo per HCING/TCING -- 2024/02/29 In MakeMoreFaces passato b3Solid alla funzione ManageAntiSplintByMill -- 2024/02/29 In lapjoint 2 facce (TestTwoFacesDownHead) migliorata la scelta della lama da sotto. -- 2024/03/01 Migliorata VerifyPocket. -- 2024/03/04 Implementato attacco esterno se tasca 4 facce sulla coda ma nessun pezzo successivo. -- 2024/03/15 Correzione a calcolo ingombro per feature basse e lunghe dalla testa. -- 2024/04/02 In ForceSideMill escluso caso 4 facce senza possibilità di ingresso lungo Y. -- 2024/04/11 Aggiunta strategia SawPlusChain per lavorazione tasche con lama + sega a catena opzionale. Attivata con Q11. -- 2024/04/15 In SideMillAsSaw gestito anche rabbet -- 2024/04/17 In MakeMoreLongFaces corretto calcolo divisione in parti per evitare problemi di ceil con interi perfetti (ceil(3) = 3 o 4??) -- 2024/04/22 In IsTailFeature se LapJoint a 2 facce che taglia intera sezione, deve essere fatto dopo taglio di coda -- 2024/06/18 In MakeByMillAsSaw si cerca di orientare il motore verso il lato più vicino (rispetto a dove è la feature) -- 2024/06/28 In VerifySideMillAsSaw modificato criterio ricerca utensile in base a normale della faccia -- 2024/07/04 In IsTailFeature controllo per spostare lapjoint dopo taglio di separazione per lavorazioni tipo BH -- 2024/09/03 In MakeLongMoreFaces si aggiunge faccia di fondo anche per topologia Groove passante a 3 facce -- Tabella per definizione modulo local ProcessLapJoint = {} -- Include require( 'EgtBase') local BL = require( 'BeamLib') local Fbs = require( 'FacesBySaw') local Fbp = require( 'FaceByPocket') local Cut = require( 'ProcessCut') local DoubleCut = require( 'ProcessDoubleCut') local LongCut = require( 'ProcessLongCut') local Long2Cut = require( 'ProcessLongDoubleCut') local Topology = require( 'FeatureTopology') EgtOutLog( ' ProcessLapJoint started', 1) -- Dati local BD = require( 'BeamData') local ML = require( 'MachiningLib') local WHISK_OFFS = 0.1 local WHISK_SAFE = 5 local MIN_LEN_CUT = 30 -- variabili assegnazione parametri Q local Q_FORCE_BLADE = '' -- i local Q_DEPTH_CHAMFER = '' -- d local Q_ONLY_CHAMFER = '' -- i local Q_USE_MILL = '' -- i local Q_USE_ROUGH_TOOL = '' -- i local Q_BORE_ON_CORNER = '' -- 1 local Q_CONTOUR_SMALL_TOOL = '' -- i local Q_ONLY_CONTOUR = '' -- i local Q_SIDE_ROUGH_TOOL = '' -- i local Q_ANTISPLINT_TYPE = '' -- i local Q_BLADE_ON_ALONG_FACE = '' -- i local Q_MAX_ELEVATION = '' -- d local Q_SAW_PLUS_CHAIN = '' -- i local Q_FORCE_CHAINSAW = '' -- i local Q_CHAINSAW_FROM_SIDE = '' -- i local Q_CONVENTIONAL_MILLING = '' -- i local Q_CLEAN_CORNER = '' -- 1 local Q_FLOATING_AGGREGATE = '' -- i local Q_DIM_STRIP = '' -- d -- variabile smussi local bMadeChamfer -- Settaggi interni local bTrySidePocketAtFirst = true --------------------------------------------------------------------- -- Riconoscimento della feature function ProcessLapJoint.Identify( Proc) if Proc.bForceMill then return true else return ( (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 16) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 17) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 20) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 25) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 30) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 32) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 33) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 34) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 90) or ( Proc.Grp == 4 and Proc.Prc == 37) or ( Proc.Grp == 4 and Proc.Prc == 39) or ( Proc.Grp == 4 and Proc.Prc == 120)) end end --------------------------------------------------------------------- local function AssignQIdent( Proc) -- reset assegnazione parametri Q Q_FORCE_BLADE = '' Q_DEPTH_CHAMFER = '' Q_ONLY_CHAMFER = '' Q_USE_MILL = '' Q_USE_ROUGH_TOOL = '' Q_BORE_ON_CORNER = '' Q_CONTOUR_SMALL_TOOL = '' Q_ONLY_CONTOUR = '' Q_SIDE_ROUGH_TOOL = '' Q_ANTISPLINT_TYPE = '' Q_MAX_ELEVATION = 'Q10' Q_STAIRCASE = '' Q_SAW_PLUS_CHAIN = 'Q11' Q_FORCE_CHAINSAW = 'Q12' -- TODO da riportare a Q13 quando è sistemata la gestione del movimento in macchina nell'attacco laterale Q_CHAINSAW_FROM_SIDE = 'Q999' Q_CONVENTIONAL_MILLING = '' Q_CLEAN_CORNER = '' Q_FLOATING_AGGREGATE = '' if ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 16 then Q_FORCE_BLADE = 'Q01' -- i Q_DEPTH_CHAMFER = 'Q04' -- d Q_ONLY_CHAMFER = 'Q05' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 17 then Q_DEPTH_CHAMFER = 'Q01' -- d Q_ONLY_CHAMFER = 'Q02' -- i Q_USE_MILL = 'Q03' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 20 then Q_DEPTH_CHAMFER = 'Q01' -- d Q_USE_MILL = 'Q02' -- i Q_USE_ROUGH_TOOL = 'Q03' -- i Q_SIDE_ROUGH_TOOL = 'Q04' -- i Q_BORE_ON_CORNER = 'Q06' -- i Q_STAIRCASE = 'Q09' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 25 then Q_BORE_ON_CORNER = 'Q01' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 30 then Q_CONTOUR_SMALL_TOOL = 'Q01' -- i Q_ONLY_CONTOUR = 'Q02' -- i Q_SIDE_ROUGH_TOOL = 'Q03' -- i Q_BLADE_ON_ALONG_FACE = 'Q04' -- i Q_ANTISPLINT_TYPE = 'Q06' -- i Q_DEPTH_CHAMFER = 'Q07' -- d Q_CONVENTIONAL_MILLING = 'Q14' -- i Q_CLEAN_CORNER = 'Q15' -- i Q_FLOATING_AGGREGATE = 'Q16' -- i Q_DIM_STRIP = 'Q17' -- d elseif ( Proc.Grp == 1 or Proc.Grp == 2) and Proc.Prc == 30 then Q_BLADE_ON_ALONG_FACE = 'Q04' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 32 then Q_SIDE_ROUGH_TOOL = 'Q01' -- i Q_CONTOUR_SMALL_TOOL = 'Q02' -- i Q_ANTISPLINT_TYPE = 'Q06' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 33 then Q_ANTISPLINT_TYPE = 'Q06' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 34 then Q_CONTOUR_SMALL_TOOL = 'Q01' -- i Q_USE_MILL = 'Q02' -- i Q_ANTISPLINT_TYPE = 'Q06' -- i elseif ( Proc.Grp == 4) and Proc.Prc == 37 then Q_ANTISPLINT_TYPE = 'Q06' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i elseif ( Proc.Grp == 4) and Proc.Prc == 39 then Q_CONTOUR_SMALL_TOOL = 'Q01' -- i Q_USE_MILL = 'Q02' -- i Q_ANTISPLINT_TYPE = 'Q06' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i elseif ( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 90 then Q_ANTISPLINT_TYPE = 'Q03' -- i Q_SIDE_ROUGH_TOOL = 'Q04' -- i Q_CONVENTIONAL_MILLING = 'Q14' -- i end -- le altre features gestite non hanno parametri Q end --------------------------------------------------------------------- local function EvaluateQParam( Proc) -- verifico che lo smusso sia richiesto local nChamfer = 0 local dDepth = EgtGetInfo( Proc.Id, Q_DEPTH_CHAMFER, 'd') or 0 if dDepth > 0 then nChamfer = 1 end -- verifico se posso fare solo lo smusso if EgtGetInfo( Proc.Id, Q_ONLY_CHAMFER, 'i') == 1 then if dDepth > 0 then nChamfer = nChamfer + 1 -- altrimenti se non ho l'affondamento esco else local sErr = 'Error : no chamfer depth' EgtOutLog( sErr) return -1, dDepth, sErr end end -- verifico se devo usare lama invece della sega-catena -- 2020-03-20 forzata abilitazione uso lama se parametro Q non è presente -- xxxx-xx-xx tolta la preferenza alla lama in favore della sega-catena per un caso particolare -- 2021-02-15 re-introdotta la preferenza alla lama se non c'è il parametro Q. Rimane da -- implementare un ulteriore parametro per poter scegliere di prediligere la sega-catena o no al fine di continuare -- a cambiare il codice per gestire il caso particolare local bForceUseBlade = false if #Q_FORCE_BLADE == 0 or EgtGetInfo( Proc.Id, Q_FORCE_BLADE, 'i') == 1 then bForceUseBlade = true end return nChamfer, dDepth, sErr, bForceUseBlade end --------------------------------------------------------------------- local function TestElleShape3( Proc, bNotProc) -- se non passato il Proc vero e proprio local nNumFacet local nProcId if bNotProc then nProcId = Proc nNumFacet = EgtSurfTmFacetCount( nProcId) else nProcId = Proc.Id nNumFacet = Proc.Fct end -- valida solo nel caso di tre facce if nNumFacet ~= 3 then return false end -- determino se L con una faccia terminale o U con tre facce local bIsL = true for i = 1, 3 do local vFacAdj = EgtSurfTmFacetAdjacencies( nProcId, i - 1)[1] -- le conto local nCount = 0 for j = 1, #vFacAdj do if vFacAdj[j] >= 0 then nCount = nCount + 1 end end if nCount == 1 then bIsL = false break end end return bIsL end --------------------------------------------------------------------- local function TestElleShape4( Proc) -- valida solo nel caso di quattro facce if Proc.Fct ~= 4 then return false end -- determino se L con due facce terminali o O local nFac3Adj = 0 local dMinArea3 = GEO.INFINITO * GEO.INFINITO local dMaxArea2 = 0 for i = 1, 4 do local vFacAdj = EgtSurfTmFacetAdjacencies( Proc.Id, i - 1)[1] -- le conto local nCount = 0 for j = 1, #vFacAdj do if vFacAdj[j] >= 0 then nCount = nCount + 1 end end local _, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, i - 1, GDB_ID.ROOT) local dArea = dH * dV if nCount == 2 then dMaxArea2 = max( dMaxArea2, dArea) elseif nCount == 3 then dMinArea3 = min( dMinArea3, dArea) nFac3Adj = nFac3Adj + 1 end end if nFac3Adj ~= 2 then return false end -- verifico se L profonda oppure lunga if dMinArea3 < 2 * dMaxArea2 then return 1 else return 2 end end --------------------------------------------------------------------- local function VerifyChainSaw( Proc, dMinDim, dMaxDim, dDepth) local bUseChainSaw = false local sMchFind = 'Sawing' -- prendo la prima sega a catena lunga a sufficienza local sSawing = ML.FindSawing( sMchFind, dDepth, true) -- se non trovo alcuna sega a catena lunga a sufficienza, accetto di non arrivare sul fondo della tasca if not sSawing then sSawing = ML.FindSawing( sMchFind, nil, nil, 'Longest') end local dMaxMat = 0 local dSawCornerRad = 0 local dSawThick = 0 local dMaxDepth = 200 local dSawWidth = 0 -- se non trova una lavorazione di sawing esco if not sSawing then return bUseChainSaw else -- recupero i dati dell'utensile local dToolLength = 0 local dSawWidth = 75 if EgtMdbSetCurrMachining( sSawing) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dToolLength = EgtTdbGetCurrToolParam( MCH_TP.LEN) or dToolLength dMaxMat = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMaxMat dSawWidth = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dSawWidth dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick dSawCornerRad = EgtTdbGetCurrToolParam( MCH_TP.CORNRAD) or dSawCornerRad dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end if dSawThick < dMinDim + 10 * GEO.EPS_SMALL and dSawWidth < dMaxDim + 10 * GEO.EPS_SMALL then bUseChainSaw = true end end end return bUseChainSaw, sSawing, dMaxMat, dSawCornerRad, dSawThick, dMaxDepth, dSawWidth end --------------------------------------------------------------------- local function VerifyPocket( Proc, dDiam, dDepth, dMaxTotLen, sMchFindMaster, bPocketUp, bPocketDown) -- tipo di svuotatura local sMchFind = EgtIf( sMchFindMaster and #sMchFindMaster > 0, sMchFindMaster, 'Pocket') -- ricerca della svuotatura local sPocketing if dDepth then sPocketing = ML.FindPocketing( sMchFind, dDiam, dDepth, dMaxTotLen, bPocketUp, bPocketDown) or ML.FindPocketing( sMchFind, dDiam, 0, dMaxTotLen, bPocketUp, bPocketDown, nil, nil, 'Longest') or ML.FindPocketing( sMchFind, dDiam, 0, dMaxTotLen) else sPocketing = ML.FindPocketing( sMchFind, dDiam, 0, dMaxTotLen) end if not sPocketing then return false end -- recupero i dati dell'utensile local bUsePocketing = false local dMaxDepth = 0 local dToolDiam = 0 if EgtMdbSetCurrMachining( sPocketing) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dToolDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dToolDiam dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end bUsePocketing = true end return bUsePocketing, sPocketing, dMaxDepth, dToolDiam end --------------------------------------------------------------------- local function VerifyBHSideMill( Proc, bIsU, bIsL, bSinglePart, bPrevBhSideMill, b3Raw) -- se non feature BlockHausHalfLap e non abilitato parametro Q per lavorarlo di fianco e non macchina BH esco local nUseSideTool = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 if Proc.Prc ~= 37 and not BD.BH_MACHINE and ( nUseSideTool == 0 or ( nUseSideTool == 4 and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right))) then return false end -- recupero l'ingombro della trave local nPartId = EgtGetParent( EgtGetParent( Proc.Id) or GDB_ID.NULL) local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then return false end -- verifico se la funzione è lanciata da IsTailFeature o Classify if bSinglePart == nil then -- se lunghezza non richiede spezzatura setto la variabile bSinglePart if not( ( Proc.Box:getDimX() > BD.LONGCUT_MAXLEN) or ( Proc.Box:getDimX() > 0.8 * b3Solid:getDimX() and Proc.Box:getDimX() > BD.LONGCUT_ENDLEN)) then bSinglePart = true end end -- determino se U o L(anche con 1 o 2 facce di terminazione) bIsU = ( bIsU or ( Proc.Fct == 3 and not TestElleShape3( Proc))) bIsL = ( bIsL or ( Proc.Fct == 2 or TestElleShape3( Proc) or TestElleShape4( Proc) == 2)) -- le facce devono contenere X e quelle di chiusura devono essere perpendicolari a X local bStopY, bStopZ if not Proc.TopologyLongName then Topology.Classify( Proc, b3Raw) end for i = 1, Proc.Fct do local vtN = EgtSurfTmFacetNormVersor( Proc.Id, i-1, GDB_ID.ROOT) -- permessa U passante non parallela agli assi principali if abs( vtN:getX()) > 0.001 and abs( vtN:getX()) < 0.999962 and Proc.TopologyLongName ~= "Groove-Through-RightAngles-NotParallel-3" then return false end if abs( vtN:getY()) > 0.866 then bStopY = true end if abs( vtN:getZ()) > 0.866 then bStopZ = true end end if bStopY and bStopZ then return false end -- se non U o L o singola faccia di multipla, non accettata if not ( ( bIsU or bIsL or ( Proc.Fct == 1 and not bSinglePart)) and Proc.Box:getDimX() <= BD.LONGCUT_MAXLEN) then return false end -- se risultato precedente di passo multiplo negativo, riporto il risultato del passo precedente if bPrevBhSideMill ~= nil and not bPrevBhSideMill then return false end -- recupero la lavorazione local sMilling = ML.FindMilling( 'BHSideMill') if not sMilling then return false end -- recupero i dati dell'utensile local dToolLength = 0 local dToolDiam = 0 local dToolMaxDepth = 0 local dToolThick = 0 local dToolFreeLen = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dToolLength = EgtTdbGetCurrToolParam( MCH_TP.LEN) or dToolLength dToolDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dToolDiam local dToolThDiam = EgtTdbGetCurrToolThDiam() or 150 if ( EgtTdbGetCurrToolParam( MCH_TP.TYPE) & MCH_TF.SAWBLADE) ~= 0 then dToolMaxDepth = EgtTdbGetCurrToolMaxDepth() or dToolMaxDepth dToolThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dToolThick dToolFreeLen = dToolLength else dToolMaxDepth = EgtTdbGetCurrToolValInNotes( MCH_TP.USERNOTES, 'SIDEDEPTH', 'd') or 0.5 * ( dToolDiam - dToolThDiam) dToolThick = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) dToolFreeLen = EgtTdbGetCurrToolMaxDepth() or dToolFreeLen end end end -- verifico se abbastanza larga (oppure L) rispetto all'utensile if Proc.Box:getDimX() < dToolThick - 15 * GEO.EPS_SMALL and not bIsL then return false end -- limiti trasversali local dDepth = min( Proc.Box:getDimY(), Proc.Box:getDimZ()) if dDepth > dToolMaxDepth then return false end -- limiti longitudinali local dMinXF = Proc.Box:getMin():getX() local dMaxXF = Proc.Box:getMax():getX() local dMinT = b3Solid:getMin():getX() local dMaxT = b3Solid:getMax():getX() -- determino se è più vicino alla testa o alla coda (con offset per evitare problemi a metà) local bHeadDir = ( dMaxT - dMinXF) < ( dMaxXF - dMinT) + 50 local bHead = bHeadDir -- verifico se raggiungibile con la testa senza collisioni local bUseBHSideMill = EgtIf( bHead, ( dMaxT - dMinXF), ( dMaxXF - dMinT)) < dToolFreeLen -- se diametro utensile maggiore della testa if BD.HEAD_DIM_FOR_BH and dToolDiam - 2 * dDepth > BD.HEAD_DIM_FOR_BH then bHead = true bUseBHSideMill = true end return bUseBHSideMill, bHead, bHeadDir, sMilling, dToolThick, dToolDiam end --------------------------------------------------------------------- local function VerifySideMillAsSaw( Proc, nAddGrpId, vtN, dDiam, dFacElev) -- Verifico sia feature L016, L030, L032, L039 if not ( Proc.Prc == 16 or Proc.Prc == 30 or Proc.Prc == 32 or Proc.Prc == 39) then return false end -- Verifico sia gola lungo X con 3 facce più eventuali terminali local nTestId = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL local bNewIsU local nFaces = EgtSurfTmFacetCount( nTestId) while nFaces >= 3 do local bDeleteFace local nInt = 0 while not bDeleteFace and nInt < nFaces do nInt = nInt + 1 local b3Facet = EgtSurfTmGetFacetBBoxGlob( nTestId, nInt-1, GDB_BB.STANDARD) local vtN = EgtSurfTmFacetNormVersor( nTestId, nInt-1, GDB_ID.ROOT) -- se dimensione faccia sulla X if b3Facet:getDimX() < 1 or abs( vtN:getX()) > 0.1 then EgtSurfTmRemoveFacet( nTestId, nInt-1) bDeleteFace = true end end nFaces = EgtSurfTmFacetCount( nTestId) -- se non ho cancellato una faccia faccio il test per forma ad U if not bDeleteFace then -- ottengo il numero di facce rimanenti bNewIsU = ( nFaces == 3 and not TestElleShape3( nTestId, true)) -- verifico che gola allineata su X if bNewIsU then local vtN1 = EgtSurfTmFacetNormVersor( nTestId, 0, GDB_ID.ROOT) bNewIsU = ( abs( vtN1:getX()) < 0.01) end -- esco dal ciclo break end end -- cancello la copia del percorso EgtErase( nTestId) -- eseguo test if not bNewIsU and not ( Proc.TopologyLongName == 'Rabbet-Through-RightAngles-Parallel-2') then return false end -- Verifico sia abbastanza lunga if not (( Proc.TotBox and Proc.TotBox:getDimX() > ( BD.MIN_LEN_LAMELLO or 1000)) or ( not Proc.TotBox and Proc.Box:getDimX() > ( BD.MIN_LEN_LAMELLO or 1000))) then return false end -- Recupero la lavorazione local bDownHead local sMillingOnSide -- se ho testa da sotto e lap-joint diretto verso il basso, cerco prima testa sotto if BD.DOWN_HEAD and vtN:getZ() < BD.NZ_MINA then bDownHead = true sMillingOnSide = ML.FindMilling( 'SideMillAsBlade_H2', nil, nil, nil, nil, not bDownHead, bDownHead) end -- se non ha trovato su testa sotto, cerco su testa sopra if not sMillingOnSide then bDownHead = false sMillingOnSide = ML.FindMilling( 'SideMillAsBlade', nil, nil, nil, nil, not bDownHead, bDownHead) end if not sMillingOnSide then return false end -- Recupero i dati dell'utensile local dToolDiamOnSide = 0 local dThickMillOnSide = 0 local dMaxDepthOnSide = 0 local dTDiamStem = 50 if EgtMdbSetCurrMachining( sMillingOnSide) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dToolDiamOnSide = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dToolDiamOnSide dThickMillOnSide = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dThickMillOnSide dTDiamStem = EgtTdbGetCurrToolParam( MCH_TP.STEMDIAM) or dTDiamStem dMaxDepthOnSide = min( EgtTdbGetCurrToolValInNotes( MCH_TP.USERNOTES, 'SIDEDEPTH', 'd') or 999, 0.5 * ( dToolDiamOnSide - dTDiamStem)) or dMaxDepthOnSide end end local bSpecialMillOnSide = ( dDiam > dThickMillOnSide - 10 * GEO.EPS_SMALL and dFacElev < dMaxDepthOnSide + 10 * GEO.EPS_SMALL) -- Restituisco i dati return bSpecialMillOnSide, sMillingOnSide, dThickMillOnSide, dToolDiamOnSide, dMaxDepthOnSide end --------------------------------------------------------------------- local function GetFaceAdj( Proc, nFacInd, dH, dV) -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] if not vAdj or #vAdj == 0 then local sErr = 'Error : main face without adjacencies' return -1, sErr end EgtOutLog( 'Adjac=' .. table.concat( vAdj, ','), 4) -- Riordino le dimensioni per avere dH > dV if dH < dV then dH, dV = dV, dH end -- Cerco una faccia adiacente alla principale sul lato lungo local nFacAdj for i = 1, #vAdj do if vAdj[i] >= 0 then local _, ptP1, ptP2, _ = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) local dLen = dist( ptP1, ptP2) if dLen > 0.5 * dH then nFacAdj = vAdj[i] EgtOutLog( string.format( 'Adjac=%d Len=%.3f H=%.3f V=%.3f', vAdj[i], dLen, dH, dV), 4) break end end end if not nFacAdj then local sErr = 'Error : main face without long adjacent face' return -1, sErr end return nFacAdj end --------------------------------------------------------------------- local function UpdateEncumbrance( Proc, nRawId, b3Raw, b3Solid) -- verifico siano una o due facce if Proc.Fct > 2 then return end -- eventuale segnalazione ingombro di testa o coda local dMinHIng = min( 0.5 * BD.VICE_MINH, 0.5 * b3Raw:getDimZ()) local dMinZ = max( BD.MIN_HEIGHT, 0.35 * b3Raw:getDimZ()) -- calcolo punto massimo in Z fino a dove considerare il pinzaggio. Minimo tra pinzaggio massimo e altezza pezzo local dMaxHZ = b3Raw:getMin():getZ() + min( BD.VICE_MAXH or BD.MAX_HEIGHT, b3Raw:getDimZ()) -- punto massimo in Z considerando anche la Z della feature local dMaxHZFeat = min( dMaxHZ, Proc.Box:getMax():getZ()) -- dimensione Z del pinzaggio (differenza massima Z pinzabile e box feature) local dDeltaZClamp = ( ( dMaxHZ - b3Raw:getMin():getZ()) - max( 0, dMaxHZFeat - Proc.Box:getMin():getZ())) -- se pinzaggio minimo è come il massimo (oppure come l'altezza massima del pezzo) significa che è verticale local bIsVertClamps = BD.VICE_MINH > BD.MAX_HEIGHT - 100 * GEO.EPS_SMALL -- condizioni per limitare pinzaggio testa/coda local bUpdateIng = true -- se dimensione del box della feature maggiore di metà pinzaggio minimo o metà spessore pezzo bUpdateIng = bUpdateIng and Proc.Box:getDimZ() > dMinHIng -- se la feature si trova più in basso del minimo pinzabile in Z o il 35% dello spessore pezzo bUpdateIng = bUpdateIng and Proc.Box:getMin():getZ() < b3Raw:getMin():getZ() + dMinZ -- se feature è al di sotto del pinzaggio massimo bUpdateIng = bUpdateIng and Proc.Box:getMin():getZ() < dMaxHZ -- se ho le morse verticali, o se la feature è in centro o verso alto, controllo se non prendo abbastanza. if bIsVertClamps or ( Proc.Box:getMin():getZ() - b3Raw:getMin():getZ()) > BD.MIN_HEIGHT then bUpdateIng = bUpdateIng and dDeltaZClamp < BD.VICE_MINH end if bUpdateIng then if Proc.Head then local dOffs = b3Solid:getMax():getX() - Proc.Box:getMin():getX() -- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse if not bIsVertClamps and dDeltaZClamp > BD.VICE_MINH and BD.VICE_MAXH then dOffs = min( dOffs, BD.VICE_MAXH - BD.VICE_MINH) end BL.UpdateHCING( nRawId, dOffs) elseif Proc.Tail then local dOffs = Proc.Box:getMax():getX() - b3Solid:getMin():getX() -- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse if not bIsVertClamps and dDeltaZClamp > BD.VICE_MINH and BD.VICE_MAXH then dOffs = min( dOffs, BD.VICE_MAXH - BD.VICE_MINH) end BL.UpdateTCING( nRawId, dOffs) elseif Proc.Box:getCenter():getX() > b3Solid:getCenter():getX() then local dOffs = b3Solid:getMax():getX() - Proc.Box:getMin():getX() local dDist = b3Solid:getMax():getX() - Proc.Box:getMax():getX() -- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse if not bIsVertClamps and dDeltaZClamp > BD.VICE_MINH and BD.VICE_MAXH then dOffs = min( dOffs, BD.VICE_MAXH - BD.VICE_MINH) end BL.UpdateHCING( nRawId, dOffs, dDist) end end end --------------------------------------------------------------------- -- Verifica se feature di testa function ProcessLapJoint.IsHeadFeature( Proc, b3Raw, dCurrOvmH) -- se una sola faccia if Proc.Fct == 1 then local _, vtN0 = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) if vtN0:getX() > 0.1 then return true end end -- verifico se è in testa if Proc.Box:getMax():getX() < b3Raw:getMax():getX() - dCurrOvmH - BD.MAX_DIST_HTFEA then return false end -- la sua lunghezza non deve superare il massimo e 60% della lunghezza della trave if Proc.Box:getDimX() > min( BD.MAX_LEN_HTFEA, 0.6 *b3Raw:getDimX()) then return false end -- recupero identificativo del pezzo local nPartId = EgtGetParent( EgtGetParent( Proc.Id) or GDB_ID.NULL) -- se una o due facce e interessa veramente la testa, allora di testa if Proc.Fct <= 2 then local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if Proc.Box:getMax():getX() > b3Solid:getMax():getX() - 1. then return true elseif Proc.Box:getMax():getX() < b3Solid:getMax():getX() - 5. then return false end end -- deve avere la normale principale diretta verso la testa Topology.Classify( Proc, b3Raw) local nFacInd, dElev = BL.GetFaceWithMostAdj( Proc, nPartId) local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) if vtN and vtN:getX() < 0.499 then return false elseif Proc.Fct >= 5 then return true end -- deve occupare la maggior parte dell'area if Proc.Box:getDimY() > 0.75 * b3Raw:getDimY() or Proc.Box:getDimZ() > 0.75 * b3Raw:getDimZ() then return true end -- non è di testa return false end --------------------------------------------------------------------- -- Verifica se feature di coda function ProcessLapJoint.IsTailFeature( Proc, b3Raw) -- se una sola faccia if Proc.Fct == 1 then local vtN0 = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT) if vtN0:getX() < -0.1 then return true end end -- se interessa l'intera sezione if BL.IsFeatureCuttingEntireSection( Proc.Box, b3Raw:getDimY(), b3Raw:getDimZ()) then -- caso con due facce if Proc.Fct == 2 then -- verifico che il versore risultante delle normali delle due facce sia orientato verso X- local vtResult = ( EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT) + EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT)) vtResult:normalize() if vtResult:getX() < 0.5 then return true end end end -- in base al tipo di feature attribuisco il significato dei parametri Q AssignQIdent( Proc) -- se può essere fatto con utensile tipo lama local bUseBHSideMill, bHead, bHeadDir = VerifyBHSideMill( Proc, nil, nil, nil, nil, b3Raw) if bUseBHSideMill then Proc.HeadDir = bHeadDir end -- recupero box del pezzo local nPartId = EgtGetParent( EgtGetParent( Proc.Id) or GDB_ID.NULL) local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) -- verifico se è in coda local dEndDist = Proc.Box:getMin():getX() - b3Solid:getMin():getX() if ( dEndDist > BD.MAX_DIST_HTFEA) or bUseBHSideMill then if not( BD.BH_MACHINE) and bUseBHSideMill and ( Proc.Box:getMax():getX() - b3Solid:getMin():getX()) < 400 and b3Solid:getDimX() > BD.LEN_VERY_SHORT_PART then return true -- se Front Slot e pezzo abbastanza lungo si rimanda la decisione a più avanti elseif not ( ( Proc.Prc == 17) and ( b3Solid:getDimX() > ( BD.LEN_VERY_SHORT_PART or BD.LEN_SHORT_PART))) then return false end end -- se lunga come trave, oppure non è trave corta e la sua lunghezza supera il massimo o il 80% della lunghezza della trave if Proc.Box:getDimX() > b3Solid:getDimX() - 1 or ( b3Solid:getDimX() > BD.LEN_SHORT_PART and Proc.Box:getDimX() > min( BD.MAX_LEN_HTFEA, 0.8 * b3Solid:getDimX())) then return false end -- se interessa la coda, e pezzo lungo, si sposta dopo separazione if b3Solid:getDimX() > BD.LEN_SHORT_PART and Proc.AffectedFaces.Left and Proc.Fct >= 2 then return true end -- se una o due facce e interessa veramente la coda, allora di coda if Proc.Fct <= 2 then if Proc.Box:getMin():getX() < b3Solid:getMin():getX() + 1. then return true elseif Proc.Box:getMin():getX() > b3Solid:getMin():getX() + 5. then return false end end -- se forzata lavorazione con lama e feature aperta sulla coda potrei lavorare anche dalla coda if Proc.AffectedFaces.Left and ( EgtGetInfo( Proc.Id, Q_SAW_PLUS_CHAIN, 'i') or 0) > 0 then return true end -- deve avere la normale principale diretta verso la coda (oppure tunnel) Topology.Classify( Proc, b3Raw) local nFacInd, dElev, nFacInd2, dElev2 = BL.GetFaceWithMostAdj( Proc, nPartId) local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) if vtN and vtN:getZ() < BD.NZ_MINA and nFacInd2 then ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd2, GDB_ID.ROOT) nFacInd, nFacInd2 = nFacInd2, nFacInd dElev, dElev2 = dElev2, dElev end if not vtN or vtN:getX() > -0.001 or dEndDist + vtN:getX() * dElev > 0 then return false else return true end end --------------------------------------------------------------------- -- Classificazione della feature function ProcessLapJoint.Classify( Proc, b3Raw) -- se 1 faccia if Proc.Fct == 1 then return true, false -- se 2 facce elseif Proc.Fct == 2 then -- se può essere fatto con utensile tipo lama local bUseBHSideMill = VerifyBHSideMill( Proc, nil, nil, nil, nil, b3Raw) if bUseBHSideMill then return true, false end -- dati delle facce local vtN = {} vtN[1] = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT) vtN[2] = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT) -- verifico se è lavorabile solo dal basso local vtParX = vtN[1] ^ vtN[2] ; vtParX:normalize() local bParX = ( abs( vtParX:getX()) > 0.985) local bSmall = ( ( Proc.Head or Proc.Tail) and Proc.Box:getDimX() <= BD.GetMaxLenRidgeLapFromBottom( b3Raw:getDimZ())) or ( not ( Proc.Head or Proc.Tail) and bParX and Proc.Box:getDimY() <= BD.GetMaxLenRidgeLapFromBottom( b3Raw:getDimZ())) local bDown = ( vtN[1]:getZ() < BD.NZ_MINB and vtN[2]:getZ() < BD.NZ_MINB) or ( vtN[1]:getZ() < BD.NZ_MINA and vtN[2]:getZ() < 0.5 and ( vtN[2]:getZ() < -0.1 or not bSmall)) or ( vtN[2]:getZ() < BD.NZ_MINA and vtN[1]:getZ() < 0.5 and ( vtN[1]:getZ() < -0.1 or not bSmall)) -- se forzata la lavorazione con fresa di lato da parametro Q03=2/3 non devo ruotare; se rabbet lungo X che guarda in giù sempre fresatura di lato e quindi non ruoto local bIsRabbetAlongXTowardsBottom = ( Proc.TopologyLongName == 'Rabbet-Through-RightAngles-Parallel-2' and ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) and Proc.AffectedFaces.Bottom and Proc.AffectedFaces.Left and Proc.AffectedFaces.Right) local bForceSideMill = ( bIsRabbetAlongXTowardsBottom or ( EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'd') == 2 or EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'd') == 3)) bDown = ( bDown and not BD.DOWN_HEAD and not BD.TURN and not bForceSideMill) return true, bDown -- se più di 2 facce else local bClosedOrthoFaces local nDeletedFace -- recupero la faccia con il maggior numero di adiacenze e minor elevazione local nPartId = EgtGetParent( EgtGetParent( Proc.Id) or GDB_ID.NULL) local nFacInd, dElev, nFacInd2, dElev2 = BL.GetFaceWithMostAdj( Proc, nPartId) if not nFacInd or nFacInd < 0 then if nFacInd == -1 then bClosedOrthoFaces = nFacInd2 else return false end end -- se è presente il rinvio angolare con lavorazioni di tasca ed è una tasca perfettamente verticale da sotto, non ruoto if BD.ANG_TRASM and Proc.Fct >= 4 and not bClosedOrthoFaces then if AreOppositeVectorApprox( Proc.Face[nFacInd + 1].VtN, Z_AX()) and ( Proc.Fct >= 5 and ML.FindPocketing( 'Pocket_AT') or ( Proc.Fct < 5 and ML.FindPocketing( 'OpenPocket_AT'))) then return true, false end end -- se groove da sotto e possibile fresatura tipo SideMillAsBlade non ruoto if Proc.AllRightAngles and ( Proc.Topology == 'Groove' or Proc.Topology == 'Pocket') and not( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) and AreOppositeVectorApprox( Proc.Face[nFacInd + 1].VtN, Z_AX()) then -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end if VerifySideMillAsSaw( Proc, nAddGrpId, Proc.Face[nFacInd + 1].VtN, min( Proc.Face[nFacInd + 1].Height, Proc.Face[nFacInd + 1].Width) , Proc.Face[nFacInd + 1].Elevation) then Proc.OkFromBottom = true return true, false end end -- se scanalatura chiusa lavoro la faccia di fondo if Proc.Topology == 'Pocket' and ( Proc.IsParallel or Proc.AllRightAngles) and not bClosedOrthoFaces then nFacInd = Topology.GetFacesWithGivenAdjacencyNumber( Proc, nil, 4)[1] nFacInd2 = nil dElev = Proc.Face[ nFacInd + 1].Elevation end -- se facce formano un tunnel e sono ortogonali if bClosedOrthoFaces then -- ottengo le dimensioni del tunnel local dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) EgtErase( nSurfInt) -- verifico se può essere fatto con svuotatura if VerifyPocket( Proc, dDimMin) then return true, false elseif VerifyChainSaw( Proc, dDimMin, dDimMax) then return true, false else return false end else -- dati della faccia local rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) -- se può essere fatto con utensile tipo lama local bUseBHSideMill, _, _, _, _, dTDiam = VerifyBHSideMill( Proc, nil, nil, nil, nil, b3Raw) if bUseBHSideMill then if vtN:getZ() > -0.5 or b3Raw:getDimZ() - Proc.Box:getDimZ() < ( BD.MAX_DIST_BH_FROM_BOTTOM or 395) - dTDiam / 2 then return true, false else return true, true end -- altrimenti controllo se deve essere ruotato con le altre lavorazioni else -- cerco se c'è faccia adiacente sul lato più lungo local nFaceAdj = GetFaceAdj( Proc, nFacInd, dH, dV) or -1 local bIsL = ( Proc.Fct == 2 or TestElleShape3( Proc) or TestElleShape4( Proc) == 2) -- verifico se è lavorabile solo dal basso local bDown = ( vtN:getZ() < BD.NZ_MINA and not BD.DOWN_HEAD and not BD.TURN) -- se verso il basso, verifico se utilizzabile seconda faccia if bDown then local bIsU = ( Proc.Fct == 3 and not TestElleShape3( Proc)) -- se forzata la lavorazione con fresa di lato da parametro Q03=2/3 non devo ruotare local nSideRoughTool = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'd') local bForceSideMill = ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) and ( nSideRoughTool == 2 or nSideRoughTool == 3) and ( Proc.Fct == 3 or Proc.Fct == 4) if bForceSideMill then bDown = false elseif nFacInd2 and dElev2 < 160 and dElev2 < 2 * dElev then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd2, GDB_ID.ROOT) bDown = ( vtN2:getZ() < BD.NZ_MINB) elseif not nFacInd2 and bIsL and nFaceAdj >= 0 then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nFaceAdj, GDB_ID.ROOT) bDown = ( vtN2:getZ() < BD.NZ_MINB) end -- verifico se la faccia principale è sottosquadra, ha forma L ed esiste la faccia adiacente elseif vtN:getZ() < -0.2589 and bIsL and nFaceAdj >= 0 then -- box del pezzo local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) -- se più di 2 facce o il box della feature supera una certa distanza dalle teste allora controllo Nz della faccia ausiiaria if Proc.Fct > 2 or ( Proc.Box:getMax():getX() < b3Solid:getMin():getX() - 150) or ( Proc.Box:getMin():getX() > b3Solid:getMax():getX() + 150) then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nFaceAdj, GDB_ID.ROOT) bDown = ( vtN2:getZ() < BD.NZ_MINB) end end local bNoRotation = ( EgtGetInfo( Proc.Id, Q_CHAINSAW_FROM_SIDE, 'i') or 0) == 1 if bDown and bNoRotation then bDown = false end return true, bDown end end end end --------------------------------------------------------------------- -- Lavorazione con fresa --------------------------------------------------------------------- local function MakeOneFaceByMill( Proc, nPhase, nRawId, nPartId) -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero l'ingombro della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then local sErr = 'Error : part box not found' EgtOutLog( sErr) return false, sErr end -- verifico il numero di facce della tacca assert( ( Proc.Fct == 1), 'Error : MakeOneFaceByMill in LapJoint with ' .. tostring( Proc.Fct) .. ' faces') -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) -- verifico se orientata verso l'alto local bUp = ( vtN:getZ() >= BD.NZ_MINA) -- scelta faccia da lavorare local nFacInd = 0 -- recupero la lavorazione local sMilling = ML.FindMilling( 'BirdsMouth') if not sMilling then local sErr = 'Error : BirdsMouth not found in library' EgtOutLog( sErr) return false, sErr end -- inserisco la lavorazione di fresatura local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia e lato correzione if vtN:getX() > 0 then EgtSetMachiningParam( MCH_MP.FACEUSE, EgtIf( bUp, MCH_MILL_FU.ORTHO_LEFT, MCH_MILL_FU.PARAL_LEFT)) else EgtSetMachiningParam( MCH_MP.FACEUSE, EgtIf( bUp, MCH_MILL_FU.ORTHO_RIGHT, MCH_MILL_FU.PARAL_RIGHT)) end -- imposto lato di correzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.RIGHT) if not bUp then EgtSetMachiningParam( MCH_MP.INVERT, true) EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) end -- imposto posizione braccio porta testa if vtN:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- eventuale segnalazione ingombro di testa o coda UpdateEncumbrance( Proc, nRawId, b3Raw, b3Solid) return true end --------------------------------------------------------------------- local function MakeTwoFacesByMill( Proc, nPhase, nRawId, nPartId, bDownHead) -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero l'ingombro della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then local sErr = 'Error : part box not found' EgtOutLog( sErr) return false, sErr end -- verifico il numero di facce della tacca assert( ( Proc.Fct == 2), 'Error : MakeTwoFacesByMill in LapJoint with ' .. tostring( Proc.Fct) .. ' faces') -- recupero il parametro Q per uso fresa local nUseRM = EgtGetInfo( Proc.Id, Q_USE_MILL, 'i') -- recupero la lavorazione local sMilling if nUseRM and nUseRM == 1 then sMilling = ML.FindMilling( 'LongSmallCut', nil, nil, nil, nil, not bDownHead, bDownHead) else sMilling = ML.FindMilling( 'BirdsMouth', nil, nil, nil, nil, not bDownHead, bDownHead) end if not sMilling then local sErr = 'Error : LongSmallCut & BirdsMouth not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile local dTDiam = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam end -- dati delle facce local ptC = {} local vtN = {} ptC[1], vtN[1] = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) ptC[2], vtN[2] = EgtSurfTmFacetCenter( Proc.Id, 1, GDB_ID.ROOT) -- dati medi local ptM = ( ptC[1] + ptC[2]) / 2 -- verifico non siano orientate verso il basso local bFaceOk = {} bFaceOk[1] = ( vtN[1]:getZ() >= BD.NZ_MINB) bFaceOk[2] = ( vtN[2]:getZ() >= BD.NZ_MINB) if not bDownHead and not BD.TURN and not bFaceOk[1] and not bFaceOk[2] then local sErr = 'Error : LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end -- scelta faccia da lavorare local nFacInd -- se entrambe possibili if bFaceOk[1] and bFaceOk[2] then -- se in testa, scelgo quella orientata verso la testa if Proc.Head then if vtN[1]:getX() > vtN[2]:getX() then nFacInd = 0 else nFacInd = 1 end -- se altrimenti in coda, scelgo quella orientata verso la coda elseif Proc.Tail then if vtN[1]:getX() < vtN[2]:getX() then nFacInd = 0 else nFacInd = 1 end -- altrimenti, scelgo quella con la normale più perpendicolare all'asse trave (se uguali, quella verso X+) else if abs( abs( vtN[1]:getX()) - abs( vtN[2]:getX())) < GEO.EPS_SMALL then if ptM:getX() > b3Raw:getCenter():getX() then nFacInd = EgtIf( vtN[1]:getX() > vtN[2]:getX(), 0, 1) else nFacInd = EgtIf( vtN[1]:getX() < vtN[2]:getX(), 0, 1) end else nFacInd = EgtIf( abs( vtN[1]:getX()) < abs( vtN[2]:getX()), 0, 1) end end elseif bFaceOk[1] then nFacInd = 0 else nFacInd = 1 end local nOthInd = 1 - nFacInd local sName local nMchFId local nFaceUse -- se forzato uso fresa controllo se posso fare in una o più passate if nUseRM and nUseRM == 1 then -- prendo la larghezza della faccia local _, pPt1, pPt2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nOthInd, GDB_ID.ROOT) local dDistPoint = dist( pPt1, pPt2) local _, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) local dWidth = EgtIf( abs( dDistPoint - dH) < abs( dDistPoint - dV), dV, dH) -- se larghezza faccia maggiore diametro utensile aggiungo una lavorazione if dTDiam > 0 and dWidth > dTDiam then -- inserisco la lavorazione di fresatura sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_1' nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia e lato correzione nFaceUse = BL.GetNearestOrthoOpposite( vtN[nOthInd+1]) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto lato di correzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- tolgo l'inversione EgtSetMachiningParam( MCH_MP.INVERT, false) -- aggiungo offset laterale EgtSetMachiningParam( MCH_MP.OFFSR , (dTDiam/2)) -- imposto posizione braccio porta testa if vtN[nFacInd+1]:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end end end -- inserisco la lavorazione di fresatura sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia e lato correzione nFaceUse = BL.GetNearestOrthoOpposite( vtN[nOthInd+1]) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto lato di correzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- tolgo l'inversione EgtSetMachiningParam( MCH_MP.INVERT, false) -- imposto posizione braccio porta testa if vtN[nFacInd+1]:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- eventuale segnalazione ingombro di testa o coda UpdateEncumbrance( Proc, nRawId, b3Raw, b3Solid) return true end --------------------------------------------------------------------- local function MakePreCuts( Proc, nPhase, nRawId, nPartId, dOvmHead, b3Raw, nChamfer) -- se interessa l'intera sezione della trave, necessaria sgrossatura if nChamfer < 2 and Proc.Box:getDimY() > 0.9 * b3Raw:getDimY() and Proc.Box:getDimZ() > 0.9 * b3Raw:getDimZ() then -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo sgrossatura e la lavoro local AddId = EgtSurfTmConvexHullInBBox( nAddGrpId, Proc.Id, b3Raw, GDB_RT.GLOB) if AddId then EgtSetName( AddId, 'AddCut_' .. tostring( Proc.Id)) -- applico lavorazione local CutProc = { Id = AddId, Grp = Proc.Grp, Prc = Proc.Prc, Box = Proc.Box, Fct = Proc.Fct, Flg = Proc.Flg, Head = Proc.Head, Tail = Proc.Tail, CutId = Proc.CutId, TaskId = Proc.TaskId, PartId = Proc.PartId} CutProc.AffectedFaces = BL.GetProcessAffectedFaces( CutProc) local nCutFacet = EgtSurfTmFacetCount( AddId) if nCutFacet == 1 then return Cut.Make( CutProc, nPhase, nRawId, nPartId, dOvmHead) elseif nCutFacet == 2 then return DoubleCut.Make( CutProc, nPhase, nRawId, nPartId, dOvmHead) end end end return true end --------------------------------------------------------------------- local function MakeByMill( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dElev, dCollSic, bSpecialApp, sMillMaster, nFacInd2, dFacElev2) -- Cerco una faccia adiacente alla principale sul lato lungo local nFacAdj, sErr = GetFaceAdj( Proc, nFacInd, dH, dV) if nFacAdj < 0 then EgtOutLog( sErr) return false, sErr end -- Determino se estremi aperti o chiusi e faccia adiacente da aggiungere alla lavorazione local bOpenStart = false local bOpenEnd = false local vAdj2 = EgtSurfTmFacetAdjacencies( Proc.Id, nFacAdj)[1] EgtOutLog( 'Adj2=' .. table.concat( vAdj2, ' ,'), 3) local _, dH2, dV2 = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacAdj, GDB_ID.ROOT) -- Riordino le dimensioni per avere dH > dV if dH2 < dV2 then dH2, dV2 = dV2, dH2 end local nFacAdj2 for j = 1, #vAdj2 do if vAdj2[j] == nFacInd then -- Se non esiste faccia adiacente a lato precedente -> inizio aperto local i = EgtIf( j > 1, j - 1, #vAdj2) while vAdj2[i] == nFacInd do i = EgtIf( i > 1, i - 1, #vAdj2) end bOpenStart = ( vAdj2[i] < 0) -- Se non esiste faccia adiacente a lato successivo -> fine aperto local k = EgtIf( j < #vAdj2, j + 1, 1) while vAdj2[k] == nFacInd do k = EgtIf( k < #vAdj2, k + 1, 1) end bOpenEnd = ( vAdj2[k] < 0) end -- decommentare questa parte per concatenare due facce --if bSpecialApp and vAdj2[j] >= 0 then -- local _, ptP1, ptP2, _ = EgtSurfTmFacetsContact( Proc.Id, nFacAdj, vAdj2[j], GDB_ID.ROOT) -- local dLen = dist( ptP1, ptP2) -- if abs( dLen - dV2) < 10 * GEO.EPS_SMALL then -- nFacAdj2 = vAdj2[j] -- end --end end -- Recupero la lavorazione di fresa local sMilling if bSpecialApp then sMilling = sMillMaster else sMilling = ML.FindMilling( 'LongSmallCut') if not sMilling then sErr = 'Error : LongSmallCut not found in library' EgtOutLog( sErr) return false, sErr end end -- recupero i dati dell'utensile local dTDiam = 50 local dMaxMat = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam dMaxMat = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMaxMat end end -- Se massimo materiale utensile è molto inferiore dell'elevazione non faccio la lavorazione e do un warning if dMaxMat > 0 and dMaxMat + 15 < dElev + dCollSic then sWarn = 'Warning : skipped milling; elevation bigger than max tool depth' return true, sWarn, dMaxMat end -- Calcolo uso faccia local nFaceUse = BL.GetNearestParalOpposite( rfFac:getVersZ()) -- inserisco la lavorazione di fresatura local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria if nFacAdj2 then EgtSetMachiningGeometry( {{ Proc.Id, nFacAdj},{ Proc.Id, nFacAdj2}}) else EgtSetMachiningGeometry( {{ Proc.Id, nFacAdj}}) end -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.ADIR_YM if rfFac:getVersZ():getY() > 100 * GEO.EPS_ZERO then nSCC = MCH_SCC.ADIR_YP end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- lato di lavoro e direzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) EgtSetMachiningParam( MCH_MP.INVERT, true) -- tipo di attacco e uscita EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.LINEAR) -- imposto accorciamento iniziale/finale per estremi aperti/chiusi if bSpecialApp then -- applico gli allungamenti o accorciamenti considerando che la lavorazione è invertita if nFacAdj2 then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dTDiam / 2) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dTDiam / 2) else EgtSetMachiningParam( MCH_MP.STARTADDLEN, EgtIf( bOpenEnd, dTDiam / 2, - dTDiam / 2)) EgtSetMachiningParam( MCH_MP.ENDADDLEN, EgtIf( bOpenStart, dTDiam / 2, - dTDiam / 2)) -- confronto la faccia applicata nella lavorazione(faccia adiacente) con la seconda faccia passata nella funzione -- se corrispondono allora aggiungo una estensione nei lati chiusi pari all'elevazione della stessa faccia corrispondente if nFacAdj == nFacInd2 then if not bOpenStart then EgtSetMachiningParam( MCH_MP.LOPERP, dFacElev2) end if not bOpenEnd then EgtSetMachiningParam( MCH_MP.LIPERP, dFacElev2) end end end -- applico elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) else EgtSetMachiningParam( MCH_MP.STARTADDLEN, EgtIf( bOpenEnd, 0, - dTDiam / 2)) EgtSetMachiningParam( MCH_MP.ENDADDLEN, EgtIf( bOpenStart, 0, - dTDiam / 2)) end -- eseguo if not ML.ApplyMachining( true, false) then _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end return true, '', dTDiam end --------------------------------------------------------------------- local function ChooseCorner( Proc, nFacInd) -- Recupero le adiacenze della faccia principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] -- Cerco i corner tra le facce adiacenti alla principale local tFacAdj = {} for i = 1, #vAdj do if vAdj[i] >= 0 then for j = i+1, #vAdj do if vAdj[j] >= 0 then local _, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, vAdj[i], vAdj[j], GDB_ID.ROOT) if ptP1 and ptP2 and dAng < 0 then local dLen = dist( ptP1, ptP2) table.insert( tFacAdj, { vAdj[i], vAdj[j], dLen, ptP1, ptP2, dAng}) end end end end end -- Tra le linee dei corner determino la più lunga local dMaxLen = 0 local nIdLine for i = 1, #tFacAdj do if tFacAdj[i][3] > dMaxLen then nIdLine = i dMaxLen = tFacAdj[i][3] end end return dMaxLen, nIdLine, tFacAdj end --------------------------------------------------------------------- local function ChooseContour( Proc, nFacInd, bVerifyCorner) -- Recupero le adiacenze della faccia principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] -- Se richiesto, verifico che ci siano facce adiacenti consecutive (sicuramente con angolo) if bVerifyCorner then local bCorner = false for i = 1, #vAdj do local j = EgtIf( i > 1, i - 1, #vAdj) if vAdj[i] >= 0 and vAdj[j] >= 0 then bCorner = true break end end if not bCorner then return {} end end -- Cerco le facce adiacenti con angolo convesso local tFacAdjMain = {} for i = 1, #vAdj do if vAdj[i] >= 0 then local _, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) if ptP1 and ptP2 and dAng < 0 then local dLen = dist( ptP1, ptP2) table.insert( tFacAdjMain, { vAdj[i], dLen, ptP1, ptP2, dAng}) end end end return tFacAdjMain end --------------------------------------------------------------------- local function CheckToInvert( AuxId, bPositive) -- recupero versore estrusione local vtExtr = EgtCurveExtrusion( AuxId, GDB_ID.ROOT) -- faccio una copia del percorso local sParnt = EgtGetParent( AuxId) local nNewEntId = EgtCopyGlob( AuxId, sParnt) -- chiudo il percorso if EgtCloseCurveCompo( nNewEntId) then local vtMPlane, dDist, dArea = EgtCurveArea( nNewEntId) -- cancello percorso copia EgtErase( nNewEntId) if dArea and abs(dArea) > 1 then local frEnt = EgtGetGlobFrame( AuxId) if vtMPlane then vtMPlane:toGlob(frEnt) if dArea and dArea * ( vtMPlane * vtExtr) < 0 then if bPositive then return true end elseif dArea and dArea * ( vtMPlane * vtExtr) > 0 then if not bPositive then return true end end end end else -- cancello percorso copia EgtErase(nNewEntId) end return false end --------------------------------------------------------------------- --- ---@param Proc table la feature ---@param vtTool Vector3d il vettore direzione utensile ---@return number dAngle angolo tra la faccia d'ingresso e la direzione utensile ---@return number dSinAngle seno dell'angolo ---@return number dCosAngle coseno dell'angolo ---@return number|nil dTanAngle tangente dell'angolo local function GetToolEntryAngle( Proc, vtTool) local dSinAngle = -10 * GEO.EPS_SMALL local vtNorm if Proc.AffectedFaces.Top then vtNorm = Z_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end if Proc.AffectedFaces.Bottom then vtNorm = -Z_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end if Proc.AffectedFaces.Front then vtNorm = -Y_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end if Proc.AffectedFaces.Back then vtNorm = Y_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end if Proc.AffectedFaces.Left then vtNorm = -X_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end if Proc.AffectedFaces.Right then vtNorm = X_AX() dSinAngle = max( dSinAngle, vtTool * vtNorm) end local dCosAngle = sqrt( 1 - sqr( dSinAngle)) local dAngle = acos( dCosAngle) local dTanAngle if dAngle ~= 0 and dAngle ~= 90 then dTanAngle = sqrt( 1 - dCosAngle * dCosAngle) / dCosAngle end return dAngle, dSinAngle, dCosAngle, dTanAngle end --------------------------------------------------------------------- local function MakeRoundCleanCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, bMillDown, bDoubleSide) -- recupero la lavorazione senza considerare l'elevazione local sMilling = ML.FindMilling( 'SmallToolContour', nil, nil, nil, nil, not ( bMillDown and not bDoubleSide), bMillDown and not bDoubleSide) if not sMilling then local sMyWarn = 'Warning : SmallToolContour not found in library' EgtOutLog( sMyWarn) return true, sMyWarn end -- recupero i dati dell'utensile local dTDiam = 50 local dTMaxDepth = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam dTMaxDepth = EgtTdbGetCurrToolMaxDepth() or dTMaxDepth end end -- se il diametro trovato non è minore dei 3/4 del diametro utilizzato in precedenza, esco if dTDiam > ( 0.75 * dDiam) then local sMyWarn = 'Warning : tool diameter not enough small' EgtOutLog( sMyWarn) return true, sMyWarn end -- ottengo gli angoli dove applicare il percorso con fresa più piccola local _, _, tFacAdj = ChooseCorner( Proc, nFacInd) -- se non trovato nessun angolo interno valido esco if #tFacAdj == 0 then return true end -- recupero la normale della faccia di fondo local vtN1 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) -- se fresatura da sotto salto la lavorazione if vtN1:getZ() < BD.DRILL_VZ_MIN and not bMillDown then local sErr = 'Error : milling from bottom ' EgtOutLog( sErr) return false, sErr end -- ciclo su tutti gli angoli trovati local sMyWarn = '' for i = 1, #tFacAdj do local pAuxId = {} -- le 2 facce di contatto devono essere perpendicolari e non sottosquadra rispetto alla faccia di fondo local _, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, tFacAdj[i][1], GDB_ID.ROOT) local _, ptP1x, ptP2x, dAngx = EgtSurfTmFacetsContact( Proc.Id, nFacInd, tFacAdj[i][2], GDB_ID.ROOT) if dAng >= 0 or dAng < -90 - 10 * GEO.EPS_SMALL or dAngx >= 0 or dAngx < -90 - 10 * GEO.EPS_SMALL then goto continue end -- prendo la lunghezza di adiacenza delle due linee local dLen1 = dist( ptP1, ptP2) local dLen2 = dist( ptP1x, ptP2x) -- cerco il punto tra le 3 facce: nIdEndPoint local nIdIniPoint local nIdEndPoint if ptP1 and ptP2 then if dist( ptP1, tFacAdj[i][4]) < GEO.EPS_SMALL or dist( ptP2, tFacAdj[i][4]) < GEO.EPS_SMALL then nIdEndPoint = 4 nIdIniPoint = 5 elseif dist( ptP1, tFacAdj[i][5]) < GEO.EPS_SMALL or dist( ptP2, tFacAdj[i][5]) < GEO.EPS_SMALL then nIdEndPoint = 5 nIdIniPoint = 4 end end -- devo avere un punto comune if not nIdEndPoint then goto continue end -- calcolo lunghezza minima in base all'angolo tra le due pareti local dMinDist = (( dDiam / 2) / tan( ( 180 + tFacAdj[i][6]) / 2)) + 2 -- verifico che entrambe le linee siano maggiori delle lunghezza minima if dLen1 <= dMinDist or dLen2 <= dMinDist then sMyWarn = 'Warning : impossible make clean corner path' goto continue end -- se il punto finale corrisponde con il punto utilizzato in precedenza, uso l'altro local ptApPoint = EgtIf( dist( tFacAdj[i][nIdEndPoint], ptP1) < 10 * GEO.EPS_SMALL, ptP2, ptP1) -- prima linea local nAuxId = EgtLine( nAddGrpId, ptApPoint, tFacAdj[i][nIdEndPoint], GDB_RT.GLOB) -- calcolo arretramento local dTrimDist = dLen1 - dMinDist -- se arretramento valido if dTrimDist > 100 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dTrimDist, ptApPoint , GDB_RT.GLOB) end table.insert( pAuxId, nAuxId) -- se il punto finale corrisponde con il punto comune, uso l'altro ptApPoint = EgtIf( dist( tFacAdj[i][nIdEndPoint], ptP1x) < 10 * GEO.EPS_SMALL, ptP2x, ptP1x) -- seconda linea nAuxId = EgtLine( nAddGrpId, tFacAdj[i][nIdEndPoint], ptApPoint, GDB_RT.GLOB) -- calcolo arretramento dTrimDist = dLen2 - dMinDist -- se arretramento valido if dTrimDist > 100 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dTrimDist, ptApPoint , GDB_RT.GLOB) end table.insert( pAuxId, nAuxId) -- trasformo in percorso local AuxId if #pAuxId > 0 then AuxId = EgtCurveCompo( nAddGrpId, pAuxId, true) end -- deve esserci il percorso if not AuxId then sMyWarn = 'Warning : impossible make clean corner path' goto continue end -- modifico versore direzione EgtModifyCurveExtrusion( AuxId, vtN1, GDB_RT.GLOB) -- inserisco la lavorazione local sName = 'Clean_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchId = EgtAddMachining( sName, sMilling) if not nMchId then sMyWarn = 'Warning : impossible add machining ' .. sName .. '-' .. sMilling goto continue end -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- imposto lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP) end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- tipo attacco e uscita EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) -- annullo allungamenti iniziale e finale EgtSetMachiningParam( MCH_MP.STARTADDLEN, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) -- setto massimo affondamento possibile local dDepth = 0 if tFacAdj[i][3] > dTMaxDepth then dDepth = dTMaxDepth - tFacAdj[i][3] end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- setto se devo invertire il percorso local bInvert = CheckToInvert( AuxId, true) EgtSetMachiningParam( MCH_MP.INVERT, bInvert) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( ( tFacAdj[i][3] + dDepth), 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if ML.ApplyMachining( true, false) then _, sMyWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) end -- altrimenti lavorazione non applicata else _, sMyWarn = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) end ::continue:: end if #sMyWarn > 0 then EgtOutLog( sMyWarn) end return true, sMyWarn end --------------------------------------------------------------------- local function MakeRoundCleanContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, nFunction, bMillDown, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShot) -- recupero la lavorazione senza considerare l'elevazione perché viene calcolata l'elevazione utile local sMilling = ML.FindMilling( 'SmallToolContour', nil, nil, nil, nil, not( bMillDown and not bDoubleSide), bMillDown and not bDoubleSide) if not sMilling then local sMyWarn = 'Warning : SmallToolContour not found in library' EgtOutLog( sMyWarn) return true, sMyWarn end -- recupero i dati dell'utensile local dTDiam = 50 local dTMaxDepth = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam dTMaxDepth = EgtTdbGetCurrToolMaxDepth() or dTMaxDepth end end local sMillingDn = ML.FindMilling( 'SmallToolContour', nil, nil, nil, nil, not( bMillDown and bDoubleSide), bMillDown and bDoubleSide) if not sMillingDn then local sMyWarn = 'Warning : Opposite SmallToolContour not found in library' EgtOutLog( sMyWarn) return true, sMyWarn end -- recupero i dati dell'utensile testa da sotto local dTDiamDn = 50 local dTMaxDepthDn = 0 if EgtMdbSetCurrMachining( sMillingDn) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTDiamDn = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiamDn dTMaxDepthDn = EgtTdbGetCurrToolMaxDepth() or dTMaxDepthDn end end -- se il diametro trovato non è minore dei 3/4 del diametro utilizzato in precedenza, esco if dTDiam > ( 0.75 * dDiam) then local sMyWarn = 'Warning : tool diameter not enough small' EgtOutLog( sMyWarn) return true, sMyWarn end local vtN1 local nFirstId, nNumId local dMaxElev local dCollSic = 0 local dExtraDepth = 0 -- se non ho la faccia aggiunta if not nPathInt then -- cerco gli angoli dove applicare il percorso con fresa piú piccola e i lati in comune local tFacAdjMain = ChooseContour( Proc, nFacInd, true) -- se non trovato nessun angolo interno da pulire esco if #tFacAdjMain == 0 then return true end -- normale alla faccia di fondo vtN1 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) -- se fresatura da sotto salto la lavorazione if vtN1:getZ() < BD.DRILL_VZ_MIN and not bMillDown then local sErr = 'Error : milling from bottom' EgtOutLog( sErr) return false, sErr end -- distanza di sicurezza per evitare collisioni dCollSic = BL.CalcCollisionSafety( vtN1) -- elevazione massima della faccia dMaxElev = BL.GetFaceElevation( Proc, nFacInd, b3Solid) -- ciclo tutta la tabella local tPaths = {} local ptIniPath local ptMidDist local dMaxLen = 0 for i = 1, #tFacAdjMain do -- le 2 facce di contatto devono essere perpendicolari o non sottosquadra rispetto alla faccia di fondo local ptP1, ptP2, dAng ptP1 = tFacAdjMain[i][3] ptP2 = tFacAdjMain[i][4] dAng = tFacAdjMain[i][5] if ( dAng < 0 and dAng >= -90 - 10 * GEO.EPS_SMALL) then -- creo la linea da P1 a P2 local nAuxId = EgtLine( nAddGrpId, ptP1, ptP2, GDB_RT.GLOB) table.insert( tPaths, nAuxId) -- prendo la lunghezza massima e il punto medio if tFacAdjMain[i][2] > dMaxLen then ptIniPath = ptP1 dMaxLen = tFacAdjMain[i][2] ptMidDist = ( ptP1 + ptP2) / 2 end end end -- costruisco il/i percorso/i nFirstId, nNumId = EgtCurveCompoByReorder( nAddGrpId, tPaths, ptIniPath, true, GDB_RT.GLOB) if nFirstId then -- se un solo percorso e chiuso cambio il punto di inizio nell'entitá piú lunga if nNumId == 1 and EgtCurveIsClosed( nFirstId) then EgtChangeClosedCurveStartPoint( nFirstId, ptMidDist, GDB_RT.GLOB) end -- modifico versore direzione for i = 1, nNumId do EgtModifyCurveExtrusion( nFirstId + i - 1, vtN1, GDB_RT.GLOB) end end -- alrimenti ho la faccia aggiunta else -- assegno il percorso nFirstId = EgtCopyGlob( nPathInt, nAddGrpId) nNumId = 1 -- distanza di sicurezza per evitare collisioni dCollSic = BL.CalcCollisionSafety( vtOrtho) -- calcolo elevazione dalla faccia trasversale aggiunta local dSurfIntElev = BL.GetFaceElevation( nSurfInt, 0, b3Solid) if bDoubleSide then dMaxElev = dSurfIntElev else dMaxElev = dDepth -- se la precedente svuotatura è stata fatta completamente in una sola volta -- valuto di nuovo se devo fare due passate o una sola if bOneShot then -- se non è possibile svuotare completamente da una sola parte if dTMaxDepth <= ( dMaxElev + BD.CUT_EXTRA + dCollSic) then bDoubleSide = true dMaxElev = BL.GetFaceElevation( nSurfInt, 0, b3Solid) else dExtraDepth = dMaxElev - BL.GetFaceElevation( nSurfInt, 0, b3Solid) end -- altrimenti non è stata fatta completamente calcolo la distanza tra faccia aggiunta e profondità superficie else dExtraDepth = dMaxElev - BL.GetFaceElevation( nSurfInt, 0, b3Solid) end end -- normale alla faccia aggiunta vtN1 = Vector3d( vtOrtho) -- imposto i lati aperti BL.SetOpenSide( nFirstId, b3Solid) BL.ChangeOrOpenStart( nFirstId, 2) end -- se non trovato il percorso, esco if not nFirstId then local sMyWarn = 'Warning : impossible make clean corner path' EgtOutLog( sMyWarn) return true, sMyWarn end -- assegno lavorazioni ad ogni percorso local sMyWarn = '' for i = 1, nNumId do local nIdPath = nFirstId + i - 1 local sName = 'Clean_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchId = EgtAddMachining( sName, sMilling) if not nMchId then sMyWarn = 'Warning : impossible add machining ' .. sName .. '-' .. sMilling goto continue end -- aggiungo geometria EgtSetMachiningGeometry( {{ nIdPath, -1}}) -- imposto lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- inversione direzione utensile local bInvertMach = false if nPathInt then -- verifico se devo invertire direzione utensile (in caso di direzione verso la verticale) if vtN1:getZ() < BD.NZ_MINA and abs(vtN1:getZ()) >= 0.707 then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true -- altrimenti se da fare in una sola volta e direzionato verso Y+ lo inverto per lavorarlo davanti elseif not bDoubleSide and vtN1:getY() > GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true end end -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP) end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- gestione attacco e uscita if EgtCurveIsClosed( nIdPath) then -- attacco e uscita a quarto di cerchio senza allungamenti a inizio e fine EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.TANGENT) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 0.5 * dTDiam) EgtSetMachiningParam( MCH_MP.LIELEV, 0) EgtSetMachiningParam( MCH_MP.STARTADDLEN, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) else -- nessun attacco e uscita, allungo inizio e fine di raggio utensile + 5mm (per evitare controllo collisioni) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.STARTADDLEN, dTDiam / 2 + 5) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dTDiam / 2 + 5) end -- setto massimo affondamento possibile local dMachDepth = 0 if ( dMaxElev + dCollSic) > dTMaxDepth then dMachDepth = dTMaxDepth - ( dMaxElev + dCollSic) end EgtSetMachiningParam( MCH_MP.DEPTH, dMachDepth + dExtraDepth) -- setto se devo invertire il percorso local bInvert = CheckToInvert( nIdPath, true) EgtSetMachiningParam( MCH_MP.INVERT, EgtIf( bInvertMach, not bInvert, bInvert)) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dMaxElev + dMachDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if ML.ApplyMachining( true, false) then _, sMyWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) end -- altrimenti lavorazione non applicata else _, sMyWarn = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) end -- se devo applicare la contornatura anche sul lato opposto if bDoubleSide then if bMillDown then sMilling = sMillingDn dTDiam = dTDiamDn dTMaxDepth = dTMaxDepthDn end sName = 'CleanOppo_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchId = EgtAddMachining( sName, sMilling) if not nMchId then sMyWarn = 'Warning : impossible add machining ' .. sName .. '-' .. sMilling goto continue end -- aggiungo geometria EgtSetMachiningGeometry( {{ nIdPath, -1}}) -- imposto lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- imposto direzione utensile opposta EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YP else nSCC = MCH_SCC.ADIR_YM end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- tipo attacco e uscita EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) -- allungo inizio e fine di 3/4 del diametro utensile EgtSetMachiningParam( MCH_MP.STARTADDLEN, dTDiam * 0.75) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dTDiam * 0.75) -- setto massimo affondamento possibile local dMachDepth = 0 if ( dMaxElev + dCollSic) > dTMaxDepth then dMachDepth = dTMaxDepth - ( dMaxElev + dCollSic) end EgtSetMachiningParam( MCH_MP.DEPTH, dMachDepth) -- setto se devo invertire il percorso local bInvert = CheckToInvert( nIdPath, true) EgtSetMachiningParam( MCH_MP.INVERT, not bInvert) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dMaxElev + dMachDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if ML.ApplyMachining( true, false) then _, sMyWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) end -- altrimenti lavorazione non applicata else _, sMyWarn = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) end end ::continue:: end if #sMyWarn > 0 then EgtOutLog( sMyWarn) end return true, sMyWarn end --------------------------------------------------------------------- local function MakeRoundCleanCornerOrContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, nFunction, bMillDown, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShot) -- se modalitá pulitura spigoli e lavorazione di lato forzo a fare il contorno if nFunction == 2 and nPathInt then nFunction = 1 end -- se richiesta pulitura del contorno if nFunction == 1 then return MakeRoundCleanContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, nFunction, bMillDown, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShot) -- se richiesta pulitura dei soli corner elseif nFunction == 2 then return MakeRoundCleanCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, bMillDown, bDoubleSide) -- altri casi non previsti else return true end end --------------------------------------------------------------------- local function MakeSharpCleanCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam) local sMyWarn = '' local pAuxId = {} local nAuxId local AuxId local ptApPoint local dLenTrimExt local sMilling local dMaxDepth = 0 -- cerco l'angolo di riferimento dove applicare il percorso di pulitura, altrimenti esco local _, nIdLine, tFacAdj = ChooseCorner( Proc, nFacInd) if #tFacAdj == 0 then return true end -- prendo il primo versore local vtN1 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, tFacAdj[nIdLine][1], GDB_ID.ROOT) local vtN3 = EgtSurfTmFacetNormVersor( Proc.Id, tFacAdj[nIdLine][2], GDB_ID.ROOT) -- trovo il punto sulla superfice di riferimento local _, ptLocP1, ptLocP2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, tFacAdj[nIdLine][1], GDB_ID.ROOT) local nIdIniPoint local nIdEndPoint if ptLocP1 and ptLocP2 then if dist( ptLocP1, tFacAdj[nIdLine][4]) < GEO.EPS_SMALL or dist( ptLocP2, tFacAdj[nIdLine][4]) < GEO.EPS_SMALL then nIdEndPoint = 4 nIdIniPoint = 5 elseif dist( ptLocP1, tFacAdj[nIdLine][5]) < GEO.EPS_SMALL or dist( ptLocP2, tFacAdj[nIdLine][5]) < GEO.EPS_SMALL then nIdEndPoint = 5 nIdIniPoint = 4 end end -- versore direzione local vtExtr = tFacAdj[nIdLine][nIdIniPoint] - tFacAdj[nIdLine][nIdEndPoint] vtExtr:normalize() -- inserisco le prime tre linee if nIdIniPoint and nIdEndPoint then -- se fresatura da sotto salto la lavorazione if vtExtr:getZ() < BD.DRILL_VZ_MIN then local sErr = 'Error : clean corner milling from bottom impossible' EgtOutLog( sErr) return false, sErr end -- sommo i tre versori per avre una direzione media vtExtr = vtN1 + vtN2 + vtN3 vtExtr:normalize() -- recupero la lavorazione non calcolando l'elevazione sMilling = ML.FindMilling( 'CleanCorner', ( 0.5 * dDiam)) if not sMilling then local sErr = 'Error : CleanCorner not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile ( temporaneo, per compensare errore nella lavorazione) if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dMaxDepth = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMaxDepth end end -- l'altezza di taglio del tagliente corrisponde al raggio del raccordo che si riesce a coprire -- quindi confronto l'elevazione con il raggio utensile utilizzato per la svuotatura if dMaxDepth < ( dDiam * 0.5) - 100 * GEO.EPS_SMALL then sMyWarn = 'Warning : skip clean corner (the cut heigth is smaller to machine the corner radius)' EgtOutLog( sMyWarn) return false, sMyWarn end nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdLine][nIdIniPoint], tFacAdj[nIdLine][nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) -- se il punto finale corrisponde con il punto utilizzato in precedenza, uso l'altro if dist( tFacAdj[nIdLine][nIdEndPoint], ptLocP1) < 10 * GEO.EPS_SMALL then ptApPoint = ptLocP2 else ptApPoint = ptLocP1 end nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdLine][nIdEndPoint], ptApPoint, GDB_RT.GLOB) dLenTrimExt = dist( tFacAdj[nIdLine][nIdEndPoint], ptApPoint) - (( dDiam/2) + 2) -- se la distanza dei due punti della linea è maggiore dal raggio fresa + delta, trimmo al raggio fresa + delta if dLenTrimExt > 10 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dLenTrimExt, ptApPoint , GDB_RT.GLOB) -- prendo il nuovo punto finale ptApPoint = EgtEP( nAuxId, GDB_RT.GLOB) end table.insert( pAuxId, nAuxId) -- creo linea di ritorno nAuxId = EgtLine( nAddGrpId, ptApPoint, tFacAdj[nIdLine][nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) end -- inserisco le ultime tre linee + uscita discostata rispetto all'ingresso -- trovo il secondo punto sulla superfice di riferimento _, ptLocP1, ptLocP2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, tFacAdj[nIdLine][2], GDB_ID.ROOT) if ptLocP1 and ptLocP2 then -- se il punto finale corrisponde con il punto utilizzato in precedenza, uso l'altro if dist( tFacAdj[nIdLine][nIdEndPoint], ptLocP1) < 10 * GEO.EPS_SMALL then ptApPoint = ptLocP2 else ptApPoint = ptLocP1 end nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdLine][nIdEndPoint], ptApPoint, GDB_RT.GLOB) dLenTrimExt = dist( tFacAdj[nIdLine][nIdEndPoint], ptApPoint) - (( dDiam/2) + 2) -- se la distanza dei due punti della linea è maggiore dal raggio fresa + delta, trimmo al raggio fresa + delta if dLenTrimExt > 10 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dLenTrimExt, ptApPoint , GDB_RT.GLOB) -- prendo il nuovo punto finale ptApPoint = EgtEP( nAuxId, GDB_RT.GLOB) end table.insert( pAuxId, nAuxId) -- creo linea di ritorno nAuxId = EgtLine( nAddGrpId, ptApPoint, tFacAdj[nIdLine][nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) -- piccolo scostamento di 2mm dall'angolo nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdLine][nIdEndPoint], tFacAdj[nIdLine][nIdEndPoint] + ( 2 * vtExtr), GDB_RT.GLOB) table.insert( pAuxId, nAuxId) -- ultima linea di risalita nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdLine][nIdEndPoint] + ( 2 * vtExtr), tFacAdj[nIdLine][nIdIniPoint] + ( 2 * vtExtr), GDB_RT.GLOB) table.insert( pAuxId, nAuxId) end -- trasformo in percorso if #pAuxId > 0 then AuxId = EgtCurveCompo( nAddGrpId, pAuxId, true) end -- se non c'é il percorso do errore if not AuxId then local sErr = 'Error : impossible make clean corner path' EgtOutLog( sErr) return false, sErr end -- modifico versore direzione EgtModifyCurveExtrusion( AuxId, vtExtr, GDB_RT.GLOB) -- inserisco la lavorazione local sName = 'Clean_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchId = EgtAddMachining( sName, sMilling) if not nMchId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YP else nSCC = MCH_SCC.ADIR_YM end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- tipo attacco e uscita EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) -- allungo inizio e fine di 10mm EgtSetMachiningParam( MCH_MP.STARTADDLEN, 10) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 10) -- setto affondamento 0 EgtSetMachiningParam( MCH_MP.DEPTH, 0) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dMaxDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn else return true, ( sMyWarn or sWarn) end end return true, sMyWarn end --------------------------------------------------------------------- local function MakeDrillOnCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiam, bSpecialMach) local sMyWarn = '' -- ottengo l'angolo dove applicare il foro local dMaxLen, nIdLine, tFacAdj = ChooseCorner( Proc, nFacInd) -- se non trovato nessun angolo interno valido esco if #tFacAdj == 0 then return true, sMyWarn end -- trovo il punto sulla superfice di riferimento local _, ptLocP1, ptLocP2, _ = EgtSurfTmFacetsContact( Proc.Id, nFacInd, tFacAdj[nIdLine][1], GDB_ID.ROOT) local nIdIniPoint local nIdEndPoint if ptLocP1 and ptLocP2 then if ( dist( ptLocP1, tFacAdj[nIdLine][4]) < GEO.EPS_SMALL) or ( dist( ptLocP2, tFacAdj[nIdLine][4]) < GEO.EPS_SMALL) then nIdEndPoint = 4 nIdIniPoint = 5 elseif ( dist( ptLocP1, tFacAdj[nIdLine][5]) < GEO.EPS_SMALL) or ( dist( ptLocP2, tFacAdj[nIdLine][5]) < GEO.EPS_SMALL) then nIdEndPoint = 5 nIdIniPoint = 4 end end -- inserisco foro if nIdIniPoint and nIdEndPoint then local vtExtr if bSpecialMach then local _, vtN0 = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) local _, vtN1 = EgtSurfTmFacetCenter( Proc.Id, tFacAdj[nIdLine][1], GDB_ID.ROOT) local _, vtN2 = EgtSurfTmFacetCenter( Proc.Id, tFacAdj[nIdLine][2], GDB_ID.ROOT) vtExtr = vtN0 + vtN1 + vtN2 else -- versore direzione vtExtr = tFacAdj[nIdLine][nIdIniPoint] - tFacAdj[nIdLine][nIdEndPoint] end vtExtr:normalize() -- se foratura da sotto salto la lavorazione if vtExtr:getZ() < BD.DRILL_VZ_MIN then local sErr = 'Error : drilling from bottom impossible' EgtOutLog( sErr) return false, sErr end -- recupero la lavorazione local sDrilling, nType = ML.FindDrilling( dDiam) if not sDrilling then local sErr = 'Error : drilling not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile local dMaxDepth = 20 local dDiamTool = 20 local dDiamTh = 35 local bIsDrilling if EgtMdbSetCurrMachining( sDrilling) then bIsDrilling = ( EgtMdbGetCurrMachiningParam( MCH_MP.TYPE) == MCH_MY.DRILLING) local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then if bIsDrilling then dMaxDepth = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMaxDepth else dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end dDiamTool = EgtTdbGetCurrToolParam( MCH_TP.DIAM) dDiamTh = EgtTdbGetCurrToolThDiam() end end -- se foro inclinato, limito il massimo affondamento local CosB = abs( vtExtr:getX()) if CosB < BD.DRILL_VX_MAX then local TgA = CosB / sqrt( 1 - CosB * CosB) dMaxDepth = dMaxDepth - dDiamTh / 2 * TgA else dMaxDepth = 0 end -- setto griglia if bSpecialMach then EgtSetGridFrame( Frame3d( tFacAdj[nIdLine][nIdEndPoint], vtExtr)) else EgtSetGridFrame( Frame3d( tFacAdj[nIdLine][nIdIniPoint], vtExtr)) end -- creo geometria local AuxId = EgtCircle( nAddGrpId, {0,0,0}, EgtIf( bIsDrilling, dDiamTool/2, ( dDiamTool/2) + 0.1), GDB_RT.GRID) -- riporto la griglia a globale EgtSetGridFrame() -- calcolo spessore local dDepthBore = dMaxLen if bSpecialMach then -- calcolo l'elevazione local dLenIn, dLedOut = BL.GetPointDirDepth( nPartId, tFacAdj[nIdLine][nIdEndPoint], vtExtr) if dLenIn > 0 then dDepthBore = dLenIn elseif dLedOut then dDepthBore = dLedOut end EgtModifyCurveThickness( AuxId, dDepthBore) else EgtModifyCurveThickness( AuxId, -dMaxLen) end -- inserisco la lavorazione local sName = 'Drill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchId = EgtAddMachining( sName, sDrilling) if not nMchId then local sErr = 'Error adding machining ' .. sName .. '-' .. sDrilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.ADIR_YM if vtExtr:getY() > 100 * GEO.EPS_ZERO then nSCC = MCH_SCC.ADIR_YP end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- aggiusto l'affondamento local dDepth if bSpecialMach then dDepth = dDepthBore else dDepth = dMaxLen if dDepth > dMaxDepth + 10 * GEO.EPS_SMALL then sMyWarn = 'Warning in drill : depth (' .. EgtNumToString( dDepth, 1) .. ') bigger than max tool depth (' .. EgtNumToString( dMaxDepth, 1) .. ')' dDepth = dMaxDepth EgtOutLog( sMyWarn) end end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- imposto il valore della distanza di sicurezza per l'attacco. Se il valore del db utensili è troppo basso lo alzo a 10. local dToolDbStartPos = EgtGetMachiningParam( MCH_MP.STARTPOS) local dMinStartPos = 10 local dStartPos = max( dMinStartPos, dToolDbStartPos) EgtSetMachiningParam( MCH_MP.STARTPOS, dStartPos) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione (coincide con affondamento) local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn else return true, ( sMyWarn or sWarn) end end end return true, sMyWarn end --------------------------------------------------------------------- local function MakeContourByMill( Proc, idContourPath, vtTunnelDirection, dTunnelDepth, dDimStrip, nPhase) local dCollSic = BL.CalcCollisionSafety( vtTunnelDirection) local bMultipleHeadsAvailble = BD.DOWN_HEAD or BD.TWO_EQUAL_HEADS local bMillFromBottom = vtTunnelDirection:getZ() < BD.NZ_MINA local bMillFromBottomOpposite = -vtTunnelDirection:getZ() < BD.NZ_MINA local sApplyWarning = '' local bIncomplete = false -- ricerca lavorazione lato principale local sMilling = ML.FindMilling( 'SmallToolContour', nil, nil, nil, nil, not bMillFromBottom, bMillFromBottom) if not sMilling then local sErr = 'Warning : SmallToolContour not found in library' EgtOutLog( sErr) return false, sErr end -- dati utensile local Tool = BL.GetToolFromMachining( sMilling) -- verifica necessità lavorazione opposta local bOppositeMillingNeeded local bMainMillingReachesFullDepth = Tool.MaxDepth > dTunnelDepth + dCollSic - dDimStrip local bMainMillingReachesHalfDepth = bMainMillingReachesFullDepth or ( Tool.MaxDepth > dTunnelDepth / 2 + dCollSic - dDimStrip / 2) if bMainMillingReachesFullDepth and not bMultipleHeadsAvailble then bOppositeMillingNeeded = false else bOppositeMillingNeeded = true end -- ricera lavorazione lato opposto local sMillingOpposite = ML.FindMilling( 'SmallToolContour', nil, nil, nil, nil, not bMillFromBottomOpposite, bMillFromBottomOpposite) if bOppositeMillingNeeded and not sMillingOpposite then local sErr = 'Warning : Opposite SmallToolContour not found in library' EgtOutLog( sErr) return false, sErr end -- dati utensile local ToolOpposite = BL.GetToolFromMachining( sMillingOpposite) local bOppositMillingReachesHalfDepth = ToolOpposite.MaxDepth > dTunnelDepth / 2 + dCollSic - dDimStrip / 2 -- eventuale lavorazione opposta local bMillingOppositeOk if bOppositeMillingNeeded then local sName = 'ContourOppo_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local idMachining = EgtAddMachining( sName, sMillingOpposite) if not idMachining then local sErr = 'Error : impossible add machining ' .. sName .. '-' .. sMilling return false, sErr end -- geometria EgtSetMachiningGeometry( {{ idContourPath, -1}}) -- lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.RIGHT) -- inversione direzione utensile EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) -- SCC local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtTunnelDirection, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtTunnelDirection:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtTunnelDirection:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YM else nSCC = MCH_SCC.ADIR_YP end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- gestione attacco e uscita if EgtCurveIsClosed( idContourPath) then -- attacco e uscita a quarto di cerchio senza allungamenti a inizio e fine EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.TANGENT) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 0.5 * Tool.Diameter) EgtSetMachiningParam( MCH_MP.LIELEV, 0) EgtSetMachiningParam( MCH_MP.STARTADDLEN, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) else -- nessun attacco e uscita, allungo inizio e fine di raggio utensile + 5mm (per evitare controllo collisioni) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.STARTADDLEN, Tool.Diameter / 2 + 5) EgtSetMachiningParam( MCH_MP.ENDADDLEN, Tool.Diameter / 2 + 5) end -- affondamento - la curva è a metà tasca quindi affondamento 0 significa che la lavorazione arriva a metà tasca local dDepth -- si arriva a metà tasca if bOppositMillingReachesHalfDepth then dDepth = -dDimStrip / 2 -- si arriva al massimo raggiungibile else dDepth = Tool.MaxDepth - dTunnelDepth / 2 - dCollSic bIncomplete = true end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dTunnelDepth / 2 + dDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if ML.ApplyMachining( true, false) then _, sApplyWarning = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( idMachining, false) end bMillingOppositeOk = true -- altrimenti lavorazione non applicata else _, sApplyWarning = EgtGetLastMachMgrError() EgtSetOperationMode( idMachining, false) bMillingOppositeOk = false end end -- applicazione lavorazione lato principale local sName = 'Contour_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local idMachining = EgtAddMachining( sName, sMilling) if not idMachining then local sErr = 'Error : impossible add machining ' .. sName .. '-' .. sMilling return false, sErr end -- geometria EgtSetMachiningGeometry( {{ idContourPath, -1}}) -- lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- inversione direzione utensile EgtSetMachiningParam( MCH_MP.TOOLINVERT, false) -- SCC local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtTunnelDirection, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtTunnelDirection:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtTunnelDirection:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YM else nSCC = MCH_SCC.ADIR_YP end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- gestione attacco e uscita if EgtCurveIsClosed( idContourPath) then -- attacco e uscita a quarto di cerchio senza allungamenti a inizio e fine EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.TANGENT) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 0.5 * Tool.Diameter) EgtSetMachiningParam( MCH_MP.LIELEV, 0) EgtSetMachiningParam( MCH_MP.STARTADDLEN, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) else -- nessun attacco e uscita, allungo inizio e fine di raggio utensile + 5mm (per evitare controllo collisioni) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.NONE) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) EgtSetMachiningParam( MCH_MP.STARTADDLEN, Tool.Diameter / 2 + 5) EgtSetMachiningParam( MCH_MP.ENDADDLEN, Tool.Diameter / 2 + 5) end -- affondamento - la curva è a metà tasca quindi affondamento 0 significa che la lavorazione arriva a metà tasca local dDepth -- c'è la lavorazione opposta if bOppositeMillingNeeded then -- si arriva a metà tasca if bMainMillingReachesHalfDepth then dDepth = -dDimStrip / 2 -- si arriva al massimo raggiungibile else dDepth = Tool.MaxDepth - dTunnelDepth / 2 - dCollSic bIncomplete = true end -- non c'è lavorazione opposta else -- si arriva fino in fondo if bMainMillingReachesFullDepth then dDepth = dTunnelDepth / 2 - dDimStrip -- si arriva al massimo raggiungibile else dDepth = Tool.MaxDepth - dTunnelDepth / 2 - dCollSic bIncomplete = true end end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- Note utente con dichiarazione nessuna generazione sfridi per Vmill e massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dTunnelDepth / 2 + dDepth, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo local bMillingOk if ML.ApplyMachining( true, false) then _, sApplyWarning = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( idMachining, false) end bMillingOk = true -- altrimenti lavorazione non applicata else _, sApplyWarning = EgtGetLastMachMgrError() EgtSetOperationMode( idMachining, false) bMillingOk = false end if bMillingOk or ( bOppositeMillingNeeded and bMillingOppositeOk) then local sWarning = '' if bIncomplete then sWarning = 'Warning : machining incomplete' end if #sApplyWarning > 0 then sWarning = sApplyWarning .. '\n' .. sWarning end return true, sWarning else local sErr = 'Error : Not applicable' return false, sErr end end --------------------------------------------------------------------- local function ExtractExternalPaths( nPathInt, nNumIdAux, vtOrtho, b3Solid, nAddGrpId) local nAuxId1, nAuxId2 if nNumIdAux == 1 then -- fondo tra loro le curve compatibili EgtMergeCurvesInCurveCompo( nPathInt) -- esplodo il percorso in modo da avere entià separate per poterle controllare local nStartId, nNumIds = EgtExplodeCurveCompo( nPathInt) if nStartId then local sDeleteByDir -- Se normale lungo la Z elimino le entità che hanno differenza in Z if abs(vtOrtho:getZ()) > 0.7 then sDeleteByDir = 'Z' -- altrimenti se normale lungo la Y elimino le entità che hanno variazione in Y -- elseif abs(vtOrtho:getZ()) < 0.001 and abs(vtOrtho:getY()) > 0.7 then elseif abs(vtOrtho:getY()) > 0.7 then sDeleteByDir = 'Y' -- caso che non dovrebbe mai capitare ma gestito per completezza -- altrimenti se normale lungo la X elimino le entità che hanno variazione in X -- elseif abs(vtOrtho:getZ()) < 0.001 and abs(vtOrtho:getX()) > 0.7 then elseif abs(vtOrtho:getX()) > 0.7 then sDeleteByDir = 'X' end if sDeleteByDir then for i = 1, nNumIds do local ptP1 = EgtSP( ( nStartId + i - 1), GDB_RT.GLOB) local ptP2 = EgtEP( ( nStartId + i - 1), GDB_RT.GLOB) if sDeleteByDir == 'Z' then -- se hanno variazione in Z cancello l'entità if abs( ptP1:getZ() - ptP2:getZ()) > 10 * GEO.EPS_SMALL then EgtErase( nStartId + i - 1) end elseif sDeleteByDir == 'Y' then -- se hanno variazione in Y cancello l'entità if abs( ptP1:getY() - ptP2:getY()) > 10 * GEO.EPS_SMALL then EgtErase( nStartId + i - 1) end elseif sDeleteByDir == 'X' then -- se hanno variazione in X cancello l'entità if abs( ptP1:getX() - ptP2:getX()) > 10 * GEO.EPS_SMALL then EgtErase( nStartId + i - 1) end end end -- ricreo i vari percorsi local dLocalVal local tPaths = {} local nNumPaths local dMaxVal local dMinVal for i = 1, nNumIds do local ptP1 = EgtSP( ( nStartId + i - 1), GDB_RT.GLOB) if ptP1 then if sDeleteByDir == 'Z' then local bInsTab for j = 1, #tPaths do local dLocalVal = tPaths[j][2] if abs( ptP1:getZ() - dLocalVal) < 10 * GEO.EPS_SMALL then local tLocIds = tPaths[j][1] table.insert( tLocIds, ( nStartId + i - 1)) tPaths[j][1] = tLocIds bInsTab = true end end -- se non ho trovato da inserirlo aggiungo nuovo elemento in tabella if not bInsTab then table.insert( tPaths, {{( nStartId + i - 1)}, ptP1:getZ()}) dMaxVal = b3Solid:getMax():getZ() dMinVal = b3Solid:getMin():getZ() end elseif sDeleteByDir == 'Y' then local bInsTab for j = 1, #tPaths do local dLocalVal = tPaths[j][2] if abs( ptP1:getY() - dLocalVal) < 10 * GEO.EPS_SMALL then local tLocIds = tPaths[j][1] table.insert( tLocIds, ( nStartId + i - 1)) tPaths[j][1] = tLocIds bInsTab = true end end -- se non ho trovato da inserirlo aggiungo nuovo elemento in tabella if not bInsTab then table.insert( tPaths, {{( nStartId + i - 1)}, ptP1:getY()}) dMaxVal = b3Solid:getMax():getY() dMinVal = b3Solid:getMin():getY() end elseif sDeleteByDir == 'X' then local bInsTab for j = 1, #tPaths do local dLocalVal = tPaths[j][2] if abs( ptP1:getX() - dLocalVal) < 10 * GEO.EPS_SMALL then local tLocIds = tPaths[j][1] table.insert( tLocIds, ( nStartId + i - 1)) tPaths[j][1] = tLocIds bInsTab = true end end -- se non ho trovato da inserirlo aggiungo nuovo elemento in tabella if not bInsTab then table.insert( tPaths, {{( nStartId + i - 1)}, ptP1:getX()}) dMaxVal = b3Solid:getMax():getX() dMinVal = b3Solid:getMin():getX() end end end end if tPaths then local tChamPath = {} -- elimino quelle che non corrispondono agli estremi for i = 1, #tPaths do -- se non corrisponde ai limiti elimino l'elemento if abs( tPaths[i][2] - dMaxVal) > 10 * GEO.EPS_SMALL and abs( tPaths[i][2] - dMinVal) > 10 * GEO.EPS_SMALL then tPaths[i] = nil end end for i = 1, #tPaths do if tPaths[i] then local tNoMatch = {} local tPathLoc = tPaths[i][1] local pIniLoc = EgtSP( tPathLoc[1], GDB_RT.GLOB) local pEndLoc = EgtEP( tPathLoc[1], GDB_RT.GLOB) -- ciclo sui percorsi per trovare i punti non coincidenti (se percorso non chiuso) for j = 2, #tPathLoc do -- prendo i punti del percorso successivo local pAddIni = EgtSP( tPathLoc[j], GDB_RT.GLOB) local pAddEnd = EgtEP( tPathLoc[j], GDB_RT.GLOB) -- se consecutivi if AreSamePointApprox( pEndLoc, pAddIni) then pEndLoc = pAddEnd elseif AreSamePointApprox( pIniLoc, pAddEnd) then pIniLoc = pAddIni else table.insert( tNoMatch, tPathLoc[j]) end end -- controllo eventuali percorsi scartati for j = 1, #tNoMatch do -- prendo i punti del percorso successivo local pAddIni = EgtSP( tNoMatch[j], GDB_RT.GLOB) local pAddEnd = EgtEP( tNoMatch[j], GDB_RT.GLOB) -- se consecutivi if AreSamePointApprox( pEndLoc, pAddIni) then pEndLoc = pAddEnd elseif AreSamePointApprox( pIniLoc, pAddEnd) then pIniLoc = pAddIni end end -- creo concatenamento partendo dal punto iniziale local nIdLoc = EgtCurveCompoByReorder( nAddGrpId, tPathLoc, pIniLoc, true) if nIdLoc then table.insert( tChamPath, nIdLoc) end end end for i = 1, #tChamPath do local ptP1 = EgtSP( tChamPath[i], GDB_RT.GLOB) -- modifico estrusione percorso if sDeleteByDir == 'Z' then if abs(ptP1:getZ() - dMaxVal) < 10 * GEO.EPS_SMALL then EgtModifyCurveExtrusion( tChamPath[i], Z_AX(), GDB_RT.GLOB) else EgtModifyCurveExtrusion( tChamPath[i], -Z_AX(), GDB_RT.GLOB) end elseif sDeleteByDir == 'Y' then if abs(ptP1:getY() - dMaxVal) < 10 * GEO.EPS_SMALL then EgtModifyCurveExtrusion( tChamPath[i], Y_AX(), GDB_RT.GLOB) else EgtModifyCurveExtrusion( tChamPath[i], -Y_AX(), GDB_RT.GLOB) end elseif sDeleteByDir == 'X' then if abs(ptP1:getX() - dMaxVal) < 10 * GEO.EPS_SMALL then EgtModifyCurveExtrusion( tChamPath[i], X_AX(), GDB_RT.GLOB) else EgtModifyCurveExtrusion( tChamPath[i], -X_AX(), GDB_RT.GLOB) end end end if #tChamPath == 1 then return tChamPath[1], 1, nil elseif #tChamPath == 2 then return tChamPath[1], 2, tChamPath[2] else for i = 1, nNumIds do EgtErase( nStartId + i - 1) end for i = 1, #tChamPath do EgtErase( tChamPath[i]) end end else for i = 1, nNumIds do EgtErase( nStartId + i - 1) end end -- altrimenti cancello tutte le emtità e restituisco nil else for i = 1, nNumIds do EgtErase( nStartId + i - 1) end end end end return nil, 0, nil end --------------------------------------------------------------------- local function MakeChamfer( Proc, bIs3Faces, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) -- Se variabile globale indica che lo smusso è già stato fatto, esco if bMadeChamfer then return 0 end bMadeChamfer = true -- recupero la lavorazione local sMilling = ML.FindMilling( 'Mark') if not sMilling then local sErr = 'Error : Mark not found in library' EgtOutLog( sErr) return -1, sErr end -- ottengo le curve di contorno libero local nAuxId1, nAuxId2, nNumIdAux local bIsOpenPath = false if bIs3Faces then -- estraggo i percorsi nAuxId1, nNumIdAux = EgtExtractSurfTmLoops( Proc.Id, nAddGrpId) -- se percorso creato estraggo solo i percorsi delle facce interessate, non di testa if nAuxId1 then nAuxId1, nNumIdAux, nAuxId2 = ExtractExternalPaths( nAuxId1, nNumIdAux, vtOrtho, b3Solid, nAddGrpId) end else nAuxId1, nNumIdAux = EgtExtractSurfTmLoops( Proc.Id, nAddGrpId) if not nNumIdAux then nNumIdAux = 0 end -- se non è una curva chiusa bisogna estrarre le sole curve da lavorare if Proc.TopologyLongName == 'Groove-Blind-RightAngles-Parallel-4' then local IdsToMachine = {} bIsOpenPath = true local nFirstId, nIdCount = EgtExplodeCurveCompo( nAuxId1) for i = nFirstId, nFirstId + nIdCount - 1, 1 do -- se segmento di retta if EgtGetType( i) == GDB_TY.CRV_LINE then local _, nEntitiesCount = EgtCurveDomain(i) for j = 0, nEntitiesCount - 1 do local ptStart = EgtUP( i, j, GDB_RT.GLOB) local ptEnd = EgtUP( i, j + 1, GDB_RT.GLOB) if ( AreSameVectorApprox( vtOrtho, X_AX()) and ( abs( ptStart:getX() - b3Solid:getMax():getX()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getX() - b3Solid:getMax():getX()) < 100 * GEO.EPS_SMALL) or AreSameVectorApprox( vtOrtho, -X_AX()) and ( abs( ptStart:getX() - b3Solid:getMin():getX()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getX() - b3Solid:getMin():getX()) < 100 * GEO.EPS_SMALL) or AreSameVectorApprox( vtOrtho, Y_AX()) and ( abs( ptStart:getY() - b3Solid:getMax():getY()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getY() - b3Solid:getMax():getY()) < 100 * GEO.EPS_SMALL) or AreSameVectorApprox( vtOrtho, -Y_AX()) and ( abs( ptStart:getY() - b3Solid:getMin():getY()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getY() - b3Solid:getMin():getY()) < 100 * GEO.EPS_SMALL) or AreSameVectorApprox( vtOrtho, Z_AX()) and ( abs( ptStart:getZ() - b3Solid:getMax():getZ()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getZ() - b3Solid:getMax():getZ()) < 100 * GEO.EPS_SMALL) or AreSameVectorApprox( vtOrtho, -Z_AX()) and ( abs( ptStart:getZ() - b3Solid:getMin():getZ()) < 100 * GEO.EPS_SMALL and abs( ptEnd:getZ() - b3Solid:getMin():getZ()) < 100 * GEO.EPS_SMALL) ) then table.insert( IdsToMachine, i) end end else return 0 end end local ptNear = EgtSurfTmFacetCenter(Proc.Id, 0, GDB_ID.ROOT) nAuxId1 = EgtCurveCompoByReorder( nAddGrpId, IdsToMachine, ptNear, true, GDB_ID.ROOT) nNumIdAux = 1 end end local dExtra = 2 for i = 1, nNumIdAux do local AuxId local vtExtr if bIs3Faces then if i == 1 then AuxId = nAuxId1 else -- faccio la copia del percorso -- AuxId = EgtCopyGlob( nAuxId1, nAddGrpId) AuxId = nAuxId2 end if AuxId then vtExtr = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) end else AuxId = nAuxId1 + i - 1 if bIsOpenPath then _, vtExtr = EgtCurveIsFlat( AuxId) else vtExtr, _, _ = EgtCurveArea( AuxId) end if vtExtr then local fFrCurve = EgtGetGlobFrame( AuxId) vtExtr:toGlob( fFrCurve) if bIsOpenPath and vtExtr * vtOrtho < GEO.EPS_SMALL then vtExtr = -vtExtr end end end if vtExtr then -- if bIs3Faces and i == nNumIdAux then -- vtExtr = -vtExtr -- end -- Se normale entro certi limiti -- if vtExtr:getZ() > -0.707 and ( abs(vtOrtho:getX()) > 0.99 or abs(vtOrtho:getY()) > 0.99 or abs(vtOrtho:getZ()) > 0.99) then if vtExtr:getZ() > -0.707 and ( abs(vtExtr:getX()) > 0.99 or abs(vtExtr:getY()) > 0.99 or abs(vtExtr:getZ()) > 0.99) then -- inserisco la lavorazione local sNameCh = 'Cham_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) local nMchId = EgtAddMachining( sNameCh, sMilling) if not nMchId then local sErr = 'Error adding machining ' .. sNameCh .. '-' .. sMilling EgtOutLog( sErr) return -1, sErr end -- modifico estrusione percorso EgtModifyCurveExtrusion( AuxId, vtExtr, GDB_RT.GLOB) -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- imposto posizione braccio porta testa if vtExtr:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- assegno affondamento e offset radiale -- EgtSetMachiningParam( MCH_MP.DEPTH, dDepthCham + dExtra - EgtIf( bIs3Faces, (dDepth / 2), 0)) EgtSetMachiningParam( MCH_MP.DEPTH, dDepthCham + dExtra) EgtSetMachiningParam( MCH_MP.OFFSR, dExtra) -- se opero su 3 facce e sono al secondo e ultimo percorso inverto la lavorazione -- if bIs3Faces and i == nNumIdAux then -- EgtSetMachiningParam( MCH_MP.INVERT, true) -- end -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return -1, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn end end -- se non perpendicolare emetto un warning -- else -- sWarn = 'Warning : chamfer skipped because not perpendicular to face or from bottom' -- EgtOutLog( sWarn) end --emetto un warning -- else -- sWarn = 'Warning : chamfer skipped because not perpendicular to face' -- EgtOutLog( sWarn) end end return 0 end --------------------------------------------------------------------- local function MakeByMillAsSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dElev, nBottomFace, nAddGrpId, b3Solid, dSawMaxDepth, sMillingOnSide, dSawDiam, dSawThick, bIgnoreCaps) local sWarn -- ingombro del grezzo local b3Raw = EgtGetRawPartBBox( nRawId) -- ottengo la distanza tra la fine del pezzo e il pezzo successivo local dDistToNextPiece = BL.GetDistanceToNextPart( nRawId, nPhase) -- verifico definizione faccia con il maggior numero di adiacenze if not nFacInd then local sErr = 'Error : MakeByMillAsSaw could not find reference face' EgtOutLog( sErr) return false, sErr end -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] if not vAdj or #vAdj == 0 then local sErr = 'Error : main face without adjacencies' EgtOutLog( sErr) return false, sErr end EgtOutLog( 'Adjac=' .. table.concat( vAdj, ','), 3) -- Cerco una faccia adiacente alla principale sul lato più lungo local nFacAdj local dMaxLen = 0 for i = 1, #vAdj do if vAdj[i] >= 0 then local _, ptP1, ptP2, _ = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) local dLen = dist( ptP1, ptP2) if abs( dLen - dMaxLen) < 5 then local vtN = EgtSurfTmFacetNormVersor( Proc.Id, vAdj[i], GDB_ID.ROOT) local bPositionedToYm = Proc.Box:getMax():getY() < ( b3Raw:getMin():getY() + b3Raw:getMax():getY()) / 2 if ( bPositionedToYm and vtN:getY() < 0.5) or ( not bPositionedToYm and vtN:getY() > 0.5) or vtN:getZ() > 0.5 then nFacAdj = vAdj[i] dMaxLen = dLen end elseif dLen > dMaxLen then nFacAdj = vAdj[i] dMaxLen = dLen end end end if not nFacAdj then local sErr = 'Error : long adjacent face not found' EgtOutLog( sErr) return false, sErr end -- Riordino le dimensioni per avere dH come lato lungo e dV come perpendicolare local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacAdj, GDB_ID.ROOT) if abs( vtN * rfFac:getVersX()) > abs( vtN * rfFac:getVersY()) then dH, dV = dV, dH end -- Determino se estremi aperti o chiusi local bOpenStart = bIgnoreCaps local bOpenEnd = bIgnoreCaps local vtNS, vtNE -- se non ho la faccia di fondo ( che comporta essere una fessura) e non da ignorare verifico se ho lati aperti if not nBottomFace and not bIgnoreCaps then local vAdj2 = EgtSurfTmFacetAdjacencies( Proc.Id, nFacAdj)[1] EgtOutLog( 'Adj2=' .. table.concat( vAdj2, ' ,'), 3) for j = 1, #vAdj2 do if vAdj2[j] == nFacInd then -- Se non esiste faccia adiacente a lato precedente -> inizio aperto local i = EgtIf( j > 1, j - 1, #vAdj2) while vAdj2[i] == nFacInd do i = EgtIf( i > 1, i - 1, #vAdj2) end bOpenStart = ( vAdj2[i] < 0) -- se è chiusa acquisisco vettore faccia tappo if not bOpenStart and vAdj2[i] >= 0 then vtNS = EgtSurfTmFacetNormVersor( Proc.Id, vAdj2[i], GDB_ID.ROOT) end -- Se non esiste faccia adiacente a lato successivo -> fine aperto local k = EgtIf( j < #vAdj2, j + 1, 1) while vAdj2[k] == nFacInd do k = EgtIf( k < #vAdj2, k + 1, 1) end bOpenEnd = ( vAdj2[k] < 0) -- se è chiusa acquisisco vettore faccia tappo if not bOpenEnd and vAdj2[k] >= 0 then vtNE = EgtSurfTmFacetNormVersor( Proc.Id, vAdj2[k], GDB_ID.ROOT) end end end end -- Recupero la lavorazione di lama local sCutting = sMillingOnSide -- Calcolo uso faccia local nFaceUse = BL.GetNearestOrthoOpposite( rfFac:getVersZ()) local dStartDist = -1 local dEndDist = -1 -- calcolo eventuali arretramenti lama if not bOpenStart then local dRadius = dSawDiam / 2 local dCat1 = dRadius - dElev dStartDist = sqrt( ( dRadius * dRadius) - (dCat1 * dCat1)) end if not bOpenEnd then if not bOpenStart then dEndDist = dStartDist else local dRadius = dSawDiam / 2 local dCat1 = dRadius - dElev dEndDist = sqrt( ( dRadius * dRadius) - (dCat1 * dCat1)) end end -- Eseguo i tagli local nStep = ceil( ( dV - 100 * GEO.EPS_SMALL) / dSawThick) local dStep = 0 if nStep > 1 then dStep = ( dV - dSawThick) / ( nStep - 1) end local dVzLimDwnUp = -0.01 for i = 1, nStep do local dOffs = ( i - 1) * dStep if vtN:getZ() < dVzLimDwnUp then dOffs = dOffs + dSawThick end -- forzatura lavorazione discorde in base a parametro Q su feature local nQ14Param = EgtGetInfo( Proc.Id, Q_CONVENTIONAL_MILLING, 'd') or 0 local bForceInvert = nQ14Param == 1 or ( nQ14Param == 2 and vtN:getX() < 0.1 and Proc.AffectedFaces.Bottom) if bForceInvert and i == 1 then dStartDist, dEndDist = dEndDist, dStartDist end local bOk, sErr, nMchId = Fbs.MakeOne( Proc.Id, nFacAdj, sCutting, dSawDiam, nFaceUse, dVzLimDwnUp, 0, BD.CUT_SIC, dOffs, dStartDist, dEndDist, nil, b3Raw, bForceInvert) if not bOk then return bOk, sErr end -- setto l'elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', 0) -- applico elevazione EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- tolgo eventuale step EgtSetMachiningParam( MCH_MP.STEP, 0) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn end end end -- in base all'elevazione calcolo l'impronta della lama local dUsedBladeLen = sqrt( ((dSawDiam / 2)*(dSawDiam / 2)) - ( ( (dSawDiam / 2) - dElev) * ( (dSawDiam / 2) - dElev))) -- controllo direzione taglio e se il minimo della feature sborda in coda if abs( vtN:getX()) < GEO.EPS_SMALL and abs( b3Solid:getMin():getX() - Proc.Box:getMin():getX()) < 100 * GEO.EPS_SMALL and dDistToNextPiece < dUsedBladeLen then -- do avviso che la lama può sbordare nel pezzo successivo sWarn = 'Warning on mill side as blade : Cut machining can damage next piece' EgtOutLog( sWarn .. ' (process ' .. tostring( Proc.Id) .. ')') end return true, sWarn end --------------------------------------------------------------------- local function MakeByChainOrSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dElev, bForceUseBlade, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, bOrthoFacesMaster, nBottomFace, nChamfer, nAddGrpId, b3Solid, dDepthCham, nSurfInt) local sWarn -- ingombro del grezzo local b3Raw = EgtGetRawPartBBox( nRawId) -- ottengo la distanza tra la fine del pezzo e il pezzo successivo local dDistToNextPiece = BL.GetDistanceToNextPart( nRawId, nPhase) -- angolo d'ingresso dell'utensile local dToolEntryAngle, _, _, dTanToolEntryAngle = GetToolEntryAngle( Proc, rfFac:getVersZ()) -- verifico se fessura con 3 facce o tunnel local bOrthoFaces local bIs3Faces = ( Proc.Fct == 3) if bIs3Faces then -- recupero la faccia con il maggior numero di adiacenze e l'elevazione relativa local nFacInd1, dFacElev1, nFacInd2, dFacElev2 = BL.GetFaceWithMostAdj( Proc, nPartId, bIs3Faces) if not nFacInd1 or nFacInd1 < 0 then if nFacInd1 == -1 then bOrthoFaces = nFacInd2 else local sErr = 'Error : MakeByChainOrSaw could not find reference face' EgtOutLog( sErr) return false, sErr end end else bOrthoFaces = bOrthoFacesMaster end -- eventuale massima elevazione imposta dall'utente local dMaxElev = EgtGetInfo( Proc.Id, Q_MAX_ELEVATION, 'd') if dMaxElev and dMaxElev < 1 then dMaxElev = nil end dElev = dMaxElev or dElev if bOrthoFaces then -- ottengo le dimensioni del tunnel dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) -- verifico la direzione -- se devo inserire il chamfer if nChamfer > 0 then local nOk, sErr = MakeChamfer( Proc, bIs3Faces, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end end -- slot aperta su due lati elseif Proc.TopologyLongName == 'Groove-Blind-RightAngles-Parallel-4' then if nChamfer > 0 then local nOk, sErr = MakeChamfer( Proc, false, nAddGrpId, rfFac:getVersZ(), b3Solid, nil, dDepthCham) if nOk < 0 then return false, sErr end end end if not dDepth then dDepth = dElev end -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] if not vAdj or #vAdj == 0 then local sErr = 'Error : main face without adjacencies' EgtOutLog( sErr) return false, sErr end EgtOutLog( 'Adjac=' .. table.concat( vAdj, ','), 3) -- Cerco una faccia adiacente alla principale sul lato più lungo local nFacAdj local dMaxLen = 0 for i = 1, #vAdj do if vAdj[i] >= 0 then local vtAdjN = EgtSurfTmFacetNormVersor( Proc.Id, vAdj[i], GDB_ID.ROOT) if not bIs3Faces or abs( rfFac:getVersZ():getY()) < 0.174 or abs( rfFac:getVersZ():getY()) > 0.984 or vtAdjN:getY() * rfFac:getVersZ():getY() > -0.1 then local _, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) local dLen = dist( ptP1, ptP2) if dLen > dMaxLen then nFacAdj = vAdj[i] dMaxLen = dLen EgtOutLog( string.format( 'Adjac=%d Len=%.3f H=%.3f V=%.3f', vAdj[i], dLen, dH, dV), 3) end end end end if not nFacAdj then local sErr = 'Error : long adjacent face not found' EgtOutLog( sErr) return false, sErr end -- Riordino le dimensioni per avere dH come lato lungo e dV come perpendicolare local _, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacAdj, GDB_ID.ROOT) if abs( vtN * rfFac:getVersX()) > abs( vtN * rfFac:getVersY()) then dH, dV = dV, dH end -- Determino se estremi aperti o chiusi local bOpenStart = false local bOpenEnd = false local vtNS, vtNE -- se non ho la faccia di fondo ( che comporta essere una fessura) verifico se ho lati aperti if not nBottomFace then local vAdj2 = EgtSurfTmFacetAdjacencies( Proc.Id, nFacAdj)[1] EgtOutLog( 'Adj2=' .. table.concat( vAdj2, ' ,'), 3) for j = 1, #vAdj2 do if vAdj2[j] == nFacInd then -- Se non esiste faccia adiacente a lato precedente -> inizio aperto local i = EgtIf( j > 1, j - 1, #vAdj2) while vAdj2[i] == nFacInd do i = EgtIf( i > 1, i - 1, #vAdj2) end bOpenStart = ( vAdj2[i] < 0) -- se è chiusa acquisisco vettore faccia tappo if not bOpenStart and vAdj2[i] >= 0 then _, vtNS = EgtSurfTmFacetCenter( Proc.Id, vAdj2[i], GDB_ID.ROOT) end -- Se non esiste faccia adiacente a lato successivo -> fine aperto local k = EgtIf( j < #vAdj2, j + 1, 1) while vAdj2[k] == nFacInd do k = EgtIf( k < #vAdj2, k + 1, 1) end bOpenEnd = ( vAdj2[k] < 0) -- se è chiusa acquisisco vettore faccia tappo if not bOpenEnd and vAdj2[k] >= 0 then _, vtNE = EgtSurfTmFacetCenter( Proc.Id, vAdj2[k], GDB_ID.ROOT) end end end end -- escludo caso per L20 che porterebbe ad una lavorazione con lama non corretta; ritorno anche 'MNF' in modo da forzare una lavorazione tasca if Proc.Prc == 20 and Proc.Fct >= 4 and bOpenStart and bOpenEnd and #vAdj >= 3 then local sErr = 'Error: improper use of L020 feature' return false, sErr, 'MNF' end -- verifico se uso lama da sotto local bCutDown = ( BD.DOWN_HEAD and rfFac:getVersZ():getZ() < - 0.5) -- Recupero il massimo affondamento possibile con la lama local dSawMaxDepth = 0 local sCutting = ML.FindCutting( 'HeadSide', not bCutDown, bCutDown) if sCutting then if EgtMdbSetCurrMachining( sCutting) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawMaxDepth = EgtTdbGetCurrToolMaxDepth() or dSawMaxDepth end end end -- se lavorazione sulle teste e altezza trave supera il limite ( che causa collisione con la forcella) e direzione taglio lungo la Z -- e limite profondità BeamData è maggiore del taglio massimo lama, assegno il massimo affondamento pari al limite profondità del BeamData if bOpenStart and bOpenEnd and bForceUseBlade and ( Proc.Head or Proc.Tail) and abs(rfFac:getVersY():getY()) > 0.866 and b3Solid:getDimZ() > BD.MIN_DIM_HBEAM and dSawMaxDepth > BD.MAX_DIM_HTCUT_HBEAM then dSawMaxDepth = BD.MAX_DIM_HTCUT_HBEAM end -- Se entrambi gli estremi sono aperti e possibile, lavoro con la lama if bOpenStart and bOpenEnd and bForceUseBlade and dElev < dSawMaxDepth + 10 * GEO.EPS_SMALL then -- recupero altri dati dell'utensile local dSawDiam = 400 local dSawThick = 4 if EgtMdbSetCurrMachining( sCutting) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dSawDiam dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick end end if dSawThick > dV + 10 * GEO.EPS_SMALL then local sErr = 'Error : sawblade too thick' EgtOutLog( sErr) return false, sErr end -- Calcolo uso faccia local nFaceUse = BL.GetNearestOrthoOpposite( rfFac:getVersZ()) -- Eseguo i tagli local nStep = ceil( ( dV - 100 * GEO.EPS_SMALL) / dSawThick) local dStep = 0 if nStep > 1 then dStep = ( dV - dSawThick) / ( nStep - 1) end for i = 1, nStep do local dOffs = ( i - 1) * dStep local bForceClimbCut = true local bOk, sErr = Fbs.MakeOne( Proc.Id, nFacAdj, sCutting, dSawDiam, nFaceUse, -0.01, 0, BD.CUT_SIC, dOffs, 0, 0, nil, b3Raw, nil, nil, nil, nil, nil, nil, bForceClimbCut) if not bOk then return bOk, sErr end end -- in base all'elevazione calcolo l'impronta della lama local dUsedBladeLen = sqrt( ((dSawDiam / 2)*(dSawDiam / 2)) - ( ( (dSawDiam / 2) - dElev) * ( (dSawDiam / 2) - dElev))) -- controllo direzione taglio e se il minimo della feature sborda in coda if not Proc.Tail and abs( vtN:getX()) < GEO.EPS_SMALL and abs( b3Solid:getMin():getX() - Proc.Box:getMin():getX()) < 100 * GEO.EPS_SMALL and dDistToNextPiece < dUsedBladeLen then -- do avviso che la lama può sbordare nel pezzo successivo sWarn = 'Warning on saw cut : Cut machining can damage next piece' EgtOutLog( sWarn .. ' (process ' .. tostring( Proc.Id) .. ')') end -- altrimenti con sega a catena else -- Recupero la lavorazione local sSawing = ML.FindSawing( 'Sawing', dDepth, true) -- se non trovo alcuna sega a catena lunga a sufficienza, accetto di non arrivare sul fondo della tasca if not sSawing then sSawing = ML.FindSawing( 'Sawing', nil, nil, 'Longest') end -- se non trova una lavorazione di sawing esco if not sSawing then local sErr = 'Error : Sawing not found in library' EgtOutLog( sErr) return false, sErr, 'MNF' end -- Recupero i dati dell'utensile local dSawWidth = 75 local dSawThick = 8 local dMaxDepth = 200 if EgtMdbSetCurrMachining( sSawing) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawWidth = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dSawWidth dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end end if dSawThick > dV + 10 * GEO.EPS_SMALL then local sErr = 'Error : chainsaw too thick' EgtOutLog( sErr) return false, sErr end local bGoFromHead = true local bAttackFromSide = ( ( EgtGetInfo( Proc.Id, Q_CHAINSAW_FROM_SIDE, 'i') or 0) == 1) and ( Proc.Fct == 4) and ( Proc.Topology == 'Groove') -- se normale lungo Z è da sopra: si tenta attacco laterale se richiesto if AreSameOrOppositeVectorApprox( Proc.Face[ nFacInd + 1].VtN, Z_AX()) then if bAttackFromSide then bGoFromHead = false end elseif dElev > dMaxDepth + 10 * GEO.EPS_SMALL then if bAttackFromSide then bGoFromHead = false -- continuo di testa se fessura con tre facce o non è tunnel else bGoFromHead = (( bIs3Faces and ( dMaxElev or ( Proc.Topology == 'Groove' and Proc.IsThrough and (Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) and not Proc.IsParallel))) or not bOrthoFaces) end end -- se continuo a lavorare di testa if bGoFromHead then -- Calcolo normale faccia adiacente local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacAdj, GDB_ID.ROOT) -- Calcolo uso faccia local nFaceUse = BL.GetNearestParalOpposite( rfFac:getVersZ(), vtN) -- Verifico se necessarie più passate local nStep = ceil( ( dV - 100 * GEO.EPS_SMALL) / dSawThick) local dStep = 0 if nStep > 1 then dStep = ( dV - dSawThick) / ( nStep - 1) end -- se necessario riduco la profondità di lavoro per considerare l'ingombro della testa local dChainSawTHLength = EgtIf( EgtTdbGetCurrToolThLength() > 10 * GEO.EPS_SMALL, EgtTdbGetCurrToolThLength(), 88) local dChainSawExtraLength = EgtTdbGetCurrToolParam( MCH_TP.TOTLEN) - dChainSawTHLength - dMaxDepth local dMaxMatReduction = 0 if dToolEntryAngle > 10 * GEO.EPS_ANG_SMALL and dToolEntryAngle < 90 - 10 * GEO.EPS_ANG_SMALL then dMaxMatReduction = max( ( ( 2 * BD.C_SIMM_ENC - dSawWidth) / ( 2 * dTanToolEntryAngle) - dChainSawExtraLength) - 5, 0) end dMaxDepth = dMaxDepth - dMaxMatReduction for i = 1, nStep do -- Applico la lavorazione con sega a catena a questa faccia local sName = 'Csaw_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) local nMchFId = EgtAddMachining( sName, sSawing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sSawing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacAdj}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- controllo direzione taglio e se il minimo della feature sborda in coda if not Proc.Tail and abs( vtN:getX()) < GEO.EPS_SMALL and abs( b3Solid:getMin():getX() - Proc.Box:getMin():getX()) < 100 * GEO.EPS_SMALL then -- se ho lato partenza aperto e lato uscita chiuso e direzione lato chiuso è negativa, allora controllo uscita lama if bOpenStart and not bOpenEnd and vtNE:getX() < -0.99 and dDistToNextPiece < (dSawWidth / 2) then -- imposto accorciamento iniziale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.STARTADDLEN, dDistToNextPiece - 1 - (dSawWidth / 2)) else -- imposto accorciamento iniziale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.STARTADDLEN, EgtIf( bOpenStart, 0, - dSawWidth / 2)) end -- se ho lato uscita aperto e lato partenza chiuso e direzione lato partenza è negativa, allora controllo uscita lama if bOpenEnd and not bOpenStart and vtNS:getX() < -0.99 and dDistToNextPiece < (dSawWidth / 2) then -- imposto accorciamento finale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.ENDADDLEN, dDistToNextPiece - 1 - (dSawWidth / 2)) else -- imposto accorciamento finale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.ENDADDLEN, EgtIf( bOpenEnd, 0, - dSawWidth / 2)) end else -- imposto accorciamento iniziale/finale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.STARTADDLEN, EgtIf( bOpenStart, 0, - dSawWidth / 2)) EgtSetMachiningParam( MCH_MP.ENDADDLEN, EgtIf( bOpenEnd, 0, - dSawWidth / 2)) end -- imposto angolo 3° asse rot e eventuale angolo suggerito per inizio EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'perpendicular')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtN, rfFac:getVersZ(), 1)) -- imposto offset radiale local dOffs = ( i - 1) * dStep EgtSetMachiningParam( MCH_MP.OFFSR, dOffs) local bElevAdj local dToolEntryAngle, _, _, dTanToolEntryAngle = GetToolEntryAngle( Proc, rfFac:getVersZ()) -- se necessario, avverto limitazione dell'affondamento if dElev > dMaxDepth + 10 * GEO.EPS_SMALL then if Proc.Fct == 3 and Proc.Topology == 'Groove' and Proc.IsThrough and (Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) and not Proc.IsParallel then local Edges = BL.GetEdgesInfo( Proc, Proc.Face[nFacAdj+1]) local dWorkEdgeWidth for i = 1, #Edges do if Edges[i].AdjacentFaceId == nFacInd then dWorkEdgeWidth = Edges[i].Length break end end local dDeltaDepth = dWorkEdgeWidth * cos( dToolEntryAngle) bElevAdj = true EgtSetMachiningParam( MCH_MP.DEPTH, dMaxDepth - dDeltaDepth) else EgtSetMachiningParam( MCH_MP.DEPTH, dMaxDepth) sWarn = 'Warning in LapJoint : elevation (' .. EgtNumToString( dElev, 1) .. ') bigger than max tool depth (' .. EgtNumToString( dMaxDepth, 1) .. ')' EgtOutLog( sWarn) end --local dDepth = dMaxDepth - dElev --EgtSetMachiningParam( MCH_MP.DEPTH_STR, 'TH '..EgtNumToString( dDepth, 1)) end -- imposto massima elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' local dElevAdj = EgtIf( bElevAdj, dElev / sin( dToolEntryAngle), dElev) sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElevAdj, 2)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then if EgtGetOutstrokeInfo() then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end -- impostazione alternativa angolo 3° asse rot EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'parallel')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtN, rfFac:getVersZ(), 2)) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end end if EgtIsMachiningEmpty() then _, sWarn = EgtGetMachMgrWarning( 0) EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- altrimenti sega a catena di fianco -- si arriva qui anche per groove 4 lati con rotazione esclusa else local vtRef = Vector3d( vtOrtho) if vtRef and ( vtRef:getY() > 0.5 or vtRef:getZ() < -0.1) then vtRef = -vtRef end if bAttackFromSide then dDimMin = min( Proc.Face[ nFacInd + 1].Width, Proc.Face[ nFacInd + 1].Height) dDimMax = min( Proc.Face[ nFacAdj + 1].Width, Proc.Face[ nFacAdj + 1].Height) nLundIdFace = nFacAdj local nFaceZ if not vtRef then if Proc.AffectedFaces.Top then vtRef = Z_AX() nFaceZ = BL.FindFaceBestOrientedAsAxis( Proc, Z_AX()) else vtRef = -Z_AX() nFaceZ = BL.FindFaceBestOrientedAsAxis( Proc, -Z_AX()) end else nFaceZ = nFacInd end dDepth = Proc.Face[ nFaceZ + 1].Elevation end local bMakeChainSaw, sSawing2, dMaxMat2, dSawCornerRad2, dSawThick2 = VerifyChainSaw( Proc, dDimMin, dDimMax, dDepth) if bMakeChainSaw then -- Calcolo normale faccia da lavorare local vtNL = EgtSurfTmFacetNormVersor( Proc.Id, nLundIdFace, GDB_ID.ROOT) -- Calcolo uso faccia local nFaceUse = BL.GetNearestParalOpposite( vtRef, vtNL) -- Verifico se necessarie più passate local nStep = ceil( ( dDimMin - 100 * GEO.EPS_SMALL) / dSawThick2) local dStep = 0 if nStep > 1 then dStep = ( dDimMin - dSawThick2) / ( nStep - 1) end for i = 1, nStep do -- inserisco la lavorazione di sawing local sName = 'Csaw_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) local nMchFId = EgtAddMachining( sName, sSawing2) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sSawing2 EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nLundIdFace}}) -- imposto uso del lato faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto angolo 3° asse rot EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'perpendicular')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtNL, vtOrtho, 1)) -- imposto offset radiale local dOffs = ( i - 1) * dStep EgtSetMachiningParam( MCH_MP.OFFSR, dOffs) local dMachiningDepth = dDepth if not bAttackFromSide then -- se possibile aumento l'affondamento pari al raggio corner + 1 if dMaxMat2 > ( dDepth + dSawCornerRad2 + 1) then dMachiningDepth = ( dDepth + dSawCornerRad2 + 1) -- se massimo affondamento supera altezza fessura, uso massimo affondamento elseif dMaxMat2 > ( dDepth + 1) then dMachiningDepth = (dMaxMat2 - 1) -- se massimo affondamento utensile inferiore fessura, setto affondamento ed emetto warning elseif dMaxMat2 < dDepth then dMachiningDepth = dMaxMat2 sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end EgtSetMachiningParam( MCH_MP.DEPTH, dMachiningDepth) else -- se possibile si lavora tutta la profondità if dMaxMat2 > (dDepth - 100 * GEO.EPS_SMALL) then dMachiningDepth = dDepth -- in alternativa si arriva al massimo materiale else dMachiningDepth = dMaxMat2 sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end EgtSetMachiningParam( MCH_MP.DEPTH, dMachiningDepth) -- si decidono lato di lavoro, inversione e estensione in base al lato aperto local nEdgeIndex = BL.GetEdgeToMachineFromVector( Proc.Id, nFacAdj, vtRef) local EdgesEgt = BL.GetEdgesInfo( Proc, Proc.Face[nFacAdj+1]) local CurrentEdge = EdgesEgt[nEdgeIndex+1] local dStartAddLen = 0 local dEndAddLen = 0 if CurrentEdge.IsStartOpen then EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MORTISE_WS.RIGHT) EgtSetMachiningParam( MCH_MP.INVERT, false) else EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MORTISE_WS.LEFT) EgtSetMachiningParam( MCH_MP.INVERT, true) end dStartAddLen = dSawWidth / 2 + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) + EgtMdbGetGeneralParam( MCH_GP.SAFEAGGRBOTTZ) dEndAddLen = - dSawWidth / 2 EgtSetMachiningParam( MCH_MP.STARTADDLEN, dStartAddLen) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dEndAddLen) end -- in caso di attacco esterno si setta in modo da fare un primo step adeguato per evitare finecorsa -- si riduce la feed opportunamente if bAttackFromSide then local dMachiningStep = EgtGetMachiningParam( MCH_MP.STEP) or 0 -- TODO qui sostituire con valore preciso da GetSetupInfo if BD.C_SIMM then dMachiningStep = 175 if vtRef:getZ() < - 10 * GEO.EPS_SMALL then dMachiningStep = 260 end end local dActualStep = ( dMachiningDepth - dMachiningStep) / ( 2 + 1) dElev = dMachiningDepth - dMachiningStep + dActualStep - 0.1 if dActualStep < 0 then dActualStep = 1 dElev = 2 end EgtSetMachiningParam( MCH_MP.STEP, dActualStep) local dFeed = EgtGetMachiningParam( MCH_MP.FEED) / 2 EgtSetMachiningParam( MCH_MP.FEED, dFeed) end local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) if bAttackFromSide then sUserNotes = EgtSetValInNotes( sUserNotes, 'Plunge', 10) end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then if EgtGetOutstrokeInfo() then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end -- impostazione alternativa angolo 3° asse rot EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'parallel')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtNL, vtOrtho, 2)) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end end if EgtIsMachiningEmpty() then _, sWarn = EgtGetMachMgrWarning( 0) EgtSetOperationMode( nMchFId, false) return false, sWarn end end end end end return true, sWarn end --------------------------------------------------------------------- local function MakeAntiSplintBySaw( Proc, nFacet, vtN, b3Raw, nFacInd, bReduceDepth, bMillDown) -- Recupero la lavorazione di lama local sCutting = ML.FindCutting( 'HeadSide', not bMillDown, bMillDown) if not sCutting then local sErr = 'Error : HeadSide (cutting) not found in library' EgtOutLog( sErr) return false, sErr end -- valuto l'angolo tra le due facce local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, nFacet, GDB_ID.ROOT) if not bAdj then local sErr = 'Error : Faces not adjacent' EgtOutLog( sErr) return false, sErr end local ptPm = (ptP1+ptP2)/2 -- ottengo il boundingBox e prendo le dimensioni lungo la normale (Z locale) che rappresenta l'elevazione della faccia -- laterale sul punto medio della linea in comune local frFc = Frame3d( ptPm, vtN) ; local b3BoxLoc = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, frFc) dDepth = b3BoxLoc:getDimZ() or 0 -- recupero i dati dell'utensile local dSawDiam = 400 local dSawThick = 0 local dMaxDepth = 0 local bSawCCW = false if EgtMdbSetCurrMachining( sCutting) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dSawDiam dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth bSawCCW = ( EgtTdbGetCurrToolParam( MCH_TP.SPEED) < 0) end end local dExtraOffs = 0 -- se il taglio è praticamente verticale, riduto massimo materiale lama if BD.DECR_VERT_CUT and vtN:getZ() > 0.985 then dMaxDepth = dMaxDepth - BD.DECR_VERT_CUT - BD.COLL_SIC end -- se profondità superiore al massimo lama modifico elevazione if dDepth > dMaxDepth then dExtraOffs = dMaxDepth - dDepth end -- se devo ridurre l'affondamento if bReduceDepth then local dLimitDepth = 100 -- se ho ridotto l'affondamento ne riduco ulteriormente l'affondamento (50mm) if abs(dExtraOffs) > 0 then if dMaxDepth > dLimitDepth then dExtraOffs = dLimitDepth - dDepth end else if dDepth > dLimitDepth then dExtraOffs = dLimitDepth - dDepth else dExtraOffs = - (dDepth/2) end end end -- eseguo il taglio local vtNfac = EgtSurfTmFacetNormVersor( Proc.Id, nFacet, GDB_ID.ROOT) local dVzLimDwnUp = EgtIf( BD.TURN, -2, BL.GetNzLimDownUp( b3Raw, vtNfac, vtN)) local bInvert = ( bSawCCW ~= ( vtNfac:getZ() < dVzLimDwnUp)) local bMadeASbyBld, sWarn, nIdMach = Fbs.MakeOne( Proc.Id, nFacet, sCutting, dSawDiam, vtN, dVzLimDwnUp, ( -0.5 + dExtraOffs), BD.CUT_SIC, 0, 0, 0, nil, b3Raw, bInvert) if bMadeASbyBld then sWarn = nil if not bReduceDepth and abs(dExtraOffs) > 0 then sWarn = 'Warning : antisplint elevation is bigger than max tool depth' end end return bMadeASbyBld, sWarn, nIdMach, dSawThick, dMaxDepth, bAdj, dAng, dExtraOffs end --------------------------------------------------------------------- local function MakePocket( Proc, nPartId, b3Solid, ptPs, tvtN, nFaceRef, sMchFind, nUseRoughTool, sMasterPocket, dPrevFaceElev, tDimAndRef, dAng, bOpenOutRaw, bLapJointAngTrasm, nPhase, nRawId, dCustomMaxElev) -- distanza dal pezzo successivo local dDistToNextPiece = BL.GetDistanceToNextPart( nRawId, nPhase) -- calcolo l'elevazione dal punto medio local dElev local dLenIn, dLedOut = BL.GetPointDirDepth( nPartId, ptPs, tvtN[2]) if dLenIn > 0 then dElev = dLenIn elseif dLedOut then dElev = dLedOut end local dCollSic = 2 * BD.COLL_SIC -- calcolo il diametro utensile local dFaceDiamTool if tDimAndRef then -- prendo il valore dalle dimensioni minime delle facce dFaceDiamTool = min( tDimAndRef[2][1], tDimAndRef[2][2]) end -- se ho lavorazione precedente ricalcolo grossolanamente l'elevazione if dPrevFaceElev and dPrevFaceElev > 0 and dAng then dElev = dElev + ( sqrt( ( dElev * dElev) - ( dPrevFaceElev * dPrevFaceElev)) * sin(dAng)) elseif dPrevFaceElev and dPrevFaceElev > dElev then dElev = dPrevFaceElev end local sPocketing if sMasterPocket then sPocketing = sMasterPocket else sPocketing = ML.FindPocketing( sMchFind, dFaceDiamTool, dElev + dCollSic) end if not sPocketing then local sErr = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr) return false, sErr end local sTuuidPk local dDiamTool = 20 local dMaxDepth = 0 local bTipMill = false if EgtMdbSetCurrMachining( sPocketing) then sTuuidPk = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuidPk) or '') then dDiamTool = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dDiamTool dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth bTipMill = (( EgtTdbGetCurrToolParam( MCH_TP.TIPFEED) or 0) > 1) end end -- se nome svuotatura non è stato ricalcolato, confronto il diametro utensile utilizzato con il minimo faccia e se non sono compatibili esco if sMasterPocket and dFaceDiamTool and dDiamTool >= dFaceDiamTool then return false, '', sTuuidPk, dDiamTool, dElev end -- inserisco la lavorazione di svuotatura local sName = 'Pock_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. 'F' .. tostring( nFaceRef) local nMchFId = EgtAddMachining( sName, sPocketing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sPocketing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria (se presente curva si lavora quella) if Proc.LoopIdFacInd then EgtSetMachiningGeometry( { Proc.LoopIdFacInd}) else EgtSetMachiningGeometry( {{ Proc.Id, (nFaceRef)}}) end -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_CONT) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE -- se si lavora una faccia orizzontale e la dimensione X della feature è sufficiente, blocco l'asse B per evitare sollecitazioni inutili local b3Face = EgtGetBBoxGlob( Proc.Id, GDB_BB.STANDARD) if BD.C_SIMM and AreSameOrOppositeVectorApprox( tvtN[2], Z_AX()) and b3Face:getDimX() > BD.LONGCUT_ENDLEN then nSCC = MCH_SCC.ADIR_YM end if bLapJointAngTrasm then nSCC = MCH_SCC.ADIR_NEAR elseif not BD.C_SIMM and not BD.TURN then nSCC = MCH_SCC.ADIR_YM if AreSameVectorApprox( tvtN[2], Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( tvtN[2]:getX()) < 0.1 then local bNearTail = ( Proc.Box:getMax():getX() < b3Solid:getCenter():getX() + 50 and Proc.Box:getMax():getX() - b3Solid:getMin():getX() < 1000) local bVeryShortPart = ( BD.LEN_VERY_SHORT_PART and b3Solid:getDimX() < BD.LEN_VERY_SHORT_PART) nSCC = EgtIf( BL.IsPartFinalPhase( EgtGetCurrPhase()) or ( bNearTail and not bVeryShortPart), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif tvtN[2]:getY() > 0.1 then nSCC = MCH_SCC.ADIR_YP end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- se tasca aperta e non lavorata col truciolatore, imposto opportuno attacco if ( sMchFind == 'OpenPocket' or sMchFind == 'OpenPocket_H2') and nUseRoughTool == 0 then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end if sMchFind == 'OpenPocket' and dDiamTool < 90 then local _, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFaceRef, GDB_ID.ROOT) local bL = ( Proc.Fct < 4 or TestElleShape4( Proc) == 2) if bL and min( dH, dV) < 1.5 * dDiamTool then EgtSetMachiningParam( MCH_MP.INVERT, false) if not bTipMill then EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_POCK_LI.HELIX) EgtSetMachiningParam( MCH_MP.LITANG, dDiamTool) EgtSetMachiningParam( MCH_MP.LIELEV, 2) end end end -- eventuale massima elevazione forzata if dCustomMaxElev and dCustomMaxElev < 1 then dCustomMaxElev = nil end -- se elevazione superiore a massimo affondamento della fresa, riduco opportunamente dElev = dCustomMaxElev or dElev local sWarn local dDepth = dElev if dElev > dMaxDepth + 10 * GEO.EPS_SMALL then dDepth = dMaxDepth - dElev EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) dElev = dMaxDepth sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end -- imposto elevazione e dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) -- Se forzato lato aperto lavorazione da curva forzo OpenOutRaw if( Proc.LoopIdFacInd and ( EgtGetInfo( Proc.LoopIdFacInd, 'OPEN', 'i') or -1) > -1) then local _, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFaceRef, GDB_ID.ROOT) -- Se larghezza tasca uguale a larghezza utensile non permetto Invert if abs( min( dH, dV) - dDiamTool) < 50 * GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.INVERT, false) end bOpenOutRaw = true end if bOpenOutRaw then sUserNotes = EgtSetValInNotes( sUserNotes, 'OpenOutRaw', 1) end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) if not ML.ApplyMachining( true, false) then -- provo ad allargare leggermente la tasca EgtSetMachiningParam( MCH_MP.OFFSR, -0.1) -- se percorso a Zig-Zag, provo a cambiarlo in spirale local nPocketSubType = EgtGetMachiningParam( MCH_MP.SUBTYPE) if nPocketSubType == MCH_POCK_SUB.ZIGZAG then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- se la lavorazione rovina il pezzo successivo emetto warning if ( not Proc.Tail or Proc.AdvTail) and Proc.AffectedFaces.Left and dDistToNextPiece < dDiamTool / 2 then sWarn = 'Warning on pocketing ' .. sName .. ': machining can damage next piece. Minimum distance needed : ' .. ( 1 + dDiamTool / 2) .. ' mm' EgtOutLog( sWarn) end if BD.TURN and BD.TURN ~= 2 then -- centro del pezzo local ptCen = ORIG() if b3Solid then ptCen = b3Solid:getCenter() end -- punto inizio lavorazione local ptStart = EgtGetMachiningStartPoint() or ORIG() -- orientamento braccio local nSCC = MCH_SCC.NONE -- se faccia verso alto o basso if abs( tvtN[2]:getZ()) > abs( tvtN[2]:getY()) then nSCC = EgtIf( ptStart:getY() > ptCen:getY(), MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) -- altrimenti faccia verso davanti o dietro else nSCC = EgtIf( ptStart:getZ() > ptCen:getZ(), MCH_SCC.ADIR_ZP, MCH_SCC.ADIR_ZM) end EgtSetMachiningParam( MCH_MP.SCC, nSCC) ML.ApplyMachining( true, false) end return true, sWarn, sTuuidPk, dDiamTool, dDepth end --------------------------------------------------------------------- local function MachineByMill( Proc, nPhase, nRawId, nPartId, b3Solid, tvtN, nBaseFace, nSideFace, ptPs, tDimAndRef, b3Raw, nDiffWidth, nUseRoughTool, dAng, sPocketing, sTuuidPk, dPrevFaceElev) local sMchFind = 'Pocket' local dAngLimit = 40 local sWarn -- se feature é larga come trave imposto openpocket if nDiffWidth == 0 then sMchFind = 'OpenPocket' -- altrimenti non è passante disabilito il truciolatore else nUseRoughTool = 0 end -- se angolo tra le facce maggiore di 90, inserisco la contornatura o svuotatura del lato più corto if ( 180 + dAng) > 90.1 then -- calcolo l'angolo dalla verticale dall'angolo tra le due facce, perchè la feature potrebbe essere ruotata sulla Z locale della -- faccia principale e quindi la componente X del versore della faccia potrebbe dare un valore non coerente local dDiffFromSqAng = dAng + 90 -- informazioni sul lato da lavorare local Edges = BL.GetEdgesInfo( Proc, Proc.Face[nSideFace + 1]) local EdgeToMachine = {} for i = 1, #Edges do local CurrentEdge = Edges[i] if CurrentEdge.AdjacentFaceId == nBaseFace then EdgeToMachine = CurrentEdge end end -- se l'angolo dalla verticale si discosta di più dell'angolo limite impostato, utilizzo la svuotatura if cos( dDiffFromSqAng) < cos( dAngLimit) then -- applico la svuotatura local bOk, sWarn, sTuuidPk, dDiamTool, dElev = MakePocket( Proc, nPartId, b3Solid, ptPs, tvtN, nSideFace, sMchFind, nUseRoughTool, sPocketing, dPrevFaceElev, tDimAndRef, dAng, nil, nil, nPhase, nRawId) if not bOk then -- se ho id utensile e diametro è perchè non ha fatto svuotatura perchè la faccia è più stretta del diametro utensile -- e provo ad inserire singola passata di testa if sTuuidPk and dDiamTool then -- recupero la lavorazione local sMilling = ML.FindMilling( 'Long2Cut', dElev, sTuuidPk) if not sMilling then local sErr = 'Error : Long2Cut not found in library' EgtOutLog( sErr) return false, sErr end -- inserisco la lavorazione local sName = 'Prof_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchId = EgtAddMachining( sName, sMilling) if not nMchId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nSideFace}}) -- imposto vettore direzione e faceUse local vtFaceUse = EdgeToMachine.ToolDirection local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VtFaceUse', EgtNumToString( vtFaceUse:getX(), 3) .. ',' .. EgtNumToString( vtFaceUse:getY(), 3) .. ',' .. EgtNumToString( vtFaceUse:getZ(), 3)) local nFaceUse = BL.GetNearestOrthoOpposite( vtFaceUse) -- aggiusto i parametri EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) EgtSetMachiningParam( MCH_MP.DEPTH_STR, 'TH') EgtSetMachiningParam( MCH_MP.OFFSR, 0) EgtSetMachiningParam( MCH_MP.INVERT, false) EgtSetMachiningParam( MCH_MP.WORKSIDE, 1) -- imposto allungamenti iniziale e finale if EdgeToMachine.IsStartOpen then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dDiamTool / 2) else EgtSetMachiningParam( MCH_MP.STARTADDLEN, -dDiamTool / 2) end if EdgeToMachine.IsEndOpen then EgtSetMachiningParam( MCH_MP.ENDADDLEN, dDiamTool / 2) else EgtSetMachiningParam( MCH_MP.ENDADDLEN, -dDiamTool / 2) end -- imposto posizione braccio porta testa if tvtN[2]:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- imposto elevazione e dichiaro non si generano sfridi per VMill sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn end end else return false, sWarn end else return bOk, sWarn end -- altrimenti contornatura di fianco else local bOpenStart = false local bOpenEnd = false if nDiffWidth == 0 then bOpenStart = true bOpenEnd = true else bOpenStart = EdgeToMachine.IsStartOpen bOpenEnd = EdgeToMachine.IsEndOpen end local sMilling if nUseRoughTool > 0 then sMilling = ML.FindMilling( 'Long2Cut', nil, sTuuidPk) if not sMilling then sMilling = ML.FindMilling( 'LongSmallCut', nil, sTuuidPk) end else sMilling = ML.FindMilling( 'LongSmallCut', nil, sTuuidPk) if not sMilling then sMilling = ML.FindMilling( 'Long2Cut', nil, sTuuidPk) end end if not sMilling then sMilling = ML.FindMilling( 'LongSmallCut') if not sMilling then sMilling = ML.FindMilling( 'Long2Cut') end if not sMilling then local sErr = 'Error : Long2Cut & LongSmallCut not found in library' EgtOutLog( sErr) return false, sErr else sWarn = 'Warning : lapjoint angled face machined with different tool' end end -- recupero i dati dell'utensile local dTDiam = 50 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam end end -- se utensile troppo più grande dell'originale salto la lavorazione if sTuuidPk and EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuidPk) or '') then local dTDiamOriginalTool = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or 0 if dTDiam > 2 * dTDiamOriginalTool then sWarn = 'Warning : lapjoint angled face skipped (no compatible tool)' EgtOutLog( sWarn) return true, sWarn end end -- Calcolo uso faccia local nFaceUse = BL.GetNearestParalOpposite( tDimAndRef[1][3]:getVersZ()) -- inserisco la lavorazione di fresatura local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, (nSideFace)}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- sistemazione inversione del percorso local nWrkSide = EgtGetMachiningParam( MCH_MP.WORKSIDE) local bInvert = nWrkSide ~= MCH_MILL_WS.RIGHT EgtSetMachiningParam( MCH_MP.INVERT, bInvert) if bInvert then bOpenStart, bOpenEnd = bOpenEnd, bOpenStart end -- setto a 0 eventuali offset EgtSetMachiningParam( MCH_MP.OFFSR, 0) -- calcolo elevazione per allungamenti attacchi con fianchi chiusi local dElev local dLenIn, dLedOut = BL.GetPointDirDepth( nPartId, ptPs, tvtN[2]) if dLenIn > 0 then dElev = dLenIn elseif dLedOut then dElev = dLedOut end -- applico gli allungamenti o accorciamenti if bOpenStart then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dTDiam / 2) else EgtSetMachiningParam( MCH_MP.STARTADDLEN, -dTDiam / 2) -- forzo attacco lineare if dElev > 0 then EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, dElev) if bOpenEnd then EgtSetMachiningParam( MCH_MP.LOPERP, 0) else EgtSetMachiningParam( MCH_MP.LOPERP, dElev) end end end if bOpenEnd then EgtSetMachiningParam( MCH_MP.ENDADDLEN, dTDiam / 2) else EgtSetMachiningParam( MCH_MP.ENDADDLEN, -dTDiam / 2) -- forzo attacco lineare if dElev > 0 then EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LOPERP, dElev) if bOpenStart then EgtSetMachiningParam( MCH_MP.LIPERP, 0) else EgtSetMachiningParam( MCH_MP.LIPERP, dElev) end end end -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end end end return true, sWarn end --------------------------------------------------------------------- local function GetUShapeWidth( Proc, nFacInd) -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] -- se non ho facce adiacenti esco subito if not vAdj or #vAdj == 0 then return 0 end -- Normale della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) -- Cerco le facce adiacenti alla principale con angolo concavo >= 90 local dWidth = 0 for i = 1, #vAdj do if vAdj[i] >= 0 then -- verifico l'angolo tra le facce ( esco se angolo compreso < 90) local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) if bAdj and dAng < -90 - 20 * GEO.EPS_ANG_SMALL then return nil end -- larghezza della faccia ortogonalmente alla adiacente local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, vAdj[i], GDB_ID.ROOT) local vtX = vtN2 ^ vtN local frRef = Frame3d( ptC, ptC + 100 * vtX, ptC + 100 * vtN2) local b3Ref = EgtSurfTmGetFacetBBoxRef( Proc.Id, nFacInd, GDB_BB.STANDARD, frRef) if b3Ref then dWidth = max( dWidth, b3Ref:getDimY()) end end end return dWidth end --------------------------------------------------------------------- local function MakeByPockets( Proc, nPhase, nRawId, nPartId, nChamfer, dDepthCham, nAddGrpId, sMchFindMaster, bIs3Faces, b3Solid, bOrthoFacesMaster, bMillDown, bSetOpenBorders, bIsU, bIsL) local nFirstMachId local bOrthoFaces local sWarn local sMchFind = 'Pocket' local dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, nSurfInt local bBadMach = false -- minima altezza della tasca sotto alla quale fa una contornatura invece di una svuotatura local dMinFaceElevForPocket = 20 if sMchFindMaster and #sMchFindMaster > 0 then sMchFind = sMchFindMaster end if bIs3Faces then -- recupero la faccia con il maggior numero di adiacenze e l'elevazione relativa local nFacInd, dFacElev, nFacInd2, dFacElev2 = BL.GetFaceWithMostAdj( Proc, nPartId, bIs3Faces) if not nFacInd or nFacInd < 0 then if nFacInd == -1 then bOrthoFaces = nFacInd2 else local sErr = 'Error : MakeByPockets could not find reference face' EgtOutLog( sErr) return -1, sErr end end else bOrthoFaces = bOrthoFacesMaster end -- se è un tunnel verifico se è possibile usare la svuotatura if bOrthoFaces then -- ottengo le dimensioni del tunnel dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) -- se due facce posso utilizzare utensile con diametro doppio della dimensione minima if Proc.Fct == 2 then dDimMin = 2 * dDimMin -- se tre facce aumento il diametro di quanto possibile elseif Proc.Fct == 3 then local nFacInd = BL.GetFaceWithMostAdj( Proc, nPartId, false) local dWidth = GetUShapeWidth( Proc, nFacInd or -1) or dDimMin if dWidth > dDimMin then dDimMin = min( 2 * dDimMin, dWidth) end end -- se devo inserire il chamfer if nChamfer > 0 then local nOk, sErr = MakeChamfer( Proc, bIs3Faces, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return -1, sErr end end -- se smusso non è esclusivo local nPathInt if nChamfer < 2 then -- ricalcolo se è lavorabile da sotto bMillDown = ( BD.DOWN_HEAD == true) -- verifico se può essere fatto con svuotatura local bMakePocket, sPocketing, dMaxDepth, dDiamTool = VerifyPocket( Proc, dDimMin, dDepth / 2, nil, sMchFind) local bMakePocketDn, sPocketingDn, dMaxDepthDn, dDiamToolDn if bMillDown then bMakePocketDn, sPocketingDn, dMaxDepthDn, dDiamToolDn = VerifyPocket( Proc, dDimMin, dDepth / 2, nil, sMchFind, nil, true) -- se è negativo inverto il versore e la faccia if vtOrtho:getZ() < 0 then vtOrtho = -vtOrtho EgtInvertSurf( nSurfInt) end end local nFacInd, dFacElev = BL.GetFaceWithMostAdj( Proc, nPartId) local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) local bMakeContour = false local sMilling if dFacElev < dMinFaceElevForPocket and ( bIsU or bIsL) and ( Proc.Fct == 2 or Proc.Fct == 3) and abs( vtN:getZ()) > 0.996 then -- recupero la lavorazione di contornatura sMilling = ML.FindMilling( 'Prof', nil, nil, nil, nil, not bMillDown, bMillDown) if not sMilling then local sMyWarn = 'Warning : Prof not found in library' EgtOutLog( sMyWarn) end -- recupero i dati dell'utensile dDiamTool = 50 dMaxDepth = 0 if sMilling and EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dDiamTool = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dMillDiam dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dToolMaxDepth bMakeContour = true end end end if bMakePocket or bMakeContour then -- gestione svuotatura da un solo lato o anche dal lato opposto (se non verticale) -- estraggo il contorno dalla superfice per evitare i problemi con la svuotatura -- e assegno l'estrusione nPathInt = EgtExtractSurfTmLoops( nSurfInt, nAddGrpId) EgtModifyCurveExtrusion( nPathInt, vtOrtho, GDB_RT.GLOB) -- se ho 3 facce oppure se forzato, ciclo sulle entià del percorso per segnare quelle che sono aperte. if bIs3Faces or bSetOpenBorders then BL.SetOpenSide( nPathInt, b3Solid) end -- variabili per parametri lavorazione local dMachDepth local dElev = 0 local bDoubleSide local bOneShot local bComplete = true -- imposto altezza aggiuntiva di elevazione local dCollSic = BL.CalcCollisionSafety( vtOrtho) -- se possibile svuotare completamente da una sola parte if dMaxDepth > ( dDepth + BD.CUT_EXTRA + dCollSic) then dMachDepth = ( dDepth / 2) + BD.CUT_EXTRA dElev = dDepth + BD.CUT_EXTRA bOneShot = true else -- se direzione verso la verticale setto max affondamento possibile ed -- emetto messaggio di warning perché non lavorabile interamente if abs( vtOrtho:getZ()) >= 0.707 and not BD.DOWN_HEAD and not bMakeContour then dMachDepth = dMaxDepth - ( dDepth / 2) - dCollSic dElev = dMaxDepth sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) bComplete = false -- altrimenti setto il flag per fare la svuotatura da due parti else -- se l'altezza utensile riesce a lavorare completamente da due parti if dMaxDepth > ( dDepth / 2) + dCollSic + BD.CUT_EXTRA_MIN then dMachDepth = BD.CUT_EXTRA_MIN dElev = ( dDepth / 2) + BD.CUT_EXTRA_MIN -- altrimenti non si riesce in due passate, limito la profondità e setto l'elevazione else dMachDepth = dMaxDepth - ( dDepth / 2) - dCollSic dElev = dMaxDepth -- se molto inclinato rispetto alla normale della faccia di riferimento, lavorazione non idonea per probabili collisioni local vtRef = Y_AX() if abs( vtOrtho:getX()) > abs( vtOrtho:getY()) and abs( vtOrtho:getX()) > abs( vtOrtho:getZ()) then vtRef = X_AX() elseif abs( vtOrtho:getZ()) > abs( vtOrtho:getX()) and abs( vtOrtho:getZ()) > abs( vtOrtho:getY()) then vtRef = Z_AX() end if abs( vtOrtho * vtRef) < 0.5 then bBadMach = true end end bDoubleSide = true end end -- se lavorazione non idonea esco if bIs3Faces and bBadMach then local sErr = 'Impossible apply perpendicular pocketing: ' .. sPocketing return -2, sErr end local sName local nMchFId if bMakeContour then -- inserisco la lavorazione di contornatura sName = 'Prof_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return -1, sErr end else -- altrimenti inserisco la lavorazione di svuotatura sName = 'Pock_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchFId = EgtAddMachining( sName, sPocketing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sPocketing EgtOutLog( sErr) return -1, sErr end end -- prendo l'id della prima lavorazione inserita if not nFirstMachId then nFirstMachId = nMchFId end if bMakeContour then -- aggiungo geometria per contornatura EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) else -- altrimenti aggiungo geometria per svuotatura EgtSetMachiningGeometry( {{ nPathInt, -1}}) end -- verifico se devo invertire direzione utensile (in caso di direzione verso la verticale) local bInvertMach if not bMakeContour then if vtOrtho:getZ() < BD.NZ_MINA and abs(vtOrtho:getZ()) >= 0.707 and not BD.DOWN_HEAD then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true -- altrimenti se da fare in una sola volta e direzionato verso Y+ lo inverto per lavorarlo davanti elseif not bDoubleSide and vtOrtho:getY() > GEO.EPS_SMALL and not ( -(vtOrtho:getZ()) < BD.NZ_MINA) then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true end end -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtOrtho, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtOrtho:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtOrtho:getY() < GEO.EPS_SMALL then nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP) end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- se tasca aperta, imposto opportuno attacco if sMchFind == 'OpenPocket' or sMchFind == 'OpenPocket_H2' then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end -- inverto il percorso di lavorazione per lavorare sinistro if not bMakeContour then EgtSetMachiningParam( MCH_MP.INVERT, true) end -- imposto affondamento if not bMakeContour then EgtSetMachiningParam( MCH_MP.DEPTH, dMachDepth) end -- se contornatura doppia anticipo la fine della lavorazione a metà trave if bMakeContour and bDoubleSide then EgtSetMachiningParam( MCH_MP.OFFSL, dDepth / 2) end -- se contornatura cerco la direzione di lavoro migliore e setto attacco e allungamenti if bMakeContour then local nFaceUse = BL.GetNearestParalOpposite( vtOrtho) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- quantità di cui allargare la contornatura per andare in tangenza con lo spigolo, nel caso di altezza tasca minore di D/2 fresa local dAddWorkWidth = EgtIf( dFacElev < dDiamTool / 2, -sqrt( dFacElev * dDiamTool - dFacElev * dFacElev), -dDiamTool / 2) EgtSetMachiningParam( MCH_MP.LIELEV, 0) EgtSetMachiningParam( MCH_MP.LOELEV, 0) if bIsU then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 30) EgtSetMachiningParam( MCH_MP.LOPERP, 30) elseif bIsL then EgtSetMachiningParam( MCH_MP.STARTADDLEN, 30) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.TANGENT) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 30) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 0) EgtSetMachiningParam( MCH_MP.LOPERP, 30) end end -- imposto elevazione e dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' if not bMakeContour then sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) end sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) or EgtIsMachiningEmpty() then -- provo ad allargare leggermente la tasca EgtSetMachiningParam( MCH_MP.OFFSR, -0.1) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return -1, sErr elseif EgtIsMachiningEmpty() then EgtRemoveOperation( nMchFId) local sErr = 'Impossible to machine (empty toolpath)' return -3, sErr end end -- se posso applicare la svuotatura sul lato opposto if bDoubleSide then -- se ho la lavorazione da sotto ricalcolo in base a questa lavorazione if bMakePocketDn then -- sPocketing = sPocketingDn -- dMaxDepth = dMaxDepthDn -- dDiamTool = dDiamToolDn -- se l'altezza utensile riesce a lavorare completamente da due parti if dMaxDepthDn > ( dDepth / 2) + dCollSic + BD.CUT_EXTRA_MIN then dMachDepth = BD.CUT_EXTRA_MIN dElev = ( dDepth / 2) + BD.CUT_EXTRA_MIN -- altrimenti non si riesce in due passate, limito la profondità e setto l'elevazione else dMachDepth = dMaxDepthDn - ( dDepth / 2) - dCollSic dElev = dMaxDepthDn bComplete = false sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end else -- se anche lavorando dal lato opposto non riesco a svuotare completamente la fessura -- setto i parametri affondamento ed emetto warning if dMaxDepth < ( dDepth / 2) + BD.CUT_EXTRA + dCollSic then dMachDepth = dMaxDepth - (dDepth / 2) - dCollSic dElev = dMaxDepth bComplete = false sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end end if bMakeContour then -- inserisco la lavorazione di contornatura sName = 'ProfOppo_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return -1, sErr end else -- inserisco la lavorazione di svuotatura sName = 'PockOppo_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) nMchFId = EgtAddMachining( sName, EgtIf( bMakePocketDn, sPocketingDn, sPocketing)) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. EgtIf( bMakePocketDn, sPocketingDn, sPocketing) EgtOutLog( sErr) return -1, sErr end end -- prendo l'id della prima lavorazione inserita if not nFirstMachId then nFirstMachId = nMchFId end if bMakeContour then -- aggiungo geometria per contornatura EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) else -- altrimenti aggiungo geometria per svuotatura EgtSetMachiningGeometry( {{ nPathInt, -1}}) end -- imposto direzione utensile opposta EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameVectorApprox( vtOrtho, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtOrtho:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtOrtho:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YP else nSCC = MCH_SCC.ADIR_YM end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- se tasca aperta, imposto opportuno attacco if sMchFind == 'OpenPocket' or sMchFind == 'OpenPocket_H2' then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end -- inverto il percorso di lavorazione per lavorare sinistro EgtSetMachiningParam( MCH_MP.INVERT, true) -- imposto affondamento if not bMakeContour then EgtSetMachiningParam( MCH_MP.DEPTH, dMachDepth) end -- se contornatura doppia anticipo la fine della lavorazione a metà trave if bMakeContour and bDoubleSide then EgtSetMachiningParam( MCH_MP.OFFSL, dDepth / 2) end -- se contornatura cerco la direzione di lavoro migliore if bMakeContour then local nFaceUse = BL.GetNearestParalOpposite( vtOrtho) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- quantità di cui allargare la contornatura per andare in tangenza con lo spigolo, nel caso di altezza tasca minore di D/2 fresa local dAddWorkWidth = EgtIf( dFacElev < dDiamTool / 2, -sqrt( dFacElev * dDiamTool - dFacElev * dFacElev), -dDiamTool / 2) EgtSetMachiningParam( MCH_MP.LIELEV, 0) EgtSetMachiningParam( MCH_MP.LOELEV, 0) if bIsU then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.STARTADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 30) EgtSetMachiningParam( MCH_MP.LOPERP, 30) elseif bIsL then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dAddWorkWidth) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 30) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.TANGENT) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 30) EgtSetMachiningParam( MCH_MP.LIPERP, 30) EgtSetMachiningParam( MCH_MP.LOPERP, 0) end end -- imposto elevazione e dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' if not bMakeContour then sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dElev, 1)) end sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then -- provo ad allargare leggermente la tasca EgtSetMachiningParam( MCH_MP.OFFSR, -0.1) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return -1, sErr end else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end end -- se non completo e U, cerco di lavorare anche la faccia di fondo (con il massimo affondamento possibile) if not bComplete and bIs3Faces then -- recupero la faccia da lavorare local nFacInd, dFacElev = BL.GetFaceWithMostAdj( Proc, nPartId) local vtN local bPock3rd = false if nFacInd then vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd, GDB_ID.ROOT) bPock3rd = ( vtN and ( vtN:getZ() >= BD.NZ_MINA or bMakePocketDn)) end if bPock3rd then -- recupero la distanza di sicurezza aggiuntiva local dFacCollSic = BL.CalcCollisionSafety( vtN) -- scelgo se lavorare da sotto local bFacPocketDn = ( bMakePocketDn and vtN:getZ() < -0.174) -- inserisco la lavorazione di svuotatura local sName = EgtIf( bDoubleSide, 'Pock3rd_', 'Pock2nd_') .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, EgtIf( bFacPocketDn, sPocketingDn, sPocketing)) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sPocketing EgtOutLog( sErr) return -1, sErr end -- prendo l'id della prima lavorazione inserita if not nFirstMachId then nFirstMachId = nMchFId end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtN, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YM else nSCC = MCH_SCC.ADIR_YP end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- se tasca aperta, imposto opportuno attacco if sMchFind == 'OpenPocket' or sMchFind == 'OpenPocket_H2' then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end -- inverto il percorso di lavorazione per lavorare sinistro EgtSetMachiningParam( MCH_MP.INVERT, true) -- imposto affondamento local dDepth = 0 local dActMaxDepth = EgtIf( bFacPocketDn, dMaxDepthDn, dMaxDepth) if dActMaxDepth < dFacElev + dFacCollSic then dDepth = dActMaxDepth - ( dFacElev + dFacCollSic) end EgtSetMachiningParam( MCH_MP.DEPTH, dDepth) -- dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then -- provo ad allargare leggermente la tasca EgtSetMachiningParam( MCH_MP.OFFSR, -0.1) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return -1, sErr end else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end end end return 1, sWarn, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, dDiamTool, bDoubleSide, nPathInt, nSurfInt, bOneShot, bMillDown, nFirstMachId end end end return 0, sWarn, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, dDiamTool, bDoubleSide, nPathInt, nSurfInt, bOneShot, bMillDown, nFirstMachId, bOrthoFaces end --------------------------------------------------------------------- local function ManageAntiSplintBySaw( Proc, b3Raw, b3Solid, bIsU, vtN, nFacInd, sWarn, bMillDown, bReduceDepth) local bMadeASbyBld = false local nNumFac = EgtIf( bIsU, 2, 1) local nPrefSide = 1 -- di preferenza il motore è meglio tenerlo sinistra -- se a U cerco di ottimizzare il lato di lavoro della lama if bIsU then if abs( vtN:getY()) > 0.996 then nPrefSide = 0 elseif abs( vtN:getZ()) > 0.63 or abs( vtN:getY()) > 0.63 then -- se X è negativa allora devo tenere il motore a destra if vtN:getX() < 0.087 then nPrefSide = 2 end end end -- va eseguito sulle facce diverse dalla principale local nPrevSCC = nil for nFacet = 0, nNumFac do if nFacet ~= nFacInd then -- lavoro local dSawThick = 0 local dMaxDepth = 200 local bAdj, dAng, dExtraOffs, sWarn2, nIdMach bMadeASbyBld, sWarn2, nIdMach, dSawThick, dMaxDepth, bAdj, dAng, dExtraOffs = MakeAntiSplintBySaw( Proc, nFacet, vtN, b3Raw, nFacInd, bReduceDepth, bMillDown) if not bMadeASbyBld then return bMadeASbyBld, false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end -- se antischeggia veramente inserito perchè necessario if nIdMach then -- verifico se da invertire local bInvertMach = false if bIsU then -- prendo il vettore normale alla faccia local vtNFc = EgtSurfTmFacetNormVersor( Proc.Id, nFacet, GDB_ID.ROOT) if abs( vtN:getZ()) > 0.63 or abs( vtN:getY()) > 0.63 then -- se superficie principale parallela al piano XZ if nPrefSide == 0 then -- se facce praticamente verticali || if abs( vtNFc:getZ()) < 0.1 then -- se FAST, mandrino a destra o sinistra come svuotatura if not BD.C_SIMM and not BD.TURN then local bNearTail = ( Proc.Box:getMax():getX() < b3Solid:getCenter():getX() + 50 and Proc.Box:getMax():getX() - b3Solid:getMin():getX() < 1000) local bVeryShortPart = ( BD.LEN_VERY_SHORT_PART and b3Solid:getDimX() < BD.LEN_VERY_SHORT_PART) nPrefSide = EgtIf( BL.IsPartFinalPhase( EgtGetCurrPhase()) or ( bNearTail and not bVeryShortPart), 1, 2) -- altrimenti sempre a destra else nPrefSide = 2 end -- se facce inclinate \\ allora mandrino a destra (per essere verso l'alto) elseif vtNFc:getX() * vtNFc:getZ() > 0 then nPrefSide = 2 -- altrimenti facce inclinate // quindi mandrino a sinistra (per essere ancora verso l'alto) else nPrefSide = 1 end end -- se faccia verso X+ e mandrino verso sinistra if vtNFc:getX() > 0 and nPrefSide == 1 then -- se angolo interno e circa -90 if abs( dAng + 90) < 5 then bInvertMach = true end -- se faccia verso X- e mandrino verso destra elseif vtNFc:getX() < 0 and nPrefSide == 2 then -- se angolo interno e circa -90 if abs( dAng + 90) < 5 then bInvertMach = true end end end -- eseguo inversione if bInvertMach then local bToolInvert = EgtGetMachiningParam( MCH_MP.TOOLINVERT) local bInvert = EgtGetMachiningParam( MCH_MP.INVERT) local nFaceUse = EgtGetMachiningParam( MCH_MP.FACEUSE) local bOrtUp = ( nFaceUse >= MCH_MILL_FU.ORTUP_DOWN and nFaceUse <= MCH_MILL_FU.ORTUP_RIGHT) if not bOrtUp then -- assegno i parametri invertiti EgtSetMachiningParam( MCH_MP.TOOLINVERT, not bToolInvert) EgtSetMachiningParam( MCH_MP.INVERT, not bInvert) -- setto l'offset pari allo spessore lama EgtSetMachiningParam( MCH_MP.OFFSL, -dSawThick) end end end -- posizione del braccio : se primo taglio la recupero, altrimenti la imposto if not nPrevSCC then nPrevSCC = EgtGetMachiningParam( MCH_MP.SCC) elseif abs( vtN:getZ()) > 0.996 then EgtSetMachiningParam( MCH_MP.SCC, nPrevSCC) end -- rieseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nIdMach, false) return false, false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nIdMach, false) return false, sWarn end end end end end return bMadeASbyBld, true, sWarn end --------------------------------------------------------------------- local function MakePathsOnExtremePoints( nAddGrpId, nIdPath, pPaths, dTDiam, b3Solid) local dLength = 2 if not nIdPath then return pPaths end -- prendo i punti iniziali e finali del percorso e i versori direzione local ptIni = EgtSP( nIdPath, GDB_RT.GLOB) local ptEnd = EgtEP( nIdPath, GDB_RT.GLOB) -- se distanza tra i punti è <= del diametro utensile esco if dist( ptIni, ptEnd) <= dTDiam then return pPaths end -- prendo i versori iniziali e finali local vtIni = EgtSV( nIdPath, GDB_RT.GLOB) local vtEnd = EgtEV( nIdPath, GDB_RT.GLOB) -- si costruisce il percorso solo per i punti sui bordi del grezzo if BL.IsPointOnBoxLimits( ptIni, b3Solid) then local ptIniP = ptIni local ptEndP = ptIniP + (vtIni * dLength) local nAuxId = EgtLine( nAddGrpId, ptIniP, ptEndP, GDB_RT.GLOB) table.insert( pPaths, { nAuxId, 1, ptIniP}) end if BL.IsPointOnBoxLimits( ptEnd, b3Solid) then local ptIniP = ptEnd local ptEndP = ptEnd - ( vtEnd * dLength) local nAuxId = EgtLine( nAddGrpId, ptIniP, ptEndP, GDB_RT.GLOB) table.insert( pPaths, { nAuxId, 2, ptIniP}) end return pPaths end --------------------------------------------------------------------- local function MakeAntiSplintByMill( Proc, nPartId, pPaths, nPathInt, vtN1, bDoubleSide, bOppoSide, sMilling, nPhase, sMyWarn, dMaxElevMaster, dExtraDepth, dCollSic, dMaxDepth, nFirstMachId) local sMyWarn2 -- assegno lavorazioni ad ogni percorso for i = 1, #pPaths do local nIdPath = pPaths[i][1] local nSide = pPaths[i][2] -- modifico versore direzione EgtModifyCurveExtrusion( nIdPath, vtN1, GDB_RT.GLOB) local sName if bOppoSide then sName = 'AntiSplintOppo_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) else sName = 'AntiSplint_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) end local nMchId = EgtAddMachining( sName, sMilling) if nMchId then -- aggiungo geometria EgtSetMachiningGeometry( {{ nIdPath, -1}}) if ( bOppoSide and nSide == 1) or ( not bOppoSide and nSide == 2) then -- imposto lato di lavoro destro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.RIGHT) else -- imposto lato di lavoro sinistro EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) end local nSCC if bOppoSide then -- imposto direzione utensile opposta EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) -- imposto posizione braccio porta testa nSCC = MCH_SCC.ADIR_YM if not BD.C_SIMM then if AreSameVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YP else nSCC = MCH_SCC.ADIR_YM end end else local bInvertMach = false if not nPathInt then -- imposto posizione braccio porta testa nSCC = MCH_SCC.ADIR_YM if vtN1:getY() > 100 * GEO.EPS_ZERO then nSCC = MCH_SCC.ADIR_YP end else -- verifico se devo invertire direzione utensile (in caso di direzione verso la verticale) if vtN1:getZ() < BD.NZ_MINA and abs(vtN1:getZ()) >= 0.707 then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true -- altrimenti se da fare in una sola volta e direzionato verso Y+ lo inverto per lavorarlo davanti elseif not bDoubleSide and vtN1:getY() > GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) bInvertMach = true end -- imposto posizione braccio porta testa nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameOrOppositeVectorApprox( vtN1, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN1:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN1:getY() < GEO.EPS_SMALL then nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( bInvertMach, MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP) end end end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- parametri attacco EgtSetMachiningParam( MCH_MP.LEADINTYPE, 1) -- allungo inizio EgtSetMachiningParam( MCH_MP.STARTADDLEN, 2) EgtSetMachiningParam( MCH_MP.LITANG, 10) EgtSetMachiningParam( MCH_MP.LIPERP, -5) -- parametri uscita EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) local dMachDepth = 0 local dExtraElev = 0 if bDoubleSide then dExtraElev = BL.GetFaceElevationFromPointDir( Proc.Id, nPartId, pPaths[i][3], EgtIf( bOppoSide, -vtN1, vtN1)) - dMaxElevMaster end local dMaxElev = dMaxElevMaster + dExtraElev if ( dMaxElev + BD.CUT_EXTRA + dCollSic) > dMaxDepth then dMachDepth = dMaxDepth - ( dMaxElev + dCollSic) end -- setto se devo invertire il percorso local bInvert = CheckToInvert( nIdPath, true) if bOppoSide then EgtSetMachiningParam( MCH_MP.DEPTH, dMachDepth) EgtSetMachiningParam( MCH_MP.INVERT, bInvert) else EgtSetMachiningParam( MCH_MP.DEPTH, (dMachDepth+dExtraDepth)) EgtSetMachiningParam( MCH_MP.INVERT, EgtIf( bInvertMach, not bInvert, bInvert)) end -- Note utente con dichiarazione nessuna generazione sfridi per Vmill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) -- aggiungo alle note massima elevazione sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( ( dMaxElev + dMachDepth), 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if ML.ApplyMachining( true, false) then _, sMyWarn2 = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) else -- se ho la lavorazione di svuotatura riloco la lavorazione antischeggia prima di questa if nFirstMachId then EgtRelocateGlob( nMchId, nFirstMachId, GDB_IN.BEFORE) end end -- altrimenti lavorazione non applicata else _, sMyWarn2 = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) end -- altrimenti non è stata inserita lavorazione else sMyWarn2 = 'warning adding machining ' .. sName .. '-' .. sMilling end end if sMyWarn2 and #sMyWarn2 > 0 then sMyWarn = sMyWarn .. '\n' .. sMyWarn2 end return sMyWarn end --------------------------------------------------------------------- local function ManageAntiSplintByMill( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, bMillDown, dDiam, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShot, nFirstMachId) local sMyWarn = '' local pPaths = {} local nAuxId local sMilling -- recupero la lavorazione tenendo conto dell'elevazione local dCheckDepth if bDoubleSide then dCheckDepth = 0.5 * dDepth else if not nPathInt then dCheckDepth = BL.GetFaceElevation( Proc, nFacInd, b3Solid) else dCheckDepth = dDepth end end sMilling = ML.FindMilling( 'AntiSplintMillCut', dCheckDepth, nil, nil, nil, not( bMillDown and not bDoubleSide), bMillDown and not bDoubleSide) or ML.FindMilling( 'AntiSplintMillCut', 2/3 * dCheckDepth, nil, nil, nil, not( bMillDown and not bDoubleSide), bMillDown and not bDoubleSide) or ML.FindMilling( 'AntiSplintMillCut', nil, nil, nil, nil, not( bMillDown and not bDoubleSide), bMillDown and not bDoubleSide) if sMilling then local vtN1 local nFirstId, nNumId local dMaxElevMaster local dExtraDepth = 0 local dCollSic local ptMidDist -- recupero i dati dell'utensile local dTDiam = 50 local dMaxDepth = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end -- se non ho la faccia aggiunta if not nPathInt then -- ottengo i percorsi da cui estrapolare il percorso di antischeggia local tFacAdjMain = ChooseContour( Proc, nFacInd, false) local tPaths = {} -- se non trovato nessun angolo interno valido esco if #tFacAdjMain == 0 then return true, sMyWarn end -- prendo il primo versore _, vtN1 = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) dCollSic = BL.CalcCollisionSafety( vtN1) or 0 -- se direzione tende verso una delle alle 3 direzioni azzero l'altezza extra if abs( vtN1:getX()) > 0.7 or abs( vtN1:getY()) > 0.7 or abs( vtN1:getZ()) > 0.7 then dCollSic = 0 end -- se fresatura da sotto salto la lavorazione if vtN1:getZ() < BD.DRILL_VZ_MIN and not bMillDown then local sErr = 'Error : milling from bottom ' EgtOutLog( sErr) return false, sErr end local ptIniPath local nMaxLen = 0 dMaxElevMaster = BL.GetFaceElevation( Proc, nFacInd, b3Solid) -- ciclo tutta la tabella for i = 1, #tFacAdjMain do -- le 2 facce di contatto devono essere perpendicolari o non sottosquadra rispetto alla faccia di fondo local ptP1, ptP2, dAng ptP1 = tFacAdjMain[i][3] ptP2 = tFacAdjMain[i][4] dAng = tFacAdjMain[i][5] if ( dAng < 0 and 180 + dAng >= 90 - 10 * GEO.EPS_SMALL) then -- creo la linea da P1 a P2 nAuxId = EgtLine( nAddGrpId, ptP1, ptP2, GDB_RT.GLOB) table.insert( tPaths, nAuxId) -- prendo la lunghezza massima e il puto medio if tFacAdjMain[i][2] > nMaxLen then ptIniPath = ptP1 nMaxLen = tFacAdjMain[i][2] ptMidDist = ( ptP1 + ptP2) / 2 end end end -- cotruisco il/i percorso/i nFirstId, nNumId = EgtCurveCompoByReorder( nAddGrpId, tPaths, ptIniPath, true, GDB_RT.GLOB) local bOkPath = true for i = 1, nNumId do local nIdPath = nFirstId + i - 1 if EgtCurveIsClosed( nIdPath) then bOkPath = false end end -- se ho un percorso chiuso cancello tutto if not bOkPath then for i = 1, nNumId do local nIdPath = nFirstId + i - 1 EgtErase(nIdPath) end else -- creo percorsi antisplint dagli estremi dei percorsi di contorno trovati for i = 1, nNumId do local nIdPath = nFirstId + i - 1 pPaths = MakePathsOnExtremePoints( nAddGrpId, nIdPath, pPaths, dTDiam, b3Solid) end end -- alrimenti ho la faccia aggiunta else dCollSic = BL.CalcCollisionSafety( vtOrtho) nFirstId = EgtCopyGlob( nPathInt, nAddGrpId) nNumId = 1 -- calcolo elevazione dalla faccia trasversale aggiunta if bDoubleSide then dMaxElevMaster = 0.5 * dDepth else dMaxElevMaster = dDepth -- se la precedente svuotatura è stata fatta completamente in una sola volta -- valuto di nuovo se devo fare due passate o una sola if bOneShot then -- se non è possibile svuotare completamente da una sola parte if dMaxDepth <= ( dMaxElevMaster + BD.CUT_EXTRA + dCollSic) then bDoubleSide = true dMaxElevMaster = BL.GetFaceElevation( nSurfInt, 0, b3Solid) else dExtraDepth = dMaxElevMaster - BL.GetFaceElevation( nSurfInt, 0, b3Solid) end -- altrimenti non è stata fatta completamente calcolo la distanza tra faccia aggiunta e profondità superficie else dExtraDepth = dMaxElevMaster - BL.GetFaceElevation( nSurfInt, 0, b3Solid) end end vtN1 = Vector3d(vtOrtho) BL.SetOpenSide( nFirstId, b3Solid) local bOpenPath = BL.ChangeOrOpenStart( nFirstId, 2) -- se non ho un percorso chiuso estraggo i percorsi if bOpenPath then -- creo percorsi antisplint dagli estremi dei percorsi di contorno trovati pPaths = MakePathsOnExtremePoints( nAddGrpId, nFirstId, pPaths, dTDiam, b3Solid) end EgtErase(nFirstId) end if #pPaths > 0 then sMyWarn = MakeAntiSplintByMill( Proc, nPartId, pPaths, nPathInt, vtN1, bDoubleSide, false, sMilling, nPhase, sMyWarn, dMaxElevMaster, dExtraDepth, dCollSic, dMaxDepth, nFirstMachId) if bDoubleSide then if bMillDown then local sMillingDn = ML.FindMilling( 'AntiSplintMillCut_H2', dCheckDepth) or ML.FindMilling( 'AntiSplintMillCut_H2', 2/3 * dCheckDepth) or ML.FindMilling( 'AntiSplintMillCut_H2') sMilling = sMillingDn -- controllo dati lavorazione if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) dTDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dTDiam dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end end -- se lavorazione valida if sMilling then sMyWarn = MakeAntiSplintByMill( Proc, nPartId, pPaths, nPathInt, vtN1, bDoubleSide, true, sMilling, nPhase, sMyWarn, dMaxElevMaster, dExtraDepth, dCollSic, dMaxDepth, nFirstMachId) else sMyWarn = 'warning in process ' .. tostring( Proc.Id) .. ' clean corner milling/tool not found in library' end end -- altrimenti non c'è il percorso else sMyWarn = 'warning in process ' .. tostring( Proc.Id) .. ' impossible make clean corner path' end -- altrimenti non è stata trovata lavorazione else sMyWarn = 'warning in process ' .. tostring( Proc.Id) .. ' clean corner milling/tool not found in library' end if #sMyWarn > 0 then EgtOutLog( sMyWarn) end return true, sMyWarn end --------------------------------------------------------------------- local function MakeTunnelByChainSaw( Proc, sSawing, nLundIdFace, vtOrtho, dWorkDepth, dMaxMat, nStep, dStep, sFaceUse, bOpposite) for i = 1, nStep do -- inserisco la lavorazione di sawing local sName = '' if bOpposite then sName = 'Csaw_Opp_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) else sName = 'Csaw_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) end local nMchFId = EgtAddMachining( sName, sSawing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sSawing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nLundIdFace}}) local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nLundIdFace, GDB_ID.ROOT) -- imposto angolo 3° asse rot EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'perpendicular')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtN, vtOrtho, 1)) -- imposto offset radiale local dOffs = ( i - 1) * dStep EgtSetMachiningParam( MCH_MP.OFFSR, dOffs) EgtSetMachiningParam( MCH_MP.FACEUSE, sFaceUse) EgtSetMachiningParam( MCH_MP.DEPTH, dWorkDepth) -- modifico la distanza di attacco per considerare anche tunnel inclinati EgtSetMachiningParam( MCH_MP.STARTPOS, 50) -- eseguo if not ML.ApplyMachining( true, false) then if EgtGetOutstrokeInfo() then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sSawing, 'parallel')) EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( vtN, vtOrtho, 2)) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end end if EgtIsMachiningEmpty() then _, sWarn = EgtGetMachMgrWarning( 0) EgtSetOperationMode( nMchFId, false) return false, sWarn end end return true end --------------------------------------------------------------------- --#region SawPlusChain -- 5 facce: la faccia di fondo è il fondo della tasca, la faccia da lavorare è grande, le facce laterali sono le due piccole -- 4 facce con faccia di fondo piccola: la faccia da lavorare è grande (2 adj) e l'unica faccia laterale è piccola -- 4 facce con faccia di fondo grande: la faccia da lavorare è piccola (3 adj) e le facce laterali sono le due piccole -- 3 facce: la faccia di fondo è il fondo della tasca, la faccia da lavorare è grande, non ci sono facce laterali -- TODO gestione messaggi in funzione apposita (almeno per append) local SawPlusChain = {} SawPlusChain.Saw = {} SawPlusChain.Chainsaw = {} SawPlusChain.Name = 'SawPlusChain' SawPlusChain.ApplyOnlySawblade = false function SawPlusChain.IsTopologyOk( Proc) if Proc.TopologyLongName == 'Pocket-Blind-RightAngles-Parallel-5' or Proc.TopologyLongName == 'Groove-Through-RightAngles-Parallel-3' or Proc.TopologyLongName == 'Groove-Through-RightAngles-NotParallel-3' or Proc.TopologyLongName == 'Groove-Blind-RightAngles-Parallel-4' or Proc.TopologyLongName == 'Tunnel-Through-RightAngles-Parallel-4' then return true else return false end end function SawPlusChain.GetTunnelFaces( Proc) local TunnelAddedFaces = {} -- TODO scrivere il box della parte nella Proc o fare funzione per recuperarlo local b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.PartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not ( Proc.IsThrough and Proc.AllRightAngles and Proc.Fct < 5) then error( 'GetTunnelFaces : Topology not implemented') end -- direzione del tunnel local vtTunnelDirection = Proc.Face[1].VtN ^ Proc.Face[ Proc.Face[1].Adjacencies[1] + 1].VtN -- centro del tunnel local frTunnel = Frame3d( Proc.Face[1].PtCenter, vtTunnelDirection) local b3Tunnel = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, frTunnel) local ptTunnelCenter = b3Tunnel:getCenter() ptTunnelCenter:toGlob( frTunnel) -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( Proc.PartId) if not nAddGrpId then EgtOutLog( 'Error : missing AddGroup') return TunnelAddedFaces end -- faccia centrale, si crea larga come la parte e poi si trimma TunnelAddedFaces.MiddleFaceTm = {} TunnelAddedFaces.MiddleFaceTm.Id = EgtSurfTmPlaneInBBox( nAddGrpId, ptTunnelCenter, vtTunnelDirection, b3Part, GDB_ID.ROOT) -- TODO se non si riesce a costruire la faccia bisogna dare errore o semplicemente non ritornarla?? for i = 1, Proc.Fct do EgtCutSurfTmPlane( TunnelAddedFaces.MiddleFaceTm.Id, Proc.Face[i].PtCenter, -Proc.Face[i].VtN, false, GDB_ID.ROOT) end local _, dFaceWidth, dFaceHeight = BL.GetFaceHvRefDim( TunnelAddedFaces.MiddleFaceTm.Id, 0) -- larghezza OCS faccia TunnelAddedFaces.MiddleFaceTm.Width = dFaceWidth -- altezza OCS faccia TunnelAddedFaces.MiddleFaceTm.Height = dFaceHeight if TunnelAddedFaces.MiddleFaceTm.Height > TunnelAddedFaces.MiddleFaceTm.Width then TunnelAddedFaces.MiddleFaceTm.Height, TunnelAddedFaces.MiddleFaceTm.Width = TunnelAddedFaces.MiddleFaceTm.Width, TunnelAddedFaces.MiddleFaceTm.Height end TunnelAddedFaces.MiddleFaceTm.Type = 'Tunnel' return TunnelAddedFaces end function SawPlusChain.GetBottomFace( Proc) local BottomFace = {} if Proc.Topology == 'Tunnel' then return nil end -- la faccia di fondo ha sempre Fct - 1 adiacenze. Se si trovano più facce di fondo si sceglie quella con minor elevazione local vBottomFace = Topology.GetFacesWithGivenAdjacencyNumber( Proc, Proc.vAdj, Proc.Fct - 1) local nBottomFace if #vBottomFace > 1 then local dMinElevation = GEO.INFINITO for i = 1, #vBottomFace do for j = 1, Proc.Fct do if vBottomFace[i] == Proc.Face[j].Id then if Proc.Face[j].Elevation < dMinElevation then dMinElevation = Proc.Face[j].Elevation nBottomFace = Proc.Face[j].Id end end end end else nBottomFace = vBottomFace[1] end BottomFace.Id = nBottomFace BottomFace.Type = 'Bottom' BottomFace.Width = Proc.Face[nBottomFace + 1].Width BottomFace.Height = Proc.Face[nBottomFace + 1].Height BottomFace.Elevation = Proc.Face[nBottomFace + 1].Elevation BottomFace.VtN = Proc.Face[nBottomFace + 1].VtN if BottomFace.Height > BottomFace.Width then BottomFace.Height, BottomFace.Width = BottomFace.Width, BottomFace.Height end return BottomFace end function SawPlusChain.GetLongFace( Proc) local LongFace = {} if not Proc.MainFaces.BottomFace or not Proc.MainFaces.BottomFace.Id then Proc.MainFaces.BottomFace = SawPlusChain.GetBottomFace( Proc) end local FacesToAnalyze = {} -- tutte le facce, ordinate per dimensione if Proc.Topology == 'Tunnel' then for i = 1, Proc.Fct do FacesToAnalyze[i] = {} FacesToAnalyze[i].Id = Proc.Face[i].Id FacesToAnalyze[i].Area = Proc.Face[i].Area FacesToAnalyze[i].LengthOnMainFace = Proc.Face[i].LengthOnMainFace end table.sort( FacesToAnalyze, function( a, b) return a.Area > b.Area end) -- facce adiacenti a quella di fondo, ordinate per lunghezza sul lato di fondo else FacesToAnalyze = BL.GetAdjacentFaces( Proc, Proc.MainFaces.BottomFace.Id) table.sort( FacesToAnalyze, function( a, b) return a.LengthOnMainFace > b.LengthOnMainFace end) end -- si sceglie la più grande (tunnel) o quella adiacente sul lato lungo LongFace.Id = FacesToAnalyze[1].Id for i = 1, Proc.Fct do if LongFace.Id == Proc.Face[i].Id then LongFace.Type = 'Long' LongFace.Width = Proc.Face[i].Width LongFace.Height = Proc.Face[i].Height LongFace.Elevation = Proc.Face[i].Elevation LongFace.VtN = Proc.Face[i].VtN if LongFace.Height > LongFace.Width then LongFace.Height, LongFace.Width = LongFace.Width, LongFace.Height end end end return LongFace end function SawPlusChain.GetSideFaces( Proc) if not Proc.MainFaces.BottomFace or not Proc.MainFaces.BottomFace.Id then Proc.MainFaces.BottomFace = SawPlusChain.GetBottomFace( Proc) end if not Proc.MainFaces.LongFace or not Proc.MainFaces.LongFace.Id then Proc.MainFaces.LongFace = SawPlusChain.GetLongFace( Proc) end local FacesToAnalyze = {} -- tutte le facce, ordinate per dimensione if Proc.Topology == 'Tunnel' then for i = 1, Proc.Fct do FacesToAnalyze[i] = {} FacesToAnalyze[i].Id = Proc.Face[i].Id FacesToAnalyze[i].Area = Proc.Face[i].Area FacesToAnalyze[i].LengthOnMainFace = Proc.Face[i].LengthOnMainFace end table.sort( FacesToAnalyze, function( a, b) return a.Area > b.Area end) -- facce adiacenti a quella di fondo, ordinate per lunghezza sul lato di fondo else FacesToAnalyze = BL.GetAdjacentFaces( Proc, Proc.MainFaces.BottomFace.Id) table.sort( FacesToAnalyze, function( a, b) return a.LengthOnMainFace > b.LengthOnMainFace end) end -- si determina il criterio di scelta delle facce laterali local FacesAdjacentToLongFace = BL.GetAdjacentFaces( Proc, Proc.MainFaces.LongFace.Id) local bIsLongFaceTheLargest = not ( Proc.Fct == 4 and #FacesAdjacentToLongFace == 3) local SideFaces = {} for i = 1, #FacesToAnalyze do if ( not bIsLongFaceTheLargest and i < #FacesToAnalyze) or ( bIsLongFaceTheLargest and i > 2) then table.insert( SideFaces, FacesToAnalyze[i]) SideFaces[#SideFaces].Id = FacesToAnalyze[i].Id SideFaces[#SideFaces].Type = 'Side' SideFaces[#SideFaces].Width = Proc.Face[FacesToAnalyze[i].Id + 1].Width SideFaces[#SideFaces].Height = Proc.Face[FacesToAnalyze[i].Id + 1].Height SideFaces[#SideFaces].Elevation = Proc.Face[FacesToAnalyze[i].Id + 1].Elevation SideFaces[#SideFaces].VtN = Proc.Face[FacesToAnalyze[i].Id + 1].VtN if SideFaces[#SideFaces].Height > SideFaces[#SideFaces].Width then SideFaces[#SideFaces].Height, SideFaces[#SideFaces].Width = SideFaces[ #SideFaces].Width, SideFaces[ #SideFaces].Height end end end return SideFaces end function SawPlusChain.GetBottomFaceEdges( Proc, Face) local Edges = {} Edges.SideEdges = {} Edges.LongEdges = {} local nFaceType, vEdges = EgtSurfTmGetFacetOutlineInfo( Proc.Id, Face.Id, GDB_ID.ROOT) if nFaceType < 1 then for j = 1, #vEdges do local nPreviousEdgeIndex = j - 1 if j == 1 then nPreviousEdgeIndex = #vEdges end local nNextEdgeIndex = j + 1 if j == #vEdges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.AdjacentFaceId = vEdges[j].Adj CurrentEdge.ToolDirection = Vector3d( vEdges[j].Norm) CurrentEdge.Length = vEdges[j].Len CurrentEdge.Elevation = vEdges[j].Elev CurrentEdge.IsOpen = vEdges[j].Open CurrentEdge.IsStartOpen = ( vEdges[nPreviousEdgeIndex].Open) CurrentEdge.IsEndOpen = ( vEdges[nNextEdgeIndex].Open) CurrentEdge.Id = j - 1 if CurrentEdge.AdjacentFaceId == Proc.MainFaces.LongFace.Id then table.insert( Edges.LongEdges, CurrentEdge) Edges.LongEdges[#Edges.LongEdges].Type = 'Long' elseif vEdges[nNextEdgeIndex].Adj == Proc.MainFaces.LongFace.Id or vEdges[nPreviousEdgeIndex].Adj == Proc.MainFaces.LongFace.Id then table.insert( Edges.SideEdges, CurrentEdge) Edges.SideEdges[#Edges.SideEdges].Type = 'Side' else table.insert( Edges.LongEdges, CurrentEdge) Edges.LongEdges[#Edges.LongEdges].Type = 'Long' end end else error( 'Face with closed hole') end return Edges end function SawPlusChain.GetLongFaceEdges( Proc, Face) local Edges = {} Edges.SideEdges = {} Edges.OppositeEdges = {} local nFaceType, vEdges = EgtSurfTmGetFacetOutlineInfo( Proc.Id, Face.Id, GDB_ID.ROOT) if nFaceType < 1 then for j = 1, #vEdges do local nPreviousEdgeIndex = j - 1 if j == 1 then nPreviousEdgeIndex = #vEdges end local nNextEdgeIndex = j + 1 if j == #vEdges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.AdjacentFaceId = vEdges[j].Adj CurrentEdge.ToolDirection = Vector3d( vEdges[j].Norm) CurrentEdge.Length = vEdges[j].Len CurrentEdge.Elevation = vEdges[j].Elev CurrentEdge.IsOpen = vEdges[j].Open CurrentEdge.IsStartOpen = ( vEdges[nPreviousEdgeIndex].Open) CurrentEdge.IsEndOpen = ( vEdges[nNextEdgeIndex].Open) CurrentEdge.Id = j - 1 if Proc.Topology == 'Tunnel' then if CurrentEdge.AdjacentFaceId > -1 then table.insert( Edges.SideEdges, CurrentEdge) else table.insert( Edges.OppositeEdges, CurrentEdge) end else if CurrentEdge.AdjacentFaceId == Proc.MainFaces.BottomFace.Id then Edges.BottomEdge = CurrentEdge Edges.BottomEdge.Type = 'Bottom' elseif vEdges[nNextEdgeIndex].Adj == Proc.MainFaces.BottomFace.Id then Edges.SideEdges.StartEdge = CurrentEdge Edges.SideEdges.StartEdge.Type = 'Side' elseif vEdges[nPreviousEdgeIndex].Adj == Proc.MainFaces.BottomFace.Id then Edges.SideEdges.EndEdge = CurrentEdge Edges.SideEdges.EndEdge.Type = 'Side' else table.insert( Edges.OppositeEdges, CurrentEdge) Edges.OppositeEdges[#Edges.OppositeEdges].Type = 'Opposite' end end end else error( 'Face with closed hole') end return Edges end function SawPlusChain.CalculateLeadInOut( Machining, EdgeToMachine) -- TODO implementare le funzioni di Tool Collision Avoidance (vedi wiki e FacesBysaw -> CalcLeadInOutPerpGeom) -- si determina l'eventuale riduzione da applicare in caso di inizio o fine chiusi local bIsMortising = ( Machining.Type == MCH_OY.MORTISING) local dAddLengthToReduce = 0 if bIsMortising then dAddLengthToReduce = Machining.Tool.Diameter / 2 else dAddLengthToReduce = sqrt( Machining.Depth * Machining.Tool.Diameter - Machining.Depth * Machining.Depth) end if Machining.Invert then Machining.IsStartClosed, Machining.IsEndClosed = Machining.IsEndClosed, Machining.IsStartClosed end local LeadIn = {} local LeadOut = {} LeadIn.StartAddLength = 0 LeadOut.EndAddLength = 0 if not bIsMortising then LeadIn.Type = MCH_MILL_LI.LINEAR LeadOut.Type = MCH_MILL_LI.LINEAR LeadIn.TangentDistance = 0 LeadOut.TangentDistance = 0 if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then LeadIn.PerpDistance = EdgeToMachine.Elevation + BD.CUT_SIC LeadOut.PerpDistance = EdgeToMachine.Elevation + BD.CUT_SIC else LeadIn.PerpDistance = BD.CUT_SIC LeadOut.PerpDistance = BD.CUT_SIC end LeadIn.Elevation = 0 LeadOut.Elevation = 0 LeadIn.CompLength = 0 LeadOut.CompLength = 0 if Machining.IsStartClosed and Machining.IsEndClosed then LeadIn.StartAddLength = -dAddLengthToReduce LeadOut.EndAddLength = -dAddLengthToReduce elseif Machining.IsStartClosed then LeadIn.StartAddLength = -dAddLengthToReduce -- eventuale correzione per accorciamento maggiore di larghezza tasca LeadOut.EndAddLength = max( -LeadIn.StartAddLength - EdgeToMachine.Length + 10 * BD.CUT_EXTRA, BD.CUT_EXTRA) elseif Machining.IsEndClosed then LeadOut.EndAddLength = -dAddLengthToReduce -- eventuale correzione per accorciamento maggiore di larghezza tasca LeadIn.StartAddLength = max( -LeadOut.EndAddLength - EdgeToMachine.Length + 10 * BD.CUT_EXTRA, BD.CUT_EXTRA) else LeadIn.StartAddLength = BD.CUT_EXTRA LeadOut.EndAddLength = BD.CUT_EXTRA end else if Machining.IsStartClosed then LeadIn.StartAddLength = -dAddLengthToReduce else LeadIn.StartAddLength = BD.CUT_EXTRA end if Machining.IsEndClosed then LeadOut.EndAddLength = -dAddLengthToReduce else LeadOut.EndAddLength = BD.CUT_EXTRA end end return LeadIn, LeadOut end function SawPlusChain.ApplyMachining( Machining, b3Raw) local sErr = '' local nOperationId = EgtAddMachining( Machining.OperationName, Machining.Name) if not nOperationId then sErr = 'Error adding machining ' .. Machining.OperationName .. '-' .. Machining.Name EgtOutLog( sErr) return false, sErr end -- impostazione parametri lavorazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' EgtSetMachiningGeometry( Machining.Geometry) EgtSetMachiningParam( MCH_MP.FACEUSE, Machining.Faceuse) EgtSetMachiningParam( MCH_MP.SCC, Machining.SCC) EgtSetMachiningParam( MCH_MP.INVERT, Machining.Invert) EgtSetMachiningParam( MCH_MP.WORKSIDE, Machining.Workside) EgtSetMachiningParam( MCH_MP.TOOLINVERT, Machining.ToolInvert) EgtSetMachiningParam( MCH_MP.OFFSR, Machining.RadialOffset) EgtSetMachiningParam( MCH_MP.OFFSL, Machining.LongitudinalOffset) if Machining.Type ~= MCH_OY.MORTISING then EgtSetMachiningParam( MCH_MP.LEADINTYPE, Machining.LeadIn.Type) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, Machining.LeadOut.Type) EgtSetMachiningParam( MCH_MP.LITANG, Machining.LeadIn.TangentDistance) EgtSetMachiningParam( MCH_MP.LOTANG, Machining.LeadOut.TangentDistance) EgtSetMachiningParam( MCH_MP.LIPERP, Machining.LeadIn.PerpDistance) EgtSetMachiningParam( MCH_MP.LOPERP, Machining.LeadOut.PerpDistance) EgtSetMachiningParam( MCH_MP.LIELEV, Machining.LeadIn.Elevation) EgtSetMachiningParam( MCH_MP.LOELEV, Machining.LeadOut.Elevation) EgtSetMachiningParam( MCH_MP.LICOMPLEN, Machining.LeadIn.CompLength) EgtSetMachiningParam( MCH_MP.LOCOMPLEN, Machining.LeadOut.CompLength) end EgtSetMachiningParam( MCH_MP.STARTADDLEN, Machining.LeadIn.StartAddLength) EgtSetMachiningParam( MCH_MP.ENDADDLEN, Machining.LeadOut.EndAddLength) if Machining.Steps then if Machining.Steps.StepType then EgtSetMachiningParam( MCH_MP.STEPTYPE, Machining.Steps.StepType) end if Machining.Steps.StepLength then EgtSetMachiningParam( MCH_MP.STEP, Machining.Steps.StepLength) end end EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( Machining.Name, Machining.BlockedAxis.Orientation, b3Raw, Machining.BlockedAxis.VtN, Machining.BlockedAxis.VtOut)) if Machining.Type == MCH_OY.MORTISING then EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( Machining.SuggestedAngles.VtN, Machining.SuggestedAngles.VtOrtho, Machining.SuggestedAngles.Index)) end EgtSetMachiningParam( MCH_MP.OVERL, Machining.Overlap) EgtSetMachiningParam( MCH_MP.STARTPOS, max( Machining.StartSafetyLength, EgtGetMachiningParam( MCH_MP.STARTPOS))) if Machining.MaxElev then sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', Machining.MaxElev) end if Machining.nEdgeFaceUse then sUserNotes = EgtSetValInNotes( sUserNotes, 'EdgesFaceUse', EgtNumToString( Machining.nEdgeFaceUse)) end EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) local bIsApplyOk = ML.ApplyMachining( true, false) if not bIsApplyOk then local nErr nErr, sErr = EgtGetLastMachMgrError() -- se mortasatura e l'errore è compatibile (Axes values not calculable) si prova con l'altra configurazione dell'asse bloccato if Machining.Type == MCH_OY.MORTISING then -- se errore "Axes values not calculable" si prova con l'altra configurazione dell'asse bloccato if nErr == 2507 then if Machining.BlockedAxis.Orientation == 'perpendicular' then Machining.BlockedAxis.Orientation = 'parallel' else Machining.BlockedAxis.Orientation = 'perpendicular' end EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( Machining.Name, Machining.BlockedAxis.Orientation, b3Raw, Machining.BlockedAxis.VtN, Machining.BlockedAxis.VtOut)) if Machining.SuggestedAngles.Index == 1 then Machining.SuggestedAngles.Index = 2 else Machining.SuggestedAngles.Index = 1 end EgtSetMachiningParam( MCH_MP.INITANGS, BL.GetChainSawInitAngs( Machining.SuggestedAngles.VtN, Machining.SuggestedAngles.VtOrtho, Machining.SuggestedAngles.Index)) sErr = '' bIsApplyOk = ML.ApplyMachining( true, false) -- se errore "Outstroke" e permesso ToolInvert provo ad invertire il lato di lavorazione elseif Machining.AllowToolInvert and nErr == 2508 then EgtSetMachiningParam( MCH_MP.TOOLINVERT, not Machining.ToolInvert) sErr = '' bIsApplyOk = ML.ApplyMachining( true, false) end end if not bIsApplyOk then nErr, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nOperationId, false) return false, sErr end end return true, sErr end function SawPlusChain.Saw.GetSCC( vtMachiningDirection) -- TODO implementare SCC come per FacesBySaw local nSCC = MCH_SCC.NONE if AreSameVectorApprox( vtMachiningDirection, Z_AX()) then nSCC = MCH_SCC.ADIR_ZP elseif AreOppositeVectorApprox( vtMachiningDirection, Z_AX()) then nSCC = MCH_SCC.ADIR_ZM elseif AreSameVectorApprox( vtMachiningDirection, Y_AX()) then nSCC = MCH_SCC.ADIR_YP elseif AreOppositeVectorApprox( vtMachiningDirection, Y_AX()) then nSCC = MCH_SCC.ADIR_YM elseif AreSameVectorApprox( vtMachiningDirection, X_AX()) then nSCC = MCH_SCC.ADIR_XP elseif AreOppositeVectorApprox( vtMachiningDirection, X_AX()) then nSCC = MCH_SCC.ADIR_XM end return nSCC end function SawPlusChain.Saw.CalculateMachiningParameters( Proc, FaceToMachine, EdgeToMachine) local Cutting = {} Cutting.CanApply = true Cutting.Message = '' Cutting.ProcId = Proc.Id local dPocketHeight = 0 if Proc.Topology == 'Tunnel' then dPocketHeight = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Height else if FaceToMachine.Type == 'Long' then dPocketHeight = Proc.MainFaces.BottomFace.Edges.SideEdges[1].Length elseif FaceToMachine.Type == 'Side' then dPocketHeight = Proc.MainFaces.BottomFace.Edges.LongEdges[1].Length end end -- ricerca lavorazione Cutting.Name = ML.FindCutting( 'HeadSide', true, false, abs( EdgeToMachine.Elevation)) if not Cutting.Name then -- ricerca lavorazione senza considerare massima elevazione Cutting.Name = ML.FindCutting( 'HeadSide', true, false, nil, 'Longest') if not Cutting.Name then Cutting.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - saw blade not found' Cutting.CanApply = false EgtOutLog( Cutting.Message) return Cutting end end Cutting.Type = MCH_OY.MILLING Cutting.Tool = BL.GetToolFromMachining( Cutting.Name) -- verifica dimensioni tasca e direzione compatibili -- se tasca meno spessa della lama la strategia non è applicabile if Cutting.Tool.Thickness > dPocketHeight + 10 * GEO.EPS_SMALL then Cutting.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - pocket too narrow for saw blade thickness' Cutting.CanApply = false EgtOutLog( Cutting.Message) end if #( Proc.MainFaces.SideFaces) > 1 then -- se tasca più stretta della lama la strategia non è applicabile if Cutting.Tool.Diameter > EdgeToMachine.Length + 10 * GEO.EPS_SMALL then Cutting.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - pocket too narrow for saw blade diameter' Cutting.CanApply = false EgtOutLog( Cutting.Message) end end if EdgeToMachine.ToolDirection:getZ() < BD.NZ_MINA and BD.C_SIMM then Cutting.CanApply = false Cutting.Message = 'Feature '.. Proc.FeatureId .. ' : skipped sawblade from bottom' EgtOutLog( Cutting.Message) end -- parametri della lavorazione -- inizio e fine aperti o chiusi Cutting.IsStartClosed = not EdgeToMachine.IsStartOpen Cutting.IsEndClosed = not EdgeToMachine.IsEndOpen -- lato di lavoro e inversioni if Cutting.Tool.IsCCW then Cutting.Workside = MCH_MILL_WS.RIGHT Cutting.Invert = true else Cutting.Workside = MCH_MILL_WS.LEFT Cutting.Invert = false end if EdgeToMachine.Elevation < -10 * GEO.EPS_SMALL then Cutting.Invert = not Cutting.Invert end -- TODO gestire lama da sotto e lama downUp if FaceToMachine.VtN:getZ() < - 10 * GEO.EPS_SMALL then Cutting.ToolInvert = true Cutting.Invert = not Cutting.Invert else Cutting.ToolInvert = false end -- profondità e offset radiale if Cutting.Tool.MaxDepth > abs( EdgeToMachine.Elevation) - 10 * GEO.EPS_SMALL then -- TODO la depth dovrebbe essere quella del machining Cutting.Depth = abs( EdgeToMachine.Elevation) if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then Cutting.RadialOffset = 0 else Cutting.RadialOffset = EdgeToMachine.Elevation end else Cutting.Depth = Cutting.Tool.MaxDepth - 1 if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then Cutting.RadialOffset = EdgeToMachine.Elevation - Cutting.Depth else Cutting.RadialOffset = -Cutting.Depth end if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL and SawPlusChain.ApplyOnlySawblade then Cutting.Message = 'Feature '.. Proc.FeatureId .. ' : sawblade elevation (' .. EgtNumToString( EdgeToMachine.Elevation, 1) .. ') bigger than max tool depth (' .. EgtNumToString( Cutting.Depth, 1) .. ')' EgtOutLog( Cutting.Message) end end -- step verticale e offset longitudinale Cutting.Steps = BL.GetMachiningSteps( dPocketHeight, Cutting.Tool.Thickness) Cutting.Steps.StepType = MCH_MILL_ST.ONEWAY Cutting.MaxElev = Cutting.Steps.StepLength * Cutting.Steps.Count - 10 * GEO.EPS_SMALL if Cutting.ToolInvert and Cutting.Steps.Count > 1 then Cutting.LongitudinalOffset = - dPocketHeight else Cutting.LongitudinalOffset = 0 end -- distanza di sicurezza Cutting.StartSafetyLength = 10 -- overlap Cutting.Overlap = 0 -- faceuse if EdgeToMachine.Elevation > - 10 * GEO.EPS_SMALL then Cutting.Faceuse = BL.GetNearestOrthoOpposite( EdgeToMachine.ToolDirection) else Cutting.Faceuse = BL.GetNearestOrthoOpposite( -EdgeToMachine.ToolDirection) end Cutting.nEdgeFaceUse = EdgeToMachine.Id -- SCC Cutting.SCC = SawPlusChain.Saw.GetSCC( EdgeToMachine.ToolDirection) -- asse bloccato Cutting.BlockedAxis = {} Cutting.BlockedAxis.Orientation = 'perpendicular' Cutting.BlockedAxis.VtN = FaceToMachine.VtN Cutting.BlockedAxis.VtOut = EgtIf( FaceToMachine.VtN:getX() > 0, X_AX(), -X_AX()) -- approccio e retrazione Cutting.LeadIn, Cutting.LeadOut = SawPlusChain.CalculateLeadInOut( Cutting, EdgeToMachine) -- eventuale step orizzontale Cutting.HorizontalSteps = {} if Cutting.Tool.SideStep then Cutting.HorizontalSteps = BL.GetMachiningSteps( Cutting.Depth, Cutting.Tool.SideStep) else Cutting.HorizontalSteps.Count = 1 Cutting.HorizontalSteps.StepLength = 0 end -- geometria Cutting.Geometry = {{Proc.Id, FaceToMachine.Id}} -- nome operazione Cutting.OperationName = 'Cut_' .. ( EgtGetName( Cutting.ProcId) or tostring( Cutting.ProcId)) .. '_' .. tostring( FaceToMachine.Id + 1) -- eventuale avviso di danneggiamento pezzo successivo local dOffsideLength = max( Cutting.LeadIn.StartAddLength, Cutting.LeadOut.EndAddLength) + Cutting.Tool.Diameter / 2 + 10 * GEO.EPS_SMALL if ( not Proc.Tail or Proc.AdvTail) and Proc.AffectedFaces.Left and ( Proc.DistanceToNextPart < dOffsideLength) then local sDamageNextPieceMessage = 'Feature '.. Proc.FeatureId .. ' : sawblade can damage next piece.' if #Cutting.Message > 0 then Cutting.Message = Cutting.Message .. '\n' .. sDamageNextPieceMessage else Cutting.Message = sDamageNextPieceMessage end EgtOutLog( sDamageNextPieceMessage) end return Cutting end function SawPlusChain.Saw.ApplyAllSteps( Cutting, b3Raw) local bIsCuttingOk = false local sCuttingOriginalMessage = Cutting.Message or '' local sCuttingApplyMessage = '' local dOriginalRadialOffset = Cutting.RadialOffset local dOriginalLeadInPerpDistance = Cutting.LeadIn.PerpDistance local dOriginalLeadOutPerpDistance = Cutting.LeadOut.PerpDistance for i = Cutting.HorizontalSteps.Count, 1, -1 do Cutting.RadialOffset = dOriginalRadialOffset + Cutting.HorizontalSteps.StepLength * ( i - 1) -- update distanza perpendicolare attacco per contemplare l'offset applicato Cutting.LeadIn.PerpDistance = dOriginalLeadInPerpDistance - Cutting.RadialOffset Cutting.LeadOut.PerpDistance = dOriginalLeadOutPerpDistance - Cutting.RadialOffset -- applicazione lavorazione bIsCuttingOk, sCuttingApplyMessage = SawPlusChain.ApplyMachining( Cutting, b3Raw) -- update messaggi if sCuttingApplyMessage and #sCuttingApplyMessage > 0 then sCuttingApplyMessage = sCuttingOriginalMessage .. '\n' .. sCuttingApplyMessage .. 'Apply : ' .. sCuttingApplyMessage .. '\n' else sCuttingApplyMessage = sCuttingOriginalMessage end end return bIsCuttingOk, sCuttingApplyMessage end function SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, FaceToMachine, EdgeToMachine) local Mortising = {} Mortising.CanApply = true Mortising.Message = '' Mortising.ProcId = Proc.Id Mortising.AllowToolInvert = false local bNeedToMachineOtherSide = false local dTestCornerRadius = 43 -- OneSide | OneSideAndExtend | BothSides | BothSidesAndExtend local sMortisingType local dPocketHeight = 0 if Proc.Topology == 'Tunnel' then dPocketHeight = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Height else if FaceToMachine.Type == 'Long' then dPocketHeight = Proc.MainFaces.BottomFace.Edges.SideEdges[1].Length elseif FaceToMachine.Type == 'Side' then dPocketHeight = Proc.MainFaces.BottomFace.Edges.LongEdges[1].Length end end -- ricerca lavorazione if Proc.Topology == 'Tunnel' then Mortising.Name = ML.FindSawing( 'Sawing', abs( EdgeToMachine.Elevation) + dTestCornerRadius + BD.CUT_EXTRA_MIN) sMortisingType = 'OneSideAndExtend' if not Mortising.Name then Mortising.Name = ML.FindSawing( 'Sawing', abs( EdgeToMachine.Elevation) / 2 + dTestCornerRadius + BD.CUT_EXTRA_MIN) sMortisingType = 'BothSidesAndExtend' end elseif EdgeToMachine.Type == 'Side' and #( Proc.MainFaces.SideFaces) == 0 then Mortising.Name = ML.FindSawing( 'Sawing', abs( EdgeToMachine.Elevation) / 2 + dTestCornerRadius + BD.CUT_EXTRA_MIN) sMortisingType = 'BothSidesAndExtend' else Mortising.Name = ML.FindSawing( 'Sawing', abs( EdgeToMachine.Elevation)) sMortisingType = 'OneSide' end if not Mortising.Name then Mortising.Name = ML.FindSawing( 'Sawing', nil, nil, 'Longest') if sMortisingType == 'BothSidesAndExtend' then sMortisingType = 'BothSides' elseif sMortisingType == 'OneSideAndExtend' then sMortisingType = 'OneSide' end end if not Mortising.Name then Mortising.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - chainsaw not found' Mortising.CanApply = false EgtOutLog( Mortising.Message) end Mortising.Type = MCH_OY.MORTISING Mortising.Tool = BL.GetToolFromMachining( Mortising.Name) -- in caso di tunnel da un lato permetto eventuale inversione lato di lavoro in caso di errori di applicazione (es: Outstroke) if Proc.Topology == 'Tunnel' and sMortisingType == 'OneSide' or sMortisingType == 'OneSideAndExtend' then Mortising.AllowToolInvert = true end -- verifica dimensioni tasca compatibili -- se tasca meno spessa della sega a catena la strategia non è applicabile if Mortising.Tool.Thickness > dPocketHeight + 10 * GEO.EPS_SMALL then Mortising.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - pocket too narrow for chainsaw thickness' Mortising.CanApply = false EgtOutLog( Mortising.Message) end if #( Proc.MainFaces.SideFaces) > 1 then -- se tasca più stretta della sega a catena la strategia non è applicabile if Mortising.Tool.Width > EdgeToMachine.Length + 10 * GEO.EPS_SMALL then Mortising.Message = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - pocket too narrow for chainsaw width' Mortising.CanApply = false EgtOutLog( Mortising.Message) end end if EdgeToMachine.ToolDirection:getZ() < - 10 * GEO.EPS_ANG_SMALL then Mortising.CanApply = false Mortising.Message = 'Feature '.. Proc.FeatureId .. ' : skipped chainsaw from bottom' EgtOutLog( Mortising.Message) end -- parametri della lavorazione -- inizio e fine aperti o chiusi Mortising.IsStartClosed = not EdgeToMachine.IsStartOpen Mortising.IsEndClosed = not EdgeToMachine.IsEndOpen -- lato di lavoro e inversioni Mortising.Invert = false if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then Mortising.Workside = MCH_MILL_WS.RIGHT Mortising.ToolInvert = false else Mortising.Workside = MCH_MILL_WS.LEFT Mortising.ToolInvert = true end -- profondità e offset longitudinale if sMortisingType == 'OneSide' then Mortising.Depth = abs( EdgeToMachine.Elevation) elseif sMortisingType == 'OneSideAndExtend' then Mortising.Depth = abs( EdgeToMachine.Elevation) + Mortising.Tool.CornerRadius + BD.CUT_EXTRA_MIN elseif sMortisingType == 'BothSides' then Mortising.Depth = abs( EdgeToMachine.Elevation) / 2 bNeedToMachineOtherSide = true elseif sMortisingType == 'BothSidesAndExtend' then Mortising.Depth = abs( EdgeToMachine.Elevation) / 2 + Mortising.Tool.CornerRadius + BD.CUT_EXTRA_MIN bNeedToMachineOtherSide = true end if Mortising.Tool.MaxMat > Mortising.Depth - 10 * GEO.EPS_SMALL then if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then Mortising.LongitudinalOffset = 0 else Mortising.LongitudinalOffset = abs( EdgeToMachine.Elevation) - Mortising.Depth end else Mortising.Depth = Mortising.Tool.MaxMat - 1 if EdgeToMachine.Elevation > -10 * GEO.EPS_SMALL then Mortising.LongitudinalOffset = EdgeToMachine.Elevation - Mortising.Depth else Mortising.LongitudinalOffset = 0 end Mortising.Message = 'Feature '.. Proc.FeatureId .. ' : chainsaw elevation (' .. EgtNumToString( EdgeToMachine.Elevation, 1) .. ') bigger than max tool depth (' .. EgtNumToString( Mortising.Depth, 1) .. ')' EgtOutLog( Mortising.Message) end -- offset radiale Mortising.RadialOffset = 0 -- distanza di sicurezza Mortising.StartSafetyLength = EdgeToMachine.Elevation -- overlap Mortising.Overlap = 0 -- faceuse if EdgeToMachine.Elevation > - 10 * GEO.EPS_SMALL then Mortising.Faceuse = BL.GetNearestParalOpposite( EdgeToMachine.ToolDirection) else Mortising.Faceuse = BL.GetNearestParalOpposite( -EdgeToMachine.ToolDirection) end -- SCC Mortising.SCC = MCH_SCC.NONE -- asse bloccato e angoli suggeriti Mortising.BlockedAxis = {} Mortising.BlockedAxis.Orientation = 'perpendicular' Mortising.BlockedAxis.VtN = FaceToMachine.VtN Mortising.SuggestedAngles = {} Mortising.SuggestedAngles.Index = 1 Mortising.SuggestedAngles.VtN = FaceToMachine.VtN Mortising.SuggestedAngles.VtOrtho = EdgeToMachine.ToolDirection -- approccio e retrazione Mortising.LeadIn, Mortising.LeadOut = SawPlusChain.CalculateLeadInOut( Mortising, EdgeToMachine) -- eventuale step verticale Mortising.VerticalSteps = BL.GetMachiningSteps( dPocketHeight, Mortising.Tool.Thickness) -- geometria Mortising.Geometry = {{Proc.Id, FaceToMachine.Id}} -- nome operazione Mortising.OperationName = 'Chainsaw_' .. ( EgtGetName( Mortising.ProcId) or tostring( Mortising.ProcId)) .. '_' .. tostring( FaceToMachine.Id + 1) -- eventuale avviso di danneggiamento pezzo successivo local dOffsideLength = max( Mortising.LeadIn.StartAddLength, Mortising.LeadOut.EndAddLength) + Mortising.Tool.Width / 2 + 10 * GEO.EPS_SMALL if ( not Proc.Tail or Proc.AdvTail) and Proc.AffectedFaces.Left and ( Proc.DistanceToNextPart < dOffsideLength) then local sDamageNextPieceMessage = 'Feature '.. Proc.FeatureId .. ' : chainsaw can damage next piece.' if #Mortising.Message > 0 then Mortising.Message = Mortising.Message .. '\n' .. sDamageNextPieceMessage else Mortising.Message = sDamageNextPieceMessage end EgtOutLog( sDamageNextPieceMessage) end return Mortising, bNeedToMachineOtherSide end function SawPlusChain.Chainsaw.ApplyAllSteps( Mortising, b3Raw) local bIsMortisingOk = false local sMortisingApplyMessage = '' local dOriginalRadialOffsetMortising = Mortising.RadialOffset for i = Mortising.VerticalSteps.Count, 1, -1 do Mortising.RadialOffset = dOriginalRadialOffsetMortising + Mortising.VerticalSteps.StepLength * ( i - 1) -- applicazione lavorazione bIsMortisingOk, sMortisingApplyMessage = SawPlusChain.ApplyMachining( Mortising, b3Raw) -- update messaggi if sMortisingApplyMessage and #sMortisingApplyMessage > 0 then Mortising.Message = Mortising.Message .. '\n' .. 'Apply : ' .. sMortisingApplyMessage end end return bIsMortisingOk, sMortisingApplyMessage end function SawPlusChain.Make( bOnlySaw, Proc, nRawId) SawPlusChain.ApplyOnlySawblade = bOnlySaw local b3Raw = EgtGetRawPartBBox( nRawId) -- TODO per implementare la strategia con lapjoint lunghe bisogna prima riconoscere le topologie che arrivano if Proc.IsSplittedLapJoint then local sErr = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not implemented for long lapjoint' EgtOutLog( sErr) return false, sErr end if not SawPlusChain.IsTopologyOk( Proc) then local sErr = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not implemented' EgtOutLog( sErr) return false, sErr end -- se tasca su faccia sotto la strategia non è applicabile (la sega a catena in generale non può lavorare da sotto) -- TODO se OnlySaw questo test è da rimuovere ma bisogna considerare anche la lama da sotto if Proc.AffectedFaces.Bottom and ( Proc.Fct > 3 or not Proc.AffectedFaces.Top) then local sErr = 'Feature '.. Proc.FeatureId .. ' : strategy ' .. SawPlusChain.Name .. ' not applicable - pocket on bottom face' EgtOutLog( sErr) return false, sErr end -- facce principali Proc.MainFaces = {} Proc.MainFaces.BottomFace = SawPlusChain.GetBottomFace( Proc) Proc.MainFaces.LongFace = SawPlusChain.GetLongFace( Proc) Proc.MainFaces.SideFaces = SawPlusChain.GetSideFaces( Proc) if Proc.Topology == 'Tunnel' then Proc.MainFaces.TunnelAddedFaces = SawPlusChain.GetTunnelFaces( Proc) else Proc.MainFaces.BottomFace.Edges = SawPlusChain.GetBottomFaceEdges( Proc, Proc.MainFaces.BottomFace) end Proc.MainFaces.LongFace.Edges = SawPlusChain.GetLongFaceEdges( Proc, Proc.MainFaces.LongFace) -- lama -- lavorazione di lama - fondo della tasca o fino a massimo materiale se tunnel local Cutting = {} if Proc.Topology == 'Tunnel' then Cutting = SawPlusChain.Saw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.OppositeEdges[1]) else Cutting = SawPlusChain.Saw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.BottomEdge) end local bIsCuttingOk = false if Cutting.CanApply then bIsCuttingOk, Cutting.Message = SawPlusChain.Saw.ApplyAllSteps( Cutting, b3Raw) if not bIsCuttingOk then return bIsCuttingOk, Cutting.Message end end local dBottomDepthToMachine = Cutting.RadialOffset -- lato opposto del tunnel if Proc.Topology == 'Tunnel' then Cutting = SawPlusChain.Saw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.OppositeEdges[2]) bIsCuttingOk = false if Cutting.CanApply then bIsCuttingOk, Cutting.Message = SawPlusChain.Saw.ApplyAllSteps( Cutting, b3Raw) if not bIsCuttingOk then return bIsCuttingOk, Cutting.Message end end elseif Proc.IsParallel then -- se la lama non è arrivata sul fondo e c'è almeno un lato aperto va lavorato if Cutting.CanApply and Cutting.RadialOffset > 10 * GEO.EPS_SMALL then -- eventuale lavorazione di lama - lato della tasca da cui inizia la lavorazione if Proc.MainFaces.LongFace.Edges.BottomEdge.IsStartOpen then Cutting = SawPlusChain.Saw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.SideEdges.StartEdge) bIsCuttingOk = false if Cutting.CanApply then bIsCuttingOk, Cutting.Message = SawPlusChain.Saw.ApplyAllSteps( Cutting, b3Raw) if not bIsCuttingOk then return bIsCuttingOk, Cutting.Message end end end -- eventuale lavorazione di lama - lato della tasca in cui finisce la lavorazione if Proc.MainFaces.LongFace.Edges.BottomEdge.IsEndOpen then Cutting = SawPlusChain.Saw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.SideEdges.EndEdge) bIsCuttingOk = false if Cutting.CanApply then bIsCuttingOk, Cutting.Message = SawPlusChain.Saw.ApplyAllSteps( Cutting, b3Raw) if not bIsCuttingOk then return bIsCuttingOk, Cutting.Message end end end -- la lama è arrivata sul fondo e tasca passante, non servono ulteriori lavorazioni elseif #( Proc.MainFaces.SideFaces) == 0 then SawPlusChain.ApplyOnlySawblade = true end end if SawPlusChain.ApplyOnlySawblade then return bIsCuttingOk, Cutting.Message end -- sega a catena -- parametri lavorazione con sega a catena - fondo della tasca o tunnel local Mortising = {} local bNeedToMachineOtherSide = false if Proc.Topology == 'Tunnel' then Mortising, bNeedToMachineOtherSide = SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.OppositeEdges[1]) else Mortising = SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.BottomEdge) -- si lavora solo quanto non lavorato dalla lama Mortising.MaxElev = dBottomDepthToMachine + BD.CUT_EXTRA end local bIsMortisingOk = false if Mortising.CanApply then bIsMortisingOk, Mortising.Message = SawPlusChain.Chainsaw.ApplyAllSteps( Mortising, b3Raw) end -- lato opposto del tunnel if Proc.Topology == 'Tunnel' and bNeedToMachineOtherSide then Mortising = SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.OppositeEdges[2]) bIsMortisingOk = false if Mortising.CanApply then bIsMortisingOk, Mortising.Message = SawPlusChain.Chainsaw.ApplyAllSteps( Mortising, b3Raw) if not bIsMortisingOk then return bIsMortisingOk, Mortising.Message end end elseif Proc.IsParallel then -- se la sega a catena non è arrivata sul fondo e c'è almeno un lato aperto va lavorato if Mortising.LongitudinalOffset > 10 * GEO.EPS_SMALL then -- eventuale lavorazione di sega a catena - lato della tasca da cui inizia la lavorazione if Proc.MainFaces.LongFace.Edges.BottomEdge.IsStartOpen then Mortising = SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.SideEdges.StartEdge) bIsMortisingOk = false if Mortising.CanApply then bIsMortisingOk, Mortising.Message = SawPlusChain.Chainsaw.ApplyAllSteps( Mortising, b3Raw) if not bIsMortisingOk then return bIsMortisingOk, Mortising.Message end end end -- eventuale lavorazione di sega a catena - lato della tasca in cui finisce la lavorazione if Proc.MainFaces.LongFace.Edges.BottomEdge.IsEndOpen then Mortising = SawPlusChain.Chainsaw.CalculateMachiningParameters( Proc, Proc.MainFaces.LongFace, Proc.MainFaces.LongFace.Edges.SideEdges.EndEdge) bIsMortisingOk = false if Mortising.CanApply then bIsMortisingOk, Mortising.Message = SawPlusChain.Chainsaw.ApplyAllSteps( Mortising, b3Raw) if not bIsMortisingOk then return bIsMortisingOk, Mortising.Message end end end end end local sFinalMessage = '' if #Cutting.Message > 0 or #Mortising.Message > 0 then sFinalMessage = Cutting.Message .. '\n' .. Mortising.Message end return bIsMortisingOk, sFinalMessage end --#endregion SawPlusChain --------------------------------------------------------------------- local function ReorderFacesFromTab( nIdSurf, vFace) local nFacCnt = EgtSurfTmFacetCount( nIdSurf) for i = 1, #vFace do for j = 1, nFacCnt do -- ottengo punto iniziale e versore della faccia local ptC, vtN = EgtSurfTmFacetCenter( nIdSurf, (j-1), GDB_ID.ROOT) -- se versore e posizione coincidono e non corrispondono al numero faccia, faccio lo swap if AreSameVectorExact( vFace[i].Norm, vtN) and AreSamePointEpsilon( vFace[i].Cen, ptC, 50*GEO.EPS_SMALL) then if (j-1) ~= vFace[i].Fac then EgtSurfTmSwapFacets( nIdSurf, vFace[i].Fac, (j-1)) end break end end end return nIdSurf end --------------------------------------------------------------------- local function CalcInterference( nNewProc, vtExtr, ptCentr, dDiam1, dDiam2, dTall1, dTall2, dDiam3, dTall3) local ptCentrGrid1 = ptCentr + ( vtExtr * 0.01) local frOriTool = Frame3d( ptCentrGrid1, vtExtr) local bColl1 = EgtTestConeSurface( frOriTool, dDiam1/2, dDiam2/2, dTall1, nNewProc, 0, GDB_RT.GLOB) if bColl1 then return true end local ptCentrGrid2 = ptCentr + ( vtExtr * ( dTall1 + 0.01)) frOriTool = Frame3d( ptCentrGrid2, vtExtr) local bColl2 = EgtTestCylSurface( frOriTool, dDiam2/2, dTall2, nNewProc, 0, GDB_RT.GLOB) if bColl2 then return true end local ptCentrGrid3 = ptCentr + ( vtExtr * ( dTall2 + 0.01)) frOriTool = Frame3d( ptCentrGrid3, vtExtr) local bColl3 = EgtTestCylSurface( frOriTool, dDiam3/2, dTall3, nNewProc, 0, GDB_RT.GLOB) if bColl3 then return true end -- restituisco risultato controllo collisioni return false end --------------------------------------------------------------------- local function MakeLocalSurf( ptP1, ptP2, ptP3, nAddGrpId) -- verifico che i tre punti siano definiti if not ptP1 or not ptP2 or not ptP3 then return nil end -- creo il contorno local nLoopId = EgtCurveCompoFromPoints( nAddGrpId, { ptP1, ptP2, ptP3, ptP1}, GDB_RT.GLOB) if not nLoopId then return nil end -- creo la superfice triangolare (quindi piana) local nFaceId = EgtSurfTmByFlatContour( nAddGrpId, nLoopId, 0.01) EgtErase( nLoopId) if not nFaceId then return nil end -- se normale negativa inverto local vtN1 = EgtSurfTmFacetNormVersor( nFaceId, 0, GDB_ID.ROOT) if vtN1:getZ() < -0.01 then EgtInvertSurf( nFaceId) end return nFaceId end --------------------------------------------------------------------- local function AddMillCornerMachining( nPartId, nNewProc, nFacInd, tFacAdj, nAddGrpId, dToolDiam, sMilling, dOffsAng, dDiam1, dDiam2, dTall1, dTall2, dDiam3, dTall3, bMakeLocSurf, vFace, vtN) -- variabili costruzione geometria local pAuxId = {} local nAuxId local ptApPoint local AuxId local nNewProcLoc -- se devo creare superfice locale if bMakeLocSurf then -- creo superfice locale o esco local nSurfToAdd = MakeLocalSurf( tFacAdj[7], tFacAdj[8], tFacAdj[9], nAddGrpId) if nSurfToAdd then local nFacCntPre = EgtSurfTmFacetCount( nNewProc.Id) -- creo copia del percorso principale e gli aggiungo la nuova faccia nNewProcLoc = EgtCopyGlob( nNewProc.Id, nAddGrpId) nNewProcLoc = EgtSurfTmBySewing( nAddGrpId, {nNewProcLoc,nSurfToAdd} , true) -- riordino le facce nNewProcLoc = ReorderFacesFromTab( nNewProcLoc, vFace) -- acquisisco il numero della faccia local nFacCnt = EgtSurfTmFacetCount( nNewProcLoc) nFacInd = nFacCnt - 1 else local sErr = 'Cannot make local bottom surface' EgtOutLog( sErr) return true, '' end else nNewProcLoc = nNewProc.Id end -- prendo il primo versore local _, vtN1 = EgtSurfTmFacetCenter( nNewProcLoc, nFacInd, GDB_ID.ROOT) local _, vtN2 = EgtSurfTmFacetCenter( nNewProcLoc, tFacAdj[1], GDB_ID.ROOT) local _, vtN3 = EgtSurfTmFacetCenter( nNewProcLoc, tFacAdj[2], GDB_ID.ROOT) -- trovo il punto sulla superfice di riferimento local _, ptLocP1, ptLocP2, _ = EgtSurfTmFacetsContact( nNewProcLoc, nFacInd, tFacAdj[1], GDB_ID.ROOT) local _, ptLocP3, ptLocP4, _ = EgtSurfTmFacetsContact( nNewProcLoc, nFacInd, tFacAdj[2], GDB_ID.ROOT) -- se ho creato faccia locale su copia superficie, cancella la copia if bMakeLocSurf then EgtErase( nNewProcLoc) end local nIdIniPoint local nIdEndPoint if ptLocP1 and ptLocP2 then if ( dist( ptLocP1, tFacAdj[4]) < GEO.EPS_SMALL) or ( dist( ptLocP2, tFacAdj[4]) < GEO.EPS_SMALL) then nIdEndPoint = 4 nIdIniPoint = 5 elseif ( dist( ptLocP1, tFacAdj[5]) < GEO.EPS_SMALL) or ( dist( ptLocP2, tFacAdj[5]) < GEO.EPS_SMALL) then nIdEndPoint = 5 nIdIniPoint = 4 end else local sErr = 'Error : Impossible insert clean corner from bottom' return false, sErr end -- versore direzione local vtExtr = tFacAdj[nIdIniPoint] - tFacAdj[nIdEndPoint] vtExtr:normalize() -- versore direzione di uscita local vtExtrExit -- inserisco le prime tre linee if nIdIniPoint and nIdEndPoint then -- se fresatura da sotto salto la lavorazione if vtExtr:getZ() < BD.DRILL_VZ_MIN then local sErr = 'Error : Impossible insert clean corner from bottom' EgtOutLog( sErr) return false, sErr end -- sommo i tre versori per avere una direzione media vtExtrExit = vtN2 + vtN3 vtExtrExit:normalize() -- calcolo angolo tilt di 45° vtExtr = vtExtrExit + vtN vtExtr:normalize() local vtCheck = Vector3d(vtExtr) -- se ho un offset angolare ruoto il percorso if abs(dOffsAng) > 100 * GEO.EPS_SMALL then vtCheck:rotate( vtN, dOffsAng) end -- controllo se c'è collisione con le facce della superfice if CalcInterference( nNewProc.Id, vtCheck, tFacAdj[nIdEndPoint], dDiam1, dDiam2, dTall1, dTall2, dDiam3, dTall3) then local sErr = 'Collision detect from clean corner tool and surface' EgtOutLog( sErr) return true, '' end nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdIniPoint], tFacAdj[nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) -- se offset angolare valido e/o negativo creo il baffo precedente if dOffsAng < ( 100 * GEO.EPS_SMALL) then -- se il punto finale corrisponde con il punto utilizzato in precedenza, uso l'altro if dist( tFacAdj[nIdEndPoint], ptLocP1) < 10 * GEO.EPS_SMALL then ptApPoint = ptLocP2 else ptApPoint = ptLocP1 end nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdEndPoint], ptApPoint, GDB_RT.GLOB) local dLenTrimExt = dist( tFacAdj[nIdEndPoint], ptApPoint) - (( dToolDiam/2) + 0.2) -- se la distanza dei due punti della linea è maggiore dal raggio fresa + delta, trimmo al raggio fresa + delta if dLenTrimExt > 10 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dLenTrimExt, ptApPoint, GDB_RT.GLOB) -- se ho l'offset angolare ruoto la linea per compensare la rotazione che verrà applicata if abs(dOffsAng) > 100 * GEO.EPS_SMALL then EgtRotate( nAuxId, tFacAdj[nIdEndPoint], vtN, -dOffsAng, GDB_RT.GLOB) end -- prendo il nuovo punto finale ptApPoint = EgtEP( nAuxId, GDB_RT.GLOB) else -- se ho l'offset angolare ruoto la linea per compensare la rotazione che verrà applicata if abs(dOffsAng) > 100 * GEO.EPS_SMALL then EgtRotate( nAuxId, tFacAdj[nIdEndPoint], vtN, -dOffsAng, GDB_RT.GLOB) end end table.insert( pAuxId, nAuxId) -- creo linea di ritorno nAuxId = EgtLine( nAddGrpId, ptApPoint, tFacAdj[nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) end end -- inserisco le ultime tre linee -- trovo il secondo punto sulla superfice di riferimento ptLocP1, ptLocP2 = ptLocP3, ptLocP4 if ptLocP1 and ptLocP2 then -- se il punto finale corrisponde con il punto utilizzato in precedenza, uso l'altro if dist( tFacAdj[nIdEndPoint], ptLocP1) < 10 * GEO.EPS_SMALL then ptApPoint = ptLocP2 else ptApPoint = ptLocP1 end -- se offset angolare valido e/o negativo creo il baffo precedente if dOffsAng > -( 100 * GEO.EPS_SMALL) then nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdEndPoint], ptApPoint, GDB_RT.GLOB) local dLenTrimExt = dist( tFacAdj[nIdEndPoint], ptApPoint) - (( dToolDiam/2) + 0.2) -- se la distanza dei due punti della linea è maggiore dal raggio fresa + delta, trimmo al raggio fresa + delta if dLenTrimExt > 10 * GEO.EPS_SMALL then EgtTrimExtendCurveByLen( nAuxId , -dLenTrimExt, ptApPoint, GDB_RT.GLOB) -- se ho l'offset angolare ruoto la linea per compensare la rotazione che verrà applicata if abs(dOffsAng) > 100 * GEO.EPS_SMALL then EgtRotate( nAuxId, tFacAdj[nIdEndPoint], vtN, -dOffsAng, GDB_RT.GLOB) end -- prendo il nuovo punto finale ptApPoint = EgtEP( nAuxId, GDB_RT.GLOB) else -- se ho l'offset angolare ruoto la linea per compensare la rotazione che verrà applicata if abs(dOffsAng) > 100 * GEO.EPS_SMALL then EgtRotate( nAuxId, tFacAdj[nIdEndPoint], vtN, -dOffsAng, GDB_RT.GLOB) end end table.insert( pAuxId, nAuxId) -- creo linea di ritorno nAuxId = EgtLine( nAddGrpId, ptApPoint, tFacAdj[nIdEndPoint], GDB_RT.GLOB) table.insert( pAuxId, nAuxId) end -- ultima linea di distacco (5mm in direzione utensile) local pEnd = tFacAdj[nIdEndPoint] + ( 5 * vtExtr) nAuxId = EgtLine( nAddGrpId, tFacAdj[nIdEndPoint], pEnd, GDB_RT.GLOB) table.insert( pAuxId, nAuxId) end -- trasformo in percorso if #pAuxId > 0 then AuxId = EgtCurveCompo( nAddGrpId, pAuxId, true) EgtSetInfo( AuxId, 'TASKID', nNewProc.TaskId) EgtSetInfo( AuxId, 'CUTID', nNewProc.CutId) end -- se non c'é il percorso do errore if not AuxId then local sErr = 'Error : impossible make clean corner path' EgtOutLog( sErr) return false, sErr end -- modifico versore direzione EgtModifyCurveExtrusion( AuxId, vtExtr, GDB_RT.GLOB) -- se ho un offset angolare ruoto il percorso if abs(dOffsAng) > 100 * GEO.EPS_SMALL then EgtRotate( AuxId, tFacAdj[nIdEndPoint], vtN, dOffsAng, GDB_RT.GLOB) end -- inserisco la lavorazione local sName = 'Clean_' .. ( EgtGetName( nNewProc.Id) or tostring( nNewProc.Id)) local nMchId = EgtAddMachining( sName, sMilling) if not nMchId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end EgtSetInfo( nMchId, 'Part', nPartId) -- aggiungo geometria EgtSetMachiningGeometry( {{ AuxId, -1}}) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.ADIR_ZP EgtSetMachiningParam( MCH_MP.SCC, nSCC) EgtSetMachiningParam( MCH_MP.LEADINTYPE, 0) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, 4) -- allungo inizio e fine di 10mm EgtSetMachiningParam( MCH_MP.STARTADDLEN, 10) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 10) -- setto affondamento 0 EgtSetMachiningParam( MCH_MP.DEPTH, 0) -- forzo lato correzione a centrato EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.CENTER) -- leggo eventuali note esistenti della lavorazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' -- Note utente con dichiarazione nessuna generazione sfridi per Vmill sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) -- aggiungo alle note massima elevazione sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( 0.0, 1)) -- scrivo le note della lavorazione EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) if not EgtApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchId, false) return false, sWarn end end return true, '' end --------------------------------------------------------------------- local function AddMillCorner( vFace, Proc, dToolDiam, nAddGrpId, nMasterNewProc, vtN) local sMilling, dMaxDepth -- se ripresa angolo con fresa cono 60° con ripresa -- recupero la lavorazione di fresatura sMilling, dMaxDepth = ML.FindMilling( 'CleanCorner60') if not sMilling then local sErr = 'Error : CleanCorner 60 not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile local dMillDiam = 20 local dMillTotDiam = 20 local dMillDiamTh = 20 local dToolLength = 20 local dThickTool = 20 local dSideAng = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dMillDiamTh = EgtTdbGetCurrToolThDiam() or dMillDiamTh dMillTotDiam = EgtTdbGetCurrToolParam( MCH_TP.TOTDIAM) or dMillTotDiam dSideAng = EgtTdbGetCurrToolParam( MCH_TP.SIDEANG) or dSideAng dMillDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dMillDiam dThickTool = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dThickTool dToolLength = EgtTdbGetCurrToolParam( MCH_TP.LEN) or dToolLength dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth -- qui è la distanza dal portautensile -- calcolo il secondo diametro del cono dMillTotDiam = dMillDiam + ( abs(dThickTool) * tan(dSideAng)) * 2 end end -- copio la feature nel layer di appoggio local nNewProc = { CutId = Proc.CutId, TaskId = Proc.TaskId} if nMasterNewProc then nNewProc.Id = nMasterNewProc else nNewProc.Id = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL end local nFacCnt = EgtSurfTmFacetCount( nNewProc.Id) local nFacInd, dDimMin, dDimMax, dDepth, nSurfInt local bMakeLocSurf = true -- verifico se ciclo chiuso local bClosed = ( abs( vFace[1].AngPrev) > 0.1) -- ciclo di inserimento delle fresate sulle facce del contorno in esame local i = 1 -- se faccia finale con fine non lavorato, forzo partenza da prima faccia non tutta saltata (tipo 4) if bClosed and ( vFace[#vFace].Type == 4 or ( vFace[#vFace].Type & 2) ~= 0) then while i <= #vFace and vFace[i].Type == 4 do i = i + 1 end end -- se facce tutte da saltare, parto dall'inizio local bAllType4 = ( i > #vFace) if bAllType4 or bClosed then i = 1 end while i <= #vFace do -- se tutta la faccia o la sua fine senza taglio, inserisco una fresatura if ( vFace[i].Type & 2) ~= 0 or vFace[i].Type == 4 then -- variabili costruzione geometria (nFace1, nFace2, tFacAdj) local nFace1 = vFace[i].Fac -- ricavo i tre punti per eventuale superficie locale local ptLoc1, ptLoc2, ptLoc3 -- aggiungo geometria local j = EgtIf( i < #vFace, i + 1, EgtIf( bClosed, 1, nil)) if not j then return true end local nFace2 = vFace[j].Fac -- punto in comune tra le due facce (punto precedente della faccia [j]) ptLoc1 = vFace[j].PPrev -- punto precedente (punto precedente della faccia [i]) if vFace[i].PPrev then ptLoc3 = vFace[i].PPrev else if abs( vtN:getZ()) > abs( vtN:getY()) then ptLoc3 = Point3d( vFace[i].Cen:getX(), vFace[i].Cen:getY(), ptLoc1:getZ()) else ptLoc3 = Point3d( vFace[i].Cen:getX(), ptLoc1:getY(), vFace[i].Cen:getZ()) end end -- punto successivo ( precedente della faccia successiva) local k = EgtIf( j < #vFace, j + 1, EgtIf( bClosed, 1, nil)) -- se è un percorso aperto prendo il punto medio della seconda faccia come punto locale 2 if not k then if abs( vtN:getZ()) > abs( vtN:getY()) then ptLoc2 = Point3d( vFace[j].Cen:getX(), vFace[j].Cen:getY(), ptLoc1:getZ()) else ptLoc2 = Point3d( vFace[j].Cen:getX(), ptLoc1:getY(), vFace[j].Cen:getZ()) end else ptLoc2 = vFace[k].PPrev end -- ricavo i punti e l'angolo interno local _, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( nNewProc.Id, nFace1, nFace2, GDB_ID.ROOT) -- se punti validi e angolo è interno e non è quasi piatto e >= 90 creo istanza local tFacAdj = {} if ptP1 and ptP2 and dAng < 0 and dAng < -6 and dAng > -( 90 + 10 * GEO.EPS_SMALL) then local dLen = dist( ptP1, ptP2) tFacAdj = { nFace1, nFace2, dLen, ptP1, ptP2, dAng, ptLoc1, ptLoc2, ptLoc3} end -- se ho un elemento creo percorso o percorsi in base al tipo di cono e all'apertura dall'angolo rispetto ai 90° -- con una tolleranza di 2 gradi if #tFacAdj > 0 then if (dAng + 90) > 2 then local dAngOffs = (dAng + 90) / 2 -- primo taglio local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nAddGrpId, dToolDiam, sMilling, -dAngOffs, dMillDiam, dMillTotDiam, abs( dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace, vtN) if not bOk then return bOk, sErr end -- secondo taglio bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nAddGrpId, dToolDiam, sMilling, dAngOffs, dMillDiam, dMillTotDiam, abs( dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace, vtN) if not bOk then return bOk, sErr end -- altrimenti ho un solo percorso else local bOk, sErr = AddMillCornerMachining( Proc.PartId, nNewProc, nFacInd, tFacAdj, nAddGrpId, dToolDiam, sMilling, 0, dMillDiam, dMillTotDiam, abs( dThickTool), dMaxDepth, dMillDiamTh, dToolLength, bMakeLocSurf, vFace, vtN) if not bOk then return bOk, sErr end end end end -- passo alla successiva i = i + 1 end -- cancello la copia della superfice if nNewProc.Id then EgtErase( nNewProc.Id) end return true end --------------------------------------------------------------------- local function GetOtherRegions( nPartId) local vOthers = {} local nOtherId = EgtGetFirstPartInRawPart( EgtGetFirstRawPart() or GDB_ID.NULL) while nOtherId do local nRegId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( nOtherId, 'Outline') or GDB_ID.NULL) while nRegId do local vtN = EgtSurfFrNormVersor( nRegId, GDB_ID.ROOT) if EgtExistsInfo( nRegId, 'REGION') and vtN and AreSameVectorApprox( vtN, Z_AX()) then local b3Reg = EgtGetBBoxGlob( nRegId, GDB_BB.STANDARD) if b3Reg then table.insert( vOthers, { PartId = nOtherId, RegId = nRegId, Box = b3Reg}) end end nRegId = EgtGetNext( nRegId) end nOtherId = EgtGetNextPartInRawPart( nOtherId) end return vOthers end --------------------------------------------------------------------- local function GetFacesData( nNewProc, dToolDiam, dToolMaxDepth, dToolThick, nAddGrpId, nPartId, vtNBottom) local nNumFacet = EgtSurfTmFacetCount( nNewProc) local vFace = {} -- recupero i dati di tutte le facce for i = 1, nNumFacet do -- indici faccia corrente e precedente local nFac = i - 1 local nPrecFac nPrecFac = EgtIf( i == 1, nNumFacet - 1, i - 2) -- recupero centro e normale della faccia local ptCen, vtN = EgtSurfTmFacetCenter( nNewProc, nFac, GDB_ID.ROOT) -- recupero le dimensioni della faccia local _, dLen, dWidth = BL.GetFaceHvRefDim( nNewProc, nFac) -- recupero l'angolo con la faccia precedente local bAdj, ptLocP1, ptLocP2, dAng = EgtSurfTmFacetsContact( nNewProc, nPrecFac, nFac, GDB_ID.ROOT) -- verifico che l'adiacenza sia veramente con il precedente (percorro con normale a destra) if bAdj then if ( vtN ^ ( ptLocP1 - ptCen)) * vtNBottom > 0 then bAdj = false end end -- salvo i dati vFace[i] = { Fac = nFac, Cen = ptCen, Norm = vtN, Len = dLen, Width = dWidth, AngPrev = EgtIf( bAdj, dAng, 0)} if bAdj then -- se rivolto verso Z if abs( vtNBottom:getZ()) > abs( vtNBottom:getY()) then if ptLocP1:getZ() < ptLocP2:getZ() then vFace[i].PPrev = ptLocP1 else vFace[i].PPrev = ptLocP2 end else if vtNBottom:getY() > 0 then vFace[i].PPrev = EgtIf( ptLocP1:getY() < ptLocP2:getY(), ptLocP1, ptLocP2) else vFace[i].PPrev = EgtIf( ptLocP1:getY() > ptLocP2:getY(), ptLocP1, ptLocP2) end end end end -- analizzo le facce local dMaxWidth = 0 for i = 1, #vFace do -- aggiorno la massima larghezza if vFace[i].Width > dMaxWidth then dMaxWidth = vFace[i].Width end -- verifico l'affondamento local dDepth = BD.CUT_EXTRA if vFace[i].Width + BD.CUT_EXTRA > dToolMaxDepth then dDepth = dToolMaxDepth - vFace[i].Width end -- lunghezza baffo local dElev = vFace[i].Width + dDepth local dWhisk = ( dToolDiam / 2) + WHISK_SAFE -- determino la lunghezza del taglio passante e il tipo di attacco e uscita local dLen = vFace[i].Len local nType = 0 if vFace[i].AngPrev < -0.1 then nType = nType + 1 end if vFace[EgtIf( i < nNumFacet, i + 1, 1)].AngPrev < -0.1 then nType = nType + 2 end -- se lunghezza non significativa, non va inserito il taglio if dLen < MIN_LEN_CUT then nType = 4 end vFace[i].Depth = dDepth vFace[i].Whisk = dWhisk vFace[i].Type = nType end -- recupero le regioni degli altri pezzi local vOthers = GetOtherRegions( nPartId) -- verifico i baffi sporgenti dei tagli rispetto alle altre regioni for i = 1, #vFace do -- verifico il baffo iniziale if vFace[i].Type ~= 4 and ( vFace[i].Type & 1) == 0 then -- creo il rettangolo del baffo local vtOrt = Vector3d( vFace[i].Norm:getX(), vFace[i].Norm:getY(), 0) ; vtOrt:normalize() local vtDir = Vector3d( vtOrt) ; vtDir:rotate( Z_AX(), -90) local vtUp = Vector3d( vtDir) ; vtUp:rotate( vFace[i].Norm, -90) local ptIni = vFace[i].Cen + vFace[i].Width / 2 * vtUp + ( vFace[i].Len / 2 + WHISK_OFFS) * vtDir + WHISK_OFFS * vtOrt local ptDir = ptIni + ( vFace[i].Whisk - WHISK_OFFS) * vtDir local ptCross = ptDir + ( dToolThick - WHISK_OFFS) * vtOrt local WhId = EgtSurfFrRectangle3P( nAddGrpId, ptIni, ptCross, ptDir, GDB_RT.GLOB) local b3Wh = EgtGetBBoxGlob( WhId or GDB_ID.NULL, GDB_BB.STANDARD) -- verifico se interferisce con gli altri pezzi for j = 1, #vOthers do if OverlapsXY( b3Wh, vOthers[j].Box) then local nClass = EgtSurfFrChunkSimpleClassify( WhId, 0, vOthers[j].RegId, 0) if nClass ~= GDB_RC.OUT then local dLen = vFace[i].Len - vFace[i].Whisk + EgtIf( ( vFace[i].Type & 2) ~= 0, -vFace[i].Whisk, 0) if dLen >= MIN_LEN_CUT then vFace[i].Type = vFace[i].Type + 1 else vFace[i].Type = 4 end break end end end EgtErase( WhId) end -- verifico il baffo finale if vFace[i].Type ~= 4 and ( vFace[i].Type & 2) == 0 then -- creo il rettangolo del baffo local vtOrt = Vector3d( vFace[i].Norm:getX(), vFace[i].Norm:getY(), 0) ; vtOrt:normalize() local vtDir = Vector3d( vtOrt) ; vtDir:rotate( Z_AX(), 90) local vtUp = Vector3d( vtDir) ; vtUp:rotate( vFace[i].Norm, 90) local ptIni = vFace[i].Cen + vFace[i].Width / 2 * vtUp + ( vFace[i].Len / 2 + WHISK_OFFS) * vtDir + WHISK_OFFS * vtOrt local ptDir = ptIni + ( vFace[i].Whisk - WHISK_OFFS) * vtDir local ptCross = ptDir + ( dToolThick - WHISK_OFFS) * vtOrt local WhId = EgtSurfFrRectangle3P( nAddGrpId, ptIni, ptCross, ptDir, GDB_RT.GLOB) local b3Wh = EgtGetBBoxGlob( WhId or GDB_ID.NULL, GDB_BB.STANDARD) -- verifico se interferisce con gli altri pezzi for j = 1, #vOthers do if OverlapsXY( b3Wh, vOthers[j].Box) then local nClass = EgtSurfFrChunkSimpleClassify( WhId, 0, vOthers[j].RegId, 0) if nClass ~= GDB_RC.OUT then local dLen = vFace[i].Len - vFace[i].Whisk + EgtIf( ( vFace[i].Type & 1) ~= 0, -vFace[i].Whisk, 0) if dLen >= MIN_LEN_CUT then vFace[i].Type = vFace[i].Type + 2 else vFace[i].Type = 4 end break end end end EgtErase( WhId) end end -- eventuali stampe for i = 1, #vFace do local Face = vFace[i] local sOut = 'Face '..tostring( Face.Fac)..' C'..tostring( Face.Cen)..' N'..tostring( Face.Norm).. ' L='..EgtNumToString( Face.Len, 1)..' W='..EgtNumToString( Face.Width, 1)..' Ap='..EgtNumToString( Face.AngPrev, 1).. ' D='..EgtNumToString( Face.Depth, 1)..' B='..EgtNumToString( Face.Whisk, 1)..' T='..tostring( Face.Type) EgtOutLog( sOut, 3) end return vFace, dMaxWidth, nNewProc end --------------------------------------------------------------------- local function ReorderFaces( nIdSurf, nNumFacet, vtNBottom) -- cerco una faccia senza precedenti local nFirstFac for i = 1, nNumFacet do -- centro e normale della faccia local ptCen, vtN = EgtSurfTmFacetCenter( nIdSurf, i - 1, GDB_ID.ROOT) -- verifico con le altre facce local bFoundPrec for j = 1, nNumFacet do if j ~= i then -- verifico se è precedente local bAdj, ptP1, _, _ = EgtSurfTmFacetsContact( nIdSurf, i - 1, j - 1, GDB_ID.ROOT) if bAdj and ( vtN ^ ( ptCen - ptP1)) * vtNBottom > 0 then bFoundPrec = true break end end end if not bFoundPrec then nFirstFac = i break end end -- se trovata, la metto al primo posto if nFirstFac and nFirstFac ~= 1 then EgtSurfTmSwapFacets( nIdSurf, nFirstFac - 1, 0) end -- ordino le facce in modo da avere una sequenza ordinata con le normali a destra for i = 1, nNumFacet - 1 do -- centro e normale della faccia local ptCen, vtN = EgtSurfTmFacetCenter( nIdSurf, i - 1, GDB_ID.ROOT) -- cerco la successiva for j = i + 1, nNumFacet do -- verifico se è successiva local bAdj, ptP1, _, _ = EgtSurfTmFacetsContact( nIdSurf, i - 1, j - 1, GDB_ID.ROOT) if bAdj and ( vtN ^ ( ptP1 - ptCen)) * vtNBottom > 0 then EgtSurfTmSwapFacets( nIdSurf, i, j - 1) break end end end end --------------------------------------------------------------------- local function RemoveBottomFaceAndReorder( Proc, nAddGrpId, nFaceToDel, vtN) -- copio la superfice nel gruppo ausiliario local nNewProc = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL EgtSurfTmRemoveFacet( nNewProc, nFaceToDel) local nNumFacet = EgtSurfTmFacetCount( nNewProc) ReorderFaces( nNewProc, nNumFacet, vtN) return nNewProc, nNumFacet end --------------------------------------------------------------------- local function MakeMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead, bSinglePart, bPrevBhSideMill, bAllWithEndCap) if not BD.MAXDIAM_POCK_CORNER then BD.MAXDIAM_POCK_CORNER = 30 end local nMGrpId = EgtGetCurrMachGroup() local sWarn -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero l'ingombro della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then local sErr = 'Error : part box not found' EgtOutLog( sErr) return false, sErr end -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- strategia lama + eventuale sega a catena if ( EgtGetInfo( Proc.Id, Q_SAW_PLUS_CHAIN, 'i') or 0) > 0 then local bOk local sErr local bOnlySaw = EgtGetInfo( Proc.Id, Q_SAW_PLUS_CHAIN, 'i') == 1 bOk, sErr = SawPlusChain.Make ( bOnlySaw, Proc, nRawId) return bOk, sErr end local bClosedOrthoFaces local nFacInd, dFacElev, nFacInd2, dFacElev2 local nBottomFace local sMchFindBackUp -- recupero la faccia con il maggior numero di adiacenze e l'elevazione relativa nFacInd, dFacElev, nFacInd2, dFacElev2 = BL.GetFaceWithMostAdj( Proc, nPartId) if not nFacInd or nFacInd < 0 then if nFacInd == -1 then bClosedOrthoFaces = nFacInd2 else local sErr = 'Error : MakeMoreFaces could not find reference face' EgtOutLog( sErr) return false, sErr end end -- se scanalatura chiusa lavoro la faccia di fondo if Proc.Topology == 'Pocket' and ( Proc.IsParallel or Proc.AllRightAngles) and not bClosedOrthoFaces then nFacInd = Topology.GetFacesWithGivenAdjacencyNumber( Proc, nil, 4)[1] nFacInd2 = nil dFacElev = Proc.Face[ nFacInd + 1].Elevation end -- se proviene da divisione in parti lungo X ed è un tunnel non è fattibile if not bSinglePart and bClosedOrthoFaces then local sErr = 'Error : long splitted tunnel not feasible' EgtOutLog( sErr) return false, sErr end -- verifico se sono presenti i parametri Q per la profondità smusso e -- per eseguire in esclusiva solo lo smusso local nChamfer, dDepthCham, sErrCham, bForceUseBlade = EvaluateQParam( Proc) -- se non posso lavorare la feature perché condizionata dall'esecuzione del solo chamfer -- genero errore e non faccio nulla if nChamfer < 0 then return false, sErrCham end -- eventuale forzatura sega a catena local bForceChainsaw = ( EgtGetInfo( Proc.Id, Q_FORCE_CHAINSAW, 'i') or 0) > 0 -- TUNNEL: svuotatura o sega a catena if bClosedOrthoFaces then local bTryWithBlades = true local dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace -- forzata sega a catena if bForceChainsaw then -- ottengo le dimensioni del tunnel dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace = BL.GetTunnelDimension( Proc, nPartId) -- se non richiesto solo contorno, lavoro fessura con svuotature (singola o doppia contrapposta) else local bOnlyContour = ( EgtGetInfo( Proc.Id, Q_ONLY_CONTOUR, 'i') or 0) > 0 if bOnlyContour then if Proc.TopologyLongName == 'Tunnel-Through-RightAngles-Parallel-4' then -- direzione e faccia aggiunta del tunnel (la groove-3 passante è uno pseudotunnel) local _, _, dTunnelDepth, vtTunnelDirection, _, idAddedTunnelTmFace = BL.GetTunnelDimension( Proc, nPartId) -- si tiene il verso del tunnel dal lato Z positiva if vtTunnelDirection:getZ() < GEO.EPS_SMALL then vtTunnelDirection = -vtTunnelDirection EgtInvertSurf( idAddedTunnelTmFace) end -- estrazione del contorno da lavorare local idContourPath = EgtExtractSurfTmLoops( idAddedTunnelTmFace, nAddGrpId) EgtModifyCurveExtrusion( idContourPath, vtTunnelDirection, GDB_RT.GLOB) -- spessore codolo da lasciare local dDimStrip = EgtGetInfo( Proc.Id, Q_DIM_STRIP, 'd') or 0 -- lavorazione local bOkContour, sWarn2 = MakeContourByMill( Proc, idContourPath, vtTunnelDirection, dTunnelDepth, dDimStrip, nPhase) if bOkContour then return true, sWarn2 else return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end else local sErr2 = 'Error : Cannot use ' .. Q_ONLY_CONTOUR .. ' on this feature' return false, sErr2 end -- svuotatura else local sMyMchFind = 'Pocket' local nOk, sErr nOk, sErr, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, sErr = MakeByPockets( Proc, nPhase, nRawId, nPartId, nChamfer, dDepthCham, nAddGrpId, sMyMchFind, false, b3Solid, bClosedOrthoFaces) if nOk < 0 then return false, sErr elseif nOk > 0 then sWarn = sErr bTryWithBlades = false end end end -- Se la svuotatura precedente non è stata fatta e chamfer non è mutuamente esclusivo provo con la sega-catena if bTryWithBlades and nChamfer < 2 then -- verifico se posso farlo con la sega-catena local bMakeChainSaw, sSawing, dMaxMat, dSawCornerRad, dSawThick, _, dSawWidth = VerifyChainSaw( Proc, dDimMin, dDimMax, dDepth) if bMakeChainSaw then -- se forzata sega a catena devo verificare se inserire lo smusso if bForceChainsaw and nChamfer > 0 then local nOk, sErr = MakeChamfer( Proc, false, nAddGrpId, vtOrtho, b3Solid, nLundIdFace, dDepthCham) if nOk < 0 then return -1, sErr end end -- Ricalcolo l'affondamento tenendo conto di eventuale inclinazione local dSlDepth local frSlDh = Frame3d( Proc.Box:getCenter(), vtOrtho) for i = 1, Proc.Fct do local b3Fac = EgtSurfTmGetFacetBBoxRef( Proc.Id, i - 1, GDB_BB.STANDARD, frSlDh) if b3Fac and ( not dSlDepth or b3Fac:getDimZ() < dSlDepth) then dSlDepth = b3Fac:getDimZ() end end if dSlDepth then dDepth = dSlDepth end -- Verifico se necessarie più passate local nStep = ceil( ( dDimMin - 100 * GEO.EPS_SMALL) / dSawThick) local dStep = 0 if nStep > 1 then dStep = ( dDimMin - dSawThick) / ( nStep - 1) end local bSplit = false local sFaceUse, sFaceUseOtherSide -- imposto il lato di lavorazione, da sopra oppure di fronte -- se è di fronte, non è una Fast e il tagliente non arriva splitto la lavorazione -- Questa feature non è applicata su facce di testa e quindi non controllo l'entrata in X if abs(vtOrtho:getZ()) >= 0.707 then sFaceUse = MCH_MILL_FU.PARAL_DOWN else sFaceUse = MCH_MILL_FU.PARAL_BACK -- per escludere la Fast controllo C_SIMM if BD.C_SIMM and dMaxMat < dDepth then bSplit = true sFaceUseOtherSide = MCH_MILL_FU.PARAL_FRONT dDepth = dDepth / 2 + BD.CUT_EXTRA end end -- se necessario riduco la profondità di lavoro per considerare l'ingombro della testa local dChainSawTHLength = EgtIf( EgtTdbGetCurrToolThLength() > 10 * GEO.EPS_SMALL, EgtTdbGetCurrToolThLength(), 88) local dChainSawExtraLength = EgtTdbGetCurrToolParam( MCH_TP.TOTLEN) - dChainSawTHLength - dMaxMat local dMaxMatReduction = 0 local dToolEntryAngle, _, _, dTanToolEntryAngle = GetToolEntryAngle( Proc, vtOrtho) if dToolEntryAngle > 10 * GEO.EPS_ANG_SMALL and dTanToolEntryAngle then dMaxMatReduction = max( ( ( 2 * BD.C_SIMM_ENC - dSawWidth) / ( 2 * dTanToolEntryAngle) - dChainSawExtraLength) - 5, 0) end local dWorkDepth = dMaxMat - dMaxMatReduction -- cerco di estendere il taglio considerando la parte arrotondata della lama if dMaxMat - dMaxMatReduction > dDepth + dSawCornerRad + 1 then dWorkDepth = dDepth + dSawCornerRad + 1 -- se massimo affondamento utensile inferiore alla profondità da lavorare, setto la profondità di lavoro e emetto warning elseif dMaxMat - dMaxMatReduction < dDepth then sWarn = 'Warning : elevation bigger than max tool depth' EgtOutLog( sWarn) end -- lavoro da un lato local bOk, sErr = MakeTunnelByChainSaw( Proc, sSawing, nLundIdFace, vtOrtho, dWorkDepth, dMaxMat, nStep, dStep, sFaceUse, false) if not bOk then return false, sErr end -- se è da lavorare anche dall'altro lato if bSplit then bOk, sErr = MakeTunnelByChainSaw( Proc, sSawing, nLundIdFace, vtOrtho, dWorkDepth, dMaxMat, nStep, dStep, sFaceUseOtherSide, true) if not bOk then return false, sErr end end end end -- NO TUNNEL: tutti gli altri casi else -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) -- larghezza della faccia local _, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) if Proc.Box:getDimX() > Proc.Box:getDimY() then if dH > dV then dH, dV = dV, dH end else if dH < dV then dH, dV = dV, dH end end -- se due o più facce (recupero la larghezza della faccia perpendicolarmente alle altre) if Proc.Fct >= 2 then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, EgtIf( nFacInd == 0, 1, 0), GDB_ID.ROOT) local vtX = vtN2 ^ vtN if not vtX:isSmall() then local frRef = Frame3d( ptC, ptC + 100 * vtX, ptC + 100 * vtN2) local b3Ref = EgtSurfTmGetFacetBBoxRef( Proc.Id, nFacInd, GDB_BB.STANDARD, frRef) if b3Ref then dH = b3Ref:getDimX() dV = b3Ref:getDimY() end end end -- verifico se U local bIsU = ( Proc.Fct == 3 and not TestElleShape3( Proc)) -- verifico se due facce o L con una o due facce di terminazione local bIsL = ( Proc.Fct == 2 or TestElleShape3( Proc) or TestElleShape4( Proc) == 2) -- se parametro Q03=2 forzo la fresatura di lato; con Q03=3 forzo solo se la faccia di lavoro non è rivolta verso l'alto +/-10°; per rabbet che guardano in giù sempre fresatura di lato local bIsRabbetAlongXTowardsBottom = ( Proc.TopologyLongName == 'Rabbet-Through-RightAngles-Parallel-2' and ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) and Proc.AffectedFaces.Bottom and Proc.AffectedFaces.Left and Proc.AffectedFaces.Right) local bForceSideMill = ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) and ( bIsRabbetAlongXTowardsBottom or ( ( EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') == 2 or ( EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') == 3 and vtN:getZ() < 0.985)) and ( ( Proc.Fct == 4 and ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back)) or Proc.Fct == 3 or Proc.Fct == 2))) -- se fattibile con fresa BH di fianco e spessore utensile inferiore alla larghezza faccia local bMakeBySideMill, bHead, bHeadDir, sMilling, dMaxMat, dToolDiam = VerifyBHSideMill( Proc, bIsU, bIsL, bSinglePart, bPrevBhSideMill, b3Raw) if bPrevBhSideMill == nil then bPrevBhSideMill = bMakeBySideMill end -- SIDEMILL (tipo BLOCKHAUS) if bMakeBySideMill then -- se smusso non è esclusivo if nChamfer < 2 then -- verifico che la faccia non sia diretta come X, altrimenti cerco di cambiarla if abs( vtN:getX()) > 0.866 and nFacInd2 then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, nFacInd2, GDB_ID.ROOT) if vtN2 and abs( vtN2:getX()) < 0.866 then nFacInd, nFacInd2 = nFacInd2, nFacInd dFacElev, dFacElev2 = dFacElev2, dFacElev vtN, vtN2 = vtN2, vtN end end -- informazioni utensile local Tool = BL.GetToolFromMachining( sMilling) -- se lavorazione da sotto e lunga, va divisa in due metà local bDouble = not Tool.IsOnAggregate and ( vtN:getZ() < -0.5 and dH > ( BD.MAX_LEN_BH_FROM_BOTTOM or 200) and not BD.TURN) -- inserisco la lavorazione di fresatura local sName = 'BHMill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end sName = EgtGetName( nMchFId) -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso del lato faccia EgtSetMachiningParam( MCH_MP.FACEUSE, EgtIf( bHeadDir, MCH_MILL_FU.PARAL_LEFT, MCH_MILL_FU.PARAL_RIGHT)) -- calcolo step effettivo ed elevazione local dVcalc = dV - dMaxMat if abs( dVcalc) < 0.1 then dVcalc = 0 end local dStep = min( EgtMdbGetCurrMachiningParam( MCH_MP.STEP), dMaxMat) local nStep = ceil( dVcalc / dStep) if nStep > 0 then dStep = dVcalc / nStep + 0.1 else dStep = 0 end -- lo step finale non deve mai superare lo spessore utensile dStep = min( dStep, dMaxMat) EgtSetMachiningParam( MCH_MP.STEP, dStep) -- imposto elevazione e dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dVcalc + dStep, 2)) sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- attacchi e uscite if vtN:getZ() > -0.5 or BD.TURN then EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, dFacElev + BD.CUT_SIC) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.AS_LI) local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, EgtIf( nFacInd == 0, 1, 0), GDB_ID.ROOT) if vtN2 then local AddLen = sqrt( dV^2 * ( ( 1 / abs( vtN2:getX())^2) - 1)) + BD.CUT_SIC EgtSetMachiningParam( MCH_MP.STARTADDLEN, AddLen) EgtSetMachiningParam( MCH_MP.ENDADDLEN, AddLen) end else EgtSetMachiningParam( MCH_MP.STARTADDLEN, 0) EgtSetMachiningParam( MCH_MP.LITANG, dToolDiam / 2 + BD.CUT_SIC) EgtSetMachiningParam( MCH_MP.LIPERP, 0) EgtSetMachiningParam( MCH_MP.ENDADDLEN, 0) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.PERP_TG) EgtSetMachiningParam( MCH_MP.LOTANG, -( dToolDiam / 2 + b3Raw:getDimY() + BD.CUT_SIC)) EgtSetMachiningParam( MCH_MP.LOPERP, EgtIf( vtN:getZ() > -0.5, dFacElev + BD.COLL_SIC, BD.COLL_SIC)) if bDouble then EgtSetMachiningParam( MCH_MP.ENDADDLEN, - dH / 2) EgtSetMachiningParam( MCH_MP.LOTANG, -( dToolDiam / 2 + dH / 2 + BD.CUT_SIC)) end end -- tipo passate multiple local nStepType = MCH_MILL_ST.ONEWAY EgtSetMachiningParam( MCH_MP.STEPTYPE, nStepType) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.TURN then nSCC = EgtIf( ( vtN:getY() > 0.5 or ( bHeadDir and vtN:getZ() > 0.5 ) or ( not bHeadDir and vtN:getZ() < -0.5)), MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else if vtN:getY() > 0.707 then nSCC = MCH_SCC.ADIR_YP elseif vtN:getY() < -0.707 then nSCC = MCH_SCC.ADIR_YM elseif vtN:getZ() > 0.707 then nSCC = MCH_SCC.ADIR_ZP elseif vtN:getZ() < -0.707 then nSCC = MCH_SCC.ADIR_ZM end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- impostazioni per fresa a disco su aggregato if Tool.IsOnAggregate then if AreSameVectorApprox( vtN, -Z_AX()) then EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.PARAL_RIGHT) EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) if bHeadDir then EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) EgtSetMachiningParam( MCH_MP.TOOLINVERT, true) else EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.RIGHT) EgtSetMachiningParam( MCH_MP.TOOLINVERT, false) end else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_ZP) end end -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- se divisa in due metà if bDouble then local nMchFNId = EgtCopyMachining( sName .. '_2', sName) if not nMchFNId then local sErr = 'Error copying machining ' .. sName EgtOutLog( sErr) return false, sErr end -- inverto direzione e lato di lavoro e direzione ausiliaria local bInvert = EgtGetMachiningParam( MCH_MP.INVERT) EgtSetMachiningParam( MCH_MP.INVERT, not bInvert) local nWorkSide = EgtGetMachiningParam( MCH_MP.WORKSIDE) EgtSetMachiningParam( MCH_MP.WORKSIDE, EgtIf( nWorkSide == MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)) EgtSetMachiningParam( MCH_MP.SCC, EgtIf( nSCC == MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP)) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFNId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFNId, false) return false, sWarn end end end end -- TASCA GENERICA: si cerca il modo migliore di lavorare in base alla forma else local bSpecial3faces = false -- verifico se lavorando la faccia principale rimane esclusa molta sezione trasversale complessiva della feature (da box) local rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) local bBoxF = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, rfFac) if dH * dV < 0.9 * ( bBoxF:getDimX() * bBoxF:getDimY()) and nFacInd2 and dFacElev2 < 1.5 * dFacElev and not ( Proc.Topology == 'Groove' and Proc.Fct == 2) then bSpecial3faces = true end local bPocketFloatingAggregate = false -- se abilitata lavorazione con aggregato flottante local sMillingFloatingAggregate if Proc.Topology == 'Groove' and Proc.Fct == 4 and EgtGetInfo( Proc.Id, Q_FLOATING_AGGREGATE, 'i') == 1 then -- verifico se è possibile lavorare con utensile su aggregato flottante sMillingFloatingAggregate = ML.FindMilling( 'FloatingAggregate', dFacElev, nil, min( dH , dV)) if sMillingFloatingAggregate then if EgtMdbSetCurrMachining( sMillingFloatingAggregate) then local sTuuidPk = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuidPk) or '') then local dToolDiameter = EgtTdbGetCurrToolParam( MCH_TP.DIAM) -- la larghezza della tasca non può superare il doppio del diametro, la lavorazione deve essere fatta con una passata di contornatura if min( dH , dV) < dToolDiameter * 1.9 then bPocketFloatingAggregate = true end end end end end -- FRESATURA SPECIALE CON AGGREGATO FLOTTANTE if bPocketFloatingAggregate then -- inserisco la lavorazione di svuotatura local sName = 'Float_Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMillingFloatingAggregate) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMillingFloatingAggregate EgtOutLog( sErr) return false, sErr end -- aggiungo geometria local Geometry = {} for Index = 1, Proc.Fct do if nFacInd ~= Index-1 then table.insert( Geometry, { Proc.Id, Index-1}) end end EgtSetMachiningGeometry( Geometry) -- imposto uso faccia local nFaceUse = BL.GetNearestParalOpposite( vtN) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- piccolo offset radiale per essere sicuri di lavorare anche con tasca larga come diametro fresa EgtSetMachiningParam( MCH_MP.OFFSR, -0.01) -- imposto posizione braccio porta testa local nSCC = MCH_SCC.NONE if not BD.C_SIMM then if AreSameVectorApprox( vtN, Z_AX()) then nSCC = MCH_SCC.ADIR_YM elseif abs( vtN:getX()) < 0.1 then nSCC = EgtIf( BL.IsPartFinalPhase( nPhase), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) elseif vtN:getY() < GEO.EPS_SMALL then nSCC = MCH_SCC.ADIR_YP else nSCC = MCH_SCC.ADIR_YM end end EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- CASO SPECIALE 3 FACCE (se rimane esclusa molta sezione trasversale complessiva della feature, solo per feature 20) elseif bSpecial3faces and Proc.Prc == 20 then -- se smusso non è esclusivo if nChamfer < 2 then -- entrambe le facce non devono essere orientate verso il basso local _, vtN2 = EgtSurfTmFacetCenter( Proc.Id, nFacInd2, GDB_ID.ROOT) -- se orientata verso il basso, verifico l'alternativa if vtN:getZ() < BD.NZ_MINA and vtN2:getZ() < BD.NZ_MINA then local sErr = 'Error : special LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) rfFac2, dH2, dV2 = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd2, GDB_ID.ROOT) -- eventuali tagli preliminari do local bOk, sErr = MakePreCuts( Proc, nPhase, nRawId, nPartId, dOvmHead, b3Raw, nChamfer) if not bOk then return false, sErr end end -- Recupero la lavorazione di fresa local sMilling = ML.FindMilling( 'LongSmallCut') if not sMilling then local sErr = 'Error : LongSmallCut not found in library' EgtOutLog( sErr) return false, sErr end -- Recupero la lavorazione di svuotatura local sMchFind = 'Pocket' -- se forzato uso truciolatore if EgtGetInfo( Proc.Id, Q_USE_ROUGH_TOOL, 'i') == 1 then sMchFind = 'OpenPocket' end local dDiam = min( dH, dV) local dDiam2 = min( dH2, dV2) local dCollSic = 2 * BD.COLL_SIC local dCollSic2 = 2 * BD.COLL_SIC if abs( vtN:getX()) > 0.7 or abs( vtN:getY()) > 0.7 or abs( vtN:getZ()) > 0.7 then dCollSic = 0 end if abs( vtN2:getX()) > 0.7 or abs( vtN2:getY()) > 0.7 or abs( vtN2:getZ()) > 0.7 then dCollSic2 = 0 end local sPocketing = ML.FindPocketing( sMchFind, dDiam2, dFacElev2 + dCollSic2) -- se non trova una svuotatura adatta provo ad assegnarla all'altra faccia if not sPocketing then dDiam, dDiam2 = dDiam2, dDiam dCollSic, dCollSic2 = dCollSic2, dCollSic nFacInd, nFacInd2 = nFacInd2, nFacInd dH, dH2 = dH2, dH dV, dV2 = dV2, dV dFacElev, dFacElev2 = dFacElev2, dFacElev rfFac, rfFac2 = rfFac2, rfFac vtN, vtN2 = vtN2, vtN sPocketing = ML.FindPocketing( sMchFind, dDiam2, dFacElev2 + dCollSic2) if not sPocketing then dDiam, dDiam2 = dDiam2, dDiam dCollSic, dCollSic2 = dCollSic2, dCollSic nFacInd, nFacInd2 = nFacInd2, nFacInd dH, dH2 = dH2, dH dV, dV2 = dV2, dV dFacElev, dFacElev2 = dFacElev2, dFacElev rfFac, rfFac2 = rfFac2, rfFac vtN, vtN2 = vtN2, vtN sPocketing = ML.FindPocketing( sMchFind, dDiam2, nil, nil, nil, nil, nil, nil, 'Longest') if not sPocketing then local sErr = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr) return false, sErr end end end -- provo con contornatura local dDiamTool = 20 if bIsL then local bOk, sErr bOk, sWarn, dDiamTool = MakeByMill( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dFacElev, dCollSic, true, sMilling, nFacInd2, dFacElev2) if not bOk then return bOk, sWarn end else local sErr = 'Error : Impossible mill special LapJoint' EgtOutLog( sErr) return false, sErr end -- inserisco la lavorazione di svuotatura local sName = 'Pock_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sPocketing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sPocketing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd2}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_CONT) -- imposto posizione braccio porta testa if vtN:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- se tasca aperta, imposto opportuno attacco if sMchFind == 'OpenPocket' then EgtSetMachiningParam( MCH_MP.SUBTYPE, MCH_POCK_SUB.SPIRALIN) end -- imposto elevazione local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'MaxElev', EgtNumToString( dFacElev2, 1)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then -- provo ad allargare leggermente la tasca EgtSetMachiningParam( MCH_MP.OFFSR, -0.1) if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- se abilitato dal parametro Q inserisco foro sullo spigolo if EgtGetInfo( Proc.Id, Q_BORE_ON_CORNER, 'i') == 1 then local bOk bOk, sWarn = MakeDrillOnCorner( Proc, nPhase, nRawId, nPartId, b3Raw, 0, nAddGrpId, dDiamTool, true) if not bOk then return false, sWarn end -- altrimenti se abilitato dal parametro Q inserisco percorso di pulitura elseif EgtGetInfo( Proc.Id, Q_BORE_ON_CORNER, 'i') == 2 then local bOk bOk, sWarn = MakeSharpCleanCorner( Proc, nPhase, nRawId, nPartId, b3Raw, 0, nAddGrpId, dDiamTool) if not bOk then return false, sWarn end end end -- SVUOTATURA O FRESATURA: si valuta se si può fare svuotatura o se provare altro else local bUseOtherFace local bLapJointAngTrasm = false -- se è presente il rinvio angolare ed è una tasca perfettamente verticale, da sotto if BD.ANG_TRASM and Proc.Fct >= 4 and AreOppositeVectorApprox( vtN, Z_AX()) then bLapJointAngTrasm = true -- se orientata verso il basso e non c'è testa da sotto, verifico l'alternativa elseif vtN:getZ() < BD.NZ_MINA and not BD.DOWN_HEAD and nFacInd2 and not Proc.OkFromBottom then ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd2, GDB_ID.ROOT) nFacInd, nFacInd2 = nFacInd2, nFacInd dFacElev, dFacElev2 = dFacElev2, dFacElev bUseOtherFace = true end -- verifico non sia orientata verso il basso o ci sia una testa dal basso o la lavorazione sia dal lato. local bFaceDown = ( vtN:getZ() < BD.NZ_MINA) if bFaceDown and not BD.DOWN_HEAD and not BD.TURN and not bForceSideMill and not bLapJointAngTrasm and not Proc.OkFromBottom then local sErr = 'Error : LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) -- se forma a L e la componente in X è maggiore di 60° e non in testa allora verifico se posso utilizzare la faccia secondaria if bIsL and abs( vtN:getX()) > 0.866 and ( Proc.Box:getMax():getX() < b3Solid:getMax():getX() - 10 or vtN:getX() < 0) and ( not Proc.Tail or vtN:getX() > 0) then -- se non ho scambiato la faccia if not bUseOtherFace then if nFacInd2 then nFacInd, nFacInd2 = nFacInd2, nFacInd dFacElev, dFacElev2 = dFacElev2, dFacElev ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) -- altrimenti cerco la faccia secondaria per adiacenza alla principale else -- Cerco una faccia adiacente alla principale sul lato lungo local nFacAdj, sErr = GetFaceAdj( Proc, nFacInd, dH, dV) if nFacAdj < 0 then EgtOutLog( sErr) return false, sErr end nFacInd = nFacAdj dFacElev = BL.GetFaceElevation( Proc, nFacInd, b3Solid) ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) end -- altrimenti se ho già cambiato faccia do errore per impossibilità di lavorazione else local sErr = 'Error : impossible to machine by side angle too big that cause collision' EgtOutLog( sErr) return false, sErr end end -- eventuali tagli preliminari do local bOk, sErr = MakePreCuts( Proc, nPhase, nRawId, nPartId, dOvmHead, b3Raw, nChamfer) if not bOk then return false, sErr end end -- imposto altezza aggiuntiva di elevazione local dCollSic = BL.CalcCollisionSafety( vtN) -- abilitazione lavorazione da sotto local bMillUp = ( BD.DOWN_HEAD and vtN:getZ() > -0.259) local bMillDown = ( BD.DOWN_HEAD and vtN:getZ() < 0.342) -- settaggio voluto da Alessandro/Fabio (per fare angoli con fresa piccola) local sMchFind = 'Pocket' local dDiam = min( dH, dV) local bTailOnSide = ( Proc.Box:getMin():getX() - b3Solid:getMin():getX() < 0.1 and not Proc.Tail and not bAllWithEndCap) if ( Proc.Fct == 1) or (( Proc.Fct == 2 or Proc.Fct == 3) and bIsL) or ((( Proc.Fct == 3 and bIsU) or ( Proc.Fct == 4 and not bTailOnSide)) and bSinglePart) then sMchFind = 'OpenPocket' if bIsU then dDiam = GetUShapeWidth( Proc, nFacInd) or dDiam elseif Proc.Fct == 4 then -- se non angoli fittizi, per rifinire gli angoli premio utensile diam 25 o da BD if not bAllWithEndCap then dDiam = min( EgtIf( bIsL, 2, 1) * dDiam + 10 * GEO.EPS_SMALL, BD.MAXDIAM_POCK_CORNER) end elseif Proc.Fct == 3 and bIsL then -- per rifinire gli angoli premio utensile diam 25 o da BD dDiam = min( 2 * dDiam + 10 * GEO.EPS_SMALL, BD.MAXDIAM_POCK_CORNER) else dDiam = 3 * dDiam end end sMchFindBackUp = sMchFind local nUseRoughTool = EgtIf( bSinglePart, 0, 1) local nUseRT -- 04/08/2020 Se settato parametro uso truciolatore (parametro Q), non si devono prendere altre frese, si da errore (Fabio) -- Questa opzione si scontra facilmente con altre interpretazioni dello stasso parametro Q (per tornare indietro bNewCheck = false) local bNewCheck = true -- se processo 20 e non sto usando il truciolatore if bNewCheck and Proc.Prc == 20 and nUseRoughTool == 0 then -- verifico se forzato uso truciolatore nUseRT = EgtGetInfo( Proc.Id, Q_USE_ROUGH_TOOL, 'i') if nUseRT and nUseRT ~= 0 then sMchFind = 'OpenPocket' nUseRoughTool = 1 end end -- se è una tasca aperta e forzo lavorazione laterale, cerco il truciolatore (di norma il truciolatore è solo OpenPocket) if bNewCheck and Proc.Prc == 30 and nUseRoughTool == 0 and Proc.Fct < 5 and not bClosedOrthoFaces then -- verifico se forzato uso truciolatore nUseRT = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') if nUseRT and nUseRT ~= 0 then sMchFind = 'OpenPocket' nUseRoughTool = 1 end end -- se processo 20 e non sto usando il truciolatore if Proc.Prc == 20 and nUseRoughTool == 0 then if nUseRT and nUseRT ~= 0 then sMchFind = 'OpenPocket' nUseRoughTool = 1 end end -- se presente curva da lavorare con lato aperto if Proc.LoopIdFacInd and ( EgtGetInfo( Proc.LoopIdFacInd, 'OPEN', 'i') or -1) > -1 then sMchFind = 'OpenPocket' nUseRoughTool = 0 end -- se abilitato rinvio da sotto if bLapJointAngTrasm then if not EgtEndsWith( sMchFind, '_AT') then sMchFind = sMchFind .. '_AT' end if not EgtEndsWith( sMchFindBackUp, '_AT') then sMchFindBackUp = sMchFindBackUp .. '_AT' end end -- se da sotto, imposto massima lunghezza secondo la direzione local dMaxTotLen if bMillDown and BD.GetBottomToolMaxTotLen then dMaxTotLen = BD.GetBottomToolMaxTotLen( vtN) end local dUserMaxElev = EgtGetInfo( Proc.Id, Q_MAX_ELEVATION, 'd') local dCustomMaxElev -- se esistono tagli troncanti in testa o in coda, si calcola il MaxElev da applicare if not dUserMaxElev then local nTailCutId = EgtGetInfo( nPartId, 'TAILCUTFEATUREID', 'i') local nHeadCutId = EgtGetInfo( nPartId, 'HEADCUTFEATUREID', 'i') if nHeadCutId or nTailCutId then local nSurfPartId = EgtCopyGlob( EgtGetFirstNameInGroup( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, 'Box'), nAddGrpId) if nHeadCutId then local ptCCutSurf, vtNCutSurf = EgtSurfTmFacetCenter( nHeadCutId, 0, GDB_ID.ROOT) EgtCutSurfTmPlane( nSurfPartId, ptCCutSurf, vtNCutSurf, false, GDB_RT.GLOB) local nSurfPartIdOld = nSurfPartId nSurfPartId = EgtSurfTmBySewing( nAddGrpId, { nSurfPartId, nHeadCutId}, false) EgtErase( nSurfPartIdOld) end -- in coda si usa il troncante solo se la feature è settata da lavorare dopo separazione (Tail), altrimenti si rischia che venga fatta prima del taglio if nTailCutId and Proc.Tail then local ptCCutSurf, vtNCutSurf = EgtSurfTmFacetCenter( nTailCutId, 0, GDB_ID.ROOT) EgtCutSurfTmPlane( nSurfPartId, ptCCutSurf, vtNCutSurf, false, GDB_RT.GLOB) local nSurfPartIdOld = nSurfPartId nSurfPartId = EgtSurfTmBySewing( nAddGrpId, { nSurfPartId, nTailCutId}, false) EgtErase( nSurfPartIdOld) end dCustomMaxElev = EgtSurfTmFacetElevationInClosedSurfTm( Proc.Id, nFacInd, nSurfPartId, true) if dCustomMaxElev then dCustomMaxElev = dCustomMaxElev + dCollSic end EgtErase( nSurfPartId) end end -- ricerca lavorazione di svuotatura local sPocketing local _, sMyPocketing, dMyTMaxDepth, dMyTDiam = VerifyPocket( Proc, dDiam, dFacElev + dCollSic, dMaxTotLen, sMchFind, bMillUp, bMillDown) if not sMyPocketing and bMillUp then _, sMyPocketing, dMyTMaxDepth, dMyTDiam = VerifyPocket( Proc, dDiam, dFacElev + dCollSic, dMaxTotLen, sMchFind) bMillDown = false end -- se è presente un'elevazione custom dCustomMaxElev si lavora sempre la faccia standard if sMyPocketing then if dUserMaxElev then dCustomMaxElev = dUserMaxElev elseif dCustomMaxElev and ( dMyTMaxDepth < dCustomMaxElev + dCollSic - 10 * GEO.EPS_SMALL) then dCustomMaxElev = nil end if ( dMyTMaxDepth > dFacElev + dCollSic - 10 * GEO.EPS_SMALL or ( dMyTMaxDepth > 0.8 * dFacElev + dCollSic and not bIsU) or ( bIsL and nUseRoughTool == 0) or ( bIsL and Proc.Prc == 20) or ( bIsL and not bSinglePart) or ( Proc.Prc == 25 and not bIsU and not bIsL)) or ( dCustomMaxElev and dCustomMaxElev > 10 * GEO.EPS_SMALL) then sPocketing = sMyPocketing end end if bMillDown then sMchFind = sMchFind ..'_H2' end -- Verifico se lavorazione "Lamello": local bSpecialMillOnSide, sMillingOnSide, dThickMillOnSide, dToolDiamOnSide, dMaxDepthOnSide = VerifySideMillAsSaw( Proc, nAddGrpId, vtN, dDiam, dFacElev) if bSpecialMillOnSide then sPocketing = nil end -- se feature 16 e forzata lama e forma ad U, annulla la svuotatura if Proc.Prc == 16 and bForceUseBlade and Proc.Fct == 3 and bIsU then sPocketing = nil end -- se richiesta fresatura di lato if bForceSideMill then sPocketing = nil end -- se forzata sega a catena if bForceChainsaw then sPocketing = nil end -- leggo parametro Q local nQAntisplintResult = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') or 0 -- se lavorazione fresa come lama disabilito eventuale antischeggia if bSpecialMillOnSide then nQAntisplintResult = 0 end -- NO SVUOTATURA (si deve provare altro) if not sPocketing then -- se forma a L provo con contornatura if bIsL and not bSpecialMillOnSide and not bForceSideMill then -- se smusso non è esclusivo if nChamfer < 2 then return MakeByMill( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dFacElev, dCollSic) end -- altrimenti, in base alla forma, provo con svuotature di fianco o con la sega a catena o lama else local bTryWithBlades = true local nOk, bOk, sStat, sErr, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, bOrthoFaces, nSurfInt if bSpecialMillOnSide then -- eseguo bOk, sWarn = MakeByMillAsSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dFacElev, nBottomFace, nAddGrpId, b3Solid, dMaxDepthOnSide, sMillingOnSide, dToolDiamOnSide, dThickMillOnSide, bAllWithEndCap) if bOk then return true, sWarn end end -- se feature 16 o 17 e se forzata lama provo prima con questa e poi con la fresa if ( Proc.Prc == 16 or Proc.Prc == 17) and bForceUseBlade then -- Se la svuotatura precedente non è stata fatta e smusso non è esclusivo, provo con le lame if bTryWithBlades and nChamfer < 2 then -- anche su macchine con testa da sotto, la sega a catena è solo da sopra if vtN:getZ() < BD.NZ_MINA and BD.DOWN_HEAD and nFacInd2 then ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd2, GDB_ID.ROOT) nFacInd, nFacInd2 = nFacInd2, nFacInd dFacElev, dFacElev2 = dFacElev2, dFacElev bUseOtherFace = true rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) end -- se forma a U (recupero la larghezza della faccia perpendicolarmente alle altre) if Proc.Fct == 3 and bIsU then local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, EgtIf( nFacInd == 0, 1, 0), GDB_ID.ROOT) local vtX = vtN2 ^ vtN if not vtX:isSmall() then local frRef = Frame3d( ptC, ptC + 100 * vtX, ptC + 100 * vtN2) local b3Ref = EgtSurfTmGetFacetBBoxRef( Proc.Id, nFacInd, GDB_BB.STANDARD, frRef) if b3Ref then dH = b3Ref:getDimX() dV = b3Ref:getDimY() end end end -- eseguo bOk, sWarn, sStat = MakeByChainOrSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dFacElev, bForceUseBlade, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, bOrthoFaces, nBottomFace, nChamfer, nAddGrpId, b3Solid, dDepthCham, nSurfInt) if not bOk then -- in base al flag interno e al numero di facce e se ha forma ad U: provo prima la svuotatura sul fianco e -- se non è possibile allora provo in seguito con lama o segacatena -- o passare subito dalla lavorazione con lama/sega catena if Proc.Fct == 3 and bIsU then -- lavoro con svuotature (singola o doppia contrapposta) local sMyMchFind = 'Pocket' nOk, sErr, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, _, _, _, _, _, _, _, bOrthoFaces = MakeByPockets( Proc, nPhase, nRawId, nPartId, nChamfer, dDepthCham, nAddGrpId, sMyMchFind, true, b3Solid, nil, bMillDown) -- se lavorazione non idonee ( asse della feature troppo inclinato e impossibile lavorare completamente da due parti) if nOk == -2 then if not sMchFind then sMchFind = sMchFindBackUp end sPocketing = ML.FindPocketing( sMchFind, dDiam, nil, nil, not bMillDown, bMillDown) if not sPocketing then local sErr = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr) return false, sErr end elseif nOk < 0 then return false, sErr elseif nOk == 0 then if sStat == 'MNF' then sPocketing = ML.FindPocketing( sMchFind, dDiam, nil, nil, not bMillDown, bMillDown) if not sPocketing then local sErr = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr) return false, sErr end else return bOk, sWarn end else bOk = true return bOk, sErr end else sPocketing = ML.FindPocketing( sMchFind, dDiam, nil, nil, not bMillDown, bMillDown) if not sPocketing then local sErr = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr) return false, sErr end end else return bOk, sWarn end else -- se devo inserire il chamfer if ( ( Proc.Fct == 3 and bIsU) or (Proc.Fct == 2 and bIsL)) and nChamfer > 0 then -- ottengo le dimensioni dello pseudotunnel local _, _, _, vtOrtho, _, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) local nOk, sErr = MakeChamfer( Proc, true, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end end bOk = true return bOk, sWarn end else -- se richiesti antischeggia con lama su U trasversale e smusso non esclusivo -- rimane da gestire: se da eseguire con fresa o se richiesto lama ma impossibile utilizzarla, si utilizza fresa -- 2021.04.27 esegue antischeggia di lama se forma U o L con feature passante in Y o Z -- 2021.07.16 Per poter eseguire antischeggia di lama su feature che non sono passanti da faccia a faccia -- ma che sono su un angolo (coinvolgono 2 facce contigue) è stato modificato il confronto in: -- esegue antischeggia di lama se forma U o L con feature passante in Y o Z, oppure se feature a furma U e con 3 facce oppore a forma a L e con 2 facce -- non fa mai antischeggia di lama se la faccia è rivolta verso il basso, a meno che ci sia una testa sotto local bMadeASbyBld = false local bPassThrou = ( Proc.Box:getDimY() > b3Raw:getDimY() - 1 or Proc.Box:getDimZ() > b3Raw:getDimZ() - 1) local bPassEdge = ((( bIsU and Proc.Fct == 3) or ( bIsL and Proc.Fct == 2)) and bSinglePart and Proc.Box:getDimX() < 0.9 * b3Raw:getDimX()) local nFacIndOri = BL.GetFaceWithMostAdj( Proc, nPartId) local vtNOri = EgtSurfTmFacetNormVersor( Proc.Id, nFacIndOri, GDB_ID.ROOT) if nChamfer < 2 and ( nQAntisplintResult == 1 or nQAntisplintResult == 3) and (( bIsU or bIsL) and ( bPassThrou or bPassEdge)) and ( vtNOri:getZ() > -0.087 or BD.DOWN_HEAD or BD.TURN) then local bOk local bSawDown = ( bMillDown and not bMillUp) bMadeASbyBld, bOk, sWarn = ManageAntiSplintBySaw( Proc, b3Raw, b3Solid, bIsU, vtNOri, nFacIndOri, sWarn, bSawDown, true) if not bOk then return false, sWarn end end -- in base al flag interno e al numero di facce e se ha forma ad U -- oppure se richiesta lavorazione di lato: -- provo prima la svuotatura sul fianco e -- se non è possibile allora provo in seguito con lama o segacatena -- o passare subito dalla lavorazione con lama/sega catena if ( bTrySidePocketAtFirst and Proc.Fct == 3 and bIsU) or bForceSideMill then -- lavoro con svuotature (singola o doppia contrapposta) local sMyMchFind = EgtIf( bForceSideMill, 'OpenPocket', 'Pocket') if Proc.TopologyLongName == 'Groove-Through-RightAngles-Parallel-3' or Proc.TopologyLongName == 'Rabbet-Through-RightAngles-Parallel-2' then sMyMchFind = 'OpenPocket' end local dDiamTool = 100 local nPathInt, nSurfInt, bOneShot, nFirstMachId local bIs3Faces = true local bOrthoFacesMaster = nil local bSetOpenBorders = nil -- trovo la faccia con normale più inclinata verso Y local nFacApproxY, ptCFacApproxY, vtNFacApproxY = BL.FindFaceBestOrientedAsAxis( Proc, Y_AX()) -- se Q03 = 2 e -- 3 facce a L, oppure -- 3 facce non a L ma con una faccia favorevole a Y, oppure -- 4 facce -- lancio la MakePocket ( lavorazione solo da un lato, fondo della tasca la faccia più favorevole a Y) if bForceSideMill and (( Proc.Fct == 3 and bIsL) or ( ( Proc.Fct == 3 or Proc.Fct == 2) and abs( vtNFacApproxY:getY()) >= 0.707 ) or ( Proc.Fct == 4 and Proc.Topology == 'Groove')) then nFacInd, vtN, ptC = nFacApproxY, vtNFacApproxY, ptCFacApproxY local tvtNx = {} tvtNx[2] = vtN local ptPs = ptC dFacElev = BL.GetFaceElevation( Proc, nFacInd, b3Solid) dCollSic = BL.CalcCollisionSafety( tvtNx[2]) local dMachDepth = dFacElev + dCollSic local frFacRec, dFacDim1, dFacDim2 = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) -- limito il diametro utensile massimo a 201 per queste lavorazioni dToolTargetDiam = min( BD.MAXDIAM_POCK_CORNER, 201) -- se è 4 facce devo capire quale è il lato libero e settare dH e dV di conseguenza if Proc.Fct == 4 then local vAdj = {} local vtN2 for i = 1, Proc.Fct do -- recupero le adiacenze del loop esterno local vFacAdj = EgtSurfTmFacetAdjacencies( Proc.Id, i - 1)[1] -- le conto local nCount = 0 for j = 1, #vFacAdj do if vFacAdj[j] >= 0 then nCount = nCount + 1 end end vAdj[i] = nCount if vAdj[i] == Proc.Fct - 1 and i ~= nFacInd + 1 then dV = BL.GetFaceElevation( Proc, i - 1, b3Solid) vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, i - 1, GDB_ID.ROOT) end end local vtRes = vtN2 ^ vtN if AreSameOrOppositeVectorApprox( frFacRec:getVersX(), vtRes) then dH = dFacDim1 else dH = dFacDim2 end -- se la tasca ha dimensioni adeguate cerco di usare una fresa con raggio fino a metà altezza dToolMaxDiam = EgtIf( dH >= dToolTargetDiam and dV > 0.5 * dToolTargetDiam, dToolTargetDiam, min( dH, dV, dToolTargetDiam)) -- per le L a 3 facce, avendo due lati aperti per l'attacco, si considera un diametro utensile pari al doppio della dimensione minima; il "- 1" è un accorgimento per impedire bug derivanti da dimensione della tasca uguale a D\2 utensile elseif Proc.Fct == 3 and bIsL then dToolMaxDiam = min ( ( min( dFacDim1, dFacDim2) * 2) - 1, dToolTargetDiam) -- in tutti gli altri casi l'utensile dovrà essere grande al massimo come il lato più piccolo else dToolMaxDiam = dToolTargetDiam end local _, sPocketing = VerifyPocket( Proc, dToolMaxDiam, dFacElev, nil, sMyMchFind) bOk, sWarn2, sTuuidPk, dDiamTool, dDepth = MakePocket( Proc, nPartId, b3Solid, ptPs, tvtNx, nFacInd, sMyMchFind, nUseRoughTool, sPocketing, dMachDepth, nil, nil, bAllWithEndCap, nil, nPhase, nRawId, dCustomMaxElev) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end bTryWithBlades = false -- se ho antischeggia con fresa le inserisco if nChamfer < 2 and ( nQAntisplintResult == 2 or ( nQAntisplintResult == 3 and not bMadeASbyBld)) then local bOk, sWarn2 = ManageAntiSplintByMill( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, bMillDown, dDiamTool, nil, nil, nil, nil, b3Solid, dDepth, bOneShot, nFirstMachId) if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end -- se abilitato dal parametro Q inserisco pulitura spigoli o contorno con fresa più piccola local nContourSmallTool = EgtGetInfo( Proc.Id, Q_CONTOUR_SMALL_TOOL, 'i') or 0 if nContourSmallTool > 0 then local bOk, sWarn2 = MakeRoundCleanCornerOrContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiamTool, nContourSmallTool, bMillDown, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShotm) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end -- in tutti gli altri casi, a meno che non sia forzata sega a catena, lancio la MakeByPockets -- se non richiesto solo contorno, lavorazione singola o doppia contrapposta, fondo della tasca una faccia fittizia perpendicolare al lato lungo elseif not bForceChainsaw then local bOnlyContour = ( EgtGetInfo( Proc.Id, Q_ONLY_CONTOUR, 'i') or 0) > 0 -- richiesto solo contorno if bOnlyContour then if Proc.TopologyLongName == 'Groove-Through-RightAngles-Parallel-3' then -- direzione e faccia aggiunta del tunnel (la groove-3 passante è uno pseudotunnel) local _, _, dTunnelDepth, vtTunnelDirection, _, idAddedTunnelTmFace = BL.GetTunnelDimension( Proc, nPartId) -- si tiene il verso del tunnel dal lato Z positiva if vtTunnelDirection:getZ() < GEO.EPS_SMALL then vtTunnelDirection = -vtTunnelDirection EgtInvertSurf( idAddedTunnelTmFace) end -- estrazione del contorno da lavorare local idContourPath = EgtExtractSurfTmLoops( idAddedTunnelTmFace, nAddGrpId) EgtModifyCurveExtrusion( idContourPath, vtTunnelDirection, GDB_RT.GLOB) -- si eliminano i lati aperti BL.SetOpenSide( idContourPath, b3Solid) BL.ChangeOrOpenStart( idContourPath, 2) -- spessore codolo da lasciare local dDimStrip = EgtGetInfo( Proc.Id, Q_DIM_STRIP, 'd') or 0 -- lavorazione local bOkContour, sWarn2 = MakeContourByMill( Proc, idContourPath, vtTunnelDirection, dTunnelDepth, dDimStrip, nPhase) if bOkContour then return true, sWarn2 else return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end else local sErr2 = 'Error : Cannot use ' .. Q_ONLY_CONTOUR .. ' on this feature' return false, sErr2 end -- svuotatura else -- se 2 facce setto i parametri corretti per la MakeByPockets if bForceSideMill and Proc.Fct == 2 then bIs3Faces = false bOrthoFacesMaster = true bSetOpenBorders = true end nOk, sErr, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, dDiamTool, bDoubleSide, nPathInt, nSurfInt, bOneShot, bMillDown, nFirstMachId, bOrthoFaces = MakeByPockets( Proc, nPhase, nRawId, nPartId, nChamfer, dDepthCham, nAddGrpId, sMyMchFind, bIs3Faces, b3Solid, bOrthoFacesMaster, bMillDown, bSetOpenBorders, bIsU, bIsL) if nOk == -3 then bTryWithBlades = true elseif nOk == -2 then if not sMchFind then sMchFind = sMchFindBackUp end sPocketing = ML.FindPocketing( sMchFind, dDiam, nil, nil, not bMillDown, bMillDown) if not sPocketing then local sErr2 = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr2) return false, sErr2 end bTryWithBlades = false sWarn = sErr elseif nOk < 0 then return false, sErr elseif nOk > 0 then bTryWithBlades = false sWarn = sErr -- se ho antischeggia con fresa le inserisco local nFacIndOri, dFacElevOri = BL.GetFaceWithMostAdj( Proc, nPartId) if nChamfer < 2 and ( nQAntisplintResult == 2 or ( nQAntisplintResult == 3 and not bMadeASbyBld)) then local bOk, sWarn2 = ManageAntiSplintByMill( Proc, nPhase, nRawId, nPartId, b3Raw, nFacIndOri, nAddGrpId, bMillDown, dDiamTool, nil, nil, nil, nil, b3Solid, dFacElevOri, bOneShot, nFirstMachId) if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end -- se abilitato dal parametro Q inserisco pulitura spigoli o contorno con fresa più piccola local nContourSmallTool = EgtGetInfo( Proc.Id, Q_CONTOUR_SMALL_TOOL, 'i') or 0 if nContourSmallTool > 0 then local bOk, sWarn2 = MakeRoundCleanCornerOrContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiamTool, nContourSmallTool, bMillDown, bDoubleSide, vtOrtho, nPathInt, nSurfInt, b3Solid, dDepth, bOneShotm) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end end end bOk = true end end -- 03/09/2020 da conferma di Fabio Squaratti: Per ora solo sulla feature 016: -- se ha fallito la fresatura (qua sopra) allora di defalut ( anche se il flag Q della lama è disattivato) prima provo la lama if Proc.Prc == 16 then bForceUseBlade = true end -- Se la svuotatura precedente non è stata fatta e smusso non è esclusivo, provo con le lame if bTryWithBlades and nChamfer < 2 then -- anche su macchine con testa da sotto, la sega a catena è solo da sopra if vtN:getZ() < BD.NZ_MINA and BD.DOWN_HEAD and nFacInd2 then ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd2, GDB_ID.ROOT) nFacInd, nFacInd2 = nFacInd2, nFacInd dFacElev, dFacElev2 = dFacElev2, dFacElev bUseOtherFace = true rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) end -- eseguo bOk, sWarn, sStat = MakeByChainOrSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV, dFacElev, bForceUseBlade, dDimMin, dDimMax, dDepth, vtOrtho, nLundIdFace, bOrthoFaces, nBottomFace, nChamfer, nAddGrpId, b3Solid, dDepthCham, nSurfInt) if not bOk and sStat == 'MNF' then _, sPocketing = VerifyPocket( Proc, dDiam, dFacElev + dCollSic, nil, sMchFind) if sPocketing then sWarn = '' else local sErr2 = 'Error : '..sMchFind..' not found in library' EgtOutLog( sErr2) return false, sErr2 end else -- se abilitato dal parametro Q inserisco pulitura spigoli o contorno con fresa più piccola local nContourSmallTool = EgtGetInfo( Proc.Id, Q_CONTOUR_SMALL_TOOL, 'i') or 0 if nContourSmallTool > 0 then local bOk, sWarn2 bOk, sWarn2 = MakeRoundCleanCornerOrContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, 100, nContourSmallTool, bMillDown) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end return bOk, sWarn end -- altrimenti verifico se ho già svuotato dal fianco, se si esco else -- se non ho annullato la/le svuotatura/e dal fianco if nOk ~= -2 then return bOk, sWarn end end end end -- SVUOTATURA OK else -- se devo inserire il chamfer if ( ( Proc.Fct == 3 and bIsU) or (Proc.Fct == 2 and bIsL)) and nChamfer > 0 then -- ottengo le dimensioni dello pseudotunnel local _, _, _, vtOrtho, _, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) local nOk, sErr = MakeChamfer( Proc, true, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end end end -- se richiesti antischeggia con lama su U trasversale e smusso non esclusivo -- rimane da gestire: se da eseguire con fresa o se richiesto lama ma impossibile utilizzarla, si utilizza fresa -- 2021.04.27 esegue antischeggia di lama se forma U o L con feature passante in Y o Z -- 2021.07.16 Per poter eseguire antischeggia di lama su feature che non sono passanti da faccia a faccia -- ma che sono su un angolo (coinvolgono 2 facce contigue) è stato modificato il confronto in: -- esegue antischeggia di lama se forma U o L con feature passante in Y o Z, oppure se feature a furma U e con 3 facce oppore a forma a L e con 2 facce -- non fa mai antischeggia di lama se la faccia è rivolta verso il basso, a meno che ci sia una testa sotto local bMadeASbyBld = false local bPassThrou = ( Proc.Box:getDimY() > b3Raw:getDimY() - 1 or Proc.Box:getDimZ() > b3Raw:getDimZ() - 1) local bPassEdge = ((( bIsU and Proc.Fct == 3) or ( bIsL and Proc.Fct == 2)) and bSinglePart and Proc.Box:getDimX() < 0.9 * b3Raw:getDimX()) local nFacIndOri = BL.GetFaceWithMostAdj( Proc, nPartId) local vtNOri = EgtSurfTmFacetNormVersor( Proc.Id, nFacIndOri, GDB_ID.ROOT) if nChamfer < 2 and ( nQAntisplintResult == 1 or nQAntisplintResult == 3) and (( bIsU or bIsL) and ( bPassThrou or bPassEdge)) and ( vtNOri:getZ() > -0.087 or BD.DOWN_HEAD or BD.TURN) then local bOk local bSawDown = ( bMillDown and not bMillUp) bMadeASbyBld, bOk, sWarn = ManageAntiSplintBySaw( Proc, b3Raw, b3Solid, bIsU, vtNOri, nFacIndOri, sWarn, bSawDown) if not bOk then return false, sWarn end end if nChamfer < 2 and ( nQAntisplintResult == 2 or ( nQAntisplintResult == 3 and not bMadeASbyBld)) then local bOk, sWarn2 = ManageAntiSplintByMill( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, bMillDown, dDiamTool, nil, nil, nil, nil, b3Solid) if not bOk then return false, sWarn2 end end -- dopo aver applicato gli antischeggia ricerco la svuotatura perchè l'ottimizzazione teste deve sapere quale è la lavorazione precedente _, sPocketing, dMyTMaxDepth, dMyTDiam = VerifyPocket( Proc, dDiam, dFacElev + dCollSic, dMaxTotLen, sMchFind, bMillUp, bMillDown) if not sPocketing and bMillUp then _, sPocketing, dMyTMaxDepth, dMyTDiam = VerifyPocket( Proc, dDiam, dFacElev + dCollSic, dMaxTotLen, sMchFind) bMillDown = false end -- se smusso non esclusivo if nChamfer < 2 then -- eseguo la svuotatura della faccia principale, mi restituisce id utensile, il diametro utensile per il foro opzionale local tvtNx = {} tvtNx[2] = vtN -- recupero alcuni parametri dell'utensile per decidere la distanza di sicurezza da utilizzare local dMaxToolCutDepth = 0 local dMaxToolMaterial = 0 local dToolThLength = 999 local dToolTotalLength = 0 local dToolThDiameter = 999 local dToolDiameter = 0 if EgtMdbSetCurrMachining( sPocketing) then local sTuuidPk = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuidPk) or '') then dMaxToolCutDepth = EgtTdbGetCurrToolMaxDepth() or dMaxToolCutDepth dMaxToolMaterial = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMaxToolMaterial dToolDiameter = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dToolDiameter dToolThLength = EgtTdbGetCurrToolThLength() or dToolThLength dToolThDiameter = EgtTdbGetCurrToolParam( MCH_TP.STEMDIAM) or dToolThDiameter dToolTotalLength = EgtTdbGetCurrToolParam( MCH_TP.TOTLEN) or dToolTotalLength end end local dMachiningDepth = 0 -- se il gambo è più largo dell'utensile verifico se la lunghezza del gambo è maggiore della distanza di sicurezza calcolata local dShankLength = dToolTotalLength - dToolThLength - dMaxToolCutDepth if ( dMaxToolCutDepth < dMaxToolMaterial - 10 * GEO.EPS_SMALL) and ( dShankLength > dCollSic + 10 * GEO.EPS_SMALL) then dMachiningDepth = dFacElev + BD.COLL_SIC else dMachiningDepth = dFacElev + dCollSic end local bOk, sWarn2 local dDistToNextPiece = BL.GetDistanceToNextPart( nRawId, nPhase) -- se avevo escluso l'attacco da fuori per non rovinare il pezzo successivo, riverifico con il diametro fresa effettivo if ( Proc.Fct == 4 and bTailOnSide) and ( dDistToNextPiece > dToolDiameter + 10 * GEO.EPS_SMALL) then sMchFind = EgtIf( bMillDown, 'OpenPocket_H2', 'OpenPocket') end bOk, sWarn2, sTuuidPk, dDiamTool = MakePocket( Proc, nPartId, b3Solid, ptC, tvtNx, nFacInd, sMchFind, nUseRoughTool, sPocketing, dMachiningDepth, nil, nil, bAllWithEndCap, bLapJointAngTrasm, nPhase, nRawId, dCustomMaxElev) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end -- se ho più di 3 facce e non di forma ad u oppure ho 3 facce e di forma ad u oppure groove a 2 facce -- e non sono stati inseriti antischeggia di lama -- controllo se c'è una faccia non ortogonale alla principale e la lavoro con una contornatura o svuotatura if ( ( Proc.Fct >= 3 and not bIsU) or ( Proc.Fct == 3 and bIsU) or ( Proc.Fct == 2)) and not bMadeASbyBld then -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] if not vAdj or #vAdj == 0 then local sErr = 'Error : main face without adjacencies' EgtOutLog( sErr) return false, sErr end -- Cerco una faccia adiacente alla principale con angolo > 90 local nFacAdj local tDimAndRef = {} tvtNx = {} tvtNx[1] = vtN tDimAndRef[1] = {dH, dV, rfFac} for i = 1, #vAdj do if vAdj[i] >= 0 then local bAdj, ptP1, ptP2, dAng = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) if bAdj and dAng < 0 and 180 + dAng > 90.1 then local rfFac2, dH2, dV2 = EgtSurfTmFacetMinAreaRectangle( Proc.Id, vAdj[i], GDB_ID.ROOT) _, tvtNx[2] = EgtSurfTmFacetCenter( Proc.Id, vAdj[i], GDB_ID.ROOT) tDimAndRef[2] = {dH2, dV2, rfFac2} local ptPs = ( ptP1 + ptP2) / 2 local bOk, sWarn2 bOk, sWarn2 = MachineByMill( Proc, nPhase, nRawId, nPartId, b3Solid, tvtNx, nFacInd, vAdj[i], ptPs, tDimAndRef, b3Raw, EgtIf( ( Proc.Fct == 3 and bIsU) or Proc.Fct == 2, 0, 2), nUseRoughTool, dAng, sPocketing, sTuuidPk, dFacElev) if not bOk then return bOk, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end end end end local nBoreOnCorner = EgtGetInfo( Proc.Id, Q_BORE_ON_CORNER, 'i') or 0 local nContourSmallTool = EgtGetInfo( Proc.Id, Q_CONTOUR_SMALL_TOOL, 'i') or 0 local nCleanCorner = EgtGetInfo( Proc.Id, Q_CLEAN_CORNER, 'i') or 0 -- se abilitato dal parametro Q inserisco foro sullo spigolo if nBoreOnCorner == 1 then local bOk, sWarn2 bOk, sWarn2 = MakeDrillOnCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiamTool) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end -- altrimenti se abilitato dal parametro Q inserisco percorso di pulitura elseif nBoreOnCorner == 2 then local bOk, sWarn2 bOk, sWarn2 = MakeSharpCleanCorner( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiamTool) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end -- altrimenti se abilitato dal parametro Q inserisco pulitura spigoli o contorno con fresa più piccola elseif nContourSmallTool > 0 then local bOk, sWarn2 bOk, sWarn2 = MakeRoundCleanCornerOrContour( Proc, nPhase, nRawId, nPartId, b3Raw, nFacInd, nAddGrpId, dDiamTool, nContourSmallTool, bMillDown) if not bOk then return false, sWarn2 end if sWarn2 then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sWarn2, sWarn2) end end -- se richiesta pulizia spigoli con fresa a V if nCleanCorner > 0 then local dThElev = dToolThDiameter / 2 * sqrt( vtN:getX() * vtN:getX() + vtN:getY() * vtN:getY()) local nNewProc = RemoveBottomFaceAndReorder( Proc, nAddGrpId, nFacInd, vtN) local vFace, dDepth = GetFacesData( nNewProc, dToolDiameter, dMaxToolMaterial, ( dToolDiameter/2), nAddGrpId, Proc.PartId, vtN) local bCleanCornerOk, sCleanCornerWarn = AddMillCorner( vFace, Proc, dToolDiameter, nAddGrpId, nNewProc, vtN) if not bCleanCornerOk then return false, sCleanCornerWarn end if sCleanCornerWarn then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sCleanCornerWarn, sCleanCornerWarn) end end end end end -- eventuale segnalazione ingombro di testa o coda UpdateEncumbrance( Proc, nRawId, b3Raw, b3Solid) end return true, sWarn, bPrevBhSideMill end --------------------------------------------------------------------- local function MakeLongMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead) -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- ottengo la distanza tra la fine del pezzo e il pezzo successivo local dDistToNextPiece = BL.GetDistanceToNextPart( nRawId, nPhase) -- verifico se applicare gestione speciale delle giunzioni (U diretta come asse X) local bAddEndCapLeftSide, bAddEndCapRightSide = false, false local dAddLen = 0 local bIsOpenU = ( Proc.Fct == 3 and not TestElleShape3( Proc)) if bIsOpenU then local ptC0, vtN0 = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) local ptC1, vtN1 = EgtSurfTmFacetCenter( Proc.Id, 1, GDB_ID.ROOT) local ptC2, vtN2 = EgtSurfTmFacetCenter( Proc.Id, 2, GDB_ID.ROOT) if abs( vtN0:getX()) < 0.0175 and abs( vtN1:getX()) < 0.0175 and abs( vtN2:getX()) < 0.0175 then local dWidth = 0 if vtN0 * vtN1 < -0.9998 then bAddEndCapLeftSide = true dWidth = ( ptC1 - ptC0) * vtN0 elseif vtN0 * vtN2 < -0.9998 then bAddEndCapLeftSide = true dWidth = ( ptC2 - ptC0) * vtN0 elseif vtN1 * vtN2 < -0.9998 then bAddEndCapLeftSide = true dWidth = ( ptC2 - ptC1) * vtN1 end dAddLen = min( dWidth, 100) / 2 end end -- verifico se applicare gestione speciale per tunnel local nSurfBottomId if Proc.Topology == 'Tunnel' or ( Proc.Topology == 'Groove' and Proc.IsThrough and Proc.Fct == 3) then bAddEndCapLeftSide = true bAddEndCapRightSide = true -- recupero centro e normale delle facce local vtN = {} for i = 1, Proc.Fct do vtN[i] = EgtSurfTmFacetNormVersor( Proc.Id, i - 1, GDB_ID.ROOT) end -- calcolo l'orientamento del tunnel local vtOrtho local bAdj = EgtSurfTmFacetsContact( Proc.Id, 0, 1) if bAdj then vtOrtho = vtN[1] ^ vtN[2] else if Proc.Fct >= 3 then vtOrtho = vtN[1] ^ vtN[3] else local sErr = 'Error : disconnected tunnel' EgtOutLog( sErr) return false, sErr end end vtOrtho = EgtIf( abs( vtOrtho:getY()) > abs( vtOrtho:getZ()), -Y_AX(), -Z_AX()) local ptMaxBox = Proc.Box:getMax() -- per creare le superfici di cap nei tunnel serve aggiungere una faccia di fondo -- recupero il box della trave e lo ingrandisco di poco per essere sicuro di avere intersezione con il piano di fondo local b3SolidExtended = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) b3SolidExtended:expand( 100 * GEO.EPS_SMALL) -- superficie di fondo nSurfBottomId = EgtSurfTmPlaneInBBox( nAddGrpId, ptMaxBox, vtOrtho, b3SolidExtended, GDB_ID.ROOT) -- calcolo di quanto allargare le superfici if dAddLen == 0 then local dWidth = EgtIf( Proc.AffectedFaces.Front, Proc.Box:getDimZ(), Proc.Box:getDimY()) dAddLen = min( dWidth, 100) / 2 end end -- la divido in parti lungo X local vAddId = {} local bAllWithEndCap = bAddEndCapLeftSide or bAddEndCapRightSide local nPart = max( ceil( Proc.Box:getDimX() / BD.LONGCUT_MAXLEN + 10 * GEO.EPS_SMALL), 2) local dPartLen = Proc.Box:getDimX() / nPart local Xmin = Proc.Box:getMin():getX() -- trimesh per la creazione degli EndCap local AddIdCopy = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL -- aggiunta di eventuale fondo alla trimesh per creare correttamente le superfici EndCap if nSurfBottomId then EgtSurfTmAdd( AddIdCopy, nSurfBottomId) end for i = 1, nPart do local nCapIdLeftSide, nCapIdRightSide -- eseguo divisione local AddId = EgtCopyGlob( Proc.Id, nAddGrpId) or GDB_ID.NULL if i > 1 or bAddEndCapLeftSide then -- definizione del piano sinsitro local dAdd = EgtIf( i > 1, dAddLen, 0) local ptOn = Point3d( Xmin - dAdd + ( i - 1) * dPartLen, 0, 0) local vtN = -X_AX() -- se richiesto, creazione tappo sinistro if bAddEndCapLeftSide then local nFirstId, nPnt, nCrv, nSrf = EgtPlaneSurfTmInters( ptOn, vtN, AddIdCopy, nAddGrpId, GDB_RT.GLOB) if nPnt == 0 and nCrv == 1 and nSrf == 0 then EgtCloseCurveCompo( nFirstId) nCapIdLeftSide = EgtSurfTmByFlatContour( nAddGrpId, nFirstId) if not nCapIdLeftSide then bAllWithEndCap = false end end if nFirstId then for nId = nFirstId, nFirstId + nPnt + nCrv + nSrf - 1 do EgtErase( nId) end end end if i > 1 then -- taglio della superficie lato sinistro EgtCutSurfTmPlane( AddId, ptOn, vtN, true, GDB_RT.GLOB) end -- se esiste, aggiunta del tappo sinistro if nCapIdLeftSide then AddId = EgtSurfTmBySewing( nAddGrpId, { AddId, nCapIdLeftSide}) -- se prima spezzatura, allungamento per non lasciare archi if i == 1 then local b3Box = EgtGetBBoxGlob( AddId, GDB_BB.STANDARD) local dCoeffX = 1 + min( dAddLen, dDistToNextPiece) / b3Box:getDimX() EgtScale( AddId, Frame3d( b3Box:getMax()), dCoeffX, 1, 1, GDB_RT.GLOB) end end end if i < nPart then -- definizione del piano destro local dAdd = EgtIf( i < nPart, dAddLen, 0) local ptOn = Point3d( Xmin + dAdd + i * dPartLen, 0, 0) local vtN = X_AX() -- taglio della superficie lato destro EgtCutSurfTmPlane( AddId, ptOn, vtN, true, GDB_RT.GLOB) -- se richiesto, creazione tappo destro if bAddEndCapRightSide then local nFirstId, nPnt, nCrv, nSrf = EgtPlaneSurfTmInters( ptOn, vtN, AddIdCopy, nAddGrpId, GDB_RT.GLOB) if nPnt == 0 and nCrv == 1 and nSrf == 0 then EgtCloseCurveCompo( nFirstId) nCapIdRightSide = EgtSurfTmByFlatContour( nAddGrpId, nFirstId) if not nCapIdRightSide then bAllWithEndCap = false end end if nFirstId then for nId = nFirstId, nFirstId + nPnt + nCrv + nSrf - 1 do EgtErase( nId) end end end end -- se esiste, aggiunta del tappo destro if nCapIdRightSide then AddId = EgtSurfTmBySewing( nAddGrpId, { AddId, nCapIdRightSide}) end EgtSetName( AddId, 'AddPart_' .. tostring( Proc.Id) .. '_' .. tostring( i)) -- eseguo inserimento in modo da ordinare da X+ a X- table.insert( vAddId, 1, AddId) end EgtErase( AddIdCopy) -- applico le lavorazioni sulle diverse parti local sWarn local bPrevBhSideMill for i = 1, #vAddId do local b3Box = EgtGetBBoxGlob( vAddId[i], GDB_BB.STANDARD) local nFct = EgtSurfTmFacetCount( vAddId[i]) local AddProc = { Id = vAddId[i], Grp = Proc.Grp, Prc = Proc.Prc, Box = b3Box, TotBox = Proc.Box, Fct = nFct, Flg = Proc.Flg, PartId = Proc.PartId, TaskId = Proc.TaskId, FeatureId = Proc.FeatureId, IsSplittedLapJoint = true, AffectedFaces = Proc.AffectedFaces, OkFromBottom = Proc.OkFromBottom} Topology.Classify( AddProc, b3Raw) -- con specifiche topologie si lavora la curva e si forza il lato aperto dove finisce la lavorazione precedente if i > 1 and ( ( Proc.Topology == 'Groove' and Proc.IsThrough and Proc.Fct == 3 and Proc.AffectedFaces.Left and Proc.AffectedFaces.Right) or ( Proc.Topology == 'Groove' and Proc.Fct == 4 and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right)) or Proc.Topology == 'Pocket') then local nFacInd = BL.GetFaceWithMostAdj( AddProc, nPartId) if type( nFacInd) == "number" and nFacInd >= 0 then local nLoopId, nLoopCnt = EgtExtractSurfTmFacetLoops( vAddId[i], nFacInd, nAddGrpId) if nLoopId and nLoopCnt == 1 then local nEdgeId = BL.GetEdgeToMachineFromVector( vAddId[i], nFacInd, -X_AX()) EgtSetInfo( nLoopId, 'OPEN', nEdgeId) AddProc.LoopIdFacInd = nLoopId end end end -- lasciare il false nel sesto parametro (perchè internamente viene verificato se diverso da nil) local bOk, sMyWarn bOk, sMyWarn, bPrevBhSideMill = MakeMoreFaces( AddProc, nPhase, nRawId, nPartId, dOvmHead, bAllWithEndCap, bPrevBhSideMill, bAllWithEndCap) if not sWarn or #sWarn == 0 then sWarn = sMyWarn end if not bOk then return bOk, sWarn end end return true, sWarn end --------------------------------------------------------------------- local function TestTwoFacesDownHead( Proc) -- test valido solo per due facce if Proc.Fct ~= 2 then return false end local bDownHeadBlade = false local bDownHeadMill = false -- verifico se da lavorare con testa da sotto if BD.DOWN_HEAD then local vtNm = ( Proc.Face[1].VtN + Proc.Face[2].VtN) vtNm:normalize() bDownHeadMill = ( vtNm:getZ() < -0.5) -- recupero il massimo materiale della lama sopra local sCutting = ML.FindCutting( 'HeadSide', true, false) if not sCutting then local sErr = 'Error : cutting not found in library' EgtOutLog( sErr) return false, sErr end local dTopBladeMaxDepth = 0 if EgtMdbSetCurrMachining( sCutting) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dTopBladeMaxDepth = EgtTdbGetCurrToolMaxDepth() or dTopBladeMaxDepth end end -- recupero le caratteristiche della feature e delle facce local vtRes = Proc.Face[1].VtN ^ Proc.Face[2].VtN Proc.IsTopDownRabbet = Proc.AffectedFaces.Top and abs( vtRes:getZ()) > 10 * GEO.EPS_SMALL for i = 1, Proc.Fct do Proc.Face[i].IsTooDownwardForTopBlade = Proc.Face[i].VtN:getZ() < ( BD.CUT_VZ_MIN or -0.484) - 10 * GEO.EPS_SMALL Proc.Face[i].IsTooWideForTopBlade = Proc.Face[i].WidthTrimmed > dTopBladeMaxDepth end -- serve la lama sotto se c'è almeno una faccia troppo inclinata verso il basso e non è un rabbet stretto lavorabile dal lato if not ( Proc.Face[1].IsTooDownwardForTopBlade or Proc.Face[2].IsTooDownwardForTopBlade) then bDownHeadBlade = false else for i = 1, Proc.Fct do if Proc.Face[i].IsTooDownwardForTopBlade and ( not Proc.IsTopDownRabbet or Proc.Face[i].IsTooWideForTopBlade) then bDownHeadBlade = true break end end end end return bDownHeadBlade, bDownHeadMill end --------------------------------------------------------------------- local function MakeStaircaseStep( Proc, nRawId, b3Raw, nPartId) local sWarn -- box della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then local sErr = 'Error : part box not found' EgtOutLog( sErr) return false, sErr end -- angolo tra le facce local _, _, _, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT) -- l'angolo tra le facce deve essere compreso tra 80 e 95 deg if ( dAng > -85 + 10 * GEO.EPS_ANG_SMALL) or ( dAng < -100 - 10 * GEO.EPS_ANG_SMALL) then return false end -- normali delle facce local vtNRiser = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT) local vtNTread = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT) -- la faccia 0 è l'alzata (faccia più verticale), la 1 la pedata; se così non è le scambio local nFacetRiser, nFacetTread = 0, 1 if abs( vtNRiser:getZ()) > abs( vtNTread:getZ()) then EgtSurfTmSwapFacets( Proc.Id, 0, 1) Proc.Face = BL.GetFacetsInfo( Proc, b3Raw) vtNRiser, vtNTread = vtNTread, vtNRiser end -- riferimenti e dimensioni delle facce local rfFacRiser, dHRiser, dVRiser = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacetRiser, GDB_ID.ROOT) local rfFacTread, dHTread, dVTread = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacetTread, GDB_ID.ROOT) -- recupero la fresatura -- verifico se fresatura da sopra local bIsMillingUpward = ( vtNTread:getZ() >= BD.NZ_MINA) -- fresatura local sMilling = ML.FindMilling( 'BirdsMouth', nil, nil, nil, nil, bIsMillingUpward, not bIsMillingUpward) if not sMilling then local sErr = 'Error : BirdsMouth not found in library' EgtOutLog( sErr) return false, sErr end -- dati utensile local dMillDiam = 50 local dMillMaxMat = 0 local dMillRotationSpeed = 0 if EgtMdbSetCurrMachining( sMilling) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dMillDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dMillDiam dMillMaxMat = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or dMillMaxMat dMillRotationSpeed = EgtMdbGetCurrMachiningParam( MCH_MP.SPEED) or dMillRotationSpeed end end -- recupero la lavorazione con lama -- verifico se uso lama da sotto local bCutDown = ( BD.DOWN_HEAD and rfFacTread:getVersZ():getZ() < - 0.5) -- lavorazione con lama local sCutting = ML.FindCutting( 'HeadSide', not bCutDown, bCutDown) -- dati utensile local dSawMaxDepth = 0 local dSawDiam = 400 local dSawRotationSpeed = 0 local dSawThick = 5 if sCutting then if EgtMdbSetCurrMachining( sCutting) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawMaxDepth = EgtTdbGetCurrToolMaxDepth() or dSawMaxDepth dSawRotationSpeed = EgtTdbGetCurrToolParam( MCH_MP.SPEED) or dSawRotationSpeed dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick end end end -- calcolo riduzione profondità lama in caso di angolo inferiore a 90deg local dCutExtraSaw = 0 if dAng < -91 and dAng > -179 then dCutExtraSaw = - dSawThick / tan( 180 + dAng) end -- eventuali smussi -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- verifiche per smusso local nChamfer, dDepthCham, sErrCham = EvaluateQParam( Proc) -- lavorazione smussi if nChamfer > 0 then local _, _, _, vtOrtho, _, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) local nOk, sErr = MakeChamfer( Proc, true, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end if sErr then if not sWarn then sWarn = '' end sWarn = EgtIf( #sWarn > 0, sWarn .. '\n' .. sErr, sErr) end end -- fresatura della pedata per fare spazio alla lama local dMillingDepth = dVTread - dSawMaxDepth + 10 -- divido in passate orizzontali local nMillHorizontalSteps = ceil( ( dMillingDepth - 100 * GEO.EPS_SMALL) / ( dMillDiam * 0.6)) local dMillHorizontalStep = 0 if nMillHorizontalSteps > 1 then dMillHorizontalStep = ( dMillingDepth - dMillDiam * 0.6) / ( nMillHorizontalSteps - 1) end for i = nMillHorizontalSteps, 1, -1 do -- inserisco la lavorazione local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacetTread}}) -- imposto uso faccia local nFaceUse = BL.GetNearestOrthoOpposite( vtNTread) EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto lato di lavoro e eventuale inversione local bInvert = dMillRotationSpeed < 0 local nWorkSide = MCH_MILL_WS.LEFT if bInvert then nWorkSide = MCH_MILL_WS.RIGHT end EgtSetMachiningParam( MCH_MP.WORKSIDE, nWorkSide) EgtSetMachiningParam( MCH_MP.INVERT, bInvert) -- imposto posizione braccio porta testa if vtNTread:getY() < GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- imposto attacchi e allungamenti if nFacetTread then EgtSetMachiningParam( MCH_MP.STARTADDLEN, dMillDiam/2 + 10) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dMillDiam/2 + 10) EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LI.LINEAR) EgtSetMachiningParam( MCH_MP.LITANG, 0) EgtSetMachiningParam( MCH_MP.LOTANG, 0) EgtSetMachiningParam( MCH_MP.LIPERP, 0) EgtSetMachiningParam( MCH_MP.LOPERP, 0) end -- imposto eventuale offset EgtSetMachiningParam( MCH_MP.OFFSR, dVTread - dMillingDepth + ( i - 1) * dMillHorizontalStep) -- se step verticale non presente, lo setto local dMillVerticalStep = EgtGetMachiningParam( MCH_MP.STEP, 'd') if not dMillVerticalStep or dMillVerticalStep <= 10 * GEO.EPS_SMALL then dMillVerticalStep = 0.25 * dMillDiam end EgtSetMachiningParam( MCH_MP.STEP, dMillVerticalStep) -- dichiaro non si generano sfridi per VMill local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VMRS', 0) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr else local _, sWarn = EgtGetMachMgrWarning( 0) if EgtIsMachiningEmpty() then EgtSetOperationMode( nMchFId, false) return false, sWarn end end -- eventuale segnalazione ingombro di testa o coda UpdateEncumbrance( Proc, nRawId, b3Raw, b3Solid) end -- taglio di lama della pedata -- calcolo faceuse local nFaceUseTread = EgtIf( vtNRiser * Z_AX() > -GEO.EPS_SMALL, MCH_MILL_FU.ORTHO_DOWN, MCH_MILL_FU.ORTHO_TOP) -- lavorazioni della faccia for i = 2, 1, -1 do local dCutRadialOffsetTread = - dSawMaxDepth / 2 * ( i - 1) -- componente limite del vettore Z per lama downUp; impostata a -2 per non farla mai rientrare in quel caso local dVzLimDwnUp = -2 local bOkSawTread, sErr = Fbs.MakeOne( Proc.Id, nFacetTread, sCutting, dSawDiam, nFaceUseTread, dVzLimDwnUp, dCutRadialOffsetTread + dCutExtraSaw, 0, 0, 0, 0, nil, b3Raw) if not bOkSawTread then return false, sErr end end -- taglio di lama dell'alzata -- calcolo faceuse local nFaceUseRiser = EgtIf( vtNRiser * Z_AX() > -GEO.EPS_SMALL, MCH_MILL_FU.ORTHO_DOWN, MCH_MILL_FU.ORTHO_TOP) -- lavorazioni della faccia for i = 2, 1, -1 do local dCutRadialOffsetRiser = - dVRiser / 2 * ( i - 1) -- componente limite del vettore Z per lama downUp; impostata a -2 per non farla mai rientrare in quel caso local dVzLimDwnUp = -2 local bOkSawRiser, sErr = Fbs.MakeOne( Proc.Id, nFacetRiser, sCutting, dSawDiam, nFaceUseRiser, dVzLimDwnUp, dCutRadialOffsetRiser + dCutExtraSaw, 0, 0, 0, 0, nil, b3Raw) if not bOkSawRiser then return false, sErr end end return true, sWarn end --------------------------------------------------------------------- -- Applicazione della lavorazione --------------------------------------------------------------------- function ProcessLapJoint.Make( Proc, nPhase, nRawId, nPartId, dOvmHead) -- inizializzazione costanti if not BD.C_SIMM_ENC then BD.C_SIMM_ENC = EgtIf( BD.C_SIMM, 180, 90) end -- setto a nil la variabile smussi bMadeChamfer = nil -- limiti di fresatura semplice local MAX_MILL_LIN = 80 -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero l'ingombro della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not b3Solid then local sErr = 'Error : part box not found' EgtOutLog( sErr) return false, sErr end -- in base al tipo di feature attribuisco il significato dei parametri Q AssignQIdent( Proc) -- se non forzate frese, uso la lama local bUseBlade = EgtIf( Proc.Prc == 90 or Proc.bForceMill, false, EgtGetInfo( Proc.Id, Q_USE_ROUGH_TOOL, 'i') ~= 1 and EgtGetInfo( Proc.Id, Q_USE_MILL, 'i') ~= 1) local nForceUseBladeOnNotContinueFace -- se ho attivo la lama e ho la feature 30, verifico i parametri Q propri della feature if bUseBlade then if Proc.Prc == 30 or Proc.Prc == 20 then local nBladeAntisplint = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') or 0 local nUseRoughToolOnSide = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 if nUseRoughToolOnSide == 4 and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) then nUseRoughToolOnSide = 0 end nForceUseBladeOnNotContinueFace = EgtGetInfo( Proc.Id, Q_BLADE_ON_ALONG_FACE, 'i') or 0 -- se antischeggia di fresa o abilitato sgrossatore di fianco if nBladeAntisplint == 2 or nUseRoughToolOnSide > 0 then bUseBlade = false end -- se ho attivo la lama e ho la feature 32, verifico i parametri Q propri della feature elseif Proc.Prc == 32 then local nBladeAntisplint = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') or 0 local nUseRoughToolOnSide = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 -- se antischeggia di fresa o abilitato sgrossatore di fianco if nBladeAntisplint == 2 or nUseRoughToolOnSide == 1 then bUseBlade = false end -- se ho attivo la lama e ho la feature 34, verifico i parametri Q propri della feature elseif Proc.Prc == 34 then local nBladeAntisplint = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') or 0 -- se antischeggia di fresa o abilitato sgrossatore di fianco if nBladeAntisplint == 2 then bUseBlade = false end end end -- se lunghezza richiede spezzatura if ( Proc.Box:getDimX() > BD.LONGCUT_MAXLEN) or ( Proc.Box:getDimX() > 0.7 * b3Solid:getDimX() and ( Proc.DistanceToNextPart > 1000 or Proc.Box:getDimX() > BD.LONGCUT_ENDLEN)) or ( ( nForceUseBladeOnNotContinueFace and nForceUseBladeOnNotContinueFace > 0) and ( Proc.Box:getDimX() > ( BD.LEN_SHORT_PART or 1000))) then local bOnlyContour = ( EgtGetInfo( Proc.Id, Q_ONLY_CONTOUR, 'i') or 0) > 0 if bOnlyContour then local sErr2 = 'Error : Cannot use ' .. Q_ONLY_CONTOUR .. ' on long features' return false, sErr2 end -- una faccia if Proc.Fct == 1 then if bUseBlade then if nForceUseBladeOnNotContinueFace and nForceUseBladeOnNotContinueFace > 0 then return LongCut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nForceUseBladeOnNotContinueFace) else return LongCut.Make( Proc, nPhase, nRawId, nPartId) end else return LongCut.Make( Proc, nPhase, nRawId, nPartId) end -- due facce elseif Proc.Fct == 2 then -- verifico se da lavorare con testa da sotto local bDownHeadBlade = TestTwoFacesDownHead( Proc) -- dati delle facce local b3Fac1 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 0, GDB_BB.STANDARD) local b3Fac2 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 1, GDB_BB.STANDARD) local vtN1 = EgtSurfTmFacetNormVersor( Proc.Id, 0, GDB_ID.ROOT) local vtN2 = EgtSurfTmFacetNormVersor( Proc.Id, 1, GDB_ID.ROOT) -- determino se due facce lunghe oppure una lunga e l'altra terminale if abs( b3Fac1:getDimX() - b3Fac2:getDimX()) < 50 and abs( b3Fac1:getCenter():getX() - b3Fac2:getCenter():getX()) < 50 and abs( vtN1:getX()) < GEO.EPS_SMALL and abs( vtN2:getX()) < GEO.EPS_SMALL then -- leggo i parametri Q per utilizzare la fresa di fianco e/o lama local nUseSideTool = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 local bUseBlade = EgtGetInfo( Proc.Id, Q_ANTISPLINT_TYPE, 'i') == 1 -- forzatura lavorazione discorde in base a parametro Q su feature local nQ14Param = EgtGetInfo( Proc.Id, Q_CONVENTIONAL_MILLING, 'd') or 0 local bOk, sMyWarn, _, AddedIds = Long2Cut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nUseSideTool, nQ14Param) -- se non sono riuscito a farlo di lama, riprovo con la fresa if not bOk and bUseBlade then bUseBlade = false return Long2Cut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nUseSideTool) else return bOk, sMyWarn, nil, AddedIds end -- prima faccia terminale elseif b3Fac1:getDimX() < 1 and abs( vtN2:getX()) < GEO.EPS_SMALL then -- la faccia 0 deve essere quella lunga EgtSurfTmSwapFacets( Proc.Id, 0, 1) Proc.Face = BL.GetFacetsInfo( Proc, b3Raw) if bUseBlade then if nForceUseBladeOnNotContinueFace and nForceUseBladeOnNotContinueFace > 0 then return LongCut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nForceUseBladeOnNotContinueFace) else return Fbs.MakeTwo( Proc, nPhase, nRawId, nPartId, dOvmHead, 'HeadSide' .. EgtIf( bDownHeadBlade, '_H2', ''), true, bDownHeadBlade) end else return LongCut.Make( Proc, nPhase, nRawId, nPartId) end -- seconda faccia terminale elseif b3Fac2:getDimX() < 1 and abs( vtN1:getX()) < GEO.EPS_SMALL then if bUseBlade then if nForceUseBladeOnNotContinueFace and nForceUseBladeOnNotContinueFace > 0 then return LongCut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nForceUseBladeOnNotContinueFace) else return Fbs.MakeTwo( Proc, nPhase, nRawId, nPartId, dOvmHead, 'HeadSide' .. EgtIf( bDownHeadBlade, '_H2', ''), true, bDownHeadBlade) end else return LongCut.Make( Proc, nPhase, nRawId, nPartId) end -- altrimenti else if bUseBlade and ( abs( vtN1:getX()) > 0.5 or abs( vtN2:getX()) > 0.5) then return Fbs.MakeTwo( Proc, nPhase, nRawId, nPartId, dOvmHead, 'HeadSide' .. EgtIf( bDownHeadBlade, '_H2', ''), true, bDownHeadBlade) else return MakeLongMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead) end end -- tre facce elseif Proc.Fct == 3 then -- determino se due facce lunghe oppure una lunga e l'altra terminale local b3Fac1 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 0, GDB_BB.STANDARD) local b3Fac2 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 1, GDB_BB.STANDARD) local b3Fac3 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 2, GDB_BB.STANDARD) local bApplyBladeOnLongNotContinueFace if b3Fac1:getDimX() < 1 and b3Fac3:getDimX() < 1 then -- la faccia 0 deve essere quella lunga EgtSurfTmSwapFacets( Proc.Id, 0, 1) Proc.Face = BL.GetFacetsInfo( Proc, b3Raw) bApplyBladeOnLongNotContinueFace = true elseif b3Fac1:getDimX() < 1 and b3Fac2:getDimX() < 1 then -- la faccia 0 deve essere quella lunga EgtSurfTmSwapFacets( Proc.Id, 0, 2) Proc.Face = BL.GetFacetsInfo( Proc, b3Raw) bApplyBladeOnLongNotContinueFace = true elseif b3Fac2:getDimX() < 1 and b3Fac3:getDimX() < 1 then bApplyBladeOnLongNotContinueFace = true end if bApplyBladeOnLongNotContinueFace and bUseBlade and nForceUseBladeOnNotContinueFace and nForceUseBladeOnNotContinueFace > 0 then return LongCut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nForceUseBladeOnNotContinueFace) else return MakeLongMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead) end -- più facce else return MakeLongMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead) end -- altrimenti lavorazione unica else -- una faccia if Proc.Fct == 1 then -- se piccola, con fresa if not bUseBlade and ( Proc.Box:getDimX() < MAX_MILL_LIN and ( Proc.Box:getDimZ() < MAX_MILL_LIN or Proc.Box:getDimY() < MAX_MILL_LIN)) then return MakeOneFaceByMill( Proc, nPhase, nRawId, nPartId) -- se è una spianatura a una faccia richiamo la LongCut elseif Proc.Prc == 90 then return LongCut.Make( Proc, nPhase, nRawId, nPartId) -- se arriva da una cut si applica una svuotatura elseif Proc.Prc == 10 then local dDiam = min( Proc.Face[1].Height, Proc.Face[1].Width) * 3 local bMillUp = ( BD.DOWN_HEAD and Proc.Face[1].VtN:getZ() > -0.259) local bMillDown = ( BD.DOWN_HEAD and Proc.Face[1].VtN:getZ() < 0.342) local sMchFindMaster = 'OpenPocket' local _, sPocketing = VerifyPocket( Proc, dDiam, nil, nil, sMchFindMaster, bMillUp, bMillDown) return Fbp.Make( Proc, Proc.Id, 0, sPocketing, nPartId, b3Solid) -- altrimenti, con lama else return Cut.Make( Proc, nPhase, nRawId, nPartId, dOvmHead) end -- due facce elseif Proc.Fct == 2 then -- se V passante e attiva Q per lavorazione speciale scala if EgtGetInfo( Proc.Id, Q_STAIRCASE, 'i') == 1 and Proc.Topology == 'Groove' and Proc.IsThrough == true then return MakeStaircaseStep( Proc, nRawId, b3Raw, nPartId) end -- se praticamente è lunga come la trave e sono due facce lunghe local b3Fac1 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 0, GDB_BB.STANDARD) local b3Fac2 = EgtSurfTmGetFacetBBoxGlob( Proc.Id, 1, GDB_BB.STANDARD) if Proc.Box:getDimX() > 0.8 * b3Solid:getDimX() and abs( b3Fac1:getDimX() - b3Fac2:getDimX()) < 50 and abs( b3Fac1:getCenter():getX() - b3Fac2:getCenter():getX()) < 50 then local nUseSideTool = EgtGetInfo( Proc.Id, Q_SIDE_ROUGH_TOOL, 'i') or 0 local bOk, sMyWarn = Long2Cut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nUseSideTool) -- se non sono riuscito a farlo di lama, riprovo con la fresa if not bOk and bUseBlade then bUseBlade = false return Long2Cut.Make( Proc, nPhase, nRawId, nPartId, bUseBlade, nUseSideTool) else return bOk, sMyWarn end -- altrimenti else -- verifico se da lavorare con testa da sotto local bDownHeadblade, bDownHeadMill = TestTwoFacesDownHead( Proc) -- determino l'angolo tra le facce local bAdj, _, _, dAng = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT) -- se con BH if VerifyBHSideMill( Proc, nil, nil, nil, nil, b3Raw) then return MakeMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead, true) -- se ortogonali e non forzata lama, con fresa elseif not bUseBlade then -- verifico se devo fare prima gli smussi -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- verifiche per smusso local nChamfer, dDepthCham, sErrCham = EvaluateQParam( Proc) -- se smusso da fare if nChamfer > 0 then local _, _, _, vtOrtho, _, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) local nOk, sErr = MakeChamfer( Proc, true, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end end -- se piccole if Proc.Box:getDimX() < MAX_MILL_LIN and ( Proc.Box:getDimZ() < MAX_MILL_LIN or Proc.Box:getDimY() < MAX_MILL_LIN) and bAdj and abs( dAng + 90) < 1 then return MakeTwoFacesByMill( Proc, nPhase, nRawId, nPartId, bDownHeadMill) else return MakeMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead, true) end -- altrimenti, con lama else -- verifico se devo fare prima gli smussi -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error : missing AddGroup' EgtOutLog( sErr) return false, sErr end -- verifiche per smusso local nChamfer, dDepthCham, sErrCham = EvaluateQParam( Proc) -- se smusso da fare if nChamfer > 0 then local _, _, _, vtOrtho, _, nSurfInt = BL.GetTunnelDimension( Proc, nPartId) local nOk, sErr = MakeChamfer( Proc, true, nAddGrpId, vtOrtho, b3Solid, nSurfInt, dDepthCham) if nOk < 0 then return false, sErr end end -- se smusso non esclusivo if nChamfer < 2 then return Fbs.MakeTwo( Proc, nPhase, nRawId, nPartId, dOvmHead, 'HeadSide' .. EgtIf( bDownHeadblade, '_H2', ''), true, bDownHeadblade or BD.TURN) end return true end end -- tre o più facce else return MakeMoreFaces( Proc, nPhase, nRawId, nPartId, dOvmHead, true) end end end --------------------------------------------------------------------- return ProcessLapJoint