Files
databeamnew/LuaLibs/FaceData.lua
T
luca.mazzoleni 1a82df39ad - tutti i campi Id sostituiti con id (minuscolo)
- in FaceData aggiunta scrittura Edges (GetFaceInfo) e MainEdges (BottomFace e LongFaces)
2024-05-16 18:16:22 +02:00

469 lines
17 KiB
Lua

-- 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.nFct do
vAdj[i] = {}
for j = i + 1, Proc.nFct 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.nFct do
vAdj[i][i] = 0
for j = i + 1, Proc.nFct 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)
-- se la feature ha una sola faccia, esco subito
if Proc.nFct <= 1 then
return
end
local vTriangularFaces = {}
for i = 1, Proc.nFct do
if BeamLib.Is3EdgesApprox( Proc, i - 1) then
table.insert( vTriangularFaces, i - 1)
end
end
return vTriangularFaces
end
-------------------------------------------------------------------------------------------------------------
local function GetNotAdjacentFaces( Proc, idFace)
local NotAdjacentFaces = {}
for i = 1, Proc.nFct do
if Proc.Faces[i].id ~= idFace then
local bIsAdjacent = false
for j = 1, #Proc.Faces[idFace + 1].Adjacencies do
if Proc.Faces[i].id == Proc.Faces[idFace + 1].Adjacencies[j] then
bIsAdjacent = true
end
end
if not bIsAdjacent then
table.insert( NotAdjacentFaces, Proc.Faces[i])
end
end
end
return NotAdjacentFaces
end
---------------------------------------------------------------------
-- restituisce una tabella che correla numero di adiacenze e id delle facce con quello stesso numero di adiacenze
function FaceData.GetFacesByAdjacencyNumber( Proc)
-- se la feature ha una sola faccia, esco subito
if Proc.nFct <= 1 then
return
end
local FacesByAdjacencyNumber = {}
for i = 1, 10 do
FacesByAdjacencyNumber[i] = {}
end
for i = 1, Proc.nFct do
table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], Proc.Faces[i])
end
return FacesByAdjacencyNumber
end
-------------------------------------------------------------------------------------------------------------
function FaceData.GetFacesInfo( Proc, Part)
EgtOutLog( '---Faces START---')
local Faces = {}
local b3Solid = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.idPart, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
local vAdj
if Proc.AdjacencyMatrix then
vAdj = Proc.AdjacencyMatrix
else
vAdj = FaceData.GetAdjacencyMatrix( Proc)
end
-- reset eventuali visualizzazioni facce a due colori
EgtSurfTmResetTwoColors( Proc.id)
for i = 1, Proc.nFct do
Faces[i] = {}
Faces[i].id = i - 1
Faces[i].ptCenter, Faces[i].vtN = EgtSurfTmFacetCenter( Proc.id, i - 1, GDB_ID.ROOT)
if Proc.nFct < 6 then
local frHV, dFaceWidth, dFaceHeight = BeamLib.GetFaceHvRefDim( Proc.id, i - 1, Part)
-- frame OCS faccia
Faces[i].vtFrameHV = frHV
-- larghezza OCS faccia
Faces[i].dWidth = dFaceWidth
-- altezza OCS faccia
Faces[i].dHeight = dFaceHeight
-- elevazione calcolata rispetto al box della parte
Faces[i].dElevation = EgtSurfTmFacetElevationInBBox( Proc.id, i - 1, b3Solid, true, GDB_ID.ROOT)
-- TODO qui sarebbe meglio l'area vera e non quella del rettangolo minimo
local _, dLongEdgeDimension, dShortEdgeDimension = EgtSurfTmFacetMinAreaRectangle( Proc.id, i - 1, GDB_ID.ROOT)
Faces[i].dArea = dShortEdgeDimension * dLongEdgeDimension
local nFaceType, vEdges = EgtSurfTmGetFacetOutlineInfo( Proc.id, i - 1, GDB_ID.ROOT)
Faces[i].IsOkForMachining = nFaceType < 1
Faces[i].Edges = vEdges
-- TODO valutare se fare un output unico alla fine o gestire log in altro modo
EgtOutLog( 'Facet ' .. Faces[i].id .. ' of ' .. Proc.nFct - 1)
EgtOutLog( ' vtN: ' .. tostring( Faces[i].vtN))
-- adiacenze della faccia
-- TODO chiamarle in modo che si capisca che sono solo gli id e non l'intero oggetto faccia
Faces[i].Adjacencies = {}
for j = 1, Proc.nFct do
if vAdj[i][j] and vAdj[i][j] ~= 0 and ( i ~= j) then
table.insert( Faces[i].Adjacencies, j - 1)
if EgtGetDebugLevel() >= 3 then
EgtOutLog( ' Adjacent to facet: ' .. j - 1)
end
end
end
end
end
EgtOutLog( '---Faces END---')
return Faces
end
-------------------------------------------------------------------------------------------------------------
-- TODO valutare refactoring per mettere i calcoli del tunnel in una funzione
-- TODO valutare se restituire anche altre informazioni oltre alle facce (es: box); magari metterle in funzione a parte chiamata allo stesso livello della GetMainFAces
local function GetTunnelFaces( Proc)
local TunnelAddedFaces = {}
-- TODO scrivere il box della parte nella Proc o fare funzione per recuperarlo
local b3Part = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Proc.idPart, 'Box') or GDB_ID.NULL, GDB_BB.STANDARD)
if not ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5) then
error( 'GetTunnelFaces : Topology not implemented')
end
-- direzione del tunnel
local vtTunnelDirection = Proc.Faces[1].vtN ^ Proc.Faces[ Proc.Faces[1].Adjacencies[1] + 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.idPart)
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 = {}
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.nFct do
EgtCutSurfTmPlane( TunnelAddedFaces.MiddleFaceTm.id, Proc.Faces[i].ptCenter, -Proc.Faces[i].vtN, false, GDB_ID.ROOT)
end
TunnelAddedFaces.MiddleFaceTm.Type = 'Tunnel'
return TunnelAddedFaces
end
-------------------------------------------------------------------------------------------------------------
local function GetBottomFace( Proc)
local BottomFace = {}
if Proc.Topology.sFamily == 'Tunnel' then
return nil
elseif not ( Proc.Topology.sFamily == 'Rabbet' or Proc.Topology.sFamily == 'VGroove' or Proc.Topology.sFamily == 'Groove' or Proc.Topology.sFamily == '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 FacesByAdjacencyNumber = FaceData.GetFacesByAdjacencyNumber( Proc)
if FacesByAdjacencyNumber then
local BottomFaces = FacesByAdjacencyNumber[ Proc.nFct - 1]
if #BottomFaces > 1 then
local dMinElevation = GEO.INFINITO
for i = 1, #BottomFaces do
if Proc.Faces[BottomFaces[i].id + 1].dElevation < dMinElevation then
dMinElevation = Proc.Faces[BottomFaces[i].id + 1].dElevation
BottomFace = Proc.Faces[BottomFaces[i].id + 1]
end
end
else
BottomFace = BottomFaces[1]
end
end
if not BottomFace.IsOkForMachining then
return nil
end
BottomFace.Type = 'Bottom'
BottomFace.MainEdges = {}
BottomFace.MainEdges.LongEdges = {}
BottomFace.MainEdges.SideEdges = {}
local EdgesSortedByGreatestLength = {}
for i = 1, #BottomFace.Edges do
EdgesSortedByGreatestLength[i] = {}
EdgesSortedByGreatestLength[i].nIndex = i
EdgesSortedByGreatestLength[i].dLength = BottomFace.Edges[i].Len
end
table.sort( EdgesSortedByGreatestLength, function (a, b) return a.dLength > b.dLength end)
local nFirstLongEdgeIndex = EdgesSortedByGreatestLength[1].nIndex
for i = 1, #BottomFace.Edges do
local nPreviousEdgeIndex = i - 1
if i == 1 then
nPreviousEdgeIndex = #BottomFace.Edges
end
local nNextEdgeIndex = i + 1
if i == #BottomFace.Edges then
nNextEdgeIndex = 1
end
local CurrentEdge = {}
CurrentEdge.idAdjacentFace = BottomFace.Edges[i].Adj
CurrentEdge.vtToolDirection = Vector3d( BottomFace.Edges[i].Norm)
CurrentEdge.dLength = BottomFace.Edges[i].Len
CurrentEdge.dElevation = BottomFace.Edges[i].Elev
CurrentEdge.bIsOpen = BottomFace.Edges[i].Open
CurrentEdge.bIsStartOpen = BottomFace.Edges[nPreviousEdgeIndex].Open
CurrentEdge.bIsEndOpen = BottomFace.Edges[nNextEdgeIndex].Open
if i == nFirstLongEdgeIndex then
BottomFace.MainEdges.LongEdges[1] = CurrentEdge
BottomFace.MainEdges.LongEdges[1].Type = 'Long'
elseif nNextEdgeIndex == nFirstLongEdgeIndex then
BottomFace.MainEdges.SideEdges[1] = CurrentEdge
BottomFace.MainEdges.SideEdges[1].Type = 'Side'
elseif nPreviousEdgeIndex == nFirstLongEdgeIndex then
BottomFace.MainEdges.SideEdges[2] = CurrentEdge
BottomFace.MainEdges.SideEdges[2].Type = 'Side'
else
BottomFace.MainEdges.LongEdges[2] = CurrentEdge
BottomFace.MainEdges.LongEdges[2].Type = 'Long'
end
end
return BottomFace
end
-------------------------------------------------------------------------------------------------------------
local function GetLongFaces( Proc, MainFaces)
local LongFaces = {}
if Proc.nFct > 5 then
error( 'GetLongFaces : Topology not implemented')
end
local BottomFace = MainFaces.BottomFace or GetBottomFace( Proc)
local nFirstLongFaceId = GDB_ID.NULL
local nSecondLongFaceId = GDB_ID.NULL
if not BottomFace then
local FacesSortedByGreatestArea = {}
for i = 1, Proc.nFct do
FacesSortedByGreatestArea[i] = {}
FacesSortedByGreatestArea[i].id = Proc.Faces[i].id
FacesSortedByGreatestArea[i].dArea = Proc.Faces[i].dArea
end
table.sort( FacesSortedByGreatestArea, function (a, b) return a.dArea > b.dArea end)
nFirstLongFaceId = FacesSortedByGreatestArea[1].id
local FacesNotAdjacent = GetNotAdjacentFaces( Proc, nFirstLongFaceId)
nSecondLongFaceId = FacesNotAdjacent[1].id
else
if not BottomFace.MainEdges.LongEdges[1].bIsOpen then
nFirstLongFaceId = BottomFace.MainEdges.LongEdges[1].idAdjacentFace
end
if not BottomFace.MainEdges.LongEdges[2].bIsOpen then
nSecondLongFaceId = BottomFace.MainEdges.LongEdges[2].idAdjacentFace
end
end
if nFirstLongFaceId > -1 then
LongFaces[1] = Proc.Faces[nFirstLongFaceId + 1]
end
if nSecondLongFaceId > -1 then
LongFaces[2] = Proc.Faces[nSecondLongFaceId + 1]
end
for i = 1, #LongFaces do
LongFaces[i].Type = 'Long'
LongFaces[i].MainEdges = {}
LongFaces[i].MainEdges.SideEdges = {}
LongFaces[i].MainEdges.OppositeEdges = {}
for j = 1, #LongFaces[i].Edges do
local nPreviousEdgeIndex = j - 1
if j == 1 then
nPreviousEdgeIndex = #LongFaces[1].Edges
end
local nNextEdgeIndex = j + 1
if j == #LongFaces[i].Edges then
nNextEdgeIndex = 1
end
local CurrentEdge = {}
CurrentEdge.idAdjacentFace = LongFaces[i].Edges[j].Adj
CurrentEdge.vtToolDirection = Vector3d( LongFaces[i].Edges[j].Norm)
CurrentEdge.dLength = LongFaces[i].Edges[j].Len
CurrentEdge.dElevation = LongFaces[i].Edges[j].Elev
CurrentEdge.bIsOpen = LongFaces[i].Edges[j].Open
CurrentEdge.bIsStartOpen = LongFaces[i].Edges[nPreviousEdgeIndex].Open
CurrentEdge.bIsEndOpen = LongFaces[i].Edges[nNextEdgeIndex].Open
if Proc.Topology.sFamily == 'Tunnel' then
if CurrentEdge.idAdjacentFace > -1 then
table.insert( LongFaces[i].MainEdges.SideEdges, CurrentEdge)
else
table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge)
end
else
if CurrentEdge.idAdjacentFace == BottomFace.id then
LongFaces[i].MainEdges.BottomEdge = CurrentEdge
LongFaces[i].MainEdges.BottomEdge.Type = 'Bottom'
elseif LongFaces[i].Edges[nNextEdgeIndex].Adj == BottomFace.id then
LongFaces[i].MainEdges.SideEdges[1] = CurrentEdge
LongFaces[i].MainEdges.SideEdges[1].Type = 'Side'
elseif LongFaces[i].Edges[nPreviousEdgeIndex].Adj == BottomFace.id then
LongFaces[i].MainEdges.SideEdges[2] = CurrentEdge
LongFaces[i].MainEdges.SideEdges[2].Type = 'Side'
else
table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge)
LongFaces[i].MainEdges.OppositeEdges[#LongFaces[i].MainEdges.OppositeEdges].Type = 'Opposite'
end
end
end
end
return LongFaces
end
-------------------------------------------------------------------------------------------------------------
local function GetSideFaces( Proc, MainFaces)
local SideFaces = {}
if Proc.nFct > 5 then
error( 'GetSideFaces : Topology not implemented')
end
local idBottomFace = GDB_ID.NULL
if Proc.Topology.sFamily ~= 'Tunnel' then
if MainFaces.BottomFace then
idBottomFace = MainFaces.BottomFace.id
else
local BottomFace = GetBottomFace( Proc)
idBottomFace = BottomFace.id or idBottomFace
end
end
local LongFaces = {}
if MainFaces.LongFaces then
LongFaces = MainFaces.LongFaces
else
LongFaces = GetLongFaces( Proc, MainFaces)
end
for i = 1, Proc.nFct do
if not idBottomFace or i ~= ( idBottomFace + 1) then
local bIsSideFace = true
for j = 1, #LongFaces do
if Proc.Faces[i].id == LongFaces[j].id then
bIsSideFace = false
break
end
end
if bIsSideFace then
table.insert( SideFaces, Proc.Faces[i])
SideFaces[#SideFaces].Type = 'Side'
end
end
end
return SideFaces
end
-------------------------------------------------------------------------------------------------------------
-- recupero facce principali della feature, in base alla topologia
function FaceData.GetMainFaces( Proc)
EgtOutLog( '---MainFaces START---')
local MainFaces = {}
-- CASO 1 : Feature tipo LapJoint
if Proc.Topology.sFamily == 'Rabbet' or Proc.Topology.sFamily == 'VGroove' or Proc.Topology.sFamily == 'Groove' or Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Tunnel' then
if Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5 then
MainFaces.TunnelAddedFaces = GetTunnelFaces( Proc)
end
MainFaces.BottomFace = GetBottomFace( Proc)
MainFaces.LongFaces = GetLongFaces( Proc, MainFaces)
MainFaces.SideFaces = GetSideFaces( Proc, MainFaces)
-- TODO funzione apposita per informazioni log?
if EgtGetDebugLevel() >= 3 then
if MainFaces.BottomFace then
-- colore differente per la faccia di fondo
EgtSurfTmSetFaceColor( Proc.id, MainFaces.BottomFace.id, 1)
EgtOutLog( 'Bottom Face : ' .. MainFaces.BottomFace.id)
end
if MainFaces.LongFaces then
for i = 1, #MainFaces.LongFaces do
EgtOutLog( 'Long Face : ' .. MainFaces.LongFaces[i].id)
end
end
if MainFaces.SideFaces then
for i = 1, #MainFaces.SideFaces do
EgtOutLog( 'Side Face : ' .. MainFaces.SideFaces[i].id)
end
end
if MainFaces.TunnelAddedFaces then
EgtOutLog( 'Middle Face (Trimesh): ' .. MainFaces.TunnelAddedFaces.MiddleFaceTm.id)
end
end
else
EgtOutLog( '---MainFaces NOT NEEDED---')
end
EgtOutLog( '---MainFaces END---')
return MainFaces
end
-------------------------------------------------------------------------------------------------------------
return FaceData