-- FeatureTopology.lua by Egaltech s.r.l. 2023/09/12 -- Libreria per classificazione topologica feature travi -- 2023/09/26 Aggiunte topologie Strip e Cut. -- 2023/09/27 Modificata GetFacesParallelToPart per tunnel, pocket e groove 3 lati -- 2023/10/16 In GetFacesParallelToPart rimossa Pocket e aggiunto Rabbet al check solo direzione principale -- 2023/11/03 In Classify ora si settano le AffectedFaces nella Proc, se non già presenti. -- Aggiunta groove 2 facce, differenziata da rabbet. -- 2024/03/04 Feature senza topologia, calcolato in BeamExec -- 2024/05/06 A topologia Cut aggiunta IsThrough = true -- Tabella per definizione modulo local FeatureTopology = {} -- Include require( 'EgtBase') -- Carico le librerie local BL = require( 'BeamLib') EgtOutLog( ' FeatureTopology started', 1) --------------------------------------------------------------------- -- restituisce gli id delle facce di Proc che hanno il numero di adiacenze nAdj function FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, nAdj) if not vAdj then vAdj = BL.GetAdjacencyMatrix( Proc) end local nFct = #( vAdj or {}) local vFacesWithGivenAdj = {} for i = 1, nFct do local nAdjCount = 0 for j = 1, nFct do if vAdj[i][j] and vAdj[i][j] ~= 0 then nAdjCount = nAdjCount + 1 end end if nAdjCount == nAdj then table.insert( vFacesWithGivenAdj, i - 1) end end return vFacesWithGivenAdj end --------------------------------------------------------------------- -- restituisce true se Proc ha tutti gli angoli concavi (bAllConcave) e, nei casi in cui ha senso, se questi sono esattamente 90 deg (bAllRight) local function AreAllAnglesConcaveOrRight( vAdj) local bAllConcave, bAllRight = true, true local nFct = #( vAdj or {}) for i = 1, nFct do for j = 1, nFct do -- se trovo un angolo convesso restituisco falso e esco subito if vAdj[i][j] and vAdj[i][j] > 0 then bAllConcave = false bAllRight = false break elseif vAdj[i][j] and vAdj[i][j] ~= 0 and vAdj[i][j] + 90 > 500 * GEO.EPS_ANG_SMALL then bAllRight = false end end end -- se 1 faccia oppure 2 facce con angolo convesso non ha senso ritornare valori per bAllRight if nFct < 2 or ( nFct == 2 and vAdj[1][2] > 0) then return bAllConcave else return bAllConcave, bAllRight end end --------------------------------------------------------------------- -- restituisce true se almeno una delle dimensioni della feature è maggiore o uguale ad una delle dimensioni principali del pezzo (tolleranza 1 mm) local function IsAnyDimensionLongAsPart( Proc) local bResult = false local nBoxSolidId = EgtGetFirstNameInGroup( Proc.PartId or GDB_ID.NULL, 'Box') local b3Solid = EgtGetBBoxGlob( nBoxSolidId, GDB_BB.STANDARD) if Proc.Box:getDimX() > b3Solid:getDimX() - 1000 * GEO.EPS_SMALL or Proc.Box:getDimY() > b3Solid:getDimY() - 1000 * GEO.EPS_SMALL or Proc.Box:getDimZ() > b3Solid:getDimZ() - 1000 * GEO.EPS_SMALL then bResult = true end return bResult end --------------------------------------------------------------------- -- retituisce un vettore con gli indici (0 based) delle facce triangolari (o quasi) di Proc local function GetTriangularFaces( Proc) local vTriangularFaces = {} for i = 1, Proc.Fct do if BL.Is3EdgesApprox( Proc, i - 1) then table.insert( vTriangularFaces, i - 1) end end return vTriangularFaces end --------------------------------------------------------------------- -- restituisce un vettore contenente gli indici delle facce di Proc parallele ad una delle direzioni principali; il check varia in base alla famiglia topologica local function GetFacesParallelToPart( Proc, sFamily) local vFacesParallelToPart = {} for i = 0, Proc.Fct - 1 do local vtN = EgtSurfTmFacetNormVersor( Proc.Id, i, GDB_ID.ROOT) if sFamily == 'Rabbet' or sFamily == 'Bevel' or sFamily == 'DoubleBevel' or sFamily == 'Strip' then local vTriangularFaces = GetTriangularFaces( Proc) local bIsTriangularFace = false -- verifico se la faccia è triangolare for j = 1, #vTriangularFaces do if i == vTriangularFaces[j] then bIsTriangularFace = true end end -- se faccia triangolare deve avere la normale parallela ad una direzione principale if bIsTriangularFace then if AreSameOrOppositeVectorApprox( vtN, X_AX()) or AreSameOrOppositeVectorApprox( vtN, Y_AX()) or AreSameOrOppositeVectorApprox( vtN, Z_AX()) then table.insert( vFacesParallelToPart, i) end -- altrimenti deve avere una componente della normale nulla else if abs( vtN:getX()) < 10 * GEO.EPS_SMALL or abs( vtN:getY()) < 10 * GEO.EPS_SMALL or abs( vtN:getZ()) < 10 * GEO.EPS_SMALL then table.insert( vFacesParallelToPart, i) end end else -- la normale deve essere parallela ad una direzione principale if AreSameOrOppositeVectorApprox( vtN, X_AX()) or AreSameOrOppositeVectorApprox( vtN, Y_AX()) or AreSameOrOppositeVectorApprox( vtN, Z_AX()) then table.insert( vFacesParallelToPart, i) end end end return vFacesParallelToPart end --------------------------------------------------------------------- -- restituisce una stringa con il nome esteso della topologia della feature -- *famiglia-passante-angoli tutti concavi a 90deg-facce tutte parallele alle dimensioni principali-numero di facce* local function GetTopologyLongName( sFamily, bIsThrough, bAllRightAngles, bIsParallel, nNumberOfFaces) -- feature passante o cieca local sThrough = '_' if bIsThrough ~= nil then sThrough = EgtIf( bIsThrough, 'Through', 'Blind') end -- tutti gli angoli della feature sono retti oppure no local sAllRightAngles = '_' if bAllRightAngles ~= nil then sAllRightAngles = EgtIf( bAllRightAngles, 'RightAngles', 'NotRightAngles') end -- tutte le dimensioni della feature sono parallele agli assi principali del pezzo oppure no local sParallel = '_' if bIsParallel ~= nil then sParallel = EgtIf( bIsParallel, 'Parallel', 'NotParallel') end local sLongName = sFamily .. '-' .. sThrough .. '-' .. sAllRightAngles .. '-' .. sParallel .. '-' .. nNumberOfFaces return sLongName end --------------------------------------------------------------------- -- riconosce se Proc è una delle topologie standard e, in caso positivo, ne scrive le caratteristiche in campi specifici della Proc stessa restituendo true function FeatureTopology.Classify( Proc, b3Raw) -- la feature deve avere geometria if not Proc.Box or Proc.Box:isEmpty() then return false end -- se già calcolato, esco if Proc.Topology then return true end -- calcoli if not Proc.AffectedFaces then Proc.AffectedFaces = BL.GetProcessAffectedFaces( Proc) end if not Proc.Face then Proc.Face = BL.GetFacetsInfo( Proc, b3Raw) end local vAdj = Proc.AdjacencyMatrix or BL.GetAdjacencyMatrix( Proc) local bAllAnglesConcave, bAllRightAngles = AreAllAnglesConcaveOrRight( vAdj) local vTriangularFaces = GetTriangularFaces( Proc) local bIsAnyDimensionLongAsPart = IsAnyDimensionLongAsPart( Proc) local vFacesWithOneAdj = FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, 1) local vFacesWithTwoAdj = FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, 2) local vFacesWithThreeAdj = FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, 3) local vFacesWithFourAdj = FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, 4) local dRawW = b3Raw:getDimY() local dRawH = b3Raw:getDimZ() local bIsFeatureCuttingEntireSection = BL.IsFeatureCuttingEntireSection( Proc.Box, dRawW, dRawH) -- assegnazione tipologia local sFamily local bIsThrough if Proc.Fct == 1 and bIsAnyDimensionLongAsPart and bIsFeatureCuttingEntireSection then sFamily = 'Cut' bIsThrough = true elseif Proc.Fct == 1 and bIsAnyDimensionLongAsPart then sFamily = 'Bevel' bIsThrough = true elseif Proc.Fct == 2 and bAllAnglesConcave and #vTriangularFaces == 1 then sFamily = 'Bevel' bIsThrough = false elseif Proc.Fct == 2 and bAllAnglesConcave and ( Proc.AffectedFaces.Left or Proc.AffectedFaces.Right) and ( Proc.AffectedFaces.Front or Proc.AffectedFaces.Back) then sFamily = 'Rabbet' bIsThrough = true -- birdsmouth elseif Proc.Fct == 2 and bAllAnglesConcave then sFamily = 'Groove' bIsThrough = true elseif Proc.Fct == 2 and not bAllAnglesConcave and bIsAnyDimensionLongAsPart then sFamily = 'DoubleBevel' bIsThrough = true elseif Proc.Fct == 3 and bAllAnglesConcave and #vFacesWithTwoAdj == 1 and #vTriangularFaces == 2 then sFamily = 'Bevel' bIsThrough = false elseif Proc.Fct == 3 and bAllAnglesConcave and #vFacesWithTwoAdj == 1 and bIsAnyDimensionLongAsPart then sFamily = 'Groove' bIsThrough = true elseif Proc.Fct == 3 and bAllAnglesConcave and #vFacesWithTwoAdj == 3 then sFamily = 'Groove' bIsThrough = false elseif Proc.Fct == 4 and bAllAnglesConcave and #vFacesWithThreeAdj == 2 then sFamily = 'Groove' bIsThrough = false elseif Proc.Fct == 4 and bAllAnglesConcave and #vFacesWithTwoAdj == 4 and bIsAnyDimensionLongAsPart then sFamily = 'Tunnel' bIsThrough = true elseif Proc.Fct >= 4 and #vFacesWithOneAdj == 2 and bIsAnyDimensionLongAsPart then sFamily = 'Strip' bIsThrough = true elseif Proc.Fct == 5 and bAllAnglesConcave and #vFacesWithFourAdj == 1 then sFamily = 'Pocket' bIsThrough = false end -- verifico se facce parallele a quelle della trave local vFacesParallelToPart = GetFacesParallelToPart( Proc, sFamily) local bIsParallel = ( #vFacesParallelToPart == Proc.Fct) -- assegnazioni if sFamily then Proc.Topology = sFamily Proc.TopologyLongName = GetTopologyLongName( sFamily, bIsThrough, bAllRightAngles, bIsParallel, Proc.Fct) Proc.IsThrough = bIsThrough Proc.AllRightAngles = bAllRightAngles Proc.IsParallel = bIsParallel Proc.vAdj = vAdj return true else Proc.Topology = 'OTHER' Proc.TopologyLongName = Proc.Topology return false end end ------------------------------------------------------------------------------------------------------------- return FeatureTopology