Files
DataBeam/LuaLibs/FeatureTopology.lua
T
andrea.villa e25ad8e4a4 BeamExec: Creata funzione calcolo dipendenze tra feature
FeatureTopology : Feature senza topologia, calcolato in BeamExec
2024-03-04 12:16:57 +01:00

261 lines
11 KiB
Lua

-- 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
-- Tabella per definizione modulo
local FeatureTopology = {}
-- Include
require( 'EgtBase')
-- Carico le librerie
local BL = require( 'BeamLib')
EgtOutLog( ' FeatureTopology 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 = {}
-- 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 gli id delle facce di Proc che hanno il numero di adiacenze nAdj
function FeatureTopology.GetFacesWithGivenAdjacencyNumber( Proc, vAdj, nAdj)
if not vAdj then vAdj = 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, 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 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
local vAdj = 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'
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, bIsThrough)
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
return true
else
Proc.Topology = 'OTHER'
Proc.TopologyLongName = Proc.Topology
return false
end
end
-------------------------------------------------------------------------------------------------------------
return FeatureTopology