-- FacesBySaw.lua by Egaltech s.r.l. 2024/01/07 -- Gestione taglio con lama di feature con una o due facce -- 2021/01/06 Cambiato limite per attacco Tg con lama e CalcLeadInOutGeom rinominata in CalcLeadInOutPerpGeom. -- 2021/02/03 In taglio lama si accettano anche due lati con deviazione minore di 20deg. -- 2021/02/09 In taglio lama con PF si preferisce testa in Y- quindi SCC di conseguenza. -- 2021/02/26 In taglio lama consento attacco anche da sotto (grazie a migliorie in MachKernel). -- 2021/03/22 Attacchi e uscite di tagli longitudinali da sotto con lama solo ortogonali. -- 2021/04/27 Migliorati controlli per attacchi e uscite Tg con lama. -- 2021/07/08 Modifiche in MakeOneFaceBySaw per gestione taglio con due segmenti. -- 2021/08/03 In MakeOneFaceBySaw mgliorata gestione tagli con normale verso il basso e da sopra. -- 2021/08/31 DS Aggiunta gestione nessun limite direzione da sotto per testa da sotto. -- 2021/11/26 DS Spostate qui MakeOneFaceBySaw (ora MakeOne), CalcLeadInOutPerpGeom e CalcLeadInOutTangGeom. -- 2022/04/12 DS Aggiunta gestione speciale cubetti con fresa da sotto. -- 2022/06/29 DS In MakeTwo modificato controllo facce dirette verso il basso. -- 2022/09/08 In MakeOne aggiunto argomento bForceInvert per poter forzare l'inversione del percorso. -- 2023/02/13 Migliorata la direzione di lavoro della lama in modo da essere tendenzialmente opposta all'avanzamento. -- 2023/04/20 Alcune modifiche per gestire tagli con faceuse parallelo. -- 2023/05/18 Imposto in ogni caso dVzLimDwnUp prima anche di bDownHead. -- 2023/06/14 Aggiunta MakeParallelOne e tolti parametri nForceWorkSide, nForceSCC da MakeOne. -- 2023/09/26 Piccola modifica per Turn su bInvert di MakeOne. -- 2023/10/24 In MakeOne migliorata gestione taglio con percorso bilinea. Aggiunta funzione GetNameSolidFaceIncludingLine. -- 2023/11/14 In MakeOne migliorato calcolo scelta soluzione per macchina TURN -- 2023/11/28 In MakeTwo raffinamento calcolo vtRef per casi dubbi. -- 2023/12/06 In CalcLeadInOutPerpGeom gestito caso in cui la geometria della feature esce dal grezzo. -- 2023/12/30 Modifiche in CalcLeadInOutPerpGeom e CalcLeadInOutTangGeom con uso di EgtCAvToolPosBox. -- 2024/01/07 Modifiche per OikosX (BD.TURN == 2). -- 2024/01/18 Gestita lama con aggregato con asse bloccato per massimizzare capacità di taglio verticale, se da sotto. -- Implementata GetBlockedAxis che gestisce gli assi bloccati per tutti i tipi di utensile. -- 2024/02/22 Migliorato calcolo area non pinzabile in testa HCING e coda TCING -- 2024/03/27 In MakeTwo rimossa gestione calcolo differente su ultima passata in caso di macchina FAST -- 2024/06/18 In MakeOne in caso di inversione del percorso, si scambia anche accorciamento start con end -- 2024/09/12 In MakeOne per settare il FaceUse si usa il versore nelle UserNotes -- Tabella per definizione modulo local FacesBySaw = {} -- Include require( 'EgtBase') local BL = require( 'BeamLib') local DC = require( 'DiceCut') EgtOutLog( ' FacesBySaw started', 1) -- Dati local BD = require( 'BeamData') local ML = require( 'MachiningLib') --------------------------------------------------------------------- function MakeParallelOne( nSurfId, nFacet, sCutting, dSawDiam, nFaceUse, dVzLimDwnUp, dCutExtra, dCutSic, dCutOffset, dAccStart, dAccEnd, sNotes, b3Raw, bForceInvert, sLeadInOutType, dActualElevation) EgtOutLog( 'FacesBySaw.MakeParallelOne', 3) -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( nSurfId, nFacet, GDB_ID.ROOT) -- accetto solo facce perpendicolari all'asse X della trave if not AreSameOrOppositeVectorApprox( vtN, X_AX()) then EgtOutLog( 'Error : MakeParallelOne only for faces perpendicular to XAxis') return false end -- l'uso della faccia deve consentire una scelta robusta del percorso if nFaceUse == MCH_MILL_FU.PARAL_LEFT or nFaceUse == MCH_MILL_FU.PARAL_RIGHT then EgtOutLog( 'Error : MakeParallelOne impossible with PARAL_LEFT or PARAL_RIGHT FaceUse') return false end -- distanza della faccia dall'estremo trave verso cui è rivolta local dDistX = EgtIf( vtN:getX() > 0, b3Raw:getMax():getX() - ptC:getX(), ptC:getX() - b3Raw:getMin():getX()) -- lunghezza attacco/uscita perpendicolari local dLiTang = 0 local dLiPerp = dDistX + dCutExtra + dCutSic local dLoTang = dLiTang local dLoPerp = dLiPerp local dLiCompLength = 0 local dLoCompLength = 0 -- lunghezza attacco/uscita tangenti local dLi2Tang = dSawDiam / 2 + dCutSic local dLi2Perp = 0 local dLo2Tang = dLi2Tang local dLo2Perp = dLi2Perp local dLi2CompLength = 0 local dLo2CompLength = 0 -- scelgo l'attacco più conveniente local bLioTang local Ktp = 1.1 if BD.KIOTP then Ktp = BD.KIOTP end if ( sLeadInOutType == 'PerpendicularOutraw') then bLioTang = false dLiCompLength = dActualElevation + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) dLoCompLength = dActualElevation + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) dLiTang = 1 dLoTang = 1 dLiPerp = 0 dLoPerp = 0 elseif ( sLeadInOutType ~= 'Perpendicular') and ( ( sLeadInOutType == 'Tangent') or ( Ktp * dLi2Tang < dLiPerp)) then bLioTang = true dLiTang, dLiPerp, dLoTang, dLoPerp = dLi2Tang, dLi2Perp, dLo2Tang, dLo2Perp if BD.TURN then local dMove = EgtIf( nFaceUse == MCH_MILL_FU.PARAL_DOWN or nFaceUse == MCH_MILL_FU.PARAL_TOP, b3Raw:getDimY(), b3Raw:getDimZ()) dLoTang = -( dLiTang - dAccStart - dAccEnd + dMove) dLoPerp = BD.COLL_SIC end end -- verifico se la lama ruota in senso antiorario if not EgtMdbSetCurrMachining( sCutting) then return false end local bIsSawCCW = ( EgtMdbGetCurrMachiningParam( MCH_MP.SPEED) < 0) local bInvert = bForceInvert -- se la lama ruota in senso antiorario inverto la direzione di lavorazione, per avere rotazione lama opposta a avanzamento if bInvert == nil then bInvert = ( not bIsSawCCW) if not BD.TURN then if bIsSawCCW then bInvert = (( nFaceUse == MCH_MILL_FU.PARAL_FRONT and vtN:getX() > 0) or ( nFaceUse == MCH_MILL_FU.PARAL_BACK and vtN:getX() < 0)) else bInvert = (( nFaceUse == MCH_MILL_FU.PARAL_FRONT and vtN:getX() < 0) or ( nFaceUse == MCH_MILL_FU.PARAL_BACK and vtN:getX() > 0)) end end end local nWorkSide = EgtIf( bInvert, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT) -- posizione braccio local nSCC = MCH_SCC.NONE if BD.TURN then nSCC = EgtIf( nFaceUse == MCH_MILL_FU.PARAL_DOWN or nFaceUse == MCH_MILL_FU.PARAL_TOP, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_ZP) else nSCC = EgtIf( vtN:getX() > 0, MCH_SCC.ADIR_XP, MCH_SCC.ADIR_XM) end -- inserisco la lavorazione di taglio local sName = 'Cut_' .. ( EgtGetName( nSurfId) or tostring( nSurfId)) .. '_' .. tostring( nFacet + 1) local nMchFId = EgtAddMachining( sName, sCutting) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sCutting EgtOutLog( sErr) return false, sErr end sName = EgtGetOperationName( nMchFId) -- aggiungo geometria EgtSetMachiningGeometry( {{ nSurfId, nFacet}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto posizione braccio porta testa EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- imposto inversione e lato correzione EgtSetMachiningParam( MCH_MP.INVERT, bInvert) EgtSetMachiningParam( MCH_MP.WORKSIDE, nWorkSide) -- affondamento aggiuntivo EgtSetMachiningParam( MCH_MP.OFFSR, -dCutExtra) -- offset longitudinale EgtSetMachiningParam( MCH_MP.OFFSL, EgtIf( bDownUp, -dCutOffset, dCutOffset)) -- imposto attacco/uscita EgtSetMachiningParam( MCH_MP.LITANG, dLiTang) EgtSetMachiningParam( MCH_MP.LIPERP, dLiPerp) EgtSetMachiningParam( MCH_MP.LICOMPLEN, dLiCompLength) if BD.TURN and bLioTang then EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.PERP_TG) end EgtSetMachiningParam( MCH_MP.LOTANG, dLoTang) EgtSetMachiningParam( MCH_MP.LOPERP, dLoPerp) EgtSetMachiningParam( MCH_MP.LOCOMPLEN, dLoCompLength) -- imposto allungamenti iniziale e finale EgtSetMachiningParam( MCH_MP.STARTADDLEN, -dAccStart) EgtSetMachiningParam( MCH_MP.ENDADDLEN, -dAccEnd) -- imposto angolo 3° asse rot local bDownHead = ( dVzLimDwnUp and dVzLimDwnUp < - 1.5) local vtTool if nFaceUse == MCH_MILL_FU.PARAL_FRONT then vtTool = Y_AX() elseif nFaceUse == MCH_MILL_FU.PARAL_BACK then vtTool = -Y_AX() elseif nFaceUse == MCH_MILL_FU.PARAL_DOWN then vtTool = Z_AX() else vtTool = -Z_AX() end local vtOut = EgtIf( vtN:getX() > 0, X_AX(), -X_AX()) EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sCutting, 'perpendicular', b3Raw, vtTool, vtOut)) local sAuxDir, sInitAngs = BL.GetAuxDir( sCutting, 'perpendicular', b3Raw, vtTool, vtOut) if sAuxDir then sNotes = EgtSetValInNotes( sNotes, 'VtAuxDir', sAuxDir) EgtSetMachiningParam( MCH_MP.INITANGS, sInitAngs) EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.STD) end -- eventuali note if ( sLeadInOutType == 'PerpendicularOutraw') then sNotes = EgtSetValInNotes( sNotes, 'OutRaw', 3) end if sNotes and #sNotes > 0 then EgtSetMachiningParam( MCH_MP.USERNOTES, sNotes) end -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end return true, sName, nMchFId end --------------------------------------------------------------------- local function GetNameSolidFaceIncludingLine( b3Solid, ptP1Comp, ptP2Comp) -- se aperto su faccia fronte if abs( b3Solid:getMin():getY() - ptP1Comp:getY()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMin():getY() - ptP2Comp:getY()) < 100 * GEO.EPS_SMALL then return true, 'Front' -- se aperto su faccia sopra elseif abs( b3Solid:getMax():getY() - ptP1Comp:getY()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMax():getY() - ptP2Comp:getY()) < 100 * GEO.EPS_SMALL then return true, 'Back' -- se aperto su faccia retro elseif abs( b3Solid:getMin():getZ() - ptP1Comp:getZ()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMin():getZ() - ptP2Comp:getZ()) < 100 * GEO.EPS_SMALL then return true, 'Bottom' -- se aperto su faccia sotto elseif abs( b3Solid:getMax():getZ() - ptP1Comp:getZ()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMax():getZ() - ptP2Comp:getZ()) < 100 * GEO.EPS_SMALL then return true, 'Top' -- se aperto su faccia sinistra elseif abs( b3Solid:getMin():getX() - ptP1Comp:getX()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMin():getX() - ptP2Comp:getX()) < 100 * GEO.EPS_SMALL then return true, 'Left' -- se aperto su faccia destra elseif abs( b3Solid:getMax():getX() - ptP1Comp:getX()) < 100 * GEO.EPS_SMALL and abs( b3Solid:getMax():getX() - ptP2Comp:getX()) < 100 * GEO.EPS_SMALL then return true, 'Right' end -- se non è sul bordo del solido return false end --------------------------------------------------------------------- local function AreSameOrOppositeDirApprox( vDir1, vDir2) if abs( abs( vDir1) - abs( vDir2)) < 10 * GEO.EPS_SMALL then return true else return false end end --------------------------------------------------------------------- local function GetEdgeToMachineFromVector( nSurfId, nFacet, vtOrthO) local _, EdgesEgt = EgtSurfTmGetFacetOutlineInfo( nSurfId, nFacet, GDB_ID.ROOT) for i = 1, #EdgesEgt do if AreOppositeVectorApprox( EdgesEgt[i].Norm, vtOrthO) then return ( i - 1) end end return nil end --------------------------------------------------------------------- function FacesBySaw.MakeOne( nSurfId, nFacet, sCutting, dSawDiam, Par5, dVzLimDwnUp, dCutExtra, dCutSic, dCutOffset, dAccStart, dAccEnd, sNotes, b3Raw, bForceInvert, bMaximizeVerticalDepth, bSpecialTangentLeadInOut, sLeadInOutType, Par5Alternative, dActualElevation, bForceClimbCut) -- se lama con asse parallelo alla faccia, passo alla apposita funzione if ( Par5 == MCH_MILL_FU.PARAL_DOWN or Par5 == MCH_MILL_FU.PARAL_TOP or Par5 == MCH_MILL_FU.PARAL_FRONT or Par5 == MCH_MILL_FU.PARAL_BACK or Par5 == MCH_MILL_FU.PARAL_LEFT or Par5 == MCH_MILL_FU.PARAL_RIGHT) then return MakeParallelOne( nSurfId, nFacet, sCutting, dSawDiam, Par5, dVzLimDwnUp, dCutExtra, dCutSic, dCutOffset, dAccStart, dAccEnd, sNotes, b3Raw, bForceInvert, sLeadInOutType, dActualElevation) end -- la lama ha asse perpendicolare alla faccia EgtOutLog( 'FacesBySaw.MakeOne', 3) -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( nSurfId, nFacet, GDB_ID.ROOT) -- risolvo parametro ambiguo local nOrthoOpposite local vtOrthO local nOrthoOppositeAlternative local vtOrthOAlternative if isVector3d( Par5) then nOrthoOpposite = BL.GetNearestOrthoOpposite( Par5, vtN) vtOrthO = Vector3d( Par5) else nOrthoOpposite = Par5 vtOrthO = BL.GetVersRef( Par5) end if Par5Alternative then if isVector3d( Par5Alternative) then nOrthoOppositeAlternative = BL.GetNearestOrthoOpposite( Par5Alternative, vtN) vtOrthOAlternative = Vector3d( Par5Alternative) else nOrthoOppositeAlternative = Par5Alternative vtOrthOAlternative = BL.GetVersRef( Par5Alternative) end end EgtOutLog( 'VtOrthO='..tostring( vtOrthO)..' FaceUse='..tostring( nOrthoOpposite), 3) -- verifico se testa da sotto oppure se lavorazione sotto con testa da sopra if not dVzLimDwnUp then dVzLimDwnUp = BL.GetNzLimDownUp( b3Raw, vtN, vtOrthO) end local bDownHead = ( dVzLimDwnUp and dVzLimDwnUp < - 1.5) local bDownUp = ( vtN:getZ() < dVzLimDwnUp) local ptP1, ptPm, ptP2, vtV1, vtV2, dLen, dWidth = EgtSurfTmFacetOppositeSide( nSurfId, nFacet, vtOrthO, GDB_ID.ROOT) if not dLen or dLen < 1.1 or not dWidth or dWidth < 1.1 then local sWarn = 'Face ' .. string.format( '%d,%d', nSurfId, nFacet) .. ' skipped : too small' EgtOutLog( sWarn, 1) return true, '' end vtV1 = - vtV1 -- verifico se la lama ruota in senso antiorario if not EgtMdbSetCurrMachining( sCutting) then return false end local bIsSawCCW = ( EgtMdbGetCurrMachiningParam( MCH_MP.SPEED) < 0) -- se settato nelle note lavorazione si lavora in discordanza EgtMdbSetCurrMachining( sCutting) local sMachiningNotes = EgtMdbGetCurrMachiningParam( MCH_MP.USERNOTES) or '' if ( EgtGetValInNotes( sMachiningNotes, 'PATHINVERT', 'd') or 0) == 1 then bIsSawCCW = not bIsSawCCW end local bInvert = bForceInvert -- l'inversione può essere comandata da rotazione lama (direzione concorde, legata anche a DownUp) oppure da direzione Z del percorso (si preferisce lavorare dal basso verso l'alto per limitare le corse) -- se c'è disaccordo tra rotazione e direzione si cambia il lato di lavoro, se possibile. Se ciò non è possbile comanda la direzione. Se percorso orizzontale comanda la rotazione. if bInvert == nil then if not BD.TURN or abs( ptP2:getY() - ptP1:getY()) < 250 then local bIsMachiningDownwards = ( ptP2:getZ() < ptP1:getZ() - 100 * GEO.EPS_SMALL) local bIsMachiningUpwards = ( ptP2:getZ() > ptP1:getZ() + 100 * GEO.EPS_SMALL) if ( bIsSawCCW ~= bDownUp) and ( bIsMachiningDownwards or not ( bIsMachiningDownwards or bIsMachiningUpwards) or bForceClimbCut) then bInvert = true elseif ( ( bIsSawCCW ~= bDownUp) ~= bIsMachiningDownwards) then if Par5Alternative then bInvert = true nOrthoOpposite = nOrthoOppositeAlternative vtOrthO = vtOrthOAlternative -- avendo riassegnato la direzione di lavoro, i dati della linea vanno ricalcolati ptP1, ptPm, ptP2, vtV1, vtV2, dLen, dWidth = EgtSurfTmFacetOppositeSide( nSurfId, nFacet, vtOrthO, GDB_ID.ROOT) if not dLen or dLen < 1.1 or not dWidth or dWidth < 1.1 then local sWarn = 'Face ' .. string.format( '%d,%d', nSurfId, nFacet) .. ' skipped : too small' EgtOutLog( sWarn, 1) return true, '' end vtV1 = - vtV1 elseif bIsMachiningDownwards or not bIsMachiningUpwards then bInvert = true else bInvert = false end else bInvert = false end else local vtTmp = ptP2 - ptP1 ; vtTmp:normalize() bInvert = ( ( vtOrthO:getX() > 0.1 and vtTmp:getX() < -0.1) or ( vtOrthO:getX() < -0.1 and vtTmp:getX() > 0.1)) end end if bInvert then ptP1, ptP2 = ptP2, ptP1 vtV1, vtV2 = vtV2, vtV1 -- se l'inversione è forzata dall'esterno, anche gli accorciamenti che arrivano dall'esterno si prendono per buoni if bForceInvert == nil then dAccStart, dAccEnd = dAccEnd, dAccStart end end local vtTg = ptP2 - ptP1 ; vtTg:normalize() local dAllStart = 0 local dAllEnd = 0 local bIsBiLinea = false local dCosAngleL1L2 = 0 local dDist1 = dist( ptP1, ptPm) local dDist2 = dist( ptP2, ptPm) -- verifico se la bilinea si trova sul bordo del solido, quindi è una geometria aperta local nIdSolid = EgtGetParent( EgtGetParent( nSurfId)) -- recupero ingombro del pezzo local Ls = EgtGetFirstNameInGroup( nIdSolid, 'Box') local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD) -- controllo se le linee sono sul bordo della trave, quindi aperte local bIsL1OnFace = GetNameSolidFaceIncludingLine( b3Solid, ptP1, ptPm) local bIsL2OnFace = GetNameSolidFaceIncludingLine( b3Solid, ptPm, ptP2) -- se bilinea, scarto la parte più allineata con la direzione ortogonale (se deviazione angolare oltre 20 deg o lunghezza minore di dSawDiam/2 * cos( 20/2)) ma maggiore di un minimo if ( ( ptPm - ptP1) - ( ptPm - ptP1) * vtTg * vtTg):len() > 100 * GEO.EPS_SMALL then bIsBiLinea = true local vtTg1 = ptPm - ptP1 ; vtTg1:normalize() local vtTg2 = ptP2 - ptPm ; vtTg2:normalize() local dCosMax = 0.966 -- cos( 15°) local dLenMin = 30 local dLenMax = max( 0.5 * dSawDiam * 0.17365 + 1, 2 * dLenMin) dCosAngleL1L2 = vtTg1 * vtTg2 if dCosAngleL1L2 < dCosMax then local dOrtho1 = abs( vtTg1 * vtOrthO) local dOrtho2 = abs( vtTg2 * vtOrthO) if dOrtho1 < dOrtho2 or ( abs( dOrtho1 - dOrtho2) < 0.1 and dDist1 > 4 * dDist2) then if dDist1 > dLenMin or dDist1 > 0.5 * dDist2 then ptP2 = Point3d( ptPm) dAllEnd = - dDist2 - 10 * GEO.EPS_SMALL end else if dDist2 > dLenMin or dDist2 > 0.5 * dDist1 then ptP1 = Point3d( ptPm) dAllStart = - dDist1 - 10 * GEO.EPS_SMALL end end vtTg = ptP2 - ptP1 ; vtTg:normalize() end end local nFaceUse = nOrthoOpposite if bDownUp then nFaceUse = BL.GetOrtupOpposite( nOrthoOpposite) end local bWsRight = ( bInvert ~= bDownUp) local nWorkSide = EgtIf( bWsRight, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT) -- Versore di riferimento local vtRef = Vector3d( vtTg) vtRef:rotate( vtN, EgtIf( bInvert, -90, 90)) -- Versore esterno local vtOut = vtRef - vtRef * vtTg * vtTg ; vtOut:normalize() -- Versore ausiliario (direzione braccio) local vtAux = Vector3d( vtN:getX(), vtN:getY(), 0) ; vtAux:normalize() vtAux:rotate( Z_AX(), EgtIf( bWsRight, 90, -90)) if vtAux:isSmall() then vtAux = Vector3d( vtOut:getX(), vtOut:getY(), 0) ; vtAux:normalize() else if abs( vtAux * vtOut) < GEO.EPS_SMALL then if abs( vtTg:getZ()) > 0.5 then if vtAux * vtRef < 0 then vtAux = - vtAux end elseif vtAux * vtTg > 0 then vtAux = - vtAux end elseif vtAux * vtOut < 0 then vtAux = - vtAux end end -- parametri di attacco/uscita local b3Box = BBox3d( b3Raw) b3Box:expand( dCutSic) local ptPa1 = ptP1 + dAccStart * vtTg local ptPa2 = ptP2 + dAccEnd * vtTg -- attacco perpendicolare local dLiTang, dLiPerp, dLoTang, dLoPerp, vtLio = FacesBySaw.CalcLeadInOutPerpGeom( ptPa1, ptPa2, vtV1, vtV2, vtN, dSawDiam / 2, vtRef, dCutExtra, b3Box) local dLenLi = sqrt( dLiTang * dLiTang + dLiPerp * dLiPerp) local dLenLo = sqrt( dLoTang * dLoTang + dLoPerp * dLoPerp) local dLiCompLength = 0 local dLoCompLength = 0 -- attacco tangente local dLi2Tang = 0 local dLi2Perp = 0 local dLo2Tang = 0 local dLo2Perp = 0 local dLi2CompLength = 0 -- si predilige un attacco tangenziale (con calcolo automatico di quanto uscire) se faccia che guarda in giù, non troppo orientata verso X e linea non troppo inclinata in X -- non si fa se macchina tipo PF e pezzo alto perchè la lama, uscendo da sopra, toccherebbe la traversa -- TODO si potranno togliere i limiti sulle normali quando si implementerà un modo per calcolare Lead In / Out correttamente in tutti i casi -- if bSpecialTangentLeadInOut and not bIsBiLinea and ( vtN:getZ() < - 0.087) and ( abs( vtN:getX()) < 0.258) and ( abs( vtTg:getX()) < 0.1736) and ( abs( vtN:getY()) < 0.5 or ( BD.MAX_DIM_HTCUT_HBEAM > 0 or ( b3Raw:getDimZ() < 420))) then dLi2Tang = 0 dLi2Perp = BD.CUT_EXTRA dLi2CompLength = dLen + dSawDiam / 2 + BD.COLL_SIC dLo2Tang = dSawDiam / 2 else dLi2Tang, dLi2Perp, dLo2Tang, dLo2Perp = FacesBySaw.CalcLeadInOutTangGeom( ptPa1, ptPa2, vtN, dSawDiam / 2, vtRef, dCutExtra, b3Box) end local dLenLi2 = abs( dLi2Tang) local dLenLo2 = abs( dLo2Tang) local dBiLineaAddLength = 0 -- se il lato non lavorato della bilinea è aperto, setto entrata/uscita con la stessa direzione if bIsBiLinea then -- angolo tra le due linee local dCosAlpha = dCosAngleL1L2 local dSinAlpha = sqrt( max( 1 - dCosAlpha * dCosAlpha, 0)) -- se ho accorciato ingresso, setto componente tangente e perpendicolare sul percorso di entrata if abs( dAllStart) > 100 * GEO.EPS_SMALL and bIsL1OnFace then -- controllo prima che il secondo lato non sia già incluso nella lavorazione del primo local dDistPtTang = dCosAlpha * dDist1 local dDistPtPerp = dSinAlpha * dDist1 local dDistToCenter = 0.5 * dSawDiam - dDistPtPerp local dDistPointToCenter = sqrt( dDistPtTang * dDistPtTang + dDistToCenter * dDistToCenter) -- se distanza al punto è maggiore del raggio lama, significa che non ho già lavorato, quindi calcolo entrata opportunamente if dDistPointToCenter > 0.5 * dSawDiam then dLiTang = -dAllStart * dCosAlpha dLiPerp = dDist1 * dSinAlpha end end -- se ho accorciato uscita, setto componente tangente e perpendicolare sul percorso di uscita if abs( dAllEnd) > 100 * GEO.EPS_SMALL and bIsL2OnFace then -- controllo prima che il secondo lato non sia già incluso nella lavorazione del primo local dDistPtTang = dCosAlpha * dDist2 local dDistPtPerp = dSinAlpha * dDist2 local dDistToCenter = 0.5 * dSawDiam - dDistPtPerp local dDistPointToCenter = sqrt( dDistPtTang * dDistPtTang + dDistToCenter * dDistToCenter) -- se distanza al punto è maggiore del raggio lama, significa che non ho già lavorato, quindi calcolo uscita opportunamente if dDistPointToCenter > 0.5 * dSawDiam then dBiLineaAddLength = dDistPointToCenter - ( 0.5 * dSawDiam) dLoTang = -dAllEnd * dCosAlpha dLoPerp = dDist2 * dSinAlpha end end end -- scelgo l'attacco più conveniente (se non taglio praticamente longitudinale) local bLioTang local Ktp = 1.1 if BD.KIOTP then Ktp = BD.KIOTP end if ( sLeadInOutType == 'PerpendicularOutraw') then bLioTang = false dLiCompLength = dActualElevation + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) + dCutExtra dLoCompLength = dActualElevation + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) + dCutExtra dLiTang = 1 dLoTang = 1 dLiPerp = 0 dLoPerp = 0 dLenLi = sqrt( dLiTang * dLiTang + dLiPerp * dLiPerp) dLenLo = sqrt( dLoTang * dLoTang + dLoPerp * dLoPerp) elseif ( sLeadInOutType ~= 'Perpendicular') and ( ( sLeadInOutType == 'Tangent') or ( not bDownUp or abs( vtTg:getY()) > 0.5) and ( not bDownHead or abs( vtTg:getZ()) < 0.51) and abs( vtTg:getX()) < 0.9848 and ( ( abs( vtTg:getZ()) < 0.17 and ( vtV1:getZ() < -0.5 or vtV2:getZ() < -0.5) and not bDownHead) or ( abs( vtTg:getZ()) < 0.51 and b3Box:getDimZ() > 300 and BD.C_SIMM and BD.MAX_HEIGHT > 450 and b3Box:getDimX() > BD.LEN_SHORT_PART) or ( abs( vtTg:getZ()) < 0.51 and ( dLenLi2 + dLenLo2) < ( dLenLi + dLenLo)) or Ktp * ( dLenLi2 + dLenLo2) < ( dLenLi + dLenLo) or ( BD.TURN == 2 and vtRef:getZ() < -0.1))) then if BD.TURN == 2 then if vtTg:getY() < -0.1 then bLioTang = 1 local dMove = dist( ptP1, ptP2) dLiTang = -( dLi2Tang - dAccStart - dAccEnd + dMove) -- dLiPerp rimane invariato dLoTang, dLoPerp = dLo2Tang, dLo2Perp else bLioTang = 2 local dMove = dist( ptP1, ptP2) dLiTang, dLiPerp = dLi2Tang, dLi2Perp dLoTang = -( dLiTang - dAccStart - dAccEnd + dMove) -- dLoPerp rimane invariato end elseif BD.TURN then dLiTang, dLiPerp = dLi2Tang, dLi2Perp -- se angolo bilinea ottuso si segue bilinea per un tratto per tagliare completamente cubetto a forma di rombo if dCosAngleL1L2 > 0.707 and bIsBiLinea then -- calcolo uscita per prolungare solo della parte mancante per completare il taglio if dBiLineaAddLength > 0 then dLoTang = dLoTang * ( dBiLineaAddLength + BD.COLL_SIC) / 100 dLoPerp = dLoPerp * ( dBiLineaAddLength + BD.COLL_SIC) / 100 end -- aggiungo componente perpendicolare a percorso per ritornare dal punto di ingresso, altrimenti l'uscita viene allungata fino dall'altra parte del grezzo dLoCompLength = 100 -- se angolo bilinea oltre 45°, faccio movimento in retrazione else bLioTang = 2 local dMove = dist( ptP1, ptP2) dLoTang = -( dLiTang - dAccStart - dAccEnd + dMove) dLoPerp = BD.COLL_SIC end else bLioTang = true dLiTang, dLiPerp, dLoTang, dLoPerp, dLiCompLength = dLi2Tang, dLi2Perp, dLo2Tang, dLo2Perp, dLi2CompLength end end -- posizione braccio EgtOutLog( 'vtN=' .. tostring( vtN) .. ' vtRef=' .. tostring( vtRef) .. ' vtOut=' .. tostring( vtOut) .. ' vtAux=' .. tostring( vtAux), 3) local nSCC = MCH_SCC.NONE if not BD.TURN then -- per ora aggregato usato in verticale solo in split e headcut; Fast non influenzata if BD.C_SIMM and bMaximizeVerticalDepth then nSCC = MCH_SCC.ADIR_ZM elseif abs( vtAux:getX()) > abs( vtAux:getY()) - GEO.EPS_SMALL then -- se il taglio è orizzontale, si gira aggregato lama per facilitare caduta del legno if abs( vtTg:getZ()) < 10 * GEO.EPS_SMALL and not AreSameOrOppositeVectorApprox( vtN, Z_AX()) then nSCC = EgtIf( ( vtAux:getX() > -GEO.EPS_SMALL), MCH_SCC.ADIR_XM, MCH_SCC.ADIR_XP) else nSCC = EgtIf( ( vtAux:getX() > -GEO.EPS_SMALL), MCH_SCC.ADIR_XP, MCH_SCC.ADIR_XM) end else -- se il taglio è orizzontale, si gira aggregato lama per facilitare caduta del legno if abs( vtTg:getZ()) < 10 * GEO.EPS_SMALL and not AreSameOrOppositeVectorApprox( vtN, Z_AX()) then nSCC = EgtIf( ( vtAux:getY() > -GEO.EPS_SMALL), MCH_SCC.ADIR_YM, MCH_SCC.ADIR_YP) else nSCC = EgtIf( ( vtAux:getY() > -GEO.EPS_SMALL), MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) end end else if BD.TURN == 2 then if vtOrthO:getZ() > -0.01 then nSCC = MCH_SCC.ADIR_ZP else nSCC = MCH_SCC.ADIR_ZM end elseif bLioTang then local vtTest = -vtTg if abs( vtTest:getY()) > abs( vtTest:getZ()) then -- calcolo direzione risultante da versore utensile e direzione di lavorazione inverso -- se la risultante tende verso Y positiva, scelgo soluzione dietro local vtRes = vtTest + vtAux ; vtRes:normalize() nSCC = EgtIf( vtRes:getY() > 0, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( vtTest:getZ() > 0, MCH_SCC.ADIR_ZP, MCH_SCC.ADIR_ZM) end else local vtTest = vtOut -- vtLio if abs( vtN:getY()) < 0.174 and abs( vtN:getZ()) < 0.174 then if abs( vtTest:getY()) > abs( vtTest:getZ()) then nSCC = EgtIf( vtTest:getY() > 0, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) else nSCC = EgtIf( vtTest:getZ() > 0, MCH_SCC.ADIR_ZP, MCH_SCC.ADIR_ZM) end elseif abs( vtN:getZ()) < 0.174 then nSCC = EgtIf( vtTest:getZ() > -0.017, MCH_SCC.ADIR_ZP, MCH_SCC.ADIR_ZM) else nSCC = EgtIf( vtTest:getY() > 0, MCH_SCC.ADIR_YP, MCH_SCC.ADIR_YM) end end end -- inserisco la lavorazione di taglio local sName = 'Cut_' .. ( EgtGetName( nSurfId) or tostring( nSurfId)) .. '_' .. tostring( nFacet + 1) local nMchFId = EgtAddMachining( sName, sCutting) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sCutting EgtOutLog( sErr) return false, sErr end sName = EgtGetOperationName( nMchFId) -- aggiungo geometria EgtSetMachiningGeometry( {{ nSurfId, nFacet}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- vtFaceUse non funziona correttamente in caso che il lato da lavorare sia a 45°. Potrebbe ritornare una trilinea, non gestibile. Quindi si setta l'EDGE local nEdgeFaceUse = GetEdgeToMachineFromVector( nSurfId, nFacet, vtOrthO) if nEdgeFaceUse and ( AreSameOrOppositeDirApprox( vtOrthO:getX(), 0.707) or AreSameOrOppositeDirApprox( vtOrthO:getY(), 0.707) or AreSameOrOppositeDirApprox( vtOrthO:getZ(), 0.707)) then local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'EdgesFaceUse', EgtNumToString( nEdgeFaceUse)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) else local sUserNotes = EgtGetMachiningParam( MCH_MP.USERNOTES) or '' sUserNotes = EgtSetValInNotes( sUserNotes, 'VtFaceUse', EgtNumToString( vtOrthO:getX(), 3) .. ',' .. EgtNumToString( vtOrthO:getY(), 3) .. ',' .. EgtNumToString( vtOrthO:getZ(), 3)) EgtSetMachiningParam( MCH_MP.USERNOTES, sUserNotes) -- imposto allungamenti iniziale e finale (in caso si utilizzi EDGE, non serve prolungare o accorciare) EgtSetMachiningParam( MCH_MP.STARTADDLEN, dAllStart - dAccStart) EgtSetMachiningParam( MCH_MP.ENDADDLEN, dAllEnd - dAccEnd) end -- imposto posizione braccio porta testa EgtSetMachiningParam( MCH_MP.SCC, nSCC) -- imposto inversione e lato correzione EgtSetMachiningParam( MCH_MP.INVERT, bInvert) EgtSetMachiningParam( MCH_MP.WORKSIDE, nWorkSide) -- affondamento aggiuntivo EgtSetMachiningParam( MCH_MP.OFFSR, -dCutExtra) -- offset longitudinale EgtSetMachiningParam( MCH_MP.OFFSL, EgtIf( bDownUp, -dCutOffset, dCutOffset)) -- imposto attacco/uscita if BD.TURN and bLioTang == 1 then EgtSetMachiningParam( MCH_MP.LEADINTYPE, MCH_MILL_LI.TG_PERP) end EgtSetMachiningParam( MCH_MP.LITANG, dLiTang) EgtSetMachiningParam( MCH_MP.LIPERP, dLiPerp) EgtSetMachiningParam( MCH_MP.LICOMPLEN, dLiCompLength) if BD.TURN and bLioTang == 2 then EgtSetMachiningParam( MCH_MP.LEADOUTTYPE, MCH_MILL_LO.PERP_TG) end EgtSetMachiningParam( MCH_MP.LOTANG, dLoTang) EgtSetMachiningParam( MCH_MP.LOPERP, dLoPerp) EgtSetMachiningParam( MCH_MP.LOCOMPLEN, dLoCompLength) -- imposto angolo 3° asse rot local sBlockedAxis = EgtIf( bMaximizeVerticalDepth, 'parallel', 'perpendicular') EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, BL.GetBlockedAxis( sCutting, sBlockedAxis, b3Raw, vtN, vtOrthO)) local sAuxDir, sInitAngs = BL.GetAuxDir( sCutting, sBlockedAxis, b3Raw, vtN, vtOrthO) if sAuxDir then sNotes = EgtSetValInNotes( sNotes, 'VtAuxDir', sAuxDir) EgtSetMachiningParam( MCH_MP.INITANGS, sInitAngs) EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.STD) end -- eventuali note if ( sLeadInOutType == 'PerpendicularOutraw') then sNotes = EgtSetValInNotes( sNotes, 'OutRaw', 3) end if sNotes and #sNotes > 0 then EgtSetMachiningParam( MCH_MP.USERNOTES, sNotes) end -- eseguo if not ML.ApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end return true, sName, nMchFId end --------------------------------------------------------------------- function FacesBySaw.MakeTwo( Proc, nPhase, nRawId, nPartId, dOvmHead, sCutType, bUpdateIng, bDownHead) EgtOutLog( 'FacesBySaw.MakeTwo', 3) -- bUpdateIng : parametro opzionale con default true if bUpdateIng == nil then bUpdateIng = true end -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- ingombro del pezzo local Ls = EgtGetFirstNameInGroup( nPartId, 'Box') local b3Solid = EgtGetBBoxGlob( Ls 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 if Proc.Fct < 2 then local sErr = 'Error : TwoFacesBySaw facet number not supported' EgtOutLog( sErr) return false, sErr end -- recupero la lavorazione local sCutting = ML.FindCutting( sCutType, nil, bDownHead) if not sCutting then local sErr = 'Error : cutting not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile local dSawDiam = 400 local dSawThick = 5 local dMaxDepth = 0 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 end 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) -- recupero dati su giunzione tra facce local bTouch, ptT1, ptT2, dAngT = EgtSurfTmFacetsContact( Proc.Id, 0, 1, GDB_ID.ROOT) if not bTouch then local sErr = 'Error : TwoFacesBySaw faces not touching' EgtOutLog( sErr) return false, sErr end local ptM = ( ptT1 + ptT2) / 2 local vtTg = ptT2 - ptT1 ; vtTg:normalize() local bConvex = ( dAngT > 0) -- verifico non siano orientate troppo verso il basso e molto sbandate (oltre 10 deg), oppure in testa o in coda e non troppo distanti dal grezzo esterno local bFaceOk = {} bFaceOk[1] = ( vtN[1]:getZ() >= ( BD.CUT_VZ_MIN or BD.NZ_MINB) or abs( vtN[1]:getY()) < 0.174 or ( Proc.AffectedFaces.Left ~= Proc.AffectedFaces.Right and Proc.Face[1].Elevation < dMaxDepth - 10 * GEO.EPS_SMALL)) bFaceOk[2] = ( vtN[2]:getZ() >= ( BD.CUT_VZ_MIN or BD.NZ_MINB) or abs( vtN[2]:getY()) < 0.174 or ( Proc.AffectedFaces.Left ~= Proc.AffectedFaces.Right and Proc.Face[2].Elevation < dMaxDepth - 10 * GEO.EPS_SMALL)) if not bDownHead and not bFaceOk[1] and not bFaceOk[2] then local sErr = 'Error : TwoFacesBySaw from bottom impossible' EgtOutLog( sErr) return false, sErr end -- calcolo direzione di lavoro local vtRef = {} vtRef[1] = vtN[1] ^ vtTg if vtRef[1] * vtN[2] < 0 then vtRef[1] = - vtRef[1] end vtRef[1]:normalize() if abs( vtTg:getZ()) < 0.708 and abs( vtRef[1]:getZ()) < 0.577 and abs( abs( vtRef[1]:getX()) - abs( vtRef[1]:getY())) < 0.05 then vtRef[1] = ptC[1] - ptM vtRef[1]:normalize() end vtRef[2] = vtN[2] ^ vtTg if vtRef[2] * vtN[1] < 0 then vtRef[2] = - vtRef[2] end vtRef[2]:normalize() if abs( vtTg:getZ()) < 0.708 and abs( vtRef[2]:getZ()) < 0.577 and abs( abs( vtRef[2]:getX()) - abs( vtRef[2]:getY())) < 0.05 then vtRef[2] = ptC[2] - ptM vtRef[2]:normalize() end -- determino quale faccia è più grande local dSqDim1 = ( ptC[1] - ptM):sqlen() local dSqDim2 = ( ptC[2] - ptM):sqlen() local nBigInd = EgtIf( dSqDim1 > dSqDim2 - 1., 1, 2) local nSmaInd = 3 - nBigInd local nUpInd = EgtIf( vtN[1]:getZ() > vtN[2]:getZ() - GEO.EPS_SMALL, 1, 2) local nOtInd = 3 - nUpInd -- metto in relazione la scelta facce con il confronto del versore Z con la scelta in base alla grandezza faccia -- se la faccia più grande è messa secondaria e il suo versore Z non è troppo negativo if nOtInd == nBigInd and (( vtN[nBigInd]:getZ() > -0.5 and vtN[nSmaInd]:getZ() < 0.966) or bDownHead) then nUpInd = nBigInd nOtInd = nSmaInd end -- calcolo extra taglio local dCutExtra = 0 if dAngT < -91 and dAngT > -179 then dCutExtra = - dSawThick / tan( 180 + dAngT) end -- sistemo direzione limite da sotto (con testa da sotto limite Vz Down Up messo a -2 per non farlo mai intervenire) local dNzLimDwnUp if bDownHead then dNzLimDwnUp = - 2 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 -- verifico se necessari tagli supplementari local vCuts = DC.GetDice( nAddGrpId, b3Solid, ptC[nUpInd], vtN[nUpInd], false, ptC[nOtInd], vtN[nOtInd]) --DC.PrintOrderCut( vCuts) if #vCuts > 0 then -- sistemo posizione nel DB, nome e info for i = 1, #vCuts do for j = 1, #vCuts[i] do EgtSetName( vCuts[i][j], 'AddCut_' .. tostring( Proc.Id)) EgtSetInfo( vCuts[i][j], 'TASKID', Proc.TaskId) end end -- con testa da sopra if not bDownHead or BD.TURN then -- eseguo for i = 1, #vCuts do -- assegno il modo di tagliare local vtOrthO = EgtIf( ( i % 2) == 1, vtRef[nOtInd], vtRef[nUpInd]) -- lavoro la faccia for j = 1, #vCuts[i] do local bSpecialTangentLeadInOut = ( i % 2 == 0) and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) local bOk, sErr = FacesBySaw.MakeOne( vCuts[i][j], 0, sCutting, dSawDiam, vtOrthO, dNzLimDwnUp, dCutExtra, BD.CUT_SIC, 0, 0, 0, nil, b3Raw, nil, nil, bSpecialTangentLeadInOut) if not bOk then return bOk, sErr end end end -- altrimenti con testa da sotto else -- eseguo (facendo di seguito i due tagli di ogni singolo cubetto) for i = 1, #vCuts, 2 do -- determino il modo di tagliare dei perpendicolari local vtOrthoO_1 = Vector3d( vtN[nUpInd]) -- determino il modo di tagliare dei paralleli local vtOrthoO_2 local bNoPerpCuts_2 = false local vtO if #vCuts[i] > 0 then vtO = EgtSurfTmFacetNormVersor( vCuts[i][1], 0, GDB_ID.ROOT) elseif vCuts[i+2] and #vCuts[i+2] > 0 then -- lunghezza faccia nell'eventuale direzione ortogonale local asseX = EgtSurfTmFacetNormVersor( vCuts[i+2][1], 0, GDB_ID.ROOT) local asseY = asseX ^ vtN[nUpInd] local Frame = Frame3d( ptC, ptC + asseX, ptC + asseY) local b3Fac = EgtGetBBoxRef( vCuts[i+1][1], GDB_BB.STANDARD, Frame) -- se lunghezza inferiore al limite, accetto la direzione if b3Fac:getDimX() < dMaxDepth - BD.CUT_EXTRA then vtO = asseX else bNoPerpCuts_2 = true end else bNoPerpCuts_2 = true end if vtO then vtOrthoO_2 = Vector3d( vtO) else if bHorizCut then vtOrthoO_2 = -Z_AX() elseif vtN:getY() > -0.02 then if not Proc.Head then vtOrthoO_2 = -Y_AX() else vtOrthoO_2 = Y_AX() end else vtOrthoO_2 = -Y_AX() end end -- lavoro le coppie di facce del singolo cubetto for j = 1, max( #vCuts[i], #vCuts[i+1]) do -- extra taglio per perpendicolari local dExtraCut_1 = -0.1 -- extra taglio per paralleli local dExtraCut_2 = -0.1 -- se non ci sono tagli ortogonali devo affondare if bNoPerpCuts_2 then dExtraCut_2 = BD.CUT_EXTRA end -- taglio perpendicolare (limite Vz Down Up messo a -2 per non farlo mai intervenire) if vCuts[i][j] then local bSpecialTangentLeadInOut = ( i % 2 == 0) and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) local bOk, sErr = FacesBySaw.MakeOne( vCuts[i][j], 0, sCutting, dSawDiam, vtOrthoO_1, -2, dExtraCut_1, BD.CUT_SIC, 0, 0, 0, nil, b3Raw, nil, nil, bSpecialTangentLeadInOut) if not bOk then return bOk, sErr end end -- taglio parallelo (limite Vz Down Up messo a -2 per non farlo mai intervenire) if vCuts[i+1][j] then local bSpecialTangentLeadInOut = ( ( i + 1) % 2 == 0) and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) local bOk, sErr = FacesBySaw.MakeOne( vCuts[i+1][j], 0, sCutting, dSawDiam, vtOrthoO_2, -2, dExtraCut_2, BD.CUT_SIC, 0, 0, 0, nil, b3Raw, nil, nil, bSpecialTangentLeadInOut) if not bOk then return bOk, sErr end end end end end else -- se prima faccia lavorata è da sotto scambio le facce if vtN[nOtInd]:getZ() < -0.5 then nUpInd, nOtInd = nOtInd, nUpInd end -- lavoro la prima faccia local bOk, sErr = FacesBySaw.MakeOne( Proc.Id, nOtInd-1, sCutting, dSawDiam, vtRef[nOtInd], dNzLimDwnUp, dCutExtra, BD.CUT_SIC, 0, 0, 0, nil, b3Raw) if not bOk then return bOk, sErr end -- lavoro seconda faccia bOk, sErr = FacesBySaw.MakeOne( Proc.Id, nUpInd-1, sCutting, dSawDiam, vtRef[nUpInd], dNzLimDwnUp, dCutExtra, BD.CUT_SIC, 0, 0, 0, nil, b3Raw) if not bOk then return bOk, sErr end 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 -- 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 -- riportata condizione, ma poco chiara bUpdateIng = bUpdateIng and not ( abs( vtN[nBigInd]:getX()) < 0.05 and vtN[nBigInd]:getY() < 0 and Proc.Box:getDimX() > 500 and Proc.Box:getDimY() < 40) -- 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 concavo aumento la distanza (rimane una punta...) --if dAngT < 0 then dDist = dDist + 10 end BL.UpdateHCING( nRawId, dOffs, dDist) end end return true end --------------------------------------------------------------------- function FacesBySaw.CalcLeadInOutPerpGeom( ptP1, ptP2, vtV1, vtV2, vtN, dRad, vtRef, dCutExtra, b3Box) -- Mi assicuro che i vettori ingresso/uscita giacciano nel piano vtV1 = vtV1 - vtV1 * vtN * vtN ; vtV1:normalize() vtV2 = vtV2 - vtV2 * vtN * vtN ; vtV2:normalize() -- Versore tangente al taglio local vtTg = ptP2 - ptP1 ; vtTg = vtTg - vtTg * vtN * vtN ; vtTg:normalize() -- Sistema di riferimento intrinseco al taglio local vtX = vtTg ^ vtN local frFace = Frame3d( ptP1, vtX, vtTg, vtN) local bRight = ( vtX * vtRef > 0) EgtOutLog( 'LioPerp --> Vref=' .. tostring( vtRef) .. ' V1=' .. tostring( vtV1) .. ' V2=' .. tostring( vtV2), 3) -- Versore di attacco e uscita local dCos1 = vtV1 * vtRef local dCos2 = vtV2 * vtRef local vtLio if abs( dCos1 - dCos2) < 0.001 then vtLio = EgtIf( abs( vtV1:getZ()) < abs( vtV2:getZ()), vtV1, vtV2) elseif dCos1 > dCos2 then vtLio = vtV1 else vtLio = vtV2 end -- Versore di attacco e uscita nel riferimento intrinseco al taglio local vtLioL = Vector3d( vtLio) ; vtLioL:toLoc( frFace) -- Centro lama a inizio fine percorso local dOffs = ( -dCutExtra + dRad) * EgtIf( bRight, 1, -1) local ptCen1 = ptP1 + dOffs * vtX local ptCen2 = ptP2 + dOffs * vtX -- Box del pezzo espansi ortogonalmente alle tre direzioni canoniche X, Y e Z local b3BoxX = BBox3d( b3Box) ; b3BoxX:expand( 0, 1000, 1000) local b3BoxY = BBox3d( b3Box) ; b3BoxY:expand( 1000, 0, 1000) local b3BoxZ = BBox3d( b3Box) ; b3BoxZ:expand( 1000, 1000, 0) -- Calcolo elevazione dei due centri local dSawThick = 6 EgtCAvSetSawTool( dSawThick, 2 * dRad, dSawThick, 0, 0) local dElev1 = min( EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxX, vtLio), EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxY, vtLio), EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxZ, vtLio)) EgtOutLog( 'Elev1=' .. EgtNumToString( dElev1), 3) local dLiTang = -dElev1 * vtLioL:getY() local dLiPerp = EgtIf( bRight, dElev1, -dElev1) * vtLioL:getX() local dElev2 = min( EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxX, vtLio), EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxY, vtLio), EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxZ, vtLio)) EgtOutLog( 'Elev2=' .. EgtNumToString( dElev2), 3) local dLoTang = dElev2 * vtLioL:getY() local dLoPerp = EgtIf( bRight, dElev2, -dElev2) * vtLioL:getX() return dLiTang, dLiPerp, dLoTang, dLoPerp, vtLio end --------------------------------------------------------------------- function FacesBySaw.CalcLeadInOutTangGeom( ptP1, ptP2, vtN, dRad, vtRef, dCutExtra, b3Box) -- Versore tangente al taglio local vtTg = ptP2 - ptP1 ; vtTg = vtTg - vtTg * vtN * vtN ; vtTg:normalize() -- Sistema di riferimento intrinseco al taglio local vtX = vtTg ^ vtN local frFace = Frame3d( ptP1, vtX, vtTg, vtN) local bRight = ( vtX * vtRef > 0) EgtOutLog( 'LioTang --> Vref=' .. tostring( vtRef), 3) -- Centro lama a inizio fine percorso local dOffs = ( -dCutExtra + dRad) * EgtIf( bRight, 1, -1) local ptCen1 = ptP1 + dOffs * vtX local ptCen2 = ptP2 + dOffs * vtX -- Box del pezzo espansi ortogonalmente alle tre direzioni canoniche X, Y e Z local b3BoxX = BBox3d( b3Box) ; b3BoxX:expand( 0, 1000, 1000) local b3BoxY = BBox3d( b3Box) ; b3BoxY:expand( 1000, 0, 1000) local b3BoxZ = BBox3d( b3Box) ; b3BoxZ:expand( 1000, 1000, 0) -- Calcolo elevazione dei due centri local dSawThick = 6 EgtCAvSetSawTool( dSawThick, 2 * dRad, dSawThick, 0, 0) local dElev1 = min( EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxX, -vtTg), EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxY, -vtTg), EgtCAvToolPosBox( ptCen1 + dSawThick * vtN, vtN, b3BoxZ, -vtTg)) EgtOutLog( 'Elev1=' .. EgtNumToString( dElev1), 3) local dLiTang = dElev1 local dLiPerp = 0 local dElev2 = min( EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxX, vtTg), EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxY, vtTg), EgtCAvToolPosBox( ptCen2 + dSawThick * vtN, vtN, b3BoxZ, vtTg)) EgtOutLog( 'Elev2=' .. EgtNumToString( dElev2), 3) local dLoTang = dElev2 local dLoPerp = 0 return dLiTang, dLiPerp, dLoTang, dLoPerp end return FacesBySaw