967117cc23
- in STR0009 aggiunto antischeggia di lama e, nel caso sia disattivato, lavorazione con lama dell'eventuale faccia inclinata
1049 lines
46 KiB
Lua
1049 lines
46 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( 'BeamDataNew')
|
|
|
|
-- 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.idPart = Part.id
|
|
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)
|
|
Proc.dVolume = FeatureLib.GetFeatureVolume( Proc, Part)
|
|
if ProcToCopyFrom and Proc.dVolume < 10 * GEO.EPS_SMALL then
|
|
Proc.dVolume = ProcToCopyFrom.dVolume
|
|
end
|
|
-- TODO servono anche altri dati raccolti nel collect??
|
|
|
|
return Proc
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- restituisce vero se la feature con box b3Proc taglia l'intera sezione della barra
|
|
local function IsFeatureCuttingEntireSection( b3Proc, Part)
|
|
return ( b3Proc:getDimY() > ( Part.b3Part:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimZ() > ( Part.b3Part:getDimZ() - 500 * GEO.EPS_SMALL))
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- restituisce vero se la feature con box b3Proc taglia l'intera lunghezza della barra
|
|
local function IsFeatureCuttingEntireLength( b3Proc, Part)
|
|
return ( ( b3Proc:getDimY() > ( Part.b3Part:getDimY() - 500 * GEO.EPS_SMALL) and b3Proc:getDimX() > ( Part.b3Part:getDimX() - 500 * GEO.EPS_SMALL)) or
|
|
( b3Proc:getDimZ() > ( Part.b3Part:getDimZ() - 500 * GEO.EPS_SMALL) and b3Proc:getDimX() > ( Part.b3Part:getDimX() - 500 * GEO.EPS_SMALL)))
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- restituisce vero se tutti i lati della faccia passata si trovano sul grezzo
|
|
local function AreAllFaceEdgesOnRaw( Part, Proc, idFace)
|
|
local bEdgeOnRaw = true
|
|
local idTempGroup = Part.idTempGroup
|
|
local nLoopId, nLoopCnt = EgtExtractSurfTmFacetLoops( Proc.id, idFace, idTempGroup)
|
|
if nLoopCnt > 1 then
|
|
error( 'AreAllFaceEdgesOnRaw : too many loops')
|
|
end
|
|
|
|
if nLoopId then
|
|
local dUmin, dUmax = EgtCurveDomain( nLoopId)
|
|
for dU = dUmin, dUmax-1 do
|
|
local ptMid = ( EgtUP( nLoopId, dU, GDB_ID.ROOT) + EgtUP( nLoopId, dU+1, GDB_ID.ROOT)) / 2
|
|
-- se punto medio dell'entita NON si trova su faccia testa o coda
|
|
if ptMid:getX() < Part.b3Part:getMin():getX() + 100 * GEO.EPS_SMALL or ptMid:getX() > Part.b3Part:getMax():getX() - 100 * GEO.EPS_SMALL or
|
|
ptMid:getY() < Part.b3Part:getMin():getY() + 100 * GEO.EPS_SMALL or ptMid:getY() > Part.b3Part:getMax():getY() - 100 * GEO.EPS_SMALL or
|
|
ptMid:getZ() < Part.b3Part:getMin():getZ() + 100 * GEO.EPS_SMALL or ptMid:getZ() > Part.b3Part:getMax():getZ() - 100 * GEO.EPS_SMALL then
|
|
bEdgeOnRaw = true
|
|
else
|
|
bEdgeOnRaw = false
|
|
break
|
|
end
|
|
end
|
|
--for j = 1, nLoopCnt do
|
|
-- EgtErase( nLoopId + j - 1)
|
|
--end
|
|
end
|
|
return bEdgeOnRaw
|
|
end
|
|
|
|
|
|
|
|
---------------------------------------------------------------------
|
|
-- recupero topologia della feature
|
|
function FeatureLib.NeedTopologyFeature( Proc, Part)
|
|
-- feature BTL con calcolo topologia SEMPRE da geometria
|
|
if ID.IsCut( Proc) then -- (1-10)
|
|
return true
|
|
elseif ID.IsLongitudinalCut( Proc) then -- (0-10)
|
|
return true
|
|
elseif ID.IsDoubleCut( Proc) then -- (1-11)
|
|
return true
|
|
elseif ID.IsDoubleLongitudinalCut( Proc) then -- (0-12)
|
|
return true
|
|
elseif ID.IsSlot( Proc) then -- (1-16)
|
|
return true
|
|
elseif ID.IsFrontSlot( Proc) then -- (1-17)
|
|
return true
|
|
elseif ID.IsBirdsMouth( Proc) then -- (1-20)
|
|
return true
|
|
elseif ID.IsLapJoint( Proc) then -- (0-30)
|
|
return true
|
|
elseif ID.IsNotchRabbet( Proc) then -- (1-32)
|
|
return true
|
|
elseif ID.IsBlockHaus( Proc) then -- (1-33)
|
|
return true
|
|
elseif ID.IsNotch( Proc) then -- (1-34)
|
|
return true
|
|
elseif ID.IsChamfer( Proc) then -- (0-36)
|
|
return true
|
|
elseif ID.IsPocket( Proc) then -- (1-39)
|
|
return true
|
|
elseif ID.IsStepJoint( Proc) then -- (1-80)
|
|
return true
|
|
elseif ID.IsStepJointNotch( Proc) then -- (0-80)
|
|
return true
|
|
-- feature con calcolo topologia da geometria SOLO se rispettano certe condizioni, altrimenti riconoscimento specifico
|
|
elseif ID.IsSawCut( Proc) and Proc.nFct == 1 and AreAllFaceEdgesOnRaw( Part, Proc, 0) then
|
|
return true
|
|
elseif ID.IsHipValleyRafterNotch( Proc) and Proc.nFct < 4 then -- (0-25)
|
|
return true
|
|
elseif ID.IsRidgeLap( Proc) and Proc.nFct ~= 3 then -- (1-30)
|
|
return true
|
|
elseif ID.IsMortise( Proc) and Proc.nFct < 6 then -- (1-50)
|
|
return true
|
|
elseif ID.IsFrontMortise( Proc) and Proc.nFct < 6 then -- (1-51)
|
|
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 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
|
|
|
|
-- caso speciale taglio di testa
|
|
if Proc.nFct == 1 and AreSameVectorApprox( Proc.Faces[1].vtN, X_AX()) and abs( Proc.Faces[1].ptCenter:getX() - Part.b3Part:getMax():getX()) < 10 * GEO.EPS_SMALL then
|
|
sFamily = 'HeadCut'
|
|
bIsThrough = true
|
|
-- caso speciale taglio di coda
|
|
elseif Proc.nFct == 1 and AreSameVectorApprox( Proc.Faces[1].vtN, -X_AX()) and abs( Proc.Faces[1].ptCenter:getX() - Part.b3Part:getMin():getX()) < 10 * GEO.EPS_SMALL then
|
|
sFamily = 'TailCut'
|
|
bIsThrough = true
|
|
elseif 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.nParts == 1 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 and Proc.nParts == 1 then
|
|
sFamily = 'VGroove'
|
|
bIsThrough = true
|
|
elseif Proc.nFct == 2 and ( not bAllAnglesConcave or Proc.nParts == 2) 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 ( ( not bAllAnglesConcave and ( ( #vFacesByAdjNumber[2] == 2 and #vTriangularFaces == 2) or ( #vFacesByAdjNumber[3] == 2)))
|
|
or ( #vTriangularFaces == 2 and Proc.nParts == 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[1] == 4 and #vFacesByAdjNumber[3] == 2 and #vTriangularFaces == 4 and not bAllAnglesConcave)
|
|
or ( #vFacesByAdjNumber[1] == 4 and #vTriangularFaces == 4 and Proc.nParts == 2)) then
|
|
sFamily = 'DoubleBevel'
|
|
bIsThrough = false
|
|
end
|
|
|
|
if sFamily then
|
|
FeatureTopology.sFamily = sFamily
|
|
FeatureTopology.bIsThrough = bIsThrough
|
|
FeatureTopology.bAllRightAngles = bAllRightAngles
|
|
-- caso speciale taglio testa e coda
|
|
if FeatureTopology.sFamily == 'HeadCut' or FeatureTopology.sFamily == 'TailCut' then
|
|
FeatureTopology.sName = FeatureTopology.sFamily
|
|
else
|
|
FeatureTopology.sName = GetTopologyName( sFamily, Proc.nFct, bIsThrough)
|
|
end
|
|
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
|
|
elseif ID.IsRidgeLap( Proc) then
|
|
Topology.sName = 'RidgeLap-3-Through'
|
|
elseif ID.IsHipValleyRafterNotch( Proc) then
|
|
Topology.sName = 'RafterNotch-' .. tostring( Proc.nFct) .. '-Through'
|
|
else
|
|
Topology.sName = 'Feature'
|
|
end
|
|
return Topology
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.GetAdditionalInfo( Proc, Part)
|
|
Proc.FeatureInfo = {}
|
|
-- se foro
|
|
if ID.IsDrill( 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, Proc.AffectedFaces = 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)
|
|
elseif ID.IsRidgeLap( Proc) then
|
|
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
|
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
|
elseif ID.IsMarking( Proc) or ID.IsText( Proc) then
|
|
Proc.FeatureInfo = FeatureLib.GetMarkTextData( Proc)
|
|
elseif ID.IsHipValleyRafterNotch( Proc) then
|
|
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
|
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
|
Proc.FeatureInfo, Proc.MainFaces = FeatureLib.GetRafterNotchData( Proc)
|
|
elseif ( ID.IsScarfJoint( Proc) or ID.IsScarfSimple( Proc)) then
|
|
Proc.AdjacencyMatrix = FaceData.GetAdjacencyMatrix( Proc)
|
|
Proc.Faces = FaceData.GetFacesInfo( Proc, Part)
|
|
end
|
|
|
|
return Proc
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- Recupero dati foro e adattamento se speciale
|
|
function FeatureLib.GetDrillingData( Proc)
|
|
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
|
|
if idAux then idAux = idAux + Proc.id end
|
|
|
|
local FeatureExtraInfo = {}
|
|
|
|
-- verifico se foro da adattare
|
|
if EgtExistsInfo( Proc.id, 'DiamUser') then
|
|
if idAux and EgtGetType( idAux) == GDB_TY.CRV_ARC and BeamData.USER_HOLE_DIAM and BeamData.USER_HOLE_DIAM > 1 then
|
|
EgtModifyArcRadius( idAux, BeamData.USER_HOLE_DIAM / 2)
|
|
end
|
|
end
|
|
|
|
FeatureExtraInfo.dDrillDiam = 2 * EgtArcRadius( idAux) or EgtGetInfo( Proc.id, 'P12', 'd') or 0
|
|
FeatureExtraInfo.dDrillLen = abs( EgtCurveThickness( idAux)) or 0
|
|
FeatureExtraInfo.ptDrillCenter = EgtCP( idAux, GDB_RT.GLOB)
|
|
FeatureExtraInfo.vtDrillExtrusion = EgtCurveExtrusion( idAux, GDB_RT.GLOB)
|
|
FeatureExtraInfo.nDrillFcs = EgtGetInfo( Proc.id, 'FCS', 'i') or 0
|
|
FeatureExtraInfo.nDrillFce = EgtGetInfo( Proc.id, 'FCE', 'i') or 0
|
|
FeatureExtraInfo.bIsDrillOpen = ( FeatureExtraInfo.nDrillFcs ~= 0 and FeatureExtraInfo.nDrillFce ~= 0)
|
|
FeatureExtraInfo.bIsDrillHorizontal = abs( FeatureExtraInfo.vtDrillExtrusion:getZ()) < 10 * GEO.EPS_SMALL
|
|
FeatureExtraInfo.idAddAuxGeom = idAux
|
|
|
|
return FeatureExtraInfo
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- Recupero dati tenone e tenone a coda di rondine
|
|
function FeatureLib.GetRafterNotchData( Proc)
|
|
local FeatureExtraInfo = {}
|
|
local MainFaces = {}
|
|
|
|
local FacesByAdjacencyNumber = FaceData.GetFacesByAdjacencyNumber( Proc)
|
|
if FacesByAdjacencyNumber then
|
|
-- si prende sempre quella con più adiacenze
|
|
MainFaces.BottomFaces = FacesByAdjacencyNumber[ Proc.nFct - 1]
|
|
MainFaces.BottomFaces[1].vtN = Proc.Faces[MainFaces.BottomFaces[1].id+1].vtN
|
|
MainFaces.BottomFaces[1].dElevation= Proc.Faces[MainFaces.BottomFaces[1].id+1].dElevation
|
|
FeatureExtraInfo.dFaceLength = 9999
|
|
-- si cerca lato aperto più corto
|
|
for i = 1, #MainFaces.BottomFaces[1].Edges do
|
|
if MainFaces.BottomFaces[1].Edges[i].bIsOpen then
|
|
FeatureExtraInfo.dFaceLength = min ( FeatureExtraInfo.dFaceLength, MainFaces.BottomFaces[1].Edges[i].dLength)
|
|
end
|
|
end
|
|
end
|
|
return FeatureExtraInfo, MainFaces
|
|
end
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- Recupero dati tenone e tenone a coda di rondine
|
|
function FeatureLib.GetMarkTextData( Proc)
|
|
local FeatureExtraInfo = {}
|
|
-- recupero i dati della marcatura
|
|
local vtExtr
|
|
if EgtGetType( Proc.id) ~= GDB_TY.EXT_TEXT then
|
|
vtExtr = EgtCurveExtrusion( Proc.id, GDB_RT.GLOB)
|
|
else
|
|
vtExtr = EgtTextNormVersor( Proc.id, GDB_ID.ROOT)
|
|
end
|
|
|
|
FeatureExtraInfo.vtExtr = vtExtr
|
|
FeatureExtraInfo.AdditionalGeometries = EgtSplitString( EgtGetInfo( Proc.id, 'AUXID', 's')) or {}
|
|
|
|
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.dTenonPathLength = EgtCurveLength( idAux)
|
|
FeatureExtraInfo.dTenonLength = dTenH
|
|
FeatureExtraInfo.dTenonMaxDist = dMaxDist
|
|
FeatureExtraInfo.vtTenonN = vtN
|
|
FeatureExtraInfo.ptTenonCenter = ptC
|
|
FeatureExtraInfo.idAddAuxGeom = idAux
|
|
|
|
-- aggiorno AffectedFaces in base al tipo di feature
|
|
local UpdatedAffectedFaces = Proc.AffectedFaces
|
|
if vtN:getX() > 0 then
|
|
UpdatedAffectedFaces.bRight = true
|
|
else
|
|
UpdatedAffectedFaces.bLeft = true
|
|
end
|
|
|
|
return FeatureExtraInfo, UpdatedAffectedFaces
|
|
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
|
|
vtDiff:normalize()
|
|
FeatureExtraInfo.vtMortisePathStart = EgtSV( idAux, GDB_RT.GLOB) * vtDiff
|
|
FeatureExtraInfo.vtMortisePathEnd = EgtEV( idAux, GDB_RT.GLOB) * vtDiff
|
|
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 dCompletionIndex = 0
|
|
|
|
-- nullo
|
|
if dCompletionPercentage < 5 then
|
|
dCompletionIndex = 0
|
|
-- Low
|
|
elseif dCompletionPercentage < 50 then
|
|
dCompletionIndex = 1
|
|
-- Medium
|
|
elseif dCompletionPercentage < 80 then
|
|
dCompletionIndex = 2
|
|
-- High
|
|
elseif dCompletionPercentage < 95 then
|
|
dCompletionIndex = 4
|
|
-- High / Complete
|
|
else
|
|
dCompletionIndex = 5
|
|
end
|
|
|
|
return dCompletionIndex
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.GetStrategyQuality( Parameter)
|
|
local dQuality = 0
|
|
|
|
-- se viene passata una tabella, si calcola media pesata di tutte le lavorazioni
|
|
if type( Parameter) == "table" then
|
|
local Machinings = Parameter
|
|
local dQualityNumerator = 0
|
|
local dQualityDenominator = 0
|
|
for i = 1, #Machinings do
|
|
local Machining = Machinings[i]
|
|
local dWeightedQuality = FeatureLib.GetStrategyQuality( TOOLS[Machining.nToolIndex].sFamily) * Machining.dLengthToMachine
|
|
if Machining.bIsApplicable then
|
|
dQualityNumerator = dQualityNumerator + dWeightedQuality
|
|
dQualityDenominator = dQualityDenominator + Machining.dLengthToMachine
|
|
end
|
|
end
|
|
dQuality = dQualityNumerator / dQualityDenominator
|
|
-- se viene passato un tag, si ritorna direttamente il voto
|
|
elseif type( Parameter) == "string" then
|
|
local sMachiningTag = Parameter
|
|
-- #### STATI DI LAVORAZIONE AGGREGATI #### --
|
|
-- BEST = lavorazione eccellente, la migliore qualità che si possa ottenere
|
|
if sMachiningTag == 'BEST' then
|
|
dQuality = 5
|
|
-- FINE = lavorazione ottima, non dovrebbero esscerci scheggiature
|
|
elseif sMachiningTag == 'FINE' then
|
|
dQuality = 4
|
|
-- STD = lavorazione accettabile, potrebbe avere scheggiature minime
|
|
elseif sMachiningTag == 'STD' then
|
|
dQuality = 3
|
|
-- SEMI = lavorazione accettabile, potrebbe avere scheggiature minime, mancano piccoli dettagli alla lavorazione (es. se vengono lasciati i raggi fresa sugli spigoli)
|
|
elseif sMachiningTag == 'SEMI' then
|
|
dQuality = 2.5
|
|
-- ROUGH = Lavorazione scadente, scheggiatura molto probabile, potrebbe non essere precisa
|
|
elseif sMachiningTag == 'ROUGH' then
|
|
dQuality = 1
|
|
-- #### UTENSILI DI LAVORAZIONE UTILIZZATI #### --
|
|
elseif sMachiningTag == 'SAWBLADE' then
|
|
dQuality = 5
|
|
elseif sMachiningTag == 'DRILLBIT' then
|
|
dQuality = 4
|
|
elseif sMachiningTag == 'MILL' then
|
|
dQuality = 3
|
|
elseif sMachiningTag == 'MORTISE' then
|
|
dQuality = 1
|
|
else
|
|
dQuality = 0
|
|
end
|
|
else
|
|
dQuality = 0
|
|
end
|
|
|
|
return dQuality
|
|
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.dCompletionIndex = 0
|
|
Result.dQuality = 0
|
|
Result.sInfo = sInfo
|
|
|
|
return Result
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
local function GetMachiningStrategyCoefficients( sMachiningStrategy)
|
|
local dCoeffQuality, dCoeffCompletion, dCoeffTime
|
|
-- queste sono tutte le opzioni possibili. Da configurazione si può settare solo: AUTO, FASTEST, HIGH_QUALITY
|
|
if sMachiningStrategy == 'FASTEST' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 0.75, 0.75, 1.5
|
|
elseif sMachiningStrategy == 'HIGH_QUALITY' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 1.5, 0.75, 0.75
|
|
elseif sMachiningStrategy == 'COMPLETEST' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 0.75, 1.5, 0.75
|
|
elseif sMachiningStrategy == 'IGNORE_TIME' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 1.25, 1.25, 0.5
|
|
elseif sMachiningStrategy == 'IGNORE_QUALITY' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 0.5, 1.25, 1.25
|
|
elseif sMachiningStrategy == 'IGNORE_COMPLETION' then
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 1.25, 0.5, 1.25
|
|
else -- sMachiningStrategy == 'FIRST_IN_LIST' or sMachiningStrategy == 'AUTO' (oppure non settato, ma dovrebbe essere sempre settato!)
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = 1, 1, 1
|
|
end
|
|
|
|
return dCoeffQuality, dCoeffCompletion, dCoeffTime
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- TODO rivedere affidabilità del calcolo del composite rating
|
|
-- funzione che calcola il 'CompositeRating' di ogni strategia
|
|
function FeatureLib.CalculateStrategiesCompositeRating( AvailableStrategies, sMachiningStrategy)
|
|
for n = 1, #AvailableStrategies do
|
|
-- se ho tutti i dati che mi servono calcolo il rating della strategia applicato alla feature
|
|
if AvailableStrategies[n].Result and AvailableStrategies[n].Result.dQuality and AvailableStrategies[n].Result.dCompletionIndex and AvailableStrategies[n].Result.dTimeToMachine then
|
|
-- il tempo è pesato sul totale delle strategie, e riportato nell'intervallo 1-5, dove 5 è il tempo migliore (il più basso)
|
|
local dIndexWeightTimeToMachine = 5 - ( 4 * ( EgtClamp( AvailableStrategies[n].Result.dTimeToMachine / AvailableStrategies.dAllStrategiesTotalTime, 0, 1)))
|
|
AvailableStrategies[n].Result.dTimeIndex = dIndexWeightTimeToMachine
|
|
|
|
-- si calcolano gli indici pesati in base alla configurazione utente. Possibili parametri di configurazione:
|
|
local dQuality, dCompletion, dTime, dCoeffQuality, dCoeffCompletion, dCoeffTime
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = GetMachiningStrategyCoefficients( sMachiningStrategy)
|
|
|
|
dQuality = AvailableStrategies[n].Result.dQuality * dCoeffQuality
|
|
dCompletion = AvailableStrategies[n].Result.dCompletionIndex * dCoeffCompletion
|
|
dTime = dIndexWeightTimeToMachine * dCoeffTime
|
|
|
|
AvailableStrategies[n].Result.dCompositeRating = dQuality + dCompletion + dTime -- TODO da verificare se meglio sommare o moltiplicare gli indici
|
|
else
|
|
AvailableStrategies[n].Result.dCompositeRating = 0
|
|
end
|
|
end
|
|
|
|
return AvailableStrategies
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- TODO rivedere affidabilità del calcolo del composite rating
|
|
-- funzione che calcola il 'CompositeRating' di ogni combinazione
|
|
function FeatureLib.CalculateCombinationsCompositeRating( CombinationsList, sMachiningStrategy)
|
|
for n = 1, #CombinationsList do
|
|
-- se ho tutti i dati che mi servono calcolo il rating della strategia applicato alla feature
|
|
if CombinationsList[n].dTotalQuality and CombinationsList[n].dTotalCompletionIndex and CombinationsList[n].dTotalTimeToMachine then
|
|
-- il tempo è pesato sul totale delle strategie, e riportato nell'intervallo 1-5, dove 5 è il tempo migliore (il più basso)
|
|
local dIndexWeightTimeToMachine = 5 - ( 4 * ( EgtClamp( CombinationsList[n].dTotalTimeToMachine / CombinationsList.dAllCombinationsTotalTime, 0, 1)))
|
|
|
|
-- si calcolano gli indici pesati in base alla configurazione utente. Possibili parametri di configurazione:
|
|
local dQuality, dCompletion, dTime, dCoeffQuality, dCoeffCompletion, dCoeffTime
|
|
dCoeffQuality, dCoeffCompletion, dCoeffTime = GetMachiningStrategyCoefficients( sMachiningStrategy)
|
|
|
|
|
|
dQuality = CombinationsList[n].dTotalQuality * dCoeffQuality
|
|
dCompletion = CombinationsList[n].dTotalCompletionIndex * dCoeffCompletion
|
|
dTime = dIndexWeightTimeToMachine * dCoeffTime
|
|
|
|
CombinationsList[n].dTotalRating = dQuality + dCompletion + dTime -- TODO da verificare se meglio sommare o moltiplicare gli indici
|
|
else
|
|
CombinationsList[n].dTotalRating = 0
|
|
end
|
|
end
|
|
|
|
return CombinationsList
|
|
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
|
|
|
|
-- TODO RIMUOVERE E SISTEMARE LA FUNZIONE!!
|
|
-- se il punto finisce fuori si mette in mezzeria
|
|
if #FeatureSplittingPoints == 1
|
|
and ( ( FeatureSplittingPoints[1]:getX() < Part.b3Part:getMin():getX() + 10 * GEO.EPS_SMALL)
|
|
or ( FeatureSplittingPoints[1]:getX() > Part.b3Part:getMax():getX() - 10 * GEO.EPS_SMALL)) then
|
|
|
|
FeatureSplittingPoints[1] = Point3d( Part.b3Part:getMin():getX() + ( Part.b3Part:getMax():getX() - Part.b3Part:getMin():getX()) / 2, 0, 0)
|
|
end
|
|
|
|
return FeatureSplittingPoints
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.GetFeatureVolume( Proc, Part)
|
|
local dProcVolume = 0
|
|
|
|
local idTempGroup = Part.idTempGroup
|
|
|
|
local idProcCopy = EgtCopyGlob( Proc.id, idTempGroup) or GDB_ID.NULL
|
|
local b3PartCopy = BBox3d( Part.b3Part)
|
|
b3PartCopy:expand( -100 * GEO.EPS_SMALL)
|
|
local idPartCopy = EgtSurfTmBBox( idTempGroup, b3PartCopy , false, GDB_RT.GLOB)
|
|
|
|
EgtSurfTmSubtract( idPartCopy, idProcCopy)
|
|
dProcVolume = EgtSurfVolume( 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, di testa e più bassa di 40mm, allora potrebbe impattare sulla misura laser, controllo caso per caso
|
|
if Proc.AffectedFaces.bRight and Proc.AffectedFaces.bFront and Proc.AffectedFaces.bBack and
|
|
( Proc.b3Box:getMin():getZ() - Part.b3Raw:getMin():getZ()) < 40 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
|
|
|
|
-- se il grezzo non è definito, prendo il box del pezzo
|
|
-- TODO 1- si sta passando b3part per riferimento, 2- non dovrebbe essre sempre definito?
|
|
if not Part.b3Raw then
|
|
Part.b3Raw = Part.b3Part
|
|
end
|
|
|
|
-- TODO se la feature ha più di 3 facce non viene mai calcolato!! Es. Tenone ecc....
|
|
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
|
|
end
|
|
if 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
|
|
end
|
|
end
|
|
end
|
|
|
|
NotClampableLength.dNotClampableLengthHead = dNotClampableLengthHead
|
|
NotClampableLength.dNotClampableLengthTail = dNotClampableLengthTail
|
|
|
|
return NotClampableLength
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
function FeatureLib.GetFeatureRotationNotClampableLengths( Proc, Part, nRotation)
|
|
local nPartIndex = Part.nIndexInParts
|
|
local nProcIndex = Proc.nIndexInVProc
|
|
local Rotations = PROCESSINGS[nPartIndex].Rotation
|
|
|
|
local dLenOnHead = 0
|
|
local dLenOnTail = 0
|
|
-- controllo che la rotazione sia attiva
|
|
if string.sub( Part.ChosenCombination, nRotation, nRotation) == '1' then
|
|
dLenOnHead = Rotations[nRotation][nProcIndex].NotClampableLength.dNotClampableLengthHead
|
|
dLenOnTail = Rotations[nRotation][nProcIndex].NotClampableLength.dNotClampableLengthTail
|
|
end
|
|
|
|
return dLenOnHead, dLenOnTail
|
|
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 |