-- BeamLib.lua by Egalware s.r.l. 2024/04/02 -- Libreria globale per Travi -- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE -- Tabella per definizione modulo local BeamLib = {} -- Include require( 'EgtBase') local BeamData = require( 'BeamData') EgtOutLog( ' BeamLib started', 1) --TODO refactoring di queste funzioni ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPartStartFace( PartId, b3Solid) -- recupero gruppo per geometria aggiuntiva local AddGrpId = BeamLib.GetAddGroup( PartId) if not AddGrpId then local sErr = 'Error on process StartFace impossible to find AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo nuovo taglio iniziale local nStmId = EgtSurfTmPlaneInBBox( AddGrpId, b3Solid:getMax(), X_AX(), b3Solid, GDB_RT.GLOB) if not nStmId then local sErr = 'Error on process StartFace impossible to create Face' EgtOutLog( sErr) return false, sErr end -- applico gli opportuni attributi di feature EgtSetName( nStmId, 'StartCut') EgtSetInfo( nStmId, 'GRP', 1) EgtSetInfo( nStmId, 'PRC', 340) -- verifico se sostituisce un taglio di testa già presente local nProcId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PartId, 'Processings') or GDB_ID.NULL) while nProcId do local nGrp = EgtGetInfo( nProcId, 'GRP', 'i') or 0 local nProc = EgtGetInfo( nProcId, 'PRC', 'i') or 0 if ( nGrp == 1 or nGrp == 2) and nProc == 10 then local ptC, vtN = EgtSurfTmFacetCenter( nProcId, 0, GDB_ID.ROOT) if ptC and vtN and AreSameVectorApprox( vtN, X_AX()) and abs( ptC:getX() - b3Solid:getMax():getX()) < 10 * GEO.EPS_SMALL then EgtSetInfo( nStmId, 'ORI', nProcId) end end nProcId = EgtGetNext( nProcId) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPartEndFace( PartId, b3Solid) -- recupero gruppo per geometria aggiuntiva local AddGrpId = BeamLib.GetAddGroup( PartId) if not AddGrpId then local sErr = 'Error on process EndFace impossible to find AddGroup' EgtOutLog( sErr) return false, sErr end -- aggiungo nuovo taglio finale local nStmId = EgtSurfTmPlaneInBBox( AddGrpId, b3Solid:getMin(), -X_AX(), b3Solid, GDB_RT.GLOB) if not nStmId then local sErr = 'Error on process EndFace impossible to create Face' EgtOutLog( sErr) return false, sErr end -- applico gli opportuni attributi di feature EgtSetName( nStmId, 'EndCut') EgtSetInfo( nStmId, 'GRP', 2) EgtSetInfo( nStmId, 'PRC', 350) -- verifico se sostituisce un taglio di coda già presente local nProcId = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PartId, 'Processings') or GDB_ID.NULL) while nProcId do local nGrp = EgtGetInfo( nProcId, 'GRP', 'i') or 0 local nProc = EgtGetInfo( nProcId, 'PRC', 'i') or 0 if ( nGrp == 1 or nGrp == 2) and nProc == 10 then local ptC, vtN = EgtSurfTmFacetCenter( nProcId, 0, GDB_ID.ROOT) if ptC and vtN and AreSameVectorApprox( vtN, -X_AX()) and abs( ptC:getX() - b3Solid:getMin():getX()) < 10 * GEO.EPS_SMALL then EgtSetInfo( nStmId, 'ORI', nProcId) end end nProcId = EgtGetNext( nProcId) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetPartSplittingPoints( Part, OptionalParameters) local PartSplittingPoints = {} local dPartLength = Part.b3Part: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 if dPartLength < dMaxSegmentLength + 10 * GEO.EPS_SMALL then return {} elseif dPartLength >= dMaxSegmentLength + 10 * GEO.EPS_SMALL and dPartLength < 3 * dMaxSegmentLengthOnEdges + 10 * GEO.EPS_SMALL then local dXPartCentralPoint = ( Part.b3Part:getMax():getX() - Part.b3Part:getMin():getX()) / 2 table.insert( PartSplittingPoints, Point3d( dXPartCentralPoint, 0, 0)) else -- punto estremo destro local dSplitXRight = Part.b3Part:getMax():getX() - dMaxSegmentLengthOnEdges table.insert( PartSplittingPoints, Point3d( dSplitXRight, 0, 0)) -- punti centrali local dPartCentralLength = dPartLength - 2 * dMaxSegmentLengthOnEdges local nSplitParts = max( ceil( dPartCentralLength / dMaxSegmentLength + 10 * GEO.EPS_SMALL), 1) local dSplitPartsLen = dPartCentralLength / nSplitParts for i = 1, ( nSplitParts - 1) do local ptOn local dCurrentPointX = dSplitXRight - i * dSplitPartsLen ptOn = Point3d( dCurrentPointX, 0, 0) table.insert( PartSplittingPoints, ptOn) end -- punto estremo sinistro local dSplitXLeft = Part.b3Part:getMin():getX() + dMaxSegmentLengthOnEdges table.insert( PartSplittingPoints, Point3d( dSplitXLeft, 0, 0)) end return PartSplittingPoints end ------------------------------------------------------------------------------------------------------------- function BeamLib.AddPhaseWithRawParts( nRawId, OriXR, PosXR, dDeltaSucc) EgtAddPhase() local dRawMove = 0 while nRawId do EgtKeepRawPart( nRawId) EgtMoveToCornerRawPart( nRawId, OriXR, PosXR) EgtMoveRawPart( nRawId, Vector3d( - dRawMove, 0, 0)) if dRawMove == 0 then dRawMove = dRawMove + dDeltaSucc end dRawMove = dRawMove + EgtGetRawPartBBox( nRawId):getDimX() nRawId = EgtGetNextRawPart( nRawId) end end ------------------------------------------------------------------------------------------------------------- --- funzione che ruota il pezzo, da lanciare per creare la disposizione corretta function BeamLib.RotatePart( Part, nPosition) -- primo posizionamento if nPosition == 1 then ; -- il pezzo è già in posizione -- rotazione 90° elseif nPosition == 2 then local dDeltaYZ = EgtGetRawPartBBox( Part.idRaw):getDimY() - EgtGetRawPartBBox( Part.idRaw):getDimZ() local vtMove = Vector3d( 0, dDeltaYZ / 2 * EgtIf( BeamData.RIGHT_LOAD, -1, 1), dDeltaYZ / 2) local bPreMove = dDeltaYZ < 0 -- ruoto le travi della fase corrente local nRId = Part.idRaw while nRId do if bPreMove then EgtMoveRawPart( nRId, vtMove) end EgtRotateRawPart( nRId, X_AX(), EgtIf( BeamData.RIGHT_LOAD, -90, 90)) if not bPreMove then EgtMoveRawPart( nRId, vtMove) end nRId = EgtGetNextRawPart( nRId) end -- rotazione 180° elseif nPosition == 3 then -- ribalto le travi della fase corrente local nRId = Part.idRaw while nRId do EgtRotateRawPart( nRId, X_AX(), 180) nRId = EgtGetNextRawPart( nRId) end -- rotazione 270° elseif nPosition == 4 then local dDeltaYZ = EgtGetRawPartBBox( Part.idRaw):getDimY() - EgtGetRawPartBBox( Part.idRaw):getDimZ() local vtMove = Vector3d( 0, dDeltaYZ / 2 * EgtIf( BeamData.RIGHT_LOAD, -1, 1), dDeltaYZ / 2) local bPreMove = dDeltaYZ < 0 -- ruoto le travi della fase corrente local nRId = Part.idRaw while nRId do if bPreMove then EgtMoveRawPart( nRId, vtMove) end EgtRotateRawPart( nRId, X_AX(), EgtIf( BeamData.RIGHT_LOAD, 90, -90)) if not bPreMove then EgtMoveRawPart( nRId, vtMove) end nRId = EgtGetNextRawPart( nRId) end end end ------------------------------------------------------------------------------------------------------------- function BeamLib.CreateOrEmptyAddGroup( PartId) -- recupero i dati del gruppo aggiuntivo local AddGrpId, sMchGrp = BeamLib.GetAddGroup( PartId) if not sMchGrp then return false end -- se esiste, aggiorno riferimento al gruppo di lavoro e lo svuoto if AddGrpId then EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) return EgtEmptyGroup( AddGrpId) end -- altrimenti lo creo AddGrpId = EgtGroup( PartId or GDB_ID.NULL) if not AddGrpId then return false end -- assegno nome, flag di layer per gruppo di lavoro e colore EgtSetName( AddGrpId, sMchGrp) EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 50)) return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetAddGroup( PartId) -- recupero il nome del gruppo di lavoro corrente local sMchGrp = EgtGetMachGroupName( EgtGetCurrMachGroup() or GDB_ID.NULL) if not sMchGrp then return nil, nil end -- cerco il gruppo aggiuntivo omonimo nel pezzo e se esiste lo restituisco local AddGrpId = EgtGetFirstNameInGroup( PartId or GDB_ID.NULL, sMchGrp) -- restituisco Id e Nome return AddGrpId, sMchGrp end ------------------------------------------------------------------------------------------------------------- -- restituisce le facce della parte interessate dalla feature Proc function BeamLib.GetAffectedFaces( Proc, Part) local vtFacesAffected = { bTop = false, bBottom = false, bFront = false, bBack = false, bLeft = false, bRight = false} if Proc.b3Box and not Proc.b3Box:isEmpty() then if Proc.b3Box:getMax():getZ() > Part.b3Part:getMax():getZ() - 500 * GEO.EPS_SMALL then vtFacesAffected.bTop = true end if Proc.b3Box:getMin():getZ() < Part.b3Part:getMin():getZ() + 500 * GEO.EPS_SMALL then vtFacesAffected.bBottom = true end if Proc.b3Box:getMin():getY() < Part.b3Part:getMin():getY() + 500 * GEO.EPS_SMALL then vtFacesAffected.bFront = true end if Proc.b3Box:getMax():getY() > Part.b3Part:getMax():getY() - 500 * GEO.EPS_SMALL then vtFacesAffected.bBack = true end if Proc.b3Box:getMin():getX() < Part.b3Part:getMin():getX() + 500 * GEO.EPS_SMALL then vtFacesAffected.bLeft = true end if Proc.b3Box:getMax():getX() > Part.b3Part:getMax():getX() - 500 * GEO.EPS_SMALL then vtFacesAffected.bRight = true end end return vtFacesAffected end --------------------------------------------------------------------- function BeamLib.GetNearestOrthoOpposite( vtRef, vtNorm) -- se definita anche la normale alla faccia, elimino la parte di vtRef parallela a questa local vtMyRef = Vector3d( vtRef) if vtNorm then vtMyRef = vtMyRef - ( vtMyRef * vtNorm) * vtNorm vtMyRef:normalize() end -- se prevalente una componente orizzontale (con piccolissimo vantaggio) if abs( vtMyRef:getX()) > 0.91 * abs( vtMyRef:getZ()) or abs( vtMyRef:getY()) > 0.91 * abs( vtMyRef:getZ()) then -- se prevale la componente destra/sinistra if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getY()) then if vtMyRef:getX() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_LEFT else return MCH_MILL_FU.ORTHO_RIGHT end else if vtMyRef:getY() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_FRONT else return MCH_MILL_FU.ORTHO_BACK end end -- altrimenti prevale la verticale else if vtMyRef:getZ() > -GEO.EPS_SMALL then return MCH_MILL_FU.ORTHO_DOWN else return MCH_MILL_FU.ORTHO_TOP end end return nil end --------------------------------------------------------------------- function BeamLib.GetNearestParalOpposite( vtRef, vtNorm) -- se definita anche la normale alla faccia, elimino la parte di vtRef parallela a questa local vtMyRef = Vector3d( vtRef) if vtNorm then vtMyRef = vtMyRef - ( vtMyRef * vtNorm) * vtNorm vtMyRef:normalize() end -- se prevalente una componente orizzontale (con piccolissimo vantaggio) if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getZ()) or abs( vtMyRef:getY()) > 0.95 * abs( vtMyRef:getZ()) then if abs( vtMyRef:getX()) > 0.95 * abs( vtMyRef:getY()) then if vtMyRef:getX() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_LEFT else return MCH_MILL_FU.PARAL_RIGHT end else if vtMyRef:getY() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_FRONT else return MCH_MILL_FU.PARAL_BACK end end -- altrimenti prevale la verticale else if vtMyRef:getZ() > -GEO.EPS_SMALL then return MCH_MILL_FU.PARAL_DOWN else return MCH_MILL_FU.PARAL_TOP end end return nil end --------------------------------------------------------------------- -- Funzione per determinare se la faccia ha lati molto corti (trascurabili) ed è quindi approssimabile ad una 3 facce function BeamLib.Is3EdgesApprox( Proc, idFace, nAddGrpId) nAddGrpId = nAddGrpId or BeamLib.GetAddGroup( Proc.idPart) if not nAddGrpId then local nEdges = #(EgtSurfTmFacetAdjacencies( Proc.id, idFace)[1]) return ( nEdges == 3) end local bResult = false local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Proc.id, idFace, nAddGrpId) if not nContourId then return false end EgtMergeCurvesInCurveCompo( nContourId) -- recupero il numero effettivo di lati local _, nEntityCount = EgtCurveDomain( nContourId) local nEdges = nEntityCount if nEntityCount and nEntityCount == 3 then bResult = true -- rimuovo i lati molto corti dal conteggio totale elseif nEntityCount then for i = 1, nEntityCount do local dLength = EgtCurveCompoLength( nContourId, i - 1) if dLength < 15 then nEdges = nEdges - 1 end end end if nEdges == 3 then bResult = true end -- cancello tutti i contorni appena creati EgtErase( EgtTableFill( nContourId, nContourCnt)) return bResult end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetNzLimDownUp( b3Raw, vtN, vtOrtho) if BeamData.GetNzLimDownUp then return BeamData.GetNzLimDownUp( b3Raw, vtN, vtOrtho) elseif BeamData.C_SIMM then return -0.484 elseif BeamData.TURN then return -2 else if vtOrtho and vtOrtho:getZ() > 0.35 then -- N_HorAng < 15° or N_HorAng > 55° if vtN and ( abs( vtN:getY()) < 0.259 or abs( vtN:getY()) > 0.819) then return -0.708 -- N_HorAng > 50° elseif vtN and abs( vtN:getY()) > 0.766 then return -0.383 else return EgtIf( b3Raw:getDimZ() < BeamData.MIN_DIM_HBEAM, -0.609, -0.383) end else -- N_HorAng > 60° if vtN and ( abs( vtN:getY()) > 0.866) then return -0.708 else if b3Raw:getDimZ() < 120 then return -0.708 elseif b3Raw:getDimZ() < 200 then -- N_HorAng < 15° or N_HorAng > 55° if vtN and ( abs( vtN:getY()) < 0.259 or abs( vtN:getY()) > 0.819) then return -0.5 else return -0.383 end elseif b3Raw:getDimZ() < 300 then -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.5 else return -0.259 end elseif b3Raw:getDimZ() < BeamData.MIN_DIM_HBEAM then -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.342 else return -0.259 end else -- N_HorAng < 10° if vtN and ( abs( vtN:getY()) < 0.174) then return -0.383 else return -0.174 end end end end end end ------------------------------------------------------------------------------------------------------------- -- sovrascrivo i parametri personalizzati salvati su Proc a quelli di default dalla strategia -- N.B. : I parametri personalizzati non più presenti tra i default della strategia, verranno ignorati. Quelli extra avranno valore di default -- Il controllo deve essere fatto SEMPRE all'inizio di ogni strategia, per controllare conformità parametri custom function BeamLib.GetUpdateCustomParameters( CustomStrategyParamList, DefaultStrategyParamList) if CustomStrategyParamList and #CustomStrategyParamList > 0 then for i = 1, #DefaultStrategyParamList do for j = 1, #CustomStrategyParamList do if DefaultStrategyParamList[i].sName == CustomStrategyParamList[j].sName then DefaultStrategyParamList[i].sValue = CustomStrategyParamList[j].sValue end end end end return DefaultStrategyParamList end ------------------------------------------------------------------------------------------------------------- -- si traduce la tabella dei parametri con tutte le informazioni in una lista contenente i parametri utilizzabili con accesso diretto function BeamLib.LoadCustomParametersInStrategy( CustomParameters) local Parameters = {} if CustomParameters and #CustomParameters > 0 then for i=1, #CustomParameters do if CustomParameters[i].sType == 'b' then Parameters[CustomParameters[i].sName] = CustomParameters[i].sValue == 'true' elseif CustomParameters[i].sType == 'd' then Parameters[CustomParameters[i].sName] = tonumber( CustomParameters[i].sValue) else --CustomParameters[i].sType == 's' or CustomParameters[i].sType == 'combo' Parameters[CustomParameters[i].sName] = CustomParameters[i].sValue end end end return Parameters end --------------------------------------------------------------------- function BeamLib.GetChainSawInitAngs( vtN, vtO, nInd) if BeamData.GetChainSawInitAngs then return BeamData.GetChainSawInitAngs( vtN, vtO, nInd) else if BeamData.C_SIMM then return EgtIf( vtN:getY() > 0, 'C=180', 'C=-180') else if nInd == 1 then return '' else return EgtIf( vtN:getY() > 0, 'C=180', 'C=-180') end end end end --------------------------------------------------------------------- function BeamLib.GetBlockedAxis( nToolIndex, sBlockedAxis, b3Raw, vtTool, vtOut) -- se presente funzione specifica nella macchina, la richiamo if BeamData.GetBlockedAxis then return BeamData.GetBlockedAxis( TOOLS[nToolIndex].sHead, TOOLS[nToolIndex].nTypeId, sBlockedAxis, b3Raw, vtTool, vtOut) or '' -- sezione mantenuta per retrocompatibilità con GetChainSawBlockedAxis elseif TOOLS[nToolIndex].nTypeId == MCH_TY.MORTISE_STD then local nInd = EgtIf( sBlockedAxis == 'parallel', 0, 1) if BeamData.GetChainSawBlockedAxis then return BeamData.GetChainSawBlockedAxis( nInd) else if nInd == 1 then return EgtIf( BeamData.C_SIMM, 'A=90', 'A=90') else return EgtIf( BeamData.C_SIMM, 'A=0', 'A=0') end end end return '' end --------------------------------------------------------------------- function BeamLib.BinaryToDecimal( dNumber) local sNumberToConvert = tostring( dNumber) local dResult = 0 local k = 0 for i = #sNumberToConvert, 1, -1 do k = k + 1 local n = string.sub(sNumberToConvert, k, k) dResult = dResult + n*(2^(i-1)) end return dResult end --------------------------------------------------------------------- function BeamLib.DecimalToBinary( dNumber) local sNumberToConvert = tostring( dNumber) local n = sNumberToConvert local tmp = {} local sResult = "" for i = sNumberToConvert, 0, -1 do local q = math.modf(n) n = n/2 local b = q%2 table.insert(tmp, b) if (q == 1) then break end end for i = #tmp, 1, -1 do sResult = sResult..tmp[i] end return tonumber( sResult) end --------------------------------------------------------------------- function BeamLib.CalculateStringBinaryFormat( dNumber, CharNumber) local NumberString = tostring( dNumber) while #NumberString < CharNumber do NumberString = '0' .. NumberString end return NumberString end --------------------------------------------------------------------- --- copia una tabella lua in modo ricorsivo, ossia mantiene indipendenti anche tutte le sottotabelle --- ATTENZIONE: in caso di modifiche vanno gestiti anche i tipi custom; sarebbe meglio metterla nel LuaLibs function BeamLib.TableCopyDeep( OriginalTable) local CopiedTable = {} for key, value in pairs( OriginalTable) do if type( value) == "table" then if isBBox3d( value) then CopiedTable[ key] = BBox3d( value) elseif isColor3d( value) then CopiedTable[ key] = Color3d( value) elseif isFrame3d( value) then CopiedTable[ key] = Frame3d( value) elseif isPoint3d( value) then CopiedTable[ key] = Point3d( value) elseif isQuaternion( value) then CopiedTable[ key] = Quaternion( value) elseif isVector3d( value) then CopiedTable[ key] = Vector3d( value) else CopiedTable[ key] = BeamLib.TableCopyDeep( value) end else CopiedTable[ key] = value end end return CopiedTable end --------------------------------------------------------------------- -- Merge sorting - algoritmo di sorting stabile, ossia che mantiene l'ordine relativo se gli elementi sono equivalenti -- TODO vedere come riordinare (tutto in tabella MergeSort??) -- TODO libreria Sorting?? do -- unisce due liste ordinate local function MergeHalves(Left, Right, Compare) local result = {} local i, j = 1, 1 while i <= #Left and j <= #Right do if Compare( Left[i], Right[j]) then table.insert( result, Left[i]) i = i + 1 else table.insert( result, Right[j]) j = j + 1 end end -- Append degli elementi rimanenti a sinistra o destra while i <= #Left do table.insert( result, Left[i]) i = i + 1 end while j <= #Right do table.insert( result, Right[j]) j = j + 1 end return result end -- Merge sort local function MergeSort( List, Compare) if #List <= 1 then return List end local mid = floor( #List / 2) local Left = MergeSort( { table.unpack( List, 1, mid)}, Compare) local Right = MergeSort( { table.unpack( List, mid + 1)}, Compare) return MergeHalves( Left, Right, Compare) end -- chiamata accessibile dall'esterno function BeamLib.StableSort( List, Compare) return MergeSort( List, Compare) end end ------------------------------------------------------------------------------------------------------------- return BeamLib