1017 lines
50 KiB
Lua
1017 lines
50 KiB
Lua
-- 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) + dCutExtra
|
|
dLoCompLength = dActualElevation + EgtMdbGetGeneralParam( MCH_GP.SAFEZ) + dCutExtra
|
|
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))
|
|
-- 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)
|
|
-- 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)) 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 correttaemnte 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 sNoteEdgeFaceUse = 'EdgesFaceUse=' .. EgtNumToString( nEdgeFaceUse) .. ';'
|
|
EgtSetMachiningParam( MCH_MP.USERNOTES, sNoteEdgeFaceUse)
|
|
else
|
|
local sNoteVtFaceUse = 'VtFaceUse=' .. EgtNumToString( vtOrthO:getX(),3) .. ',' .. EgtNumToString( vtOrthO:getY(),3) .. ',' .. EgtNumToString( vtOrthO:getZ(),3) .. ';'
|
|
EgtSetMachiningParam( MCH_MP.USERNOTES, sNoteVtFaceUse)
|
|
-- 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))
|
|
-- 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
|