399 lines
16 KiB
Lua
399 lines
16 KiB
Lua
-- FeatureLib.lua by Egalware s.r.l. 2024/04/02
|
|
-- Libreria lettura o calcolo dati e proprietà della feature
|
|
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
|
|
|
-- Tabella per definizione modulo
|
|
local FeatureLib = {}
|
|
|
|
-- Carico i dati globali
|
|
local BeamData = require( 'BeamData')
|
|
|
|
-- carico librerie
|
|
local BeamLib = require( 'BeamLib')
|
|
local FaceData = require( 'FaceData')
|
|
local ID = require( 'Identity')
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- recupero topologia della feature
|
|
function FeatureLib.NeedTopologyFeature( Proc)
|
|
-- features tipo taglio
|
|
if ID.IsCut( Proc) then
|
|
return true
|
|
elseif ID.IsHeadCut( Proc) then
|
|
return true
|
|
elseif ID.IsSplitCut( Proc) then
|
|
return true
|
|
elseif ID.IsDoubleCut( Proc) then
|
|
return true
|
|
elseif ID.IsSawCut( Proc) then
|
|
return true
|
|
-- features tipo taglio longitudinale
|
|
elseif ID.IsLongitudinalCut( Proc) then
|
|
return true
|
|
elseif ID.IsDoubleLongitudinalCut( Proc) then
|
|
return true
|
|
elseif ID.IsChamfer( Proc) then
|
|
return true
|
|
-- features tipo LapJoint
|
|
elseif ID.IsSlot( Proc) then
|
|
return true
|
|
elseif ID.IsFrontSlot( Proc) then
|
|
return true
|
|
elseif ID.IsRidgeLap( Proc) then
|
|
return true
|
|
elseif ID.IsLapJoint( Proc) then
|
|
return true
|
|
elseif ID.IsNotchRabbet( Proc) then
|
|
return true
|
|
elseif ID.IsNotch( Proc) then
|
|
return true
|
|
elseif ID.IsPocket( Proc) then
|
|
return true
|
|
-- calcolo topologia SOLO se non raggiata
|
|
-- TODO oppure riconoscerla come feature speciale; valutare se controllare il numero di facce è un metodo efficace
|
|
elseif ID.IsMortise( Proc) and Proc.nFct < 6 then
|
|
return true
|
|
-- calcolo topologia SOLO se non raggiata
|
|
-- TODO oppure riconoscerla come feature speciale; valutare se controllare il numero di facce è un metodo efficace
|
|
elseif ID.IsFrontMortise( Proc) and Proc.nFct < 6 then
|
|
return true
|
|
end
|
|
|
|
-- se feature non tra quelle sopra, riconoscimento topologico non necessario
|
|
return false
|
|
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)
|
|
-- se la feature ha una sola faccia, esco subito
|
|
if #vAdj <= 1 then
|
|
return
|
|
end
|
|
|
|
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.idPart or GDB_ID.NULL, 'Box')
|
|
local b3Solid = EgtGetBBoxGlob( nBoxSolidId, GDB_BB.STANDARD)
|
|
|
|
if Proc.b3Box:getDimX() > b3Solid:getDimX() - 1000 * GEO.EPS_SMALL or
|
|
Proc.b3Box:getDimY() > b3Solid:getDimY() - 1000 * GEO.EPS_SMALL or
|
|
Proc.b3Box:getDimZ() > b3Solid:getDimZ() - 1000 * GEO.EPS_SMALL then
|
|
bResult = true
|
|
end
|
|
|
|
return bResult
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- restituisce vero se la feature con box b3Proc taglia l'intera sezione della barra, rappresentata dalle sue dimensioni W e H
|
|
local function IsFeatureCuttingEntireSection( b3Proc, Part)
|
|
return ( b3Proc:getDimY() > ( Part.b3Raw:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimZ() > ( Part.b3Raw:getDimZ() - 500 * GEO.EPS_SMALL))
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- restituisce vero se la feature con box b3Proc taglia l'intera lunghezza della barra, rappresentata dalle sue dimensioni W e L oppure H e L
|
|
local function IsFeatureCuttingEntireLength( b3Proc, Part)
|
|
return ( ( b3Proc:getDimY() > ( Part.b3Raw:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimX() > ( Part.b3Raw:getDimX() - 500 * GEO.EPS_SMALL)) or
|
|
( b3Proc:getDimZ() > ( Part.b3Raw:getDimZ() - 500 * GEO.EPS_SMALL) and b3Proc:getDimX() > ( Part.b3Raw:getDimX() - 500 * GEO.EPS_SMALL)))
|
|
end
|
|
|
|
---------------------------------------------------------------------
|
|
-- restituisce una stringa con il nome esteso della topologia della feature
|
|
-- *famiglia - numero di facce - passante*
|
|
local function GetTopologyName( sFamily, nNumberOfFaces, bIsThrough)
|
|
return sFamily .. '-' .. tostring( nNumberOfFaces) .. '-' .. EgtIf( bIsThrough, 'Through', 'Blind')
|
|
end
|
|
|
|
---------------------------------------------------------------------
|
|
-- recupera topologia feature
|
|
function FeatureLib.ClassifyTopology( Proc, Part)
|
|
local FeatureTopology = {}
|
|
|
|
if not Proc.AffectedFaces then Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part) end
|
|
|
|
local bIsFeatureCuttingEntireSection = IsFeatureCuttingEntireSection( Proc.b3Box, Part)
|
|
local bIsFeatureCuttingEntireLength = IsFeatureCuttingEntireLength( Proc.b3Box, Part)
|
|
local bIsAnyDimensionLongAsPart = IsAnyDimensionLongAsPart( Proc)
|
|
local vAdj = Proc.AdjacencyMatrix
|
|
local bAllAnglesConcave, bAllRightAngles = AreAllAnglesConcaveOrRight( vAdj)
|
|
local vTriangularFaces = FaceData.GetTriangularFaces( Proc)
|
|
local vFacesByAdjNumber = FaceData.GetFacesByAdjacencyNumber( Proc)
|
|
|
|
local sFamily
|
|
local bIsThrough
|
|
if Proc.nFct == 1 and ( bIsFeatureCuttingEntireSection or bIsFeatureCuttingEntireLength) then
|
|
sFamily = 'Cut'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 1 then
|
|
sFamily = 'Bevel'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 2 and bAllAnglesConcave and #vTriangularFaces == 1 then
|
|
sFamily = 'Bevel'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 2 and bAllAnglesConcave and ( Proc.AffectedFaces.bLeft or Proc.AffectedFaces.bRight) and ( Proc.AffectedFaces.bFront or Proc.AffectedFaces.bBack) then
|
|
sFamily = 'Rabbet'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 2 and bAllAnglesConcave then
|
|
sFamily = 'VGroove'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 2 and not bAllAnglesConcave and bIsAnyDimensionLongAsPart then
|
|
sFamily = 'DoubleBevel'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 3 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 1 and #vTriangularFaces == 2 then
|
|
sFamily = 'Bevel'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 3 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 1 and bIsAnyDimensionLongAsPart then
|
|
sFamily = 'Groove'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 3 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 3 then
|
|
sFamily = 'Groove'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 4 and #vFacesByAdjNumber[2] == 4 and #vTriangularFaces == 2 then
|
|
sFamily = 'DoubleBevel'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 4 and bAllAnglesConcave and #vFacesByAdjNumber[3] == 2 then
|
|
sFamily = 'Groove'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 4 and bAllAnglesConcave and #vFacesByAdjNumber[2] == 4 and bIsAnyDimensionLongAsPart then
|
|
sFamily = 'Tunnel'
|
|
bIsThrough = true
|
|
elseif Proc.nFct >= 4 and #vFacesByAdjNumber[1] == 2 and bIsAnyDimensionLongAsPart then
|
|
sFamily = 'Strip'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 5 and bAllAnglesConcave and #vFacesByAdjNumber[4] == 1 then
|
|
sFamily = 'Pocket'
|
|
bIsThrough = false
|
|
elseif Proc.nFct == 6 and #vFacesByAdjNumber[2] == 4 and #vFacesByAdjNumber[3] == 2 and #vTriangularFaces == 4 then
|
|
sFamily = 'DoubleBevel'
|
|
bIsThrough = false
|
|
end
|
|
|
|
if sFamily then
|
|
FeatureTopology.sFamily = sFamily
|
|
FeatureTopology.bIsThrough = bIsThrough
|
|
FeatureTopology.bAllRightAngles = bAllRightAngles
|
|
FeatureTopology.sName = GetTopologyName( sFamily, Proc.nFct, bIsThrough)
|
|
FeatureTopology.AdjacencyMatrix = vAdj
|
|
-- feature che necessita di essere catalogata, ma non si capisce come
|
|
else
|
|
FeatureTopology.sFamily = 'NOT_IMPLEMENTED'
|
|
FeatureTopology.sName = FeatureTopology.sFamily
|
|
end
|
|
|
|
return FeatureTopology
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- Recupero dati foro e adattamento se speciale
|
|
function FeatureLib.GetDrillingData( Proc)
|
|
local AuxId = EgtGetInfo( Proc.id, 'AUXID', 'i')
|
|
|
|
-- verifico se foro da adattare
|
|
if EgtExistsInfo( Proc.id, 'DiamUser') then
|
|
if AuxId then AuxId = AuxId + Proc.id end
|
|
if AuxId and EgtGetType( AuxId) == GDB_TY.CRV_ARC and BeamData.USER_HOLE_DIAM and BeamData.USER_HOLE_DIAM > 1 then
|
|
EgtModifyArcRadius( AuxId, BeamData.USER_HOLE_DIAM / 2)
|
|
end
|
|
end
|
|
|
|
local dDiam = EgtGetInfo( Proc.id, 'P12', 'd') or 0
|
|
local dLen = abs( EgtCurveThickness( Proc.id + AuxId)) or 0
|
|
local nFcs = EgtGetInfo( Proc.id, 'FCS', 'i') or 0
|
|
local nFce = EgtGetInfo( Proc.id, 'FCE', 'i') or 0
|
|
|
|
return dDiam, dLen, nFcs, nFce
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che restituisce indice di completamento in base alla percentuale di volume lavorato
|
|
function FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
|
-- indice di completamento
|
|
local nCompletionIndex = 0
|
|
|
|
-- nullo
|
|
if dCompletionPercentage < 5 then
|
|
nCompletionIndex = 0
|
|
-- Low
|
|
elseif dCompletionPercentage < 50 then
|
|
nCompletionIndex = 1
|
|
-- Medium
|
|
elseif dCompletionPercentage < 80 then
|
|
nCompletionIndex = 2
|
|
-- High / Complete
|
|
else
|
|
nCompletionIndex = 5
|
|
end
|
|
|
|
return nCompletionIndex
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che restituisce qualità della lavorazione in base agli utensili utilizzati
|
|
function FeatureLib.GetFeatureQuality( sTypeTools)
|
|
local nQuality = 5
|
|
local TypeTools = EgtSplitString( sTypeTools)
|
|
|
|
-- indice in base a utensile
|
|
for i=1, #TypeTools do
|
|
if TypeTools[i] == 'Blade' then
|
|
nQuality = min( nQuality, 5)
|
|
elseif TypeTools[i] == 'Mill' then
|
|
nQuality = min( nQuality, 4)
|
|
elseif TypeTools[i] == 'Chainsaw' then
|
|
nQuality = min( nQuality, 2)
|
|
else
|
|
nQuality = min( nQuality, 1)
|
|
end
|
|
end
|
|
-- se si utilizzano più utensili si perde in qualità
|
|
if #TypeTools > 1 then
|
|
nQuality = max( nQuality - 1, 0.5)
|
|
end
|
|
|
|
return nQuality
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- funzione che calcola il 'CompositeRating' di ogni strategia
|
|
function FeatureLib.CalculateCompositeRating( StrategyResult)
|
|
-- se ho tutti i dati che mi servono calcolo il rating della strategia applicato alla feature
|
|
if StrategyResult and StrategyResult.nQuality and StrategyResult.nCompletionIndex and StrategyResult.dMRR then
|
|
StrategyResult.dCompositeRating = ceil( StrategyResult.nQuality * StrategyResult.nCompletionIndex * StrategyResult.dMRR)
|
|
else
|
|
StrategyResult.dCompositeRating = 0
|
|
end
|
|
|
|
return StrategyResult
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.MachiningNeedsSplitting( dMachiningLengthOnX, Part, OptionalParameters)
|
|
local bMachiningNeedsSplitting
|
|
|
|
-- parametri opzionali
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local dMaxSegmentLength = OptionalParameters.dMaxSegmentLength or BeamData.LONGCUT_MAXLEN
|
|
|
|
bMachiningNeedsSplitting = ( dMachiningLengthOnX > dMaxSegmentLength + 10 * GEO.EPS_SMALL)
|
|
or ( dMachiningLengthOnX > 0.7 * Part.b3Solid:getDimX() + 10 * GEO.EPS_SMALL)
|
|
|
|
return bMachiningNeedsSplitting
|
|
end
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.GetFeatureSplittingPoints( Proc, Part, OptionalParameters)
|
|
local vFeatureSplittingPoints = {}
|
|
local bFeatureStartsOnEdgeLeft = false
|
|
local bFeatureStartsOnEdgeRight = false
|
|
local dSplitXLeft = Proc.b3Box:getMin():getX()
|
|
local dSplitXRight = Proc.b3Box:getMax():getX()
|
|
local dFeatureCentralLength = Proc.b3Box:getDimX()
|
|
|
|
-- parametri opzionali
|
|
if not OptionalParameters then
|
|
OptionalParameters = {}
|
|
end
|
|
local dMaxSegmentLength = OptionalParameters.dMaxSegmentLength or BeamData.LONGCUT_MAXLEN
|
|
local dMaxSegmentLengthOnEdges = OptionalParameters.dMaxSegmentLengthOnEdges or BeamData.LONGCUT_ENDLEN
|
|
local dToolOverlapBetweenSegments = OptionalParameters.dToolOverlapBetweenSegments or BeamData.MILL_OVERLAP
|
|
|
|
-- verifica spezzatura necessaria
|
|
if not FeatureLib.MachiningNeedsSplitting( Proc.b3Box:getDimX(), Part) then
|
|
return {}
|
|
end
|
|
|
|
-- verifica se necessari spezzoni differenti sugli estremi
|
|
if Proc.b3Box:getMin():getX() < Part.b3Solid:getMin():getX() + dMaxSegmentLengthOnEdges - 10 * GEO.EPS_SMALL then
|
|
bFeatureStartsOnEdgeLeft = true
|
|
end
|
|
if Proc.b3Box:getMax():getX() > Part.b3Solid:getMax():getX() - dMaxSegmentLengthOnEdges + 10 * GEO.EPS_SMALL then
|
|
bFeatureStartsOnEdgeRight = true
|
|
end
|
|
|
|
-- calcolo punto estremo sinistro
|
|
local ptSplitXLeft
|
|
if bFeatureStartsOnEdgeLeft then
|
|
-- decido punto spezzatura verso la coda
|
|
if Proc.b3Box:getDimX() > dMaxSegmentLengthOnEdges * 2 then
|
|
dSplitXLeft = max( Part.b3Solid:getMin():getX() + dMaxSegmentLengthOnEdges, Proc.b3Box:getMin():getX() + dMaxSegmentLengthOnEdges / 2)
|
|
else
|
|
-- se pezzo abbastanza piccolo, spezzo in mezzo al 'pezzo + grezzo restante'
|
|
if Part.dRestLength + Part.b3Solid:getDimX() < BeamData.dMinRaw * 1.5 then
|
|
dSplitXLeft = Part.b3Solid:getMax():getX() - ( ( Part.dRestLength + Part.b3Solid:getDimX()) / 2)
|
|
else
|
|
dSplitXLeft = max( Proc.b3Box:getMin():getX() + ( BeamData.dMinRaw)/2 + 150, Part.b3Solid:getMax():getX() - dMaxSegmentLengthOnEdges)
|
|
end
|
|
end
|
|
dFeatureCentralLength = abs( dSplitXRight - dSplitXLeft)
|
|
ptSplitXLeft = Point3d( dSplitXLeft, 0, 0)
|
|
end
|
|
|
|
-- calcolo punto estremo destro
|
|
local ptSplitXRight
|
|
if bFeatureStartsOnEdgeRight then
|
|
dSplitXRight = min( ( Proc.b3Box:getMax():getX() - dSplitXRight * 3), Part.b3Solid:getMax():getX() - dMaxSegmentLengthOnEdges)
|
|
if dSplitXRight - dSplitXLeft < 500 * GEO.EPS_SMALL then
|
|
dSplitXRight = dSplitXLeft - dToolOverlapBetweenSegments
|
|
dFeatureCentralLength = 0
|
|
else
|
|
dFeatureCentralLength = dSplitXRight - dSplitXLeft
|
|
end
|
|
ptSplitXRight = Point3d( dSplitXRight, 0, 0)
|
|
end
|
|
|
|
-- aggiungo eventuale punto estremo destro
|
|
if bFeatureStartsOnEdgeRight then
|
|
table.insert( vFeatureSplittingPoints, ptSplitXRight)
|
|
end
|
|
|
|
-- aggiungo punti centrali della feature
|
|
if dFeatureCentralLength > 0 then
|
|
local nSplitParts = max( ceil( dFeatureCentralLength / dMaxSegmentLength + 10 * GEO.EPS_SMALL), 1)
|
|
local dSplitPartsLen = dFeatureCentralLength / nSplitParts
|
|
for i = 1, ( nSplitParts - 1) do
|
|
local ptOn
|
|
local dCurrentPointX = dSplitXRight - i * dSplitPartsLen
|
|
ptOn = Point3d( dCurrentPointX, 0, 0)
|
|
table.insert( vFeatureSplittingPoints, ptOn)
|
|
end
|
|
end
|
|
|
|
-- aggiungo eventuale punto estemo sinistro
|
|
if bFeatureStartsOnEdgeLeft then
|
|
table.insert( vFeatureSplittingPoints, ptSplitXLeft)
|
|
end
|
|
|
|
return vFeatureSplittingPoints
|
|
end
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
return FeatureLib |