-- ProcessLapJoint.lua by Egaltech s.r.l. 2019/03/26 -- Gestione calcolo mezzo-legno per Travi -- Tabella per definizione modulo local ProcessLapJoint = {} -- Include require( 'EgtBase') local BL = require( 'BeamLib') local Cut = require( 'ProcessCut') local DoubleCut = require( 'ProcessDoubleCut') local Tfs = require( 'TwoFacesBySaw') EgtOutLog( ' ProcessLapJoint started', 1) -- Dati local BD = require( 'BeamData') local Cuttings = require( 'CutData') local Millings = require( 'MillingData') local Pocketings = require( 'PocketingData') local Sawings = require( 'SawingData') --------------------------------------------------------------------- -- Riconoscimento della feature function ProcessLapJoint.Identify( Proc) return ( (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 16) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 17) or (( Proc.Grp == 3 or Proc.Grp == 4) and Proc.Prc == 30)) end --------------------------------------------------------------------- -- Verifica se feature di testa function ProcessLapJoint.IsHeadFeature( Proc, b3Raw, dCurrOvmH) -- verifico se è in testa if Proc.Box:getMax():getX() < b3Raw:getMax():getX() - dCurrOvmH - BD.MAX_DIST_HTFEA then return false end -- deve occupare la maggior parte dell'area if Proc.Box:getDimY() > 0.75 * b3Raw:getDimY() or Proc.Box:getDimZ() > 0.75 * b3Raw:getDimZ() then return true end -- deve avere la normale principale diretta verso la testa local nFacInd = BL.GetFaceWithMostAdj( Proc.Id) local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) if vtN:getX() > 0.5 then return true end -- non è di testa return false end --------------------------------------------------------------------- -- Verifica se feature di coda function ProcessLapJoint.IsTailFeature( Proc, b3Raw) -- verifico se è in coda if Proc.Box:getMin():getX() > b3Raw:getMin():getX() + BD.MAX_DIST_HTFEA then return false end -- deve occupare la maggior parte dell'area if Proc.Box:getDimY() > 0.75 * b3Raw:getDimY() or Proc.Box:getDimZ() > 0.75 * b3Raw:getDimZ() then return true end -- deve avere la normale principale diretta verso la coda local nFacInd = BL.GetFaceWithMostAdj( Proc.Id) local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) if vtN:getX() < -0.5 then return true end -- non è di coda return false end --------------------------------------------------------------------- -- Classificazione della feature function ProcessLapJoint.Classify( Proc) -- se 1 faccia if Proc.Fct == 1 then -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) -- verifico se è lavorabile solo dal basso local bDown = ( vtN:getZ() < BD.NZ_MINA) return true, bDown -- se 2 facce elseif Proc.Fct == 2 then -- 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) -- verifico se è lavorabile solo dal basso local bDown = ( vtN[1]:getZ() < BD.NZ_MINB and vtN[2]:getZ() < BD.NZ_MINB) return true, bDown -- se più di 2 facce else -- recupero la faccia con il maggior numero di adiacenze più grande local nFacInd = BL.GetFaceWithMostAdj( Proc.Id) -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) -- verifico se è lavorabile solo dal basso local bDown = ( vtN:getZ() < BD.NZ_MINA) return true, bDown end end --------------------------------------------------------------------- -- Lavorazione con fresa --------------------------------------------------------------------- local function FindMilling( sType) for i = 1, #Millings do local Milling = Millings[i] if Milling.Type == sType then return i, Milling.Name end end return 0 end --------------------------------------------------------------------- local function MakeOneFaceByMill( Proc, nPhase, nRawId, nPartId) -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- verifico il numero di facce della tacca assert( ( Proc.Fct == 1), 'Error : MakeOneFaceByMill in LapJoint with ' .. tostring( Proc.Fct) .. ' faces') -- dati delle facce local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) -- verifico non siano orientate verso il basso local bFaceOk = ( vtN:getZ() >= BD.NZ_MINB) if not bFaceOk then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end -- scelta faccia da lavorare local nFacInd = 0 -- recupero la lavorazione local nMill, sMilling = FindMilling( 'BirdsMouth') if not sMilling then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' milling not found in library' EgtOutLog( sErr) return false, sErr end -- inserisco la lavorazione di fresatura local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia e lato correzione if vtN:getX() > 0 then EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_LEFT) else EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_RIGHT) end -- imposto lato di correzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- imposto posizione braccio porta testa if vtN:getY() <= 0 then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- eseguo if not EgtApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end return true end --------------------------------------------------------------------- local function MakeTwoFacesByMill( Proc, nPhase, nRawId, nPartId) -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- verifico il numero di facce della tacca assert( ( Proc.Fct == 2), 'Error : MakeTwoFacesByMill in LapJoint with ' .. tostring( Proc.Fct) .. ' faces') -- dati delle facce local ptC = {} local vtN = {} ptC[0], vtN[0] = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) ptC[1], vtN[1] = EgtSurfTmFacetCenter( Proc.Id, 1, GDB_ID.ROOT) -- dati medi local ptM = ( ptC[0] + ptC[1]) / 2 -- verifico non siano orientate verso il basso local bFaceOk = {} bFaceOk[0] = ( vtN[0]:getZ() >= BD.NZ_MINB) bFaceOk[1] = ( vtN[1]:getZ() >= BD.NZ_MINB) if not bFaceOk[0] and not bFaceOk[1] then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end -- scelta faccia da lavorare local nFacInd -- se entrambe possibili, scelgo quella con la normale più perpendicolare all'asse trave (se uguali, quella verso X+) if bFaceOk[0] and bFaceOk[1] then if abs( abs( vtN[0]:getX()) - abs( vtN[1]:getX())) < GEO.EPS_SMALL then if ptM:getX() > b3Raw:getCenter():getX() then nFacInd = EgtIf( vtN[0]:getX() > vtN[1]:getX(), 0, 1) else nFacInd = EgtIf( vtN[0]:getX() < vtN[1]:getX(), 0, 1) end else nFacInd = EgtIf( abs( vtN[0]:getX()) < abs( vtN[1]:getX()), 0, 1) end elseif bFaceOk[0] then nFacInd = 0 else nFacInd = 1 end local nOthInd = 1 - nFacInd -- recupero la lavorazione local nMill, sMilling = FindMilling( 'BirdsMouth') if not sMilling then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' milling not found in library' EgtOutLog( sErr) return false, sErr end -- inserisco la lavorazione di fresatura local sName = 'Mill_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sMilling) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sMilling EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia e lato correzione if vtN[nOthInd]:getX() > 0 then EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_LEFT) else EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_RIGHT) end -- imposto lato di correzione EgtSetMachiningParam( MCH_MP.WORKSIDE, MCH_MILL_WS.LEFT) -- imposto posizione braccio porta testa if vtN[nFacInd]:getY() <= 0 then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- eseguo if not EgtApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end return true end --------------------------------------------------------------------- local function MakePreCuts( Proc, nPhase, nRawId, nPartId, b3Raw) -- se interessa l'intera sezione della trave, necessaria sgrossatura if Proc.Box:getDimY() > 0.9 * b3Raw:getDimY() and Proc.Box:getDimZ() > 0.9 * b3Raw:getDimZ() then -- recupero gruppo per geometria addizionale local nAddGrpId = BL.GetAddGroup( nPartId) if not nAddGrpId then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' missing AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo sgrossatura e la lavoro local AddId = EgtSurfTmConvexHullInBBox( EgtGetParent( Proc.Id), Proc.Id, b3Raw, GDB_RT.GLOB) if AddId then EgtRelocate( AddId, nAddGrpId) EgtSetName( AddId, 'AddCut_' .. tostring( Proc.Id)) -- applico lavorazione local CutProc = { Id = AddId, Grp = Proc.Grp, Prc = Proc.Prc, Box = Proc.Box, Fct = Proc.Fct, Flg = Proc.Flg} local nCutFacet = EgtSurfTmFacetCount( AddId) if nCutFacet == 1 then local bOk, sErr = Cut.Make( CutProc, nPhase, nRawId, nPartId, 0) if not bOk then return bOk, sErr end elseif nCutFacet == 2 then local bOk, sErr = DoubleCut.Make( CutProc, nPhase, nRawId, nPartId, 0) if not bOk then return bOk, sErr end end end end return true end --------------------------------------------------------------------- local function FindSawing( sType) for i = 1, #Sawings do local Sawing = Sawings[i] if Sawing.Type == sType then return i, Sawing.Name end end return 0 end --------------------------------------------------------------------- local function MakeByChainSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV) -- Recupero le facce adiacenti alla principale local vAdj = EgtSurfTmFacetAdjacencies( Proc.Id, nFacInd)[1] if not vAdj or #vAdj == 0 then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' main face without adjacencies' EgtOutLog( sErr) return false, sErr end EgtOutLog( 'Adjac=' .. table.concat( vAdj, ','), 3) -- Riordino le dimensioni per avere dH > dV if dH < dV then dH, dV = dV, dH end -- Cerco una faccia adiacente alla principale sul lato lungo local nFacAdj for i = 1, #vAdj do if vAdj[i] >= 0 then local _, ptP1, ptP2, _ = EgtSurfTmFacetsContact( Proc.Id, nFacInd, vAdj[i], GDB_ID.ROOT) local dLen = dist( ptP1, ptP2) if dLen > 0.5 * dH then nFacAdj = vAdj[i] EgtOutLog( string.format( 'Adjac=%d Len=%.3f H=%.3f V=%.3f', vAdj[i], dLen, dH, dV), 3) break end end end -- Determino se estremi aperti o chiusi local bOpenStart = false local bOpenEnd = false local vAdj2 = EgtSurfTmFacetAdjacencies( Proc.Id, nFacAdj)[1] for j = 1, #vAdj2 do if vAdj2[j] == nFacInd then -- Se non esiste faccia adiacente a lato precedente -> inizio aperto local i = EgtIf( j > 1, j - 1, #vAdj2) bOpenStart = ( vAdj2[i] < 0) -- Se non esiste faccia adiacente a lato successivo -> fine aperto local k = EgtIf( j < #vAdj2, j + 1, 1) bOpenEnd = ( vAdj2[k] < 0) end end -- Calcolo uso faccia local nFaceUse = BL.GetNearestParalOpposite( rfFac:getVersZ()) -- Calcolo angolo 3° asse rot (da direz. utensile) local vtN = EgtSurfTmFacetNormVersor( Proc.Id, nFacAdj, GDB_ID.ROOT) local ptP1, ptP2 = EgtSurfTmFacetOppositeSide( Proc.Id, nFacAdj, rfFac:getVersZ(), GDB_ID.ROOT) local vtT = vtN ^ (ptP2 - ptP1) local d3RotAng = EgtIf( abs( vtT:getZ()) < GEO.EPS_SMALL, 0, 90) -- Recupero la lavorazione local nSaw, sSawing = FindSawing( 'Sawing') if not sSawing then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' chainsawing not found in library' EgtOutLog( sErr) return false, sErr end -- Recupero i dati dell'utensile local dSawWidth = 75 local dSawThick = 8 if EgtMdbSetCurrMachining( sSawing) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dSawWidth = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dSawWidth dSawThick = EgtTdbGetCurrToolParam( MCH_TP.THICK) or dSawThick end end -- Verifico se necessarie più passate local nStep = ceil( ( dV - 0.5) / dSawThick) local dStep = 0 if nStep > 1 then dStep = ( dV - dSawThick) / ( nStep - 1) end for i = 1, nStep do -- Applico la lavorazione con sega a catena a questa faccia local sName = 'Csaw_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) .. '_' .. tostring( i) local nMchFId = EgtAddMachining( sName, sSawing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sSawing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacAdj}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, nFaceUse) -- imposto accorciamento iniziale/finale per estremi aperti/chiusi EgtSetMachiningParam( MCH_MP.STARTADDLEN, EgtIf( bOpenStart, 0, - dSawWidth / 2)) EgtSetMachiningParam( MCH_MP.ENDADDLEN, EgtIf( bOpenEnd, 0, - dSawWidth / 2)) -- imposto angolo 3° asse rot EgtSetMachiningParam( MCH_MP.BLOCKEDAXIS, 'A=' .. EgtNumToString( d3RotAng)) -- imposto offset radiale local dOffs = ( i - 1) * dStep EgtSetMachiningParam( MCH_MP.OFFSR, dOffs) -- eseguo if not EgtApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end end return true end --------------------------------------------------------------------- local function FindPocketing( sType) for i = 1, #Pocketings do local Pocketing = Pocketings[i] if Pocketing.Type == sType then return i, Pocketing.Name end end return 0 end --------------------------------------------------------------------- local function MakeMoreFacesByMillOrChain( Proc, nPhase, nRawId, nPartId) -- recupero l'ingombro del grezzo di appartenenza local b3Raw = EgtGetRawPartBBox( nRawId) -- recupero il numero di facce della tacca assert( ( Proc.Fct > 2), 'Error : MakeMoreFacesByMillOrChain in LapJoint with ' .. tostring( Proc.Fct) .. ' faces') -- recupero la faccia con il maggior numero di adiacenze e l'elevazione relativa local nFacInd, dFacElev = BL.GetFaceWithMostAdj( Proc.Id) assert( nFacInd, 'Error : MakeMoreFacesByMillOrChain could not find reference face') -- dati della faccia local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFacInd, GDB_ID.ROOT) local rfFac, dH, dV = EgtSurfTmFacetMinAreaRectangle( Proc.Id, nFacInd, GDB_ID.ROOT) -- verifico non sia orientata verso il basso local bFaceOk = ( vtN:getZ() >= BD.NZ_MINB) if not bFaceOk then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' LapJoint from bottom impossible' EgtOutLog( sErr) return false, sErr end -- eventuali tagli preliminari do local bOk, sErr = MakePreCuts( Proc, nPhase, nRawId, nPartId, b3Raw) if not bOk then return false, sErr end end -- recupero la lavorazione local nMill, sPocketing = FindPocketing( 'Mortise') if not sPocketing then local sErr = 'Error on process ' .. tostring( Proc.Id) .. ' pocketing not found in library' EgtOutLog( sErr) return false, sErr end -- recupero i dati dell'utensile local dMillDiam = 20 local dMaxDepth = 0 if EgtMdbSetCurrMachining( sPocketing) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then dMillDiam = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or dMillDiam dMaxDepth = EgtTdbGetCurrToolMaxDepth() or dMaxDepth end end -- se una dimensione della faccia è più piccola del diametro utensile, va usata la sega a catena if dH < dMillDiam or dV < dMillDiam then return MakeByChainSaw( Proc, nPhase, nRawId, nPartId, nFacInd, rfFac, dH, dV) end -- inserisco la lavorazione di svuotatura local sName = 'Pock_' .. ( EgtGetName( Proc.Id) or tostring( Proc.Id)) local nMchFId = EgtAddMachining( sName, sPocketing) if not nMchFId then local sErr = 'Error adding machining ' .. sName .. '-' .. sPocketing EgtOutLog( sErr) return false, sErr end -- aggiungo geometria EgtSetMachiningGeometry( {{ Proc.Id, nFacInd}}) -- imposto uso faccia EgtSetMachiningParam( MCH_MP.FACEUSE, MCH_MILL_FU.ORTHO_CONT) -- imposto posizione braccio porta testa if vtN:getY() <= 0 then EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YM) else EgtSetMachiningParam( MCH_MP.SCC, MCH_SCC.ADIR_YP) end -- se elevazione superiore a massimo affondamento della fresa, riduco opportunamente if dFacElev > dMaxDepth + 10 * GEO.EPS_SMALL then EgtSetMachiningParam( MCH_MP.DEPTH, dMaxDepth - dFacElev) dFacElev = dMaxDepth local sWarn = 'Warning in process ' .. tostring( Proc.Id) .. ' : elevation bigger than max tool depth' EgtOutLog( sWarn) end -- imposto elevazione EgtSetMachiningParam( MCH_MP.USERNOTES, 'MaxElev=' .. EgtNumToString( dMaxDepth, 1) .. ';') -- eseguo if not EgtApplyMachining( true, false) then local _, sErr = EgtGetLastMachMgrError() EgtSetOperationMode( nMchFId, false) return false, sErr end return true end --------------------------------------------------------------------- local function MakeByMillOrChain( Proc, nPhase, nRawId, nPartId) -- richiamo la routine di lavorazione opportuna a seconda del numero di facce if Proc.Fct == 1 then return MakeOneFaceByMill( Proc, nPhase, nRawId, nPartId) elseif Proc.Fct == 2 then return MakeTwoFacesByMill( Proc, nPhase, nRawId, nPartId) else return MakeMoreFacesByMillOrChain( Proc, nPhase, nRawId, nPartId) end end --------------------------------------------------------------------- -- Applicazione della lavorazione --------------------------------------------------------------------- function ProcessLapJoint.Make( Proc, nPhase, nRawId, nPartId) -- con fresa local MAX_MILL_X = 80 local MAX_MILL_VOL = ( 80 * 240 * 20) / 2 if Proc.Fct > 2 or ( Proc.Box:getDimX() < MAX_MILL_X and Proc.Box:getDimX() * Proc.Box:getDimY() * Proc.Box:getDimZ() < MAX_MILL_VOL) then return MakeByMillOrChain( Proc, nPhase, nRawId, nPartId) -- con lama else return Tfs.Make( Proc, nPhase, nRawId, nPartId, 'HeadSide') end end --------------------------------------------------------------------- return ProcessLapJoint