-- 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.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.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, 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 ------------------------------------------------------------------------------------------------------------- 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) 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 vtExtr = EgtCurveExtrusion( idAux, GDB_RT.GLOB) local ptBC = EgtGP( idAux, GDB_RT.GLOB) -- determino altezza del tenone local frTen = Frame3d( ptBC, vtExtr) local b3Ten = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frTen) local dTenH = b3Ten:getDimZ() -- assegno centro e normale della faccia top local vtN = vtExtr 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 = vtExtr FeatureExtraInfo.ptTenonCenter = ptC FeatureExtraInfo.idAddAuxGeom = idAux 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 ------------------------------------------------------------------------------------------------------------- -- 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 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 nAddGrpId = BeamLib.GetAddGroup( Part.id) if not nAddGrpId then -- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste? EgtOutLog( 'Error : missing AddGroup') return 0 end local idProcCopy = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL local b3PartCopy = BBox3d( Part.b3Part) b3PartCopy:expand( -100 * GEO.EPS_SMALL) local idPartCopy = EgtSurfTmBBox( nAddGrpId, b3PartCopy , false, GDB_RT.GLOB) EgtSurfTmSubtract( idPartCopy, idProcCopy) dProcVolume = EgtSurfVolume( idPartCopy) EgtErase( { idProcCopy, idPartCopy}) return dProcVolume end ------------------------------------------------------------------------------------------------------------- -- TODO funzione copiata direttamente da automatismo vecchio, da migliorare / completare function FeatureLib.CalculateFeatureNotClampableLengths( Proc, Part) local NotClampableLength = {} -- verifico siano una o due facce if Proc.nFct > 2 then return end -- 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 local dNotClampableLengthHead = 0 local dNotClampableLengthTail = 0 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 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