Files
databeamnew/LuaLibs/FeatureLib.lua
T

830 lines
34 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')
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetProcFromTrimesh( idTrimesh, Part, ProcToCopyFrom)
local Proc = {}
-- eventuale copia dati da ProcToCopyFrom in arrivo
if type( ProcToCopyFrom) == "table" then
Proc = BeamLib.TableCopyDeep( ProcToCopyFrom)
end
-- dati specifici della Proc
Proc.id = idTrimesh
Proc.nFct = EgtSurfTmFacetCount( Proc.id) or 0
Proc.b3Box = EgtGetBBoxGlob( idTrimesh or GDB_ID.NULL, GDB_BB.STANDARD)
Proc.AffectedFaces = BeamLib.GetAffectedFaces( Proc, Part)
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
-- TODO servono anche altri dati raccolti nel collect??
return Proc
end
---------------------------------------------------------------------
-- 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.IsTailCut( 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.IsBirdsMouth( 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 da geometria SOLO se non raggiata
elseif ID.IsMortise( Proc) and Proc.nFct < 6 then
return true
-- calcolo topologia da geometria SOLO se non raggiata
elseif ID.IsFrontMortise( Proc) and Proc.nFct < 6 then
return true
elseif ID.IsBlockHaus( Proc) 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, Part)
local bResult = false
if Proc.b3Box:getDimX() > Part.b3Part:getDimX() - 1000 * GEO.EPS_SMALL or
Proc.b3Box:getDimY() > Part.b3Part:getDimY() - 1000 * GEO.EPS_SMALL or
Proc.b3Box:getDimZ() > Part.b3Part: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, Part)
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
---------------------------------------------------------------------
-- recupera classificazione feature (da info BTL, non geometrica)
function FeatureLib.GetTopologyFromFeature( Proc, Part)
local Topology = {}
Topology.sFamily = 'FEATURE'
-- per feature 'Mortasa' si setta topologia da info BTL se raggiata
if ID.IsMortise( Proc) or ID.IsFrontMortise( Proc) then
Topology.sName = 'Pocket-Round'
if Proc.FeatureInfo.bIsFrontMortise then
Topology.sName = Topology.sName .. '-Front'
elseif Proc.FeatureInfo.bIsMortiseThrough then
Topology.sName = Topology.sName .. '-Through'
end
else
Topology.sName = 'FEATURE'
end
return Topology
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetAdditionalInfo( Proc, Part)
Proc.FeatureInfo = {}
-- se foro
if ID.IsDrilling( Proc) then
Proc.FeatureInfo = FeatureLib.GetDrillingData( Proc)
-- se tenone o tenone a coda di rondine
elseif ID.IsTenon( Proc) or ID.IsDovetailTenon( Proc) then
Proc.FeatureInfo = FeatureLib.GetTenonData( Proc)
-- se mortasa a coda di rondine o mortasa frontale a coda di rondine
elseif ID.IsDovetailMortise( Proc) or ID.IsFrontDovetailMortise( Proc) then
Proc.FeatureInfo = FeatureLib.GetDTMortiseData( Proc)
-- se mortasa a coda di rondine o mortasa frontale a coda di rondine
elseif ID.IsMortise( Proc) or ID.IsFrontMortise( Proc) then
Proc.FeatureInfo = FeatureLib.GetMortiseData( Proc, Part)
end
return Proc
end
-------------------------------------------------------------------------------------------------------------
-- Recupero dati foro e adattamento se speciale
function FeatureLib.GetDrillingData( Proc)
local AuxId = EgtGetInfo( Proc.id, 'AUXID', 'i')
local FeatureExtraInfo = {}
-- 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
FeatureExtraInfo.dDrillDiam = EgtGetInfo( Proc.id, 'P12', 'd') or 0
FeatureExtraInfo.dDrillLen = abs( EgtCurveThickness( Proc.id + AuxId)) or 0
FeatureExtraInfo.nDrillFcs = EgtGetInfo( Proc.id, 'FCS', 'i') or 0
FeatureExtraInfo.nDrillFce = EgtGetInfo( Proc.id, 'FCE', 'i') or 0
return FeatureExtraInfo
end
-------------------------------------------------------------------------------------------------------------
-- Recupero dati tenone e tenone a coda di rondine
function FeatureLib.GetTenonData( Proc)
local FeatureExtraInfo = {}
-- recupero e verifico l'entità curva
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
if idAux then idAux = idAux + Proc.id end
-- recupero i dati della curva
local vtN = EgtCurveExtrusion( idAux, GDB_RT.GLOB)
local ptBC = EgtGP( idAux, GDB_RT.GLOB)
-- determino altezza del tenone
local frTen = Frame3d( ptBC, vtN)
local b3Ten = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frTen)
local dTenH = b3Ten:getDimZ()
-- assegno centro e normale della faccia top
local ptC = ptBC + vtN * dTenH
-- calcolo distanza massima della curva dal punto più lontano della base tenone (facet 0)
local dMaxDist
for i = 0, Proc.nFct - 1 do
local ptFC, vtFN = EgtSurfTmFacetCenter( Proc.id, i, GDB_ID.ROOT)
if not AreSameVectorApprox( vtFN, vtN) or abs( ( ptFC - ptBC) * vtN) > 100 * GEO.EPS_SMALL then
break
end
local nLoopId, nLoopCnt = EgtExtractSurfTmFacetLoops( Proc.id, i, EgtGetParent( Proc.id))
if nLoopId then
local dUmin, dUmax = EgtCurveDomain( nLoopId)
for dU = dUmin, dUmax do
local ptP = EgtUP( nLoopId, dU, GDB_ID.ROOT)
local ptNear = EgtNP( idAux, ptP, GDB_ID.ROOT)
local dDist = dist( ptP, ptNear)
if not dMaxDist or dDist > dMaxDist then
dMaxDist = dDist
end
end
for j = 1, nLoopCnt do
EgtErase( nLoopId + j - 1)
end
end
end
if not dMaxDist then
local b3TenonAux = EgtGetBBoxRef( idAux, GDB_BB.STANDARD, frTen)
dMaxDist = 2 * ( b3Ten:getRadius() - b3TenonAux:getRadius())
end
FeatureExtraInfo.dTenonLength = dTenH
FeatureExtraInfo.dTenonMaxDist = dMaxDist
FeatureExtraInfo.vtTenonN = vtN
FeatureExtraInfo.ptTenonCenter = ptC
FeatureExtraInfo.idAddAuxGeom = idAux
return FeatureExtraInfo
end
-------------------------------------------------------------------------------------------------------------
-- Recupero dati fmortasa a coda di rondine
function FeatureLib.GetDTMortiseData( Proc)
local FeatureExtraInfo = {}
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
if idAux then idAux = idAux + Proc.id end
local vtMortiseN = EgtCurveExtrusion( idAux, GDB_RT.GLOB)
-- ne determino l'asse
local vtAx = EgtEV( idAux, GDB_RT.GLOB) - EgtSV( idAux, GDB_RT.GLOB)
vtAx:normalize()
-- determino l'altezza della mortasa (0=faccia di fondo)
local rFrameDtMortise, dMortiseLength, dMortiseWidth = EgtSurfTmFacetMinAreaRectangle( Proc.id, 0, GDB_RT.GLOB)
if abs( rFrameDtMortise:getVersY() * vtAx) > abs( rFrameDtMortise:getVersX() * vtAx) then
rFrameDtMortise:rotate( rFrameDtMortise:getOrigin(), rFrameDtMortise:getVersZ(), 90)
dMortiseLength, dMortiseWidth = dMortiseWidth, dMortiseLength
end
local b3DtMortise = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, rFrameDtMortise)
local dMortiseDepth = b3DtMortise:getDimZ()
-- recupero il raggio minimo della mortasa
local dMortiseMinRadius = 1000
local nSt, nEnd = EgtCurveDomain( idAux)
for i = nSt, nEnd - 1 do
local dRad = EgtCurveCompoRadius( idAux, i)
if dRad > 0 and dRad < dMortiseMinRadius then
dMortiseMinRadius = dRad
end
end
-- distanza massima all'imbocco ortogonale all'asse
local vtDiff = EgtEP( idAux, GDB_RT.GLOB) - EgtSP( idAux, GDB_RT.GLOB)
local vtOrtDiff = vtDiff - vtDiff * vtAx * vtAx
local dMortiseMaxDist = min( vtOrtDiff:len(), dMortiseWidth)
FeatureExtraInfo.bIsFrontMortise = Proc.nPrc == 56
FeatureExtraInfo.dMortiseLength = dMortiseLength
FeatureExtraInfo.dMortiseWidth = dMortiseWidth
FeatureExtraInfo.dMortiseMaxDist = dMortiseMaxDist
FeatureExtraInfo.dMortiseDepth = dMortiseDepth
FeatureExtraInfo.dMortiseMinRadius = dMortiseMinRadius
FeatureExtraInfo.vtMortiseN = vtMortiseN
FeatureExtraInfo.idAddAuxGeom = idAux
return FeatureExtraInfo
end
-------------------------------------------------------------------------------------------------------------
-- Recupero dati mortasa
function FeatureLib.GetMortiseData( Proc, Part)
local FeatureExtraInfo = {}
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
if idAux then idAux = idAux + Proc.id end
local vtMortiseN = EgtCurveExtrusion( idAux, GDB_RT.GLOB)
-- recupero i dati della faccia di fondo
local frMortise, dMortiseLength, dMortiseWidth = EgtSurfTmFacetMinAreaRectangle( Proc.id, 0, GDB_ID.ROOT)
-- se curva di contorno aperta la rendo chiusa
local _, bCurveModified = BeamLib.ConvertToClosedCurve( Proc, idAux)
-- Confronto le direzioni dei 2 versori : se diverse la faccia 0 non è il fondo => mortasa passante
local bMortiseThrough = not AreSameVectorApprox( vtMortiseN, frMortise:getVersZ())
-- in caso sia passante si ricalcola tutto sul contorno della tasca
if bMortiseThrough then
-- creo superficie chiusa sul contorno
local nFlat = EgtSurfTmByFlatContour( EgtGetParent( idAux), idAux, 0.05)
if nFlat then
frMortise, dMortiseLength, dMortiseWidth = EgtSurfTmFacetMinAreaRectangle( nFlat, 0, GDB_ID.ROOT)
-- verifico se copiare la geometria lungo l'asse Z
local b3Aux = EgtGetBBoxRef( idAux, GDB_BB.STANDARD, frMortise)
local bxMax = b3Aux:getMax()
local b3Mor = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frMortise)
local bxMin = b3Mor:getMin()
local dMove = bxMin:getZ() - bxMax:getZ()
-- se il percorso ausiliario è esterno al grezzo, lo riavvicino
if abs( dMove) > GEO.EPS_SMALL then
idAux = EgtCopyGlob( idAux, BeamLib.GetAddGroup( Part.id))
local vtMove = Vector3d( 0, 0, dMove)
vtMove:toGlob( frMortise)
EgtMove( idAux, vtMove, GDB_RT.GLOB)
EgtMove( nFlat, vtMove, GDB_RT.GLOB)
frMortise, dMortiseLength, dMortiseWidth = EgtSurfTmFacetMinAreaRectangle( nFlat, 0, GDB_ID.ROOT)
end
-- cancello la superficie piana utilizzata per ricalcolare dati
EgtErase( nFlat)
end
end
-- determino altezza della mortasa
local b3Mortise = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frMortise)
local dMortiseDepth = b3Mortise:getDimZ()
-- recupero il raggio minimo della mortasa
local dMortiseMinRadius = 1000
local nSt, nEnd = EgtCurveDomain( idAux)
for i = nSt, nEnd - 1 do
local dRad = EgtCurveCompoRadius( idAux, i)
if dRad > 0 and dRad < dMortiseMinRadius then
dMortiseMinRadius = dRad
end
end
-- se la mortasa passante il contorno è sulla faccia della trave e il riconoscimento lati aperti non è corretto
if not bCurveModified and not bMortiseThrough then
BeamLib.SetOpenSide( idAux, Part.b3Part)
end
FeatureExtraInfo.bIsFrontMortise = Proc.nPrc == 51
FeatureExtraInfo.bIsMortiseThrough = bMortiseThrough
FeatureExtraInfo.bIsMortiseOpen = bCurveModified
FeatureExtraInfo.dMortiseLength = dMortiseLength
FeatureExtraInfo.dMortiseWidth = dMortiseWidth
FeatureExtraInfo.dMortiseDepth = dMortiseDepth
FeatureExtraInfo.dMortiseMinRadius = dMortiseMinRadius
FeatureExtraInfo.vtMortiseN = vtMortiseN
FeatureExtraInfo.idAddAuxGeom = idAux
-- aggiustamento affected faces in caso di feature frontale
if FeatureExtraInfo.bIsFrontMortise and FeatureExtraInfo.vtMortiseN:getX() < 0 then
Proc.AffectedFaces.bLeft = true
elseif FeatureExtraInfo.bIsFrontMortise and FeatureExtraInfo.vtMortiseN:getX() > 0 then
Proc.AffectedFaces.bRight = true
end
return FeatureExtraInfo
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
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetStrategyQuality( Machinings)
local nQuality = 0
local dQualityNumerator = 0
local dQualityDenominator = 0
for i = 1, #Machinings do
local Machining = Machinings[i]
local dWeightedQuality = TOOLS[Machining.nToolIndex].nQuality * Machining.dLengthToMachine
if Machining.bIsApplicable then
dQualityNumerator = dQualityNumerator + dWeightedQuality
dQualityDenominator = dQualityDenominator + Machining.dLengthToMachine
end
end
nQuality = dQualityNumerator / dQualityDenominator
return nQuality
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetStrategyTimeToMachine( Machinings)
local dTimeToMachine = 0
for i = 1, #Machinings do
local Machining = Machinings[i]
if Machining.bIsApplicable then
dTimeToMachine = dTimeToMachine + Machining.dTimeToMachine
end
end
return dTimeToMachine
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetStrategyResultNotApplicable( sInfo)
local Result = {}
if not type( sInfo) == "string" then
sInfo = ''
end
Result.dTimeToMachine = 0
Result.dMRR = 0
Result.dCompletionPercentage = 0
Result.sStatus = 'Not-Applicable'
Result.nCompletionIndex = 0
Result.nQuality = 0
Result.sInfo = sInfo
return Result
end
-------------------------------------------------------------------------------------------------------------
-- TODO rivedere affidabilità del calcolo del composite rating
-- 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
-- indice bonta lavorazione feature in rotazione è opzionale, se non settato viene messo a 3
if not StrategyResult.nFeatureRotationIndex then
StrategyResult.nFeatureRotationIndex = 3
end
StrategyResult.dCompositeRating = ceil( StrategyResult.nQuality * StrategyResult.nCompletionIndex * StrategyResult.dMRR * StrategyResult.nFeatureRotationIndex)
else
StrategyResult.dCompositeRating = 0
end
return StrategyResult
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.IsMachiningLong( dMachiningLengthOnX, Part, OptionalParameters)
local bIsMachiningLong
-- parametri opzionali
if not OptionalParameters then
OptionalParameters = {}
end
local dMaxSegmentLength = OptionalParameters.dMaxSegmentLength or BeamData.LONGCUT_MAXLEN
bIsMachiningLong = ( dMachiningLengthOnX > dMaxSegmentLength + 10 * GEO.EPS_SMALL)
or ( dMachiningLengthOnX > 0.7 * Part.b3Part:getDimX() + 10 * GEO.EPS_SMALL)
return bIsMachiningLong
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetFeatureSplittingPoints( Proc, Part, OptionalParameters)
local FeatureSplittingPoints = {}
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 dMinSegmentLength = OptionalParameters.dMinSegmentLength or dMaxSegmentLengthOnEdges / 2
local dToolOverlapBetweenSegments = OptionalParameters.dToolOverlapBetweenSegments or BeamData.MILL_OVERLAP
-- verifica spezzatura necessaria
if not FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part) then
return {}
end
-- verifica se necessari spezzoni differenti sugli estremi
if Proc.b3Box:getMin():getX() < Part.b3Part:getMin():getX() + dMaxSegmentLengthOnEdges - 10 * GEO.EPS_SMALL then
bFeatureStartsOnEdgeLeft = true
end
if Proc.b3Box:getMax():getX() > Part.b3Part: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.b3Part:getMin():getX() + dMaxSegmentLengthOnEdges, Proc.b3Box:getMin():getX() + dMinSegmentLength)
else
-- se pezzo abbastanza piccolo, spezzo in mezzo al 'pezzo + grezzo restante'
if Part.dRestLength + Part.b3Part:getDimX() < BeamData.dMinRaw * 1.5 then
dSplitXLeft = Part.b3Part:getMax():getX() - ( ( Part.dRestLength + Part.b3Part:getDimX()) / 2)
else
dSplitXLeft = max( Proc.b3Box:getMin():getX() + ( BeamData.dMinRaw)/2 + 150, Part.b3Part: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() - dMinSegmentLength), Part.b3Part:getMax():getX() - dMaxSegmentLengthOnEdges)
if dSplitXRight - dSplitXLeft < 500 * GEO.EPS_SMALL then
dSplitXRight = dSplitXLeft - dToolOverlapBetweenSegments
dFeatureCentralLength = 0
bFeatureStartsOnEdgeLeft = false
else
dFeatureCentralLength = dSplitXRight - dSplitXLeft
end
ptSplitXRight = Point3d( dSplitXRight, 0, 0)
end
-- aggiungo eventuale punto estremo destro
if bFeatureStartsOnEdgeRight then
table.insert( FeatureSplittingPoints, 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( FeatureSplittingPoints, ptOn)
end
end
-- aggiungo eventuale punto estemo sinistro
if bFeatureStartsOnEdgeLeft then
table.insert( FeatureSplittingPoints, ptSplitXLeft)
end
return FeatureSplittingPoints
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetFeatureVolume( Proc, Part)
local dProcVolume = 0
local idAddGroup = BeamLib.GetAddGroup( Part.id)
if not idAddGroup then
-- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste?
EgtOutLog( 'Error : missing AddGroup')
return 0
end
local idProcCopy = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
local b3PartCopy = BBox3d( Part.b3Part)
b3PartCopy:expand( -100 * GEO.EPS_SMALL)
local idPartCopy = EgtSurfTmBBox( idAddGroup, b3PartCopy , false, GDB_RT.GLOB)
EgtSurfTmSubtract( idPartCopy, idProcCopy)
dProcVolume = EgtSurfVolume( idPartCopy)
EgtErase( { idProcCopy, idPartCopy})
return dProcVolume
end
-------------------------------------------------------------------------------------------------------------
-- funzione che verifica se la feature, lavorata in questa fase, compromette lettura misura laser
function FeatureLib.CalculateFeatureHindersLaserMeasure( Proc, Part)
local bFeatureHindersLaserMeasure = false
-- se la feature è aperta frontalmente, posteriormente e di testa, allora potrebbe impattare sulla misura laser, controllo caso per caso
if Proc.AffectedFaces.bRight and Proc.AffectedFaces.bFront and Proc.AffectedFaces.bBack then
bFeatureHindersLaserMeasure = true
end
return bFeatureHindersLaserMeasure
end
-------------------------------------------------------------------------------------------------------------
-- TODO funzione copiata direttamente da automatismo vecchio, da migliorare / completare
function FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part)
local NotClampableLength = {}
local dNotClampableLengthHead = 0
local dNotClampableLengthTail = 0
-- TODO al momento con meno di 3 facce si restituisce 0
if Proc.nFct < 3 then
-- eventuale segnalazione ingombro di testa o coda
local dMinHIng = min( 0.5 * BeamData.VICE_MINH, 0.5 * Part.b3Raw:getDimZ())
local dMinZ = max( BeamData.MIN_HEIGHT, 0.35 * Part.b3Raw:getDimZ())
-- calcolo punto massimo in Z fino a dove considerare il pinzaggio. Minimo tra pinzaggio massimo e altezza pezzo
local dMaxHZ = Part.b3Raw:getMin():getZ() + min( BeamData.VICE_MAXH or BeamData.MAX_HEIGHT, Part.b3Raw:getDimZ())
-- punto massimo in Z considerando anche la Z della feature
local dMaxHZFeat = min( dMaxHZ, Proc.b3Box:getMax():getZ())
-- dimensione Z del pinzaggio (differenza massima Z pinzabile e box feature)
local dDeltaZClamp = ( ( dMaxHZ - Part.b3Raw:getMin():getZ()) - max( 0, dMaxHZFeat - Proc.b3Box:getMin():getZ()))
-- se pinzaggio minimo è come il massimo (oppure come l'altezza massima del pezzo) significa che è verticale
local bIsVertClamps = BeamData.VICE_MINH > BeamData.MAX_HEIGHT - 100 * GEO.EPS_SMALL
-- condizioni per limitare pinzaggio testa/coda
local bUpdateIng = true
-- se dimensione del box della feature maggiore di metà pinzaggio minimo o metà spessore pezzo
bUpdateIng = bUpdateIng and Proc.b3Box:getDimZ() > dMinHIng
-- se la feature si trova più in basso del minimo pinzabile in Z o il 35% dello spessore pezzo
bUpdateIng = bUpdateIng and Proc.b3Box:getMin():getZ() < Part.b3Raw:getMin():getZ() + dMinZ
-- se feature è al di sotto del pinzaggio massimo
bUpdateIng = bUpdateIng and Proc.b3Box:getMin():getZ() < dMaxHZ
-- se ho le morse verticali, o se la feature è in centro o verso alto, controllo se non prendo abbastanza.
if bIsVertClamps or ( Proc.b3Box:getMin():getZ() - Part.b3Raw:getMin():getZ()) > BeamData.MIN_HEIGHT then
bUpdateIng = bUpdateIng and dDeltaZClamp < BeamData.VICE_MINH
end
if bUpdateIng then
if Proc.AffectedFaces.bRight then
local dOffs = Part.b3Part:getMax():getX() - Proc.b3Box:getMin():getX()
-- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse
if not bIsVertClamps and dDeltaZClamp > BeamData.VICE_MINH and BeamData.VICE_MAXH then
dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
end
dNotClampableLengthHead = dOffs
elseif Proc.AffectedFaces.bLeft then
local dOffs = Proc.b3Box:getMax():getX() - Part.b3Part:getMin():getX()
-- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse
if not bIsVertClamps and dDeltaZClamp > BeamData.VICE_MINH and BeamData.VICE_MAXH then
dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
end
dNotClampableLengthTail = dOffs
elseif Proc.b3Box:getCenter():getX() > Part.b3Part:getCenter():getX() then
local dOffs = Part.b3Part:getMax():getX() - Proc.b3Box:getMin():getX()
local dDist = Part.b3Part:getMax():getX() - Proc.b3Box:getMax():getX()
-- se pinze a 45° e pinza abbastanza materiale, compenso comunque, ma solo inclinazione morse
if not bIsVertClamps and dDeltaZClamp > BeamData.VICE_MINH and BeamData.VICE_MAXH then
dOffs = min( dOffs, BeamData.VICE_MAXH - BeamData.VICE_MINH)
end
-- dDist serve??
dNotClampableLengthHead = dOffs
end
end
end
NotClampableLength.dNotClampableLengthHead = dNotClampableLengthHead
NotClampableLength.dNotClampableLengthTail = dNotClampableLengthTail
return NotClampableLength
end
-------------------------------------------------------------------------------------------------------------
function FeatureLib.GetFeatureMaxNotClampableLengths( Proc, Part)
local nPartIndex = Part.nIndexInParts
local nProcIndex = Proc.nIndexInVProc
local Rotations = PROCESSINGS[nPartIndex].Rotation
local dMaxOnHead = 0
local dMaxOnTail = 0
for i = 1, #Part.CombinationList do
for j = 1, 4 do
-- controllo che la rotazione sia attiva
if string.sub( Part.CombinationList[i].sBitIndexCombination, j, j) == '1' then
dMaxOnHead = max( Rotations[j][nProcIndex].NotClampableLength.dNotClampableLengthHead, dMaxOnHead)
dMaxOnTail = max( Rotations[j][nProcIndex].NotClampableLength.dNotClampableLengthTail, dMaxOnTail)
end
end
end
return dMaxOnHead, dMaxOnTail
end
-------------------------------------------------------------------------------------------------------------
return FeatureLib