-- FaceData.lua by Egalware s.r.l. 2024/04/18 -- Libreria lettura o calcolo dati e proprietà delle facce di una trimesh -- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE -- Tabella per definizione modulo local FaceData = {} -- carico librerie local BeamLib = require( 'BeamLib') --------------------------------------------------------------------- -- 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 FaceData.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 --------------------------------------------------------------------- -- restituisce un vettore con gli indici (0 based) delle facce triangolari (o quasi) di Proc function FaceData.GetTriangularFaces( Proc) local vTriangularFaces = {} for i = 1, Proc.Fct do if BeamLib.Is3EdgesApprox( Proc, i - 1) then table.insert( vTriangularFaces, i - 1) end end return vTriangularFaces end ------------------------------------------------------------------------------------------------------------- local function GetAdjacentFaces( Proc, idFace) local AdjacentFaces = {} local vAdj if Proc.AdjacencyMatrix then vAdj = Proc.AdjacencyMatrix else vAdj = FaceData.GetAdjacencyMatrix( Proc) end for i = 1, Proc.Fct do if vAdj[idFace + 1][i] and vAdj[idFace + 1][i] ~= 0 and ( idFace + 1 ~= i) then AdjacentFaces[i] = {} AdjacentFaces[i].Id = i - 1 end end return AdjacentFaces end --------------------------------------------------------------------- local function GetFacesContactLength( Proc, idFace1, idFace2) local _, ptP1, ptP2 = EgtSurfTmFacetsContact( Proc.Id, idFace1, idFace2, GDB_ID.ROOT) local dLength = dist( ptP1, ptP2) return dLength end --------------------------------------------------------------------- -- restituisce una tabella che correla numero di adiacenze e id delle facce con quello stesso numero di adiacenze function FaceData.GetFacesByAdjacencyNumber( Proc) local FacesByAdjacencyNumber = {} for i = 1, Proc.Fct do if not FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies] then FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies] = {} end table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], i - 1) end return FacesByAdjacencyNumber end ------------------------------------------------------------------------------------------------------------- function FaceData.GetFacesInfo( Proc) local Faces = {} local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.PartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) for i = 1, Proc.Fct do Faces[i] = {} Faces[i].Id = i - 1 Faces[i].PtCenter, Faces[i].VtN = EgtSurfTmFacetCenter( Proc.Id, i - 1, GDB_ID.ROOT) if Proc.Fct < 6 then local frHV, dFaceWidth, dFaceHeight = BeamLib.GetFaceHvRefDim( Proc.Id, i - 1) -- frame OCS faccia Faces[i].FrameHV = frHV -- larghezza OCS faccia Faces[i].Width = dFaceWidth -- altezza OCS faccia Faces[i].Height = dFaceHeight -- elevazione calcolata rispetto al box della parte Faces[i].Elevation = EgtSurfTmFacetElevationInBBox( Proc.Id, i - 1, b3Solid, true, GDB_ID.ROOT) -- adiacenze della faccia Faces[i].Adjacencies = GetAdjacentFaces( Proc, i - 1) end end return Faces end ------------------------------------------------------------------------------------------------------------- local function GetFaceInfoFromId( Proc, idFace) local Face = {} if not Proc.Faces then Proc.Faces = FaceData.GetFacesInfo( Proc) end Face.Id = idFace Face.FrameHV = Proc.Faces[Face.Id + 1].FrameHV Face.Width = Proc.Faces[Face.Id + 1].Width Face.Height = Proc.Faces[Face.Id + 1].Height Face.Elevation = Proc.Faces[Face.Id + 1].Elevation Face.VtN = Proc.Faces[Face.Id + 1].VtN return Face end ------------------------------------------------------------------------------------------------------------- -- TODO valutare se local function GetTunnelFaces( Proc) local TunnelAddedFaces = {} -- TODO scrivere il box della parte nella Proc o fare funzione per recuperarlo local b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.PartId, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD) if not ( Proc.Topology.IsThrough and Proc.Fct < 5) then error( 'GetTunnelFaces : Topology not implemented') end -- direzione del tunnel local vtTunnelDirection = Proc.Faces[1].VtN ^ Proc.Faces[Proc.Faces[1].AdjacentFaces[1].Id + 1].VtN -- centro del tunnel local frTunnel = Frame3d( Proc.Faces[1].PtCenter, vtTunnelDirection) local b3Tunnel = EgtGetBBoxRef( Proc.Id, GDB_BB.STANDARD, frTunnel) local ptTunnelCenter = b3Tunnel:getCenter() ptTunnelCenter:toGlob( frTunnel) -- recupero gruppo per geometria addizionale local nAddGrpId = BeamLib.GetAddGroup( Proc.PartId) if not nAddGrpId then -- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste? EgtOutLog( 'Error : missing AddGroup') return TunnelAddedFaces end -- faccia centrale, si crea larga come la parte e poi si trimma TunnelAddedFaces.MiddleFaceTm.Id = EgtSurfTmPlaneInBBox( nAddGrpId, ptTunnelCenter, vtTunnelDirection, b3Part, GDB_ID.ROOT) -- TODO se non si riesce a costruire la faccia bisogna dare errore o semplicemente non ritornarla?? for i = 1, Proc.Fct do EgtCutSurfTmPlane( TunnelAddedFaces.MiddleFaceTm.Id, Proc.Faces[i].PtCenter, -Proc.Faces[i].VtN, false, GDB_ID.ROOT) end return TunnelAddedFaces end ------------------------------------------------------------------------------------------------------------- local function GetBottomFace( Proc) local BottomFace = {} if Proc.Topology.Family == 'Tunnel' then return BottomFace elseif not ( Proc.FeatureTopology.Family == 'Rabbet' or Proc.FeatureTopology.Family == 'VGroove' or Proc.FeatureTopology.Family == 'Groove' or Proc.FeatureTopology.Family == 'Pocket') then error( 'GetBottomFace : Topology not implemented') end -- la faccia di fondo ha sempre Fct - 1 adiacenze. Se si trovano più facce di fondo si sceglie quella con minor elevazione local vFacesByAdjNumber = FaceData.GetFacesByAdjacencyNumber( Proc) local vBottomFace = vFacesByAdjNumber[ Proc.Fct - 1] local idBottomFace if #vBottomFace > 1 then local dMinElevation = GEO.INFINITO for i = 1, #vBottomFace do for j = 1, Proc.Fct do if vBottomFace[i] == Proc.Faces[j].Id then if Proc.Faces[j].Elevation < dMinElevation then dMinElevation = Proc.Faces[j].Elevation idBottomFace = Proc.Faces[j].Id end end end end else idBottomFace = vBottomFace[1] end BottomFace = GetFaceInfoFromId( Proc, idBottomFace) return BottomFace end ------------------------------------------------------------------------------------------------------------- local function GetLongFaces( Proc, MainFaces) local LongFaces = {} if Proc.Fct > 5 then error( 'GetLongFaces : Topology not implemented') end local idBottomFace = GDB_ID.NULL if MainFaces.BottomFace then idBottomFace = MainFaces.BottomFace.Id else local BottomFace = GetBottomFace( Proc) idBottomFace = BottomFace.Id or idBottomFace end local idTunnelMiddleFace = GDB_ID.NULL if Proc.Topology.Family == 'Tunnel' then if MainFaces.TunnelAddedFaces then idTunnelMiddleFace = MainFaces.TunnelAddedFaces.MiddleFaceTm.Id else local TunnelAddedFaces = GetTunnelFaces( Proc) idTunnelMiddleFace = TunnelAddedFaces.MiddleFaceTm.Id or idTunnelMiddleFace end end local FacesToAnalyze = {} for i = 1, Proc.Fct do if Proc.Faces[i].Id ~= idBottomFace then FacesToAnalyze[i] = Proc.Faces[i] if Proc.Topology.Family == 'Tunnel' then FacesToAnalyze[i].LengthOnMainFace = GetFacesContactLength( Proc, idTunnelMiddleFace, Proc.Faces[i].Id) else FacesToAnalyze[i].LengthOnMainFace = GetFacesContactLength( Proc, idBottomFace, Proc.Faces[i].Id) end end end table.sort( FacesToAnalyze, function( a, b) return a.LengthOnMainFace > b.LengthOnMainFace end) -- la prima faccia lunga è sempre la prima della lista LongFaces[1].Id = FacesToAnalyze[1].Id -- si cerca l'eventuale seconda faccia lunga, ossia quella non adiacente alla prima if Proc.Fct > 3 then for i = 1, #FacesToAnalyze do if ( i - 1) ~= idBottomFace and ( i - 1) ~= LongFaces[1].Id then local bIsAdjacent = false for j = 1, #FacesToAnalyze[i].Adjacences do if FacesToAnalyze[i].Adjacences[j].Id == LongFaces[i].Id then bIsAdjacent = true end end if not bIsAdjacent then LongFaces[2].Id = i - 1 break end end end end for i = 1, #LongFaces do LongFaces[i] = GetFaceInfoFromId( Proc, LongFaces[i].Id) end return LongFaces end ------------------------------------------------------------------------------------------------------------- -- recupero facce principali della feature, in base alla topologia function FaceData.GetMainFaces( Proc) local MainFaces = {} if Proc.Topology.IsThrough and Proc.Fct < 5 then MainFaces.TunnelAddedFaces = GetTunnelFaces( Proc) end if Proc.Topology.Family == 'Rabbet' or Proc.Topology.Family == 'VGroove' or Proc.Topology.Family == 'Groove' or Proc.Topology.Family == 'Pocket' then MainFaces.BottomFace = GetBottomFace( Proc) MainFaces.LongFaces = GetLongFaces( Proc, MainFaces) end return MainFaces end ------------------------------------------------------------------------------------------------------------- return FaceData