-- BeamLib.lua by Egaltech s.r.l. 2023/12/15 -- Libreria globale per Travi -- 2020/07/28 Corretto calcolo attacchi e uscite di lame per non uscire dalla faccia sotto. -- 2020/08/18 Aggiunto a GetNearestParalOpposite e GetNearestOrthoOpposite parametro opzionale vtNorm. -- 2020/11/03 Aggiunta funzione IsEndOrEnd2Phase. -- 2020/11/18 Correzioni a GetParallelOpposite e a GetFaceElevation. -- 2021/06/27 Aggiunta funzione GetOtherFaceElevation. -- 2021/07/01 In GetNearestOrthoOpposite premio direzioni destra/sinistra. -- 2021/07/15 Aggiunta GetFaceElevationFromPointDir. -- 2021/09/12 Aggiustamenti in GetNearestParalOpposite e GetNearestOrthoOpposite. -- 2022/01/11 In GetNearest*Opposite ridotto vantaggio XY rispetto a Z da 1 -> 0.9 a 1 -> 0.99. -- 2022/04/05 Modifiche a GetNzLimDownUp per FAST. -- 2022/05/03 Ulteriore limitazione a GetNzLimDownUp per FAST. -- 2022/05/18 Correzioni e migliorie a PutStartNearestToEdge. -- 2022/06/25 Rese globali le funzioni GetChainSawBlockedAxis e GetChainSawInitAngs prima in ProcessLapJpoint. -- 2022/07/12 A GetFaceHvRefDim aggiunta possibilità di confronto e limitazione dimensioni con grezzo/pezzo (conta solo la sezione). -- 2022/07/26 Aggiunta la funzione FindFaceBestOrientedAsAxis, precedentemente in ProcessLapJoint -- 2022/07/26 Alla funzione FindFaceBestOrientedAsAxis aggiunta la possibilità di escludere una faccia dalla ricerca -- 2022/09/01 Aggiunte le funzioni GetTunnelDimension, CalcCollisionSafety, SetOpenSide, precedentemente in ProcessLapJoint. -- 2023/01/10 In GetFaceWithMostAdj aggiunta verifica che la feature abbia almeno una faccia aperta. -- 2023/01/20 Modificata PutStartNearestToEdge per gestire lato preferito come Y+, Y-, z*, Z-. Aggiunta funzione GetDistanceToNextPart. -- 2023/01/31 Aggiunta funzione ConvertToClosedCurve, precedentemente parte di ProcessMortise.Make -- 2023/02/22 Modifiche a SetOpenSide, aggiunte ChangeOrOpenStart e CurveWithOnlyStraightLines. -- 2023/06/12 In ChangeOrOpenStart corretta ricerca segmento più lungo. -- 2023/09/13 Aggiunte funzioni Is3EdgesApprox e GetProcessAffectedFaces. -- 2023/09/25 In GetFaceWithMostAdj aggiunta verifica sottosquadro anche per facce non adiacenti. -- 2023/09/26 In GetFaceWithMostAdj gestito primo parametro anche come Proc; gestito caso strip con facce tutte in sottosquadro. -- 2023/09/26 Spostata qui funzione IsFeatureCuttingEntireSection da BeamExec. -- 2023/11/30 Calcolo elevazione velocizzato e centralizzato tramite la funzione GetFaceElevation. Se l'elevazione è già calcolata la recupera da Proc, altrimenti la calcola al momento. -- 2023/12/15 Correzione a GetFaceWithMostAdj per calcoli con facce che fanno ombra. -- 2024/01/08 Correzione a Is3EdgesApprox per casi in cui nAddGroup non esista ancora. -- 2024/01/18 Aggiunta funzione GetBlockedAxis che gestisce gli assi bloccati per tutti i tipi di utensile. -- Tabella per definizione modulo local BeamLib = {} -- Include require( 'EgtBase') EgtOutLog( ' BeamLib started', 1) -- Dati local BD = require( 'BeamData') ------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------- function BeamLib.GetAddGroup( PartId) -- recupero il nome del gruppo di lavoro corrente local sMchGrp = EgtGetMachGroupName( EgtGetCurrMachGroup() or GDB_ID.NULL) if not sMchGrp then return nil, nil end -- cerco il gruppo aggiuntivo omonimo nel pezzo e se esiste lo restituisco local AddGrpId = EgtGetFirstNameInGroup( PartId or GDB_ID.NULL, sMchGrp) -- restituisco Id e Nome return AddGrpId, sMchGrp end ------------------------------------------------------------------------------------------------------------- function BeamLib.CreateOrEmptyAddGroup( PartId) -- recupero i dati del gruppo aggiuntivo local AddGrpId, sMchGrp = BeamLib.GetAddGroup( PartId) if not sMchGrp then return false end -- se esiste, aggiorno riferimento al gruppo di lavoro e lo svuoto if AddGrpId then EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) return EgtEmptyGroup( AddGrpId) end -- altrimenti lo creo AddGrpId = EgtGroup( PartId or GDB_ID.NULL) if not AddGrpId then return false end -- assegno nome, flag di layer per gruppo di lavoro e colore EgtSetName( AddGrpId, sMchGrp) EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 50)) return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPartStartFace( PartId, b3Solid) -- recupero gruppo per geometria aggiuntiva local AddGrpId = BeamLib.GetAddGroup( PartId) if not AddGrpId then local sErr = 'Error on process StartFace impossible to find AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo nuovo taglio iniziale local nStmId = EgtSurfTmPlaneInBBox( AddGrpId, b3Solid:getMax(), X_AX(), b3Solid, GDB_RT.GLOB) if not nStmId then local sErr = 'Error on process StartFace impossible to create Face' EgtOutLog( sErr) return false, sErr end -- applico gli opportuni attributi di feature EgtSetName( nStmId, 'StartCut') EgtSetInfo( nStmId, 'GRP', 1) EgtSetInfo( nStmId, 'PRC', 340) -- verifico se sostituisce un taglio di testa già presente local nProcId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PartId, 'Processings') or GDB_ID.NULL) while nProcId do local nGrp = EgtGetInfo( nProcId, 'GRP', 'i') or 0 local nProc = EgtGetInfo( nProcId, 'PRC', 'i') or 0 if ( nGrp == 1 or nGrp == 2) and nProc == 10 then local ptC, vtN = EgtSurfTmFacetCenter( nProcId, 0, GDB_ID.ROOT) if ptC and vtN and AreSameVectorApprox( vtN, X_AX()) and abs( ptC:getX() - b3Solid:getMax():getX()) < 10 * GEO.EPS_SMALL then EgtSetInfo( nStmId, 'ORI', nProcId) end end nProcId = EgtGetNext( nProcId) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPartEndFace( PartId, b3Solid) -- recupero gruppo per geometria aggiuntiva local AddGrpId = BeamLib.GetAddGroup( PartId) if not AddGrpId then local sErr = 'Error on process EndFace impossible to find AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo nuovo taglio finale local nStmId = EgtSurfTmPlaneInBBox( AddGrpId, b3Solid:getMin(), -X_AX(), b3Solid, GDB_RT.GLOB) if not nStmId then local sErr = 'Error on process EndFace impossible to create Face' EgtOutLog( sErr) return false, sErr end -- applico gli opportuni attributi di feature EgtSetName( nStmId, 'EndCut') EgtSetInfo( nStmId, 'GRP', 2) EgtSetInfo( nStmId, 'PRC', 350) -- verifico se sostituisce un taglio di coda già presente local nProcId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PartId, 'Processings') or GDB_ID.NULL) while nProcId do local nGrp = EgtGetInfo( nProcId, 'GRP', 'i') or 0 local nProc = EgtGetInfo( nProcId, 'PRC', 'i') or 0 if ( nGrp == 1 or nGrp == 2) and nProc == 10 then local ptC, vtN = EgtSurfTmFacetCenter( nProcId, 0, GDB_ID.ROOT) if ptC and vtN and AreSameVectorApprox( vtN, -X_AX()) and abs( ptC:getX() - b3Solid:getMin():getX()) < 10 * GEO.EPS_SMALL then EgtSetInfo( nStmId, 'ORI', nProcId) end end nProcId = EgtGetNext( nProcId) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPhaseWithRawParts( nFirstRawId, OriXR, PosXR, dDeltaSucc) EgtAddPhase() local nRawId = nFirstRawId local dRawMove = 0 while nRawId do EgtKeepRawPart( nRawId) EgtMoveToCornerRawPart( nRawId, OriXR, PosXR) EgtMoveRawPart( nRawId, Vector3d( - dRawMove, 0, 0)) if dRawMove == 0 then dRawMove = dRawMove + dDeltaSucc end dRawMove = dRawMove + EgtGetRawPartBBox( nRawId):getDimX() nRawId = EgtGetNextRawPart( nRawId) end end ------------------------------------------------------------------------------------------------------------- function BeamLib.PutStartOnTop( nCrvId) -- verifico che la curva sia chiusa if not EgtCurveIsClosed( nCrvId) then return false end -- cerco l'estremo più alto e lo imposto come inizio local dUmax = 0 local dZmax = - GEO.INFINITO local dUi, dUf = EgtCurveDomain( nCrvId) for dU = dUi, dUf, 0.5 do local ptP = EgtUP( nCrvId, dU, GDB_ID.ROOT) if ptP and ptP:getZ() > dZmax + GEO.EPS_SMALL then dZmax = ptP:getZ() dUmax = dU end end if abs( dUmax - dUi) > GEO.EPS_ZERO then EgtChangeClosedCurveStart( nCrvId, dUmax) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.PutStartOnLonger( nCrvId) -- verifico che la curva sia chiusa if not EgtCurveIsClosed( nCrvId) then return false end -- cerco l'entità più lunga e la imposto come inizio local dUmax = 0 local dLmax = - GEO.INFINITO local dUi, dUf = EgtCurveDomain( nCrvId) for dU = dUi, dUf - 1 do local ptP1 = EgtUP( nCrvId, dU, GDB_ID.ROOT) local ptP2 = EgtUP( nCrvId, dU + 0.5, GDB_ID.ROOT) local ptP3 = EgtUP( nCrvId, dU + 1.0, GDB_ID.ROOT) local dL = dist( ptP1, ptP2) + dist( ptP2, ptP3) if dL > dLmax + GEO.EPS_SMALL then dLmax = dL dUmax = dU end end if abs( dUmax - dUi) > GEO.EPS_ZERO then EgtChangeClosedCurveStart( nCrvId, dUmax) end return true end ------------------------------------------------------------------------------------------------------------- -- nNearSide : 2=Y+, -2=Y-, 3=Z+, -3=Z- function BeamLib.PutStartNearestToEdge( nCrvId, b3Raw, dMaxDist, nNearSide) -- verifico che la curva sia chiusa if not EgtCurveIsClosed( nCrvId) then return false end -- recupero il versore normale al piano di lavoro o estrusione local vtN = EgtCurveExtrusion( nCrvId, GDB_ID.ROOT) -- coefficienti per riportare la distanza nel piano di lavoro local dCoeffY = 0 if abs( vtN:getY()) < 0.999 then dCoeffY= 1 / ( sqrt( 1 - vtN:getY() * vtN:getY())) end local dCoeffZ = 0 if abs( vtN:getZ()) < 0.999 then dCoeffZ = 1 / ( sqrt( 1 - vtN:getZ() * vtN:getZ())) end -- cerco l'estremo più vicino al box e lo imposto come inizio (se da sotto escludo Zmax e viceversa) local dUopt = 0 local dDopt = GEO.INFINITO local dSopt = GEO.INFINITO local dUi, dUf = EgtCurveDomain( nCrvId) for dU = dUi, dUf, 0.5 do local ptP = EgtUP( nCrvId, dU, GDB_ID.ROOT) local vtDp = EgtUV( nCrvId, dU, -1, GDB_ID.ROOT) local vtDs = EgtUV( nCrvId, dU, 1, GDB_ID.ROOT) local bTg = ( vtDp and vtDs and vtDp * vtDs > 0.96) if ptP and bTg then local vtMin = ptP - b3Raw:getMin() local vtMax = ptP - b3Raw:getMax() local dD = abs( vtMin:getY()) * dCoeffY dD = min( abs( vtMax:getY()) * dCoeffY, dD) dD = min( abs( vtMin:getZ()) * dCoeffZ, dD) dD = min( abs( vtMax:getZ()) * dCoeffZ, dD) local dS if nNearSide == -2 then dS = abs( vtMin:getY() * dCoeffY) elseif nNearSide == 2 then dS = abs( vtMax:getY() * dCoeffY) elseif nNearSide == -3 then dS = abs( vtMin:getZ() * dCoeffZ) else --nNearSide == 3 dS = abs( vtMax:getZ() * dCoeffZ) end if dD < dMaxDist and dS < dSopt + GEO.EPS_SMALL then dUopt = dU dDopt = dD dSopt = dS end end end if abs( dUopt - dUi) > GEO.EPS_ZERO and abs( dUopt - dUf) > GEO.EPS_ZERO then EgtChangeClosedCurveStart( nCrvId, dUopt) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetPointDirDepth( nPartId, ptP, vtDir) -- recupero il solido del grezzo local nSolId = EgtGetFirstNameInGroup( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, 'Box') if not nSolId then return end -- interseco con la retta local bOk, vType, vPar = EgtLineSurfTmInters( ptP, vtDir, nSolId, GDB_RT.GLOB) if not bOk then return end if not vPar or #vPar == 0 then return -2 end local dLenIn, dLenOut for i = 1, #vPar do if vPar[i] < 0 then if vType[i] == GDB_SLT.IN or vType[i] == GDB_SLT.TG_INI then dLenIn = -1 end if vType[i] == GDB_SLT.OUT or vType[i] == GDB_SLT.TG_FIN then dLenIn = -2 end else if vType[i] == GDB_SLT.IN or vType[i] == GDB_SLT.TG_INI then dLenIn = vPar[i] end if vType[i] == GDB_SLT.OUT or vType[i] == GDB_SLT.TG_FIN or vType[i] == GDB_SLT.TOUCH then dLenOut = vPar[i] end end end return dLenIn, dLenOut end --------------------------------------------------------------------- function BeamLib.GetNearestParalOpposite( vtRef, vtNorm) -- se definita anche la normale alla faccia, elimino la parte di vtRef parallela a questa local vtMyRef = Vector3d( vtRef) if vtNorm then vtMyRef = vtMyRef - ( vtMyRef * vtNorm) * vtNorm vtMyRef:normalize() end -- se prevalente una componente orizzontale (con piccolissimo vantaggio) if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getZ()) or abs( vtMyRef:getY()) > 0.95 * abs( vtMyRef:getZ()) then if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getY()) then if vtMyRef:getX() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_LEFT else return MCH_MILL_FU.PARAL_RIGHT end else if vtMyRef:getY() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_FRONT else return MCH_MILL_FU.PARAL_BACK end end -- altrimenti prevale la verticale else if vtMyRef:getZ() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_DOWN else return MCH_MILL_FU.PARAL_TOP end end return nil end --------------------------------------------------------------------- function BeamLib.GetNearestOrthoOpposite( vtRef, vtNorm) -- se definita anche la normale alla faccia, elimino la parte di vtRef parallela a questa local vtMyRef = Vector3d( vtRef) if vtNorm then vtMyRef = vtMyRef - ( vtMyRef * vtNorm) * vtNorm vtMyRef:normalize() end -- se prevalente una componente orizzontale (con piccolissimo vantaggio) if abs( vtMyRef:getX()) > 0.91 * abs( vtMyRef:getZ()) or abs( vtMyRef:getY()) > 0.91 * abs( vtMyRef:getZ()) then -- se prevale la componente destra/sinistra if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getY()) then if vtMyRef:getX() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_LEFT else return MCH_MILL_FU.ORTHO_RIGHT end else if vtMyRef:getY() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_FRONT else return MCH_MILL_FU.ORTHO_BACK end end -- altrimenti prevale la verticale else if vtMyRef:getZ() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_DOWN else return MCH_MILL_FU.ORTHO_TOP end end return nil end --------------------------------------------------------------------- function BeamLib.GetOrtupOpposite( nOrthoOpposite) if nOrthoOpposite == MCH_MILL_FU.ORTHO_LEFT then return MCH_MILL_FU.ORTUP_LEFT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_RIGHT then return MCH_MILL_FU.ORTUP_RIGHT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_FRONT then return MCH_MILL_FU.ORTUP_FRONT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_BACK then return MCH_MILL_FU.ORTUP_BACK elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_DOWN then return MCH_MILL_FU.ORTUP_DOWN elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_TOP then return MCH_MILL_FU.ORTUP_TOP end return nil end --------------------------------------------------------------------- function BeamLib.GetParallelOpposite( nOrthoOpposite) if nOrthoOpposite == MCH_MILL_FU.ORTHO_LEFT then return MCH_MILL_FU.PARAL_LEFT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_RIGHT then return MCH_MILL_FU.PARAL_RIGHT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_FRONT then return MCH_MILL_FU.PARAL_FRONT elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_BACK then return MCH_MILL_FU.PARAL_BACK elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_DOWN then return MCH_MILL_FU.PARAL_DOWN elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_TOP then return MCH_MILL_FU.PARAL_TOP end return nil end --------------------------------------------------------------------- function BeamLib.GetVersRef( nOrthoOpposite) if nOrthoOpposite == MCH_MILL_FU.ORTHO_LEFT or nOrthoOpposite == MCH_MILL_FU.ORTUP_LEFT or nOrthoOpposite == MCH_MILL_FU.PARAL_LEFT then return X_AX() elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_RIGHT or nOrthoOpposite == MCH_MILL_FU.ORTUP_RIGHT or nOrthoOpposite == MCH_MILL_FU.PARAL_RIGHT then return -X_AX() elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_FRONT or nOrthoOpposite == MCH_MILL_FU.ORTUP_FRONT or nOrthoOpposite == MCH_MILL_FU.PARAL_FRONT then return Y_AX() elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_BACK or nOrthoOpposite == MCH_MILL_FU.ORTUP_BACK or nOrthoOpposite == MCH_MILL_FU.PARAL_BACK then return -Y_AX() elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_DOWN or nOrthoOpposite == MCH_MILL_FU.ORTUP_DOWN or nOrthoOpposite == MCH_MILL_FU.PARAL_DOWN then return Z_AX() elseif nOrthoOpposite == MCH_MILL_FU.ORTHO_TOP or nOrthoOpposite == MCH_MILL_FU.ORTUP_TOP or nOrthoOpposite == MCH_MILL_FU.PARAL_TOP then return -Z_AX() end return nil end --------------------------------------------------------------------- function BeamLib.GetBoxFaceNorm( b3Box, ptP, vtV) local vtNx = V_NULL() if abs( ptP:getX() - b3Box:getMin():getX()) < 10 * GEO.EPS_SMALL then vtNx = -X_AX() elseif abs( ptP:getX() - b3Box:getMax():getX()) < 10 * GEO.EPS_SMALL then vtNx = X_AX() end local vtNy = V_NULL() if abs( ptP:getY() - b3Box:getMin():getY()) < 10 * GEO.EPS_SMALL then vtNy = -Y_AX() elseif abs( ptP:getY() - b3Box:getMax():getY()) < 10 * GEO.EPS_SMALL then vtNy = Y_AX() end local vtNz = V_NULL() if abs( ptP:getZ() - b3Box:getMin():getZ()) < 10 * GEO.EPS_SMALL then vtNz = -Z_AX() elseif abs( ptP:getZ() - b3Box:getMax():getZ()) < 10 * GEO.EPS_SMALL then vtNz = Z_AX() end local dNxDotV = vtNx * vtV local dNyDotV = vtNy * vtV local dNzDotV = vtNz * vtV if dNxDotV > dNyDotV and dNxDotV > dNzDotV then return vtNx elseif dNyDotV > dNzDotV then return vtNy else return vtNz end end --------------------------------------------------------------------- function BeamLib.GetFaceElevation( procOrProcId, nFacet, b3Solid) local Proc, nProcId if type( procOrProcId) == "table" then Proc = procOrProcId nProcId = Proc.Id else nProcId = procOrProcId end local dElevation if not Proc or not Proc.Face or not Proc.Face[nFacet + 1].Elevation then dElevation = EgtSurfTmFacetElevationInBBox( nProcId, nFacet, b3Solid, true, GDB_ID.ROOT) else dElevation = Proc.Face[nFacet + 1].Elevation end return dElevation end --------------------------------------------------------------------- function BeamLib.GetFaceElevationFromPointDir( nSurfId, nPartId, ptC, vtN, nIdGeomMaster) if not ptC or not vtN then return 0 end -- riferimento OCS della faccia per ricavare elevazione rispetto alla faccia della superficie local frOCS = Frame3d( ptC, vtN) local b3Box = EgtGetBBoxRef( nSurfId, GDB_BB.STANDARD, frOCS) local dElev = b3Box:getMax():getZ() -- se definito identificativo di pezzo if nPartId then -- se superficie con più facce if EgtSurfTmFacetCount( nSurfId) > 1 then _, dElev = BeamLib.GetPointDirDepth( nPartId, ptC, vtN) else local b3Solid = EgtGetBBoxRef( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD, frOCS) if b3Solid and b3Solid:getMax():getZ() > dElev then dElev = b3Solid:getMax():getZ() end end end return dElev end --------------------------------------------------------------------- function BeamLib.GetFaceWithMostAdj( Proc, nPartId, bCompare3Fc, dCosSideAng) local nSurfId = Proc.Id local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) -- verifica che la superficie non sia chiusa e quindi non lavorabile if EgtSurfIsClosed( nSurfId) then return end -- recupero il numero di facce local nFacCnt = EgtSurfTmFacetCount( nSurfId) if not dCosSideAng then dCosSideAng = -0.09 end -- recupero le normali delle facce local vvtN = {} local vPtC = {} for i = 1, nFacCnt do local ptC, vtN = EgtSurfTmFacetCenter( nSurfId, i - 1, GDB_ID.ROOT) vvtN[i] = vtN ; vPtC[i] = ptC end -- adiacenze e sottosquadra delle facce local vAdj = {} local vUcut = {} local vOrtho = {} local nFacesWithUnderCut = 0 for i = 1, nFacCnt do -- recupero le adiacenze del loop esterno local vFacAdj = EgtSurfTmFacetAdjacencies( nSurfId, i - 1)[1] -- le conto local nCount = 0 for j = 1, #vFacAdj do if vFacAdj[j] >= 0 then nCount = nCount + 1 end end vAdj[i] = nCount -- ne determino eventuale sottosquadro ( dal valore passato o - 3deg) e ortogonalità, per facce adiacenti local bUcut = false local bOrtho = true for j = 1, #vFacAdj do if vFacAdj[j] >= 0 then local vtN = vvtN[i] local vtN2 = vvtN[vFacAdj[j]+1] local dResV = vtN * vtN2 if dResV < dCosSideAng - GEO.EPS_SMALL then bUcut = true end if abs( dResV) > 2 * GEO.EPS_SMALL then bOrtho = false end end end -- determino evenutale sottosquadro per facce non adiacenti for j = 1, nFacCnt do local bIsFaceAdjacent = false for k = 1, #vFacAdj do if j - 1 == vFacAdj[k] then bIsFaceAdjacent = true break end end if not ( bIsFaceAdjacent or ( j == i)) then -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( nPartId) if not nAddGrpId then EgtOutLog( 'Error : missing AddGroup') return 0, 0, 0, 0 end -- verifico eventuale intersezione tra la faccia i-1 esima e la proiezione dell'altra sulla stessa local nShadowFacetId = EgtCopySurfTmFacet( nSurfId, j - 1, nAddGrpId) local nMasterContourId = EgtExtractSurfTmFacetLoops( nSurfId, i - 1, nAddGrpId) local nShadowContourId = EgtExtractSurfTmLoops( nShadowFacetId, nAddGrpId) EgtCutSurfTmPlane( nShadowFacetId, vPtC[i], -vvtN[i], false, GDB_RT.GLOB) if nMasterContourId and nShadowContourId then local nMasterSurfFlatId = EgtSurfFlatRegion( nAddGrpId, nMasterContourId) local frOCSMaster = Frame3d( vPtC[i], vvtN[i]) EgtScale( nShadowContourId, frOCSMaster, 1, 1, 0, GDB_RT.GLOB) EgtModifyCurveExtrusion( nShadowContourId, vvtN[i], GDB_RT.GLOB) local nShadowSurfFlatId -- se non troppo ortogonale (almeno 0.5deg di delta) local dResV = vvtN[i] * vvtN[j] if abs( dResV) > 0.087 then EgtOffsetCurve( nShadowContourId, EgtIf( dResV > GEO.EPS_SMALL, - 50, 50) * GEO.EPS_SMALL) local nShadowSurfFlatId = EgtSurfFlatRegion( nAddGrpId, nShadowContourId) local bShadowSurfIsExternal = EgtSurfFrTestExternal( nMasterSurfFlatId, nShadowSurfFlatId) if not bShadowSurfIsExternal then bUcut = true end EgtErase( nShadowSurfFlatId) end EgtErase( nMasterSurfFlatId) end EgtErase( { nMasterContourId, nShadowContourId, nShadowFacetId}) end end if bUcut then nFacesWithUnderCut = nFacesWithUnderCut + 1 end vUcut[i] = bUcut vOrtho[i] = bOrtho end local bEveryFaceHasUndercut = ( nFacesWithUnderCut == nFacCnt) -- tunnel o assimilabile if Proc.Topology == 'Tunnel' or ( bCompare3Fc and Proc.Topology == 'Groove' and Proc.IsThrough and not (Proc.AffectedFaces.Left or Proc.AffectedFaces.Right)) or ( Proc.Topology == 'Strip' and bEveryFaceHasUndercut) then if Proc.IsParallel or Proc.AllRightAngles then return -1, GEO.INFINITO, true else -- non gestito nella LapJoint return -1, GEO.INFINITO end end -- recupero le facce non in sottosquadra e con il maggior numero di adiacenze local nFacInd = {} local nMaxAdj = -1 local nSupAdj = -1 for i = 1, nFacCnt do if not vUcut[i] then if vAdj[i] > nMaxAdj then nFacInd = {} nFacInd[1] = i - 1 nMaxAdj = vAdj[i] elseif vAdj[i] == nMaxAdj and nMaxAdj > 0 then table.insert( nFacInd, i - 1) end end if vAdj[i] > nSupAdj then nSupAdj = vAdj[i] end end -- verifico non ci sia una faccia in sottosquadra con adiacenza superiore if nSupAdj > nMaxAdj then return -2, GEO.INFINITO end -- premio la faccia con minore elevazione local nFacOpt, nFacOpt2 local dMinElev, dMinElev2 = GEO.INFINITO, GEO.INFINITO local dtElev = {} for i = 1, #nFacInd do local dElev = BeamLib.GetFaceElevation( Proc, nFacInd[i], b3Solid) table.insert( dtElev, dElev) if dElev < dMinElev then if dMinElev < dMinElev2 then nFacOpt2 = nFacOpt dMinElev2 = dMinElev end nFacOpt = nFacInd[i] dMinElev = dElev elseif dElev < dMinElev2 then nFacOpt2 = nFacInd[i] dMinElev2 = dElev end end -- faccio una ulteriore verifica -- se le elevazioni di max 3 facce sono in un range minimo o al di sotto dell'elevazione ritenuta fattibile, -- premio quella che non è sottosquadra e che ha la X minore local bDiffSmall = true for i = 1, #dtElev do if ( dtElev[i] > dMinElev + 5 or dtElev[i] > 80) and dMinElev < 0.85 * dtElev[i] then bDiffSmall = false end end -- se tutte sono nel range minimo posso prendere la faccia che ha la componente Z magiore, e se sono uguali, prendo quella con componente X minore local dMaxZ, dMaxZ2 = -1.1, -1.1 if bDiffSmall and #nFacInd <= 3 then for i = 1, #nFacInd do if vvtN[nFacInd[i]+1]:getZ() > dMaxZ then if dMaxZ > dMaxZ2 then nFacOpt2 = nFacOpt dMinElev2 = dMinElev dMaxZ2 = dMaxZ end nFacOpt = nFacInd[i] dMinElev = dtElev[i] dMaxZ = vvtN[nFacInd[i]+1]:getZ() elseif vvtN[nFacInd[i]+1]:getZ() > dMaxZ2 then nFacOpt2 = nFacInd[i] dMinElev2 = dtElev[i] dMaxZ2 = vvtN[nFacInd[i]+1]:getZ() end end -- se hanno uguale Z premio quella con la componente X minore if abs( dMaxZ - dMaxZ2) < 10*GEO.EPS_SMALL then if abs(vvtN[nFacOpt+1]:getX()) > abs(vvtN[nFacOpt2+1]:getX()) then nFacOpt, nFacOpt2 = nFacOpt2, nFacOpt dMinElev, dMinElev2 = dMinElev2, dMinElev end end end return nFacOpt, dMinElev, nFacOpt2, dMinElev2 end --------------------------------------------------------------------- --- ritorna il riferimento di tipo OCS della faccia *nFacet* della trimesh *nSurfId* e le dimensioni orizzontale e verticale, eventualmente limitate dal grezzo *b3Raw* ---@param nSurfId integer Id della trimesh ---@param nFacet integer Indice 0-based della faccia della trimesh di cui restituire le informazioni ---@param b3Raw? BBox3d Eventuale box del grezzo per limitare le dimensioni ---@return Frame3d frHv riferimento faccia OCS ---@return number dDimH dimensione orizzontale OCS ---@return number dDmiV dimensione verticale OCS function BeamLib.GetFaceHvRefDim( nSurfId, nFacet, b3Raw) -- recupero centro e normale della faccia local ptC, vtN = EgtSurfTmFacetCenter( nSurfId, nFacet, GDB_ID.ROOT) if not ptC or not vtN then return end -- riferimento tipo OCS della faccia (X orizz, Y max pendenza, Z normale) local frHV = Frame3d( ptC, vtN) if frHV:getVersY():getZ() < 0 then frHV:rotate( ptC, vtN, 180) end -- determino l'ingombro in questo riferimento local b3HV = EgtSurfTmGetFacetBBoxRef( nSurfId, nFacet, GDB_BB.STANDARD, frHV) local dDimH = b3HV:getDimX() local dDimV = b3HV:getDimY() -- Si mantiene rettangolo minimo perchè in alcuni casi andava in collisione. Lascio il calcolo in caso si debba ripristinare. -- se definito grezzo (o solido), applico eventuali limiti -- if b3Raw then -- local dCoeffY = abs( frHV:getVersX():getY()) -- if dCoeffY > GEO.EPS_SMALL then -- dDimH = min( dDimH, b3Raw:getDimY() / dCoeffY) -- end -- local dCoeffZ = abs( frHV:getVersY():getZ()) -- if dCoeffZ > GEO.EPS_SMALL then -- dDimV = min( dDimV, b3Raw:getDimZ() / dCoeffZ) -- end -- end -- restituisco i valori calcolati return frHV, dDimH, dDimV end ------------------------------------------------------------------------------------------------------------- function BeamLib.UpdateHCING( nRawId, dHCI, dDist) local dOldHCI = EgtGetInfo( nRawId, 'HCING', 'd') or 0 if dDist and dDist > dOldHCI + 0.1 then return end if dHCI > dOldHCI then EgtSetInfo( nRawId, 'HCING', dHCI) end end ------------------------------------------------------------------------------------------------------------- function BeamLib.UpdateTCING( nRawId, dTCI) local dOldTCI = EgtGetInfo( nRawId, 'TCING', 'd') or 0 if dTCI > dOldTCI then EgtSetInfo( nRawId, 'TCING', dTCI) end end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetNzLimDownUp( b3Raw, vtN, vtOrtho) if BD.GetNzLimDownUp then return BD.GetNzLimDownUp( b3Raw, vtN, vtOrtho) elseif BD.C_SIMM then return -0.484 elseif BD.TURN then return -2 else if vtOrtho and vtOrtho:getZ() > 0.35 then -- N_HorAng < 15° or N_HorAng > 55° if vtN and ( abs( vtN:getY()) < 0.259 or abs( vtN:getY()) > 0.819) then return -0.708 -- N_HorAng > 50° elseif vtN and abs( vtN:getY()) > 0.766 then return -0.383 else return EgtIf( b3Raw:getDimZ() < BD.MIN_DIM_HBEAM, -0.609, -0.383) end else -- N_HorAng > 60° if vtN and ( abs( vtN:getY()) > 0.866) then return -0.708 else if b3Raw:getDimZ() < 120 then return -0.708 elseif b3Raw:getDimZ() < 200 then -- N_HorAng < 15° or N_HorAng > 55° if vtN and ( abs( vtN:getY()) < 0.259 or abs( vtN:getY()) > 0.819) then return -0.5 else return -0.383 end elseif b3Raw:getDimZ() < 300 then -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.5 else return -0.259 end elseif b3Raw:getDimZ() < BD.MIN_DIM_HBEAM then -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.342 else return -0.259 end else -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.383 else return -0.174 end end end end end end ------------------------------------------------------------------------------------------------------------- function BeamLib.IsSplittedPartPhase( nPhase) local sVal = BeamLib.GetPhaseType( nPhase) return ( sVal == 'END' or sVal == 'MID2' or sVal == 'END2') end ------------------------------------------------------------------------------------------------------------- function BeamLib.IsPartFinalPhase( nPhase) local sVal = BeamLib.GetPhaseType( nPhase) return ( sVal == 'END' or sVal == 'END2') end --------------------------------------------------------------------- function BeamLib.GetPhaseType( nPhase) return ( EgtGetInfo( EgtGetPhaseDisposition( nPhase) or GDB_ID.NULL, 'TYPE') or '') end --------------------------------------------------------------------- function BeamLib.GetDistanceToNextPart( nRawId, nPhase) -- Recupero la distanza tra la fine del pezzo e il pezzo successivo local dDistToNextPiece = EgtGetInfo( nRawId, 'BDST', 'd') or BD.OVM_MID -- se segue una parte rimanente riutilizzabile, modifico opportunamente questa distanza if not BeamLib.IsSplittedPartPhase( nPhase) then local nNextRawId = EgtGetNextRawPart( nRawId) if nNextRawId and EgtGetPartInRawPartCount( nNextRawId) <= 0 and EgtGetRawPartBBox( nNextRawId):getDimX() >= BD.MinRaw then dDistToNextPiece = BD.OVM_MID end end return dDistToNextPiece end --------------------------------------------------------------------- function BeamLib.GetChainSawInitAngs( vtN, vtO, nInd) if BD.GetChainSawInitAngs then return BD.GetChainSawInitAngs( vtN, vtO, nInd) else if BD.C_SIMM then return EgtIf( vtN:getY() > 0, 'C=180', 'C=-180') else if nInd == 1 then return '' else return EgtIf( vtN:getY() > 0, 'C=180', 'C=-180') end end end end --------------------------------------------------------------------- --- ---@param sMachining string nome della lavorazione di cui bloccare l'asse ---@param sBlockedAxis string rappresenta lo stato desiderato dell'asse bloccato, parallelo o perpendicolare all'asse rotante da cui dipende (*parallel* o *perpendicular*) ---@param b3Raw? BBox3d ---@param vtTool? Vector3d ---@param vtOut? Vector3d ---@return string # testo contenente il valore dell'asse rotante bloccato da scrivere nel parametro *MCH_MP.BLOCKEDAXIS* della lavorazione (es: 'A2=90') function BeamLib.GetBlockedAxis( sMachining, sBlockedAxis, b3Raw, vtTool, vtOut) -- informazioni sull'utensile della lavorazione local nToolType, sHead if EgtMdbSetCurrMachining( sMachining) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then nToolType = EgtTdbGetCurrToolParam( MCH_TP.TYPE) sHead = EgtTdbGetCurrToolParam( MCH_TP.HEAD) end end -- se presente funzione specifica nella macchina, la richiamo if BD.GetBlockedAxis then return BD.GetBlockedAxis( sHead, nToolType, sBlockedAxis, b3Raw, vtTool, vtOut) or '' -- sezione mantenuta per retrocompatibilità con GetChainSawBlockedAxis elseif nToolType == MCH_TY.MORTISE_STD then local nInd = EgtIf( sBlockedAxis == 'parallel', 0, 1) if BD.GetChainSawBlockedAxis then return BD.GetChainSawBlockedAxis( nInd) else if nInd == 1 then return EgtIf( BD.C_SIMM, 'A=90', 'A=90') else return EgtIf( BD.C_SIMM, 'A=0', 'A=0') end end end return '' end --------------------------------------------------------------------- -- Trova l'Ind (0 based) della faccia meglio orientata come l'asse vtAx. Restituisce anche vtN e ptC della faccia stessa. La faccia di indice (0 based) fctExclude non viene considerata nella ricerca. function BeamLib.FindFaceBestOrientedAsAxis( Proc, vtAx, fctExclude) local nFaceIndMax = 0 local dMaxComp = 0 fctExclude = fctExclude or -1 for i = 1, Proc.Fct do local vtN = EgtSurfTmFacetNormVersor( Proc.Id, i - 1, GDB_ID.ROOT) local dComp = abs( vtN * vtAx) if dComp > dMaxComp and i ~= fctExclude + 1 then nFaceIndMax = i -1 dMaxComp = dComp end end local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, nFaceIndMax, GDB_ID.ROOT) return nFaceIndMax, ptC, vtN end --------------------------------------------------------------------- function BeamLib.GetEdgeToMachineFromVector( nSurfId, nFacet, vtOrtho) local _, EdgesEgt = EgtSurfTmGetFacetOutlineInfo( nSurfId, nFacet, GDB_ID.ROOT) local nEdgeIndMax = 0 local dMaxComp = - GEO.INFINITO for i = 1, #EdgesEgt do local vtN = EdgesEgt[i].Norm if EdgesEgt[i].Open then vtN = -vtN end local dComp = vtN * vtOrtho if dComp > dMaxComp then nEdgeIndMax = i -1 dMaxComp = dComp end end return nEdgeIndMax end --------------------------------------------------------------------- function BeamLib.GetTunnelDimension( Proc, nPartId) -- sono necessarie almeno due facce if Proc.Fct < 2 then return 0, 0, 0 end -- recupero l'ingombro della trave local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( nPartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) -- recupero centro e normale delle facce local ptC = {} local vtN = {} for i = 1, Proc.Fct do ptC[i], vtN[i] = EgtSurfTmFacetCenter( Proc.Id, i - 1, GDB_ID.ROOT) end -- calcolo l'orientamento del tunnel local vtOrtho local bAdj = EgtSurfTmFacetsContact( Proc.Id, 0, 1) if bAdj then vtOrtho = vtN[1] ^ vtN[2] else if Proc.Fct >= 3 then vtOrtho = vtN[1] ^ vtN[3] else return 0, 0, 0 end end -- ottengo il boundingBox e prendo le dimensioni lungo la direzione (Z locale) che rappresenta la profondità della fessura local frFc = Frame3d( ptC[1], vtOrtho) ; local b3BoxLoc = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, frFc) local dDepth = b3BoxLoc:getDimZ() -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( nPartId) if not nAddGrpId then EgtOutLog( 'Error : missing AddGroup') return 0, 0, 0 end -- centro del bounding box locale local ptCen = b3BoxLoc:getCenter() ptCen:toGlob( frFc) -- creo superficie intermedia local nSurfInt = EgtSurfTmPlaneInBBox( nAddGrpId, ptCen, vtOrtho, b3Solid, GDB_ID.ROOT) if not nSurfInt then return 0, 0, 0 end -- ritaglio la superficie con le facce della fessura for i = 1, Proc.Fct do EgtCutSurfTmPlane( nSurfInt, ptC[i], -vtN[i], false, GDB_ID.ROOT) end local frSurfInt, dDimMax, dDimMin = EgtSurfTmFacetMinAreaRectangle( nSurfInt, 0, GDB_ID.ROOT) -- cerco la faccia con larghezza pari a dimensione massima della fessura local nLongIdFace = 0 for i = 1, Proc.Fct do if abs( vtN[i] * frSurfInt:getVersX()) < 0.5 then nLongIdFace = i - 1 break end end return dDimMin, dDimMax, dDepth, vtOrtho, nLongIdFace, nSurfInt end --------------------------------------------------------------------- function BeamLib.CalcCollisionSafety( vtDir) local dCollSic = 10 * BD.COLL_SIC if abs( vtDir:getX()) > 0.999 or abs( vtDir:getY()) > 0.999 or abs( vtDir:getZ()) > 0.999 then dCollSic = 0 elseif abs( vtDir:getX()) > 0.996 or abs( vtDir:getY()) > 0.996 or abs( vtDir:getZ()) > 0.996 then dCollSic = 1 * BD.COLL_SIC elseif abs( vtDir:getX()) > 0.89 or abs( vtDir:getY()) > 0.89 or abs( vtDir:getZ()) > 0.89 then dCollSic = 2.5 * BD.COLL_SIC elseif abs( vtDir:getX()) > 0.86 or abs( vtDir:getY()) > 0.86 or abs( vtDir:getZ()) > 0.86 then dCollSic = 4 * BD.COLL_SIC elseif abs( vtDir:getX()) > 0.707 or abs( vtDir:getY()) > 0.707 or abs( vtDir:getZ()) > 0.707 then dCollSic = 5.5 * BD.COLL_SIC end return dCollSic end --------------------------------------------------------------------- function BeamLib.SetOpenSide( nPathInt, b3Solid) -- fondo tra loro le curve compatibili EgtMergeCurvesInCurveCompo( nPathInt) -- vettore indici lati aperti local vOpen = {} -- ciclo sulle curve elementari della composita local _, nNumEnt = EgtCurveDomain( nPathInt) for i = 0, nNumEnt - 1 do -- se segmento di retta if EgtCurveCompoRadius( nPathInt, i) == -1 then -- verifico se giace in uno dei piani limite del pezzo quindi se è un lato aperto local ptIni = EgtUP( nPathInt, i, GDB_RT.GLOB) local ptFin = EgtUP( nPathInt, i + 1, GDB_RT.GLOB) if ( abs( ptIni:getX() - b3Solid:getMax():getX()) < 100 * GEO.EPS_SMALL and abs( ptFin:getX() - b3Solid:getMax():getX()) < 100 * GEO.EPS_SMALL) or ( abs( ptIni:getX() - b3Solid:getMin():getX()) < 100 * GEO.EPS_SMALL and abs( ptFin:getX() - b3Solid:getMin():getX()) < 100 * GEO.EPS_SMALL) or ( abs( ptIni:getY() - b3Solid:getMax():getY()) < 100 * GEO.EPS_SMALL and abs( ptFin:getY() - b3Solid:getMax():getY()) < 100 * GEO.EPS_SMALL) or ( abs( ptIni:getY() - b3Solid:getMin():getY()) < 100 * GEO.EPS_SMALL and abs( ptFin:getY() - b3Solid:getMin():getY()) < 100 * GEO.EPS_SMALL) or ( abs( ptIni:getZ() - b3Solid:getMax():getZ()) < 100 * GEO.EPS_SMALL and abs( ptFin:getZ() - b3Solid:getMax():getZ()) < 100 * GEO.EPS_SMALL) or ( abs( ptIni:getZ() - b3Solid:getMin():getZ()) < 100 * GEO.EPS_SMALL and abs( ptFin:getZ() - b3Solid:getMin():getZ()) < 100 * GEO.EPS_SMALL) then -- aggiorno il vettore dei lati aperti table.insert( vOpen, i) end end end -- assegno gli indici dei lati aperti EgtSetInfo( nPathInt, 'OPEN', vOpen) return true end --------------------------------------------------------------------- function BeamLib.ChangeOrOpenStart( nPathInt, nStartPoint) -- verifico richiesta if nStartPoint ~= 1 and nStartPoint ~= 2 then return false end -- verifico che la curva sia chiusa if not EgtCurveIsClosed( nPathInt) then return true end -- recupero l'indice del segmento aperto più lungo local nMaxOpen, dMaxLen local vOpen = EgtGetInfo( nPathInt or GDB_ID.NULL, 'OPEN', 'vi') for i = 1, #( vOpen or {}) do -- se primo o più lungo, lo salvo local dLen = EgtCurveCompoLength( nPathInt, vOpen[i]) if not dMaxLen or dLen > dMaxLen then dMaxLen = dLen nMaxOpen = vOpen[i] end end -- se esiste tratto aperto if nMaxOpen then -- sposto il punto di inizio a metà del tratto aperto più lungo (la curva deve essere chiusa) EgtChangeClosedCurveStart( nPathInt, nMaxOpen + 0.5) -- aggiorno il vettore dei lati aperti for i = 1, #vOpen do vOpen[i] = vOpen[i] - nMaxOpen end table.insert( vOpen, #vOpen) -- se devo eliminare gli estremi aperti if nStartPoint == 2 then -- elimino gli estremi EgtRemoveCurveCompoCurve( nPathInt, true) EgtRemoveCurveCompoCurve( nPathInt, false) -- aggiorno il vettore dei lati aperti table.remove( vOpen, 1) table.remove( vOpen) for i = 1, #vOpen do vOpen[i] = vOpen[i] - 1 end end end -- assegno gli indici modificati dei lati aperti EgtSetInfo( nPathInt, 'OPEN', vOpen) -- restituisco flag percorso aperto return ( not EgtCurveIsClosed( nPathInt)) end ------------------------------------------------------------------------------------------------------------- function BeamLib.ConvertToClosedCurve( Proc, AuxId) local bCurveModified = false if not EgtCurveIsClosed( AuxId) then local NewId, nCount = EgtExtractSurfTmFacetLoops( Proc.Id, 0, EgtGetParent( Proc.Id)) if NewId then -- elimino eventuali loop interni (non dovrebbero comunque esserci) for i = 1, nCount - 1 do EgtErase( NewId + i) end local vtExtr = EgtCurveExtrusion( AuxId, GDB_ID.ROOT) -- sostituisco il loop esterno alla curva originale EgtModifyCurveExtrusion( NewId, vtExtr, GDB_ID.ROOT) EgtRelocate( NewId, AuxId, GDB_IN.AFTER) EgtErase( AuxId) EgtChangeId( NewId, AuxId) bCurveModified = true -- sistemo i lati aperti local vFacAdj = EgtSurfTmFacetAdjacencies( Proc.Id, 0)[1] if vFacAdj then local vOpen = {} for i = 1, #vFacAdj do if vFacAdj[i] < 0 then table.insert( vOpen, i - 1) end end EgtSetInfo( AuxId, 'OPEN', vOpen) end end end return true, bCurveModified end --------------------------------------------------------------------- function BeamLib.CurveWithOnlyStraightLines( nPathInt) -- verifico sia una retta oppure una curva composita local nType = EgtGetType( nPathInt) if nType == GDB_TY.CRV_LINE then return true elseif nType~= GDB_TY.CRV_COMPO then return false end -- ciclo sulle curve elementari della composita local _, nNumEnt = EgtCurveDomain( nPathInt) for i = 0, nNumEnt - 1 do -- se segmento di retta if EgtCurveCompoRadius( nPathInt, i) ~= -1 then return false end end return true end --------------------------------------------------------------------- -- Funzione per determinare se la faccia ha lati molto corti (trascurabili) ed è quindi approssimabile ad una 3 facce function BeamLib.Is3EdgesApprox( Proc, nFacet, nAddGrpId) nAddGrpId = nAddGrpId or BeamLib.GetAddGroup( Proc.PartId) if not nAddGrpId then local nEdges = #(EgtSurfTmFacetAdjacencies( Proc.Id, nFacet)[1]) return ( nEdges == 3) end local bResult = false local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Proc.Id, nFacet, nAddGrpId) if not nContourId then return false end EgtMergeCurvesInCurveCompo( nContourId) -- recupero il numero effettivo di lati local _, nEntityCount = EgtCurveDomain( nContourId) local nEdges = nEntityCount if nEntityCount and nEntityCount == 3 then bResult = true -- rimuovo i lati molto corti dal conteggio totale elseif nEntityCount then for i = 1, nEntityCount do local dLength = EgtCurveCompoLength( nContourId, i - 1) if dLength < 15 then nEdges = nEdges - 1 end end end if nEdges == 3 then bResult = true end -- cancello tutti i contorni appena creati EgtErase( EgtTableFill( nContourId, nContourCnt)) return bResult end ------------------------------------------------------------------------------------------------------------- function BeamLib.IsPointOnBoxLimits( ptPoint, b3Solid) local dTol = 500 * GEO.EPS_SMALL local dMinX = b3Solid:getMin():getX() local dMinY = b3Solid:getMin():getY() local dMinZ = b3Solid:getMin():getZ() local dMaxX = b3Solid:getMax():getX() local dMaxY = b3Solid:getMax():getY() local dMaxZ = b3Solid:getMax():getZ() -- Check di ogni piano limite if abs( ptPoint:getX() - dMinX) < dTol then return true, "Left" end if abs( ptPoint:getX() - dMaxX) < dTol then return true, "Right" end if abs( ptPoint:getY() - dMinY) < dTol then return true, "Front" end if abs( ptPoint:getY() - dMaxY) < dTol then return true, "Back" end if abs( ptPoint:getZ() - dMinZ) < dTol then return true, "Bottom" end if abs( ptPoint:getZ() - dMaxZ) < dTol then return true, "Top" end return false end ------------------------------------------------------------------------------------------------------------- -- restituisce le facce della parte interessate dalla feature Proc function BeamLib.GetProcessAffectedFaces( Proc) local nBoxSolidId = EgtGetFirstNameInGroup( Proc.PartId or GDB_ID.NULL, 'Box') local b3Part = EgtGetBBoxGlob( nBoxSolidId, GDB_BB.STANDARD) local vtFacesAffected = { Top = false, Bottom = false, Front = false, Back = false, Left = false, Right = false} if Proc.Box and not Proc.Box:isEmpty() then if Proc.Box:getMax():getZ() > b3Part:getMax():getZ() - 500 * GEO.EPS_SMALL then vtFacesAffected.Top = true end if Proc.Box:getMin():getZ() < b3Part:getMin():getZ() + 500 * GEO.EPS_SMALL then vtFacesAffected.Bottom = true end if Proc.Box:getMin():getY() < b3Part:getMin():getY() + 500 * GEO.EPS_SMALL then vtFacesAffected.Front = true end if Proc.Box:getMax():getY() > b3Part:getMax():getY() - 500 * GEO.EPS_SMALL then vtFacesAffected.Back = true end if Proc.Box:getMin():getX() < b3Part:getMin():getX() + 500 * GEO.EPS_SMALL then vtFacesAffected.Left = true end if Proc.Box:getMax():getX() > b3Part:getMax():getX() - 500 * GEO.EPS_SMALL then vtFacesAffected.Right = true end end return vtFacesAffected end ------------------------------------------------------------------------------------------------------------- -- restituisce vero se la feature con box b3Proc taglia l'intera sezione della barra, rappresentata dalle sue dimensioni W e H function BeamLib.IsFeatureCuttingEntireSection( b3Proc, dRawW, dRawH) return ( b3Proc:getDimY() > ( dRawW - 500 * GEO.EPS_SMALL) and b3Proc:getDimZ() > ( dRawH - 500 * GEO.EPS_SMALL)) end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetAdjacentFaces( Proc, nFacet) local AdjacentFaces = {} local vFaceAdjacencies = EgtSurfTmFacetAdjacencies( Proc.Id, nFacet)[1] for i = 1, #vFaceAdjacencies do if vFaceAdjacencies[i] > -1 then local _, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, nFacet, vFaceAdjacencies[i], GDB_ID.ROOT) local dLen = dist( ptP1, ptP2) table.insert( AdjacentFaces, { Id = vFaceAdjacencies[i], LengthOnMainFace = dLen}) end end return AdjacentFaces end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetFacetsInfo( Proc, b3Raw) if Proc.Fct > 20 then return nil end local Face = {} local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.PartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) local vAdj if Proc.AdjacencyMatrix then vAdj = Proc.AdjacencyMatrix else vAdj = BeamLib.GetAdjacencyMatrix( Proc) end for i = 1, Proc.Fct do Face[i] = {} Face[i].Id = i - 1 Face[i].PtCenter, Face[i].VtN = EgtSurfTmFacetCenter( Proc.Id, i - 1, GDB_ID.ROOT) if Proc.Fct < 10 then local frHV, dFaceWidthTrimmed, dFaceHeightTrimmed = BeamLib.GetFaceHvRefDim( Proc.Id, i - 1, b3Raw) -- frame OCS faccia Face[i].FrameHV = frHV -- larghezza OCS faccia trimmata con grezzo Face[i].WidthTrimmed = dFaceWidthTrimmed -- altezza OCS faccia trimmata con grezzo Face[i].HeightTrimmed = dFaceHeightTrimmed local _, dFaceWidth, dFaceHeight = BeamLib.GetFaceHvRefDim( Proc.Id, i - 1) -- larghezza OCS faccia Face[i].Width = dFaceWidth -- altezza OCS faccia Face[i].Height = dFaceHeight -- elevazione calcolata rispetto al box della parte Face[i].Elevation = EgtSurfTmFacetElevationInBBox( Proc.Id, i - 1, b3Solid, true, GDB_ID.ROOT) -- area della faccia -- TODO qui sarebbe meglio l'area vera e non quella del rettangolo minimo local _, dLongEdgeDimension, dShortEdgeDimension = EgtSurfTmFacetMinAreaRectangle( Proc.Id, i - 1, GDB_ID.ROOT) Face[i].Area = dShortEdgeDimension * dLongEdgeDimension -- adiacenze della faccia -- TODO chiamarle in modo che si capisca che sono solo gli id e non l'intero oggetto faccia Face[i].Adjacencies = {} for j = 1, Proc.Fct do if vAdj[i][j] and vAdj[i][j] ~= 0 and ( i ~= j) then table.insert( Face[i].Adjacencies, j - 1) end end end end return Face end --------------------------------------------------------------------- function BeamLib.GetEdgesInfo( Proc, Face) local Edges = {} local nFaceType, vEdges = EgtSurfTmGetFacetOutlineInfo( Proc.Id, Face.Id, GDB_ID.ROOT) if nFaceType < 1 then for j = 1, #vEdges do local nPreviousEdgeIndex = j - 1 if j == 1 then nPreviousEdgeIndex = #vEdges end local nNextEdgeIndex = j + 1 if j == #vEdges then nNextEdgeIndex = 1 end local CurrentEdge = {} CurrentEdge.AdjacentFaceId = vEdges[j].Adj CurrentEdge.ToolDirection = Vector3d( vEdges[j].Norm) CurrentEdge.Length = vEdges[j].Len CurrentEdge.Elevation = vEdges[j].Elev CurrentEdge.IsOpen = vEdges[j].Open CurrentEdge.IsStartOpen = ( vEdges[nPreviousEdgeIndex].Open) CurrentEdge.IsEndOpen = ( vEdges[nNextEdgeIndex].Open) table.insert( Edges, CurrentEdge) end else error( 'Face with closed hole') end return Edges end --------------------------------------------------------------------- -- restituisce la matrice delle adiacenze di Proc dove i e j sono le facce e a(ij) è l'angolo tra di esse; 0 se nessuna adiacenza function BeamLib.GetAdjacencyMatrix( Proc) local vAdj = {} -- essendo la matrice simmetrica a diagonale nulla, ne calcolo solo la metà superiore for i = 1, Proc.Fct do vAdj[i] = {} for j = i + 1, Proc.Fct do _, _, _, vAdj[i][j] = EgtSurfTmFacetsContact( Proc.Id, i - 1, j - 1, GDB_ID.ROOT) if not vAdj[i][j] then vAdj[i][j] = 0 end end end -- riempio di conseguenza il resto della matrice for i = 1, Proc.Fct do vAdj[i][i] = 0 for j = i + 1, Proc.Fct do vAdj[j][i] = vAdj[i][j] end end return vAdj end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetMachiningSteps( dMachiningDepth, dStep) local MachiningSteps = {} MachiningSteps.StepLength = 0 MachiningSteps.Count = ceil( ( dMachiningDepth - 10 * GEO.EPS_SMALL) / dStep) if MachiningSteps.Count > 1 then MachiningSteps.StepLength = ( dMachiningDepth - dStep) / ( MachiningSteps.Count - 1) end return MachiningSteps end ------------------------------------------------------------------------------------------------------------- function BeamLib.IsCutNeeded( Proc, b3Raw, dOvmHead, dOvmTail) if not dOvmTail then dOvmTail = BD.OVM_MID end local ptC, vtN = EgtSurfTmFacetCenter( Proc.Id, 0, GDB_ID.ROOT) if Proc.Head then -- se coincide con il taglio di separazione precedente, non va fatto if AreSameVectorApprox( vtN, X_AX()) and abs( ptC:getX() - b3Raw:getMax():getX() + dOvmHead) < 10 * GEO.EPS_SMALL then return false end -- altrimenti taglio di coda else -- se coincide con taglio di separazione, non va fatto if AreSameVectorApprox( vtN, - X_AX()) and abs( ptC:getX() - b3Raw:getMin():getX()) < dOvmTail + 10 * GEO.EPS_SMALL then return false end end -- se coincide con un taglio frontale non va fatto if Proc.CutFront then return false end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetToolFromMachining( sMachiningName) local Tool = {} if EgtMdbSetCurrMachining( sMachiningName) then local sTuuid = EgtMdbGetCurrMachiningParam( MCH_MP.TUUID) if EgtTdbSetCurrTool( EgtTdbGetToolFromUUID( sTuuid) or '') then Tool.Name = EgtTdbGetCurrToolParam( MCH_TP.NAME) Tool.IsCCW = ( EgtMdbGetCurrMachiningParam( MCH_MP.SPEED) < 0) Tool.Type = EgtTdbGetCurrToolParam( MCH_TP.TYPE) Tool.Diameter = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or 0 Tool.HeadType = {} Tool.PreferredSide = {} if BD.GetSetupInfo then Tool.HeadType = BD.GetSetupInfo( EgtTdbGetCurrToolParam( MCH_TP.HEAD)).HeadType Tool.PreferredSide = BD.GetSetupInfo( EgtTdbGetCurrToolParam( MCH_TP.HEAD)).PreferredSide end -- lama if Tool.Type == MCH_TY.SAW_STD or Tool.Type == MCH_TY.SAW_FLAT then Tool.Thickness = EgtTdbGetCurrToolParam(MCH_TP.THICK) or 0 Tool.MaxDepth = EgtTdbGetCurrToolMaxDepth() or 0 Tool.SideStep = EgtTdbGetCurrToolValInNotes( MCH_TP.USERNOTES, 'SIDESTEP', 'd') -- sega a catena elseif Tool.Type == MCH_TY.MORTISE_STD then Tool.Length = EgtTdbGetCurrToolParam( MCH_TP.LEN) or 0 Tool.MaxMat = EgtTdbGetCurrToolParam( MCH_TP.MAXMAT) or 0 Tool.Width = EgtTdbGetCurrToolParam( MCH_TP.DIAM) or 0 Tool.Thickness = EgtTdbGetCurrToolParam( MCH_TP.THICK) or 0 Tool.CornerRadius = EgtTdbGetCurrToolParam( MCH_TP.CORNRAD) or 0 -- fresa (TODO al momento aggiunte solo le informazioni che servono) elseif Tool.Type == MCH_TY.MILL_STD or MCH_TY.MILL_NOTIP then if BD.GetSetupInfo then Tool.IsOnAggregate = BD.GetSetupInfo( EgtTdbGetCurrToolParam( MCH_TP.HEAD)).bToolOnAggregate else Tool.IsOnAggregate = false end Tool.StemDiameter = EgtTdbGetCurrToolParam( MCH_TP.STEMDIAM) or 0 Tool.MaxDepth = EgtTdbGetCurrToolMaxDepth() or 0 if Tool.StemDiameter > Tool.Diameter + GEO.EPS_SMALL then Tool.MaxDepth = Tool.MaxDepth - BD.COLL_SIC end -- altri utensili al momento non previsti else error( 'Wrong tool type') end end end return Tool end ------------------------------------------------------------------------------------------------------------- --- copia una tabella lua in modo ricorsivo, ossia mantiene indipendenti anche tutte le sottotabelle --- ATTENZIONE: in caso di modifiche vanno gestiti anche i tipi custom; sarebbe meglio metterla nel LuaLibs function BeamLib.TableCopyDeep( OriginalTable) -- controllo se oggetto passato è valido, altrimenti errore. Non deve mai succedere if not OriginalTable then error( "TableCopyDeep : can't copy nil object") end local CopiedTable = {} for key, value in pairs( OriginalTable) do if type( value) == "table" then if isBBox3d( value) then CopiedTable[ key] = BBox3d( value) elseif isColor3d( value) then CopiedTable[ key] = Color3d( value) elseif isFrame3d( value) then CopiedTable[ key] = Frame3d( value) elseif isPoint3d( value) then CopiedTable[ key] = Point3d( value) elseif isQuaternion( value) then CopiedTable[ key] = Quaternion( value) elseif isVector3d( value) then CopiedTable[ key] = Vector3d( value) else CopiedTable[ key] = BeamLib.TableCopyDeep( value) end else CopiedTable[ key] = value end end return CopiedTable end ------------------------------------------------------------------------------------------------------------- return BeamLib