-- WFeatureTopology.lua by Egaltech s.r.l. 2023/06/23 -- Libreria per classificazione topologica feature pareti -- 2023/12/11 Modifiche varie per allineamento con Beam. -- Tabella per definizione modulo local WFeatureTopology = {} -- Include require( 'EgtBase') -- Carico le librerie local WL = require( 'WallLib') EgtOutLog( ' WFeatureTopology started', 1) --------------------------------------------------------------------- -- 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 local function GetAdjacencyMatrix( Proc) local vAdj = {} for i = 1, Proc.Fct do vAdj[i] = {} for j = 1, Proc.Fct do if i == j then vAdj[i][j] = 0 else _, _, _, 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 j = j + 1 end i = i + 1 end return vAdj end --------------------------------------------------------------------- -- restituisce gli id delle facce di Proc che hanno il numero di adiacenze nAdj function WFeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, nAdj) local vAdj = GetAdjacencyMatrix( Proc) local vFacesWithGivenAdj = {} for i = 1, Proc.Fct do local nAdjCount = 0 for j = 1, Proc.Fct 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( Proc) local vAdj = GetAdjacencyMatrix( Proc) local bAllConcave, bAllRight = true, true for i = 1, Proc.Fct do for j = 1, Proc.Fct 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 Proc.Fct < 2 or ( Proc.Fct == 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 WL.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, bIsThrough) 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' or sFamily == 'Tunnel' or ( sFamily == 'Groove' and bIsThrough) 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 WFeatureTopology.Classify( Proc, b3Raw) if not Proc.AffectedFaces then Proc.AffectedFaces = WL.GetProcessAffectedFaces( Proc) end if not Proc.Box or Proc.Box:isEmpty() then return false end local bRecognized = false local sFamily local bIsThrough local bAllRightAngles local bIsParallel local sLongName = '' -- SE NON HA TUTTE LE FACCE PIANE RITORNARE NIL!! local bAllAnglesConcave bAllAnglesConcave, bAllRightAngles = AreAllAnglesConcaveOrRight( Proc) local vTriangularFaces = GetTriangularFaces( Proc) local bIsAnyDimensionLongAsPart = IsAnyDimensionLongAsPart( Proc) local vFacesWithOneAdj = WFeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, 1) local vFacesWithTwoAdj = WFeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, 2) local vFacesWithThreeAdj = WFeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, 3) local vFacesWithFourAdj = WFeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, 4) local dRawW, dRawH, dRawL = b3Raw:getDimY(), b3Raw:getDimZ(), b3Raw:getDimX() local bIsFeatureCuttingEntireSection = WL.IsFeatureCuttingEntireSection( Proc.Box, dRawW, dRawH, dRawL) if Proc.IsOutline then sFamily = 'OUTLINE' elseif Proc.Prc == 40 then sFamily = 'DRILLING' elseif 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 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 local vFacesParallelToPart = GetFacesParallelToPart( Proc, sFamily, bIsThrough) bIsParallel = ( #vFacesParallelToPart == Proc.Fct) if sFamily == 'OUTLINE' or sFamily == 'DRILLING' then Proc.Topology = sFamily Proc.TopologyLongName = sFamily bRecognized = true elseif sFamily then sLongName = GetTopologyLongName( sFamily, bIsThrough, bAllRightAngles, bIsParallel, Proc.Fct) Proc.Topology, Proc.IsThrough, Proc.AllRightAngles, Proc.IsParallel, Proc.TopologyLongName = sFamily, bIsThrough, bAllRightAngles, bIsParallel, sLongName bRecognized = true else Proc.Topology = 'OTHER' Proc.TopologyLongName = 'OTHER' end return bRecognized end ------------------------------------------------------------------------------------------------------------- return WFeatureTopology