-- 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( 'BeamDataNew') 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 EgtSetInfo( nStmId, 'HEAD_ADD_CUT', 1) EgtSetInfo( nStmId, 'GRP', 1) EgtSetInfo( nStmId, 'PRC', 10) -- ex 340 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 EgtSetInfo( nStmId, 'HEAD_ADD_CUT', 1) EgtSetInfo( nStmId, 'GRP', 2) EgtSetInfo( nStmId, 'PRC', 10) -- ex 350 return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetPartBoxWithHeadTail( Part, sSide) local _sSide = sSide or '' -- si può usare il box del grezzo che contiene sempre il sovramateriale di testa if _sSide == 'Head' then local b3WithHead = BBox3d( Part.b3Raw) return b3WithHead -- se è l'ultimo pezzo della barra si aggiunge il box dell'eventuale grezzo successivo -- se non lo è, si estende il box del pezzo fino alla fine della barra elseif _sSide == 'Tail' then local b3WithTail = BBox3d( Part.b3Part) if Part.bIsLastPart then local nNextRawId = EgtGetNextRawPart( Part.idRaw) if nNextRawId then local b3Tail = EgtGetRawPartBBox( nNextRawId) b3WithTail:Add( b3Tail) end else -- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende) local ptXMin = Point3d( Part.b3Raw:getMin():getX() - Part.dRestLength, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ()) b3WithTail:Add( ptXMin) end return b3WithTail -- per aggiungere entrambi si procede come per la coda ma partendo dal box del grezzo, che già contiene la testa elseif sSide == 'HeadTail' then local b3WithHeadTail = BBox3d( Part.b3Raw) if Part.bIsLastPart then local nNextRawId = EgtGetNextRawPart( Part.idRaw) if nNextRawId then local b3Tail = EgtGetRawPartBBox( nNextRawId) b3WithHeadTail:Add( b3Tail) end else -- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende) local ptXMin = Point3d( Part.b3Raw:getMin():getX() - Part.dRestLength, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ()) b3WithHeadTail:Add( ptXMin) end return b3WithHeadTail -- sSide non definito, si restituisce il box del pezzo con l'aggiunta dello spessore lama/catena in coda else local b3WithSplit = BBox3d( Part.b3Part) -- per il punto di inizio barra si parte dal box del grezzo perchè contiene già il sovramateriale spessore lama/catena in coda (la restLength non lo comprende) local ptXMin = Point3d( Part.b3Raw:getMin():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ()) b3WithSplit:Add( ptXMin) return b3WithSplit end end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetPartSplittingPoints( Part) local PartSplittingPoints = {} local dPartLength = Part.b3Part:getDimX() local dMaxSegmentLength = BeamData.LONGCUT_MAXLEN local dMaxSegmentLengthOnEdges = 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( idRaw, OriXR, PosXR, dDeltaSucc) local nPhase = EgtAddPhase() -- si aprono i limiti tavola per permettere rotazioni di pezzi più larghi della tavola EgtSetTableAreaOffset( 2000, 2000, 2000, 2000) local dRawMove = 0 while idRaw do EgtKeepRawPart( idRaw) EgtMoveToCornerRawPart( idRaw, OriXR, PosXR) EgtMoveRawPart( idRaw, Vector3d( - dRawMove, 0, 0)) if dRawMove == 0 then dRawMove = dRawMove + dDeltaSucc end dRawMove = dRawMove + EgtGetRawPartBBox( idRaw):getDimX() idRaw = EgtGetNextRawPart( idRaw) end -- salvo info nuova fase aggiunta local MachExtraInfo = { sType = 'DISP', nPhase = nPhase} table.insert( DB_MACH_APPLIED, MachExtraInfo) end ------------------------------------------------------------------------------------------------------------- function BeamLib.IsPointOnBoxLimit( ptPointToCheck, b3Solid) local bOnBoxLimit = false if abs( ptPointToCheck:getX() - b3Solid:getMax():getX()) < 100 * GEO.EPS_SMALL or abs( ptPointToCheck:getX() - b3Solid:getMin():getX()) < 100 * GEO.EPS_SMALL or abs( ptPointToCheck:getY() - b3Solid:getMax():getY()) < 100 * GEO.EPS_SMALL or abs( ptPointToCheck:getY() - b3Solid:getMin():getY()) < 100 * GEO.EPS_SMALL or abs( ptPointToCheck:getZ() - b3Solid:getMax():getZ()) < 100 * GEO.EPS_SMALL or abs( ptPointToCheck:getZ() - b3Solid:getMin():getZ()) < 100 * GEO.EPS_SMALL then bOnBoxLimit = true end return bOnBoxLimit end ------------------------------------------------------------------------------------------------------------- function BeamLib.SetOpenSide( nPathInt, b3Solid) -- fondo tra loro le curve compatibili EgtMergeCurvesInCurveCompo( nPathInt) -- vettore indici lati aperti local vOpen = {} -- ciclo sulle curve elementari della composita local _, nNumEnt = EgtCurveDomain( nPathInt) for i = 0, nNumEnt - 1 do -- se segmento di retta if EgtCurveCompoRadius( nPathInt, i) == -1 then -- verifico se giace in uno dei piani limite del pezzo quindi se è un lato aperto local ptIni = EgtUP( nPathInt, i, GDB_RT.GLOB) local ptFin = EgtUP( nPathInt, i + 1, GDB_RT.GLOB) if BeamLib.IsPointOnBoxLimit( ptIni, b3Solid) and BeamLib.IsPointOnBoxLimit( ptFin, b3Solid) then -- aggiorno il vettore dei lati aperti table.insert( vOpen, i) end end end -- assegno gli indici dei lati aperti EgtSetInfo( nPathInt, 'OPEN', vOpen) return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.ConvertToClosedCurve( Proc, AuxId) local bCurveModified = false if not EgtCurveIsClosed( AuxId) then local NewId, nCount = EgtExtractSurfTmFacetLoops( Proc.id, 0, EgtGetParent( Proc.id)) if NewId then -- elimino eventuali loop interni (non dovrebbero comunque esserci) for i = 1, nCount - 1 do EgtErase( NewId + i) end local vtExtr = EgtCurveExtrusion( AuxId, GDB_ID.ROOT) -- sostituisco il loop esterno alla curva originale EgtModifyCurveExtrusion( NewId, vtExtr, GDB_ID.ROOT) EgtRelocate( NewId, AuxId, GDB_IN.AFTER) EgtErase( AuxId) EgtChangeId( NewId, AuxId) bCurveModified = true -- sistemo i lati aperti local vFacAdj = EgtSurfTmFacetAdjacencies( Proc.id, 0)[1] if vFacAdj then local vOpen = {} for i = 1, #vFacAdj do if vFacAdj[i] < 0 then table.insert( vOpen, i - 1) end end EgtSetInfo( AuxId, 'OPEN', vOpen) end end end return true, bCurveModified end ------------------------------------------------------------------------------------------------------------- --- funzione che inverte il grezzo testa-coda function BeamLib.InvertRawPart( Part, nNumberOfRotations) -- se non si deve ruotare, si esce subito if nNumberOfRotations == 0 then return end -- box del solido local b3BoxPart = EgtGetBBoxGlob( EgtGetFirstNameInGroup( Part.id or GDB_ID.NULL, 'Box') or GDB_ID.NULL, GDB_BB.EXACT) -- box esatto del pezzo local b3BoxExact = EgtGetBBoxGlob( Part.id or GDB_ID.NULL, GDB_BB.EXACT) -- rotazione local dAngRot = nNumberOfRotations * 90 EgtRotatePartInRawPart( Part.id, Z_AX(), dAngRot) -- correggo per eccentricità solido rispetto a geometria complessiva del pezzo local vtEccOri = b3BoxPart:getCenter() - b3BoxExact:getCenter() local vtEccRot = Vector3d( vtEccOri) vtEccRot:rotate( Z_AX(), dAngRot) EgtMovePartInRawPart( Part.id, ( vtEccOri - vtEccRot)) -- si salva posizione corrente if Part.bIsInverted then Part.bIsInverted = false else Part.bIsInverted = true end end ------------------------------------------------------------------------------------------------------------- --- funzione che ruota il grezzo function BeamLib.RotateRawPart( Part, nNumberOfRotations) -- sistemo numero rotazioni in caso sia negativa if nNumberOfRotations < 0 then nNumberOfRotations = nNumberOfRotations + 4 end -- primo posizionamento if nNumberOfRotations == 0 then ; -- il pezzo è già in posizione -- rotazione 90° elseif nNumberOfRotations == 1 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 local bIsRotationOK = EgtRotateRawPart( nRId, X_AX(), EgtIf( BeamData.RIGHT_LOAD, -90, 90)) if not bIsRotationOK then error( 'UNEXPECTED ERROR: rotation of the raw not executed') end if not bPreMove then EgtMoveRawPart( nRId, vtMove) end nRId = EgtGetNextRawPart( nRId) end -- rotazione 180° elseif nNumberOfRotations == 2 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 nNumberOfRotations == 3 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 local bIsRotationOK = EgtRotateRawPart( nRId, X_AX(), EgtIf( BeamData.RIGHT_LOAD, 90, -90)) if not bIsRotationOK then error( 'UNEXPECTED ERROR: rotation of the raw not executed') end if not bPreMove then EgtMoveRawPart( nRId, vtMove) end nRId = EgtGetNextRawPart( nRId) end end end ------------------------------------------------------------------------------------------------------------- function BeamLib.CreateAddGroup( PartId, sGroupName) 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, sGroupName) EgtSetInfo( AddGrpId, GDB_SI.MGRPONLY, EgtGetCurrMachGroup()) EgtSetColor( AddGrpId, Color3d( 80, 160, 160, 25)) 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 BeamLib.CreateAddGroup( PartId, sMchGrp) return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.CreateTempGroup() local idTempGroup = BeamLib.GetTempGroup() -- se non esiste, lo creo if not idTempGroup then idTempGroup = EgtGroup( GDB_ID.ROOT) EgtSetName( idTempGroup, "#TEMP_GROUP#") EgtSetColor( idTempGroup, Color3d( 80, 160, 160, 1)) EgtSetLevel( idTempGroup, GDB_LV.TEMP) EgtSetStatus( idTempGroup, GDB_ST.OFF) end return idTempGroup end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetTempGroup() local idTempGroup = EgtGetFirstNameInGroup( GDB_ID.ROOT, "#TEMP_GROUP#") or nil return idTempGroup 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 -- TODO da spostare in FeatureLib??? -- TODO le feature 1 faccia devono essere settate aperte sulla faccia indicata dalla normale 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 ------------------------------------------------------------------------------------------------------------- -- TODO gestire anche altri valori function BeamLib.GetDirectionFromSCC( nSCC) local vtSCC if nSCC == MCH_SCC.ADIR_XP then vtSCC = X_AX() elseif nSCC == MCH_SCC.ADIR_XM then vtSCC = -X_AX() elseif nSCC == MCH_SCC.ADIR_YP then vtSCC = Y_AX() elseif nSCC == MCH_SCC.ADIR_YM then vtSCC = -Y_AX() elseif nSCC == MCH_SCC.ADIR_ZP then vtSCC = Z_AX() elseif nSCC == MCH_SCC.ADIR_ZM then vtSCC = -Z_AX() end return vtSCC 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 < 5 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 ------------------------------------------------------------------------------------------------------------- -- funzione con valore di default in caso la GetSetupInfo della testa della macchina non avesse la funzione definita function BeamLib.GetMinNzDownUpDefault( b3Raw, vtNFace, vtToolDirection, Tool) return -2 end ------------------------------------------------------------------------------------------------------------- -- funzione con valore di default in caso la GetSetupInfo della testa della macchina non avesse la funzione definita function BeamLib.GetMinNzDefault( vtNFace, Tool) return 0 end ------------------------------------------------------------------------------------------------------------- -- funzione con valore di default in caso la GetSetupInfo della testa della macchina non avesse la funzione definita function BeamLib.GetMaxNzDefault( vtNFace, Tool) return 0 end -- TODO bisogna recuperare il nome del parametro NGE, perchè in questo caso è forzato ------------------------------------------------------------------------------------------------------------- function BeamLib.GetPieceGeneralParameters( Part, DefaultGeneralParamList) local GeneralParameters = {} -- si salvano sul pezzo le note forzate, altrimenti si leggeranno dopo, quando si prendono i dati della strategia for i = 1, #DefaultGeneralParamList do local sParamNameNGE = DefaultGeneralParamList[i].sNameNge local xParameterValue = EgtGetInfo( Part.id, sParamNameNGE, 's') or nil -- se il paraemtro esiste, salvataggio dato su lista con accesso diretto if xParameterValue then if DefaultGeneralParamList[i].sType == 'b' then GeneralParameters[DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true elseif DefaultGeneralParamList[i].sType == 'd' then if #DefaultGeneralParamList[i].sValue > 0 then GeneralParameters[DefaultGeneralParamList[i].sName] = tonumber( xParameterValue) -- stringa vuota equivale a non passare alcun valore (deciderà la strategia) else GeneralParameters[DefaultGeneralParamList[i].sName] = nil end else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo' GeneralParameters[DefaultGeneralParamList[i].sName] = xParameterValue end else if GENERAL_PARAMETERS.BTL and GENERAL_PARAMETERS.BTL[Part.sBTLInfo] and GENERAL_PARAMETERS.BTL[Part.sBTLInfo][DefaultGeneralParamList[i].sName] ~= nil then GeneralParameters[DefaultGeneralParamList[i].sName] = GENERAL_PARAMETERS.BTL[Part.sBTLInfo][DefaultGeneralParamList[i].sName] elseif GENERAL_PARAMETERS.PROJECT[DefaultGeneralParamList[i].sName] ~= nil then GeneralParameters[DefaultGeneralParamList[i].sName] = GENERAL_PARAMETERS.PROJECT[DefaultGeneralParamList[i].sName] end end end return GeneralParameters end ------------------------------------------------------------------------------------------------------------- local function GetInheritedParameter( Part, sSourceParamName) local sValue = nil if sSourceParamName and #sSourceParamName > 0 then if Part.GeneralParameters[sSourceParamName] ~= nil then sValue = Part.GeneralParameters[sSourceParamName] elseif GENERAL_PARAMETERS.BTL and GENERAL_PARAMETERS.BTL[Part.sBTLInfo] and GENERAL_PARAMETERS.BTL[Part.sBTLInfo][sSourceParamName] ~= nil then sValue = GENERAL_PARAMETERS.BTL[Part.sBTLInfo][sSourceParamName] elseif GENERAL_PARAMETERS.PROJECT[sSourceParamName] ~= nil then sValue = GENERAL_PARAMETERS.PROJECT[sSourceParamName] end end return sValue end ------------------------------------------------------------------------------------------------------------- -- si traduce la tabella dei parametri con tutte le informazioni in una lista contenente i parametri utilizzabili con accesso diretto function BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, DefaultStrategyParamList) local UpdatedParameters = {} -- TODO serve controllare se campo 'sStrategyId' congruente tra il Config (DefaultStrategyParamList) e i parametri custom (CustomParameters)? if DefaultStrategyParamList and DefaultStrategyParamList.ParameterList and #DefaultStrategyParamList.ParameterList > 0 then -- lettura e settaggio parametri finali per la strategia (customizzati o default) for i = 1, #DefaultStrategyParamList.ParameterList do local xParameterValue = nil -- se strategia forzata, leggo eventuali parametri nelle info if CustomParameters and CustomParameters.bForcedStrategy and DefaultStrategyParamList.ParameterList[i].sNameNge then local sParameterToRead = DefaultStrategyParamList.sStrategyId .. '_' .. DefaultStrategyParamList.ParameterList[i].sNameNge local sForcedParameterForProc = EgtGetInfo( Proc.id, sParameterToRead, 's') -- se ho trovato il valore, lo sovrascrivo al default if sForcedParameterForProc then xParameterValue = sForcedParameterForProc end -- altrimenti i parametri custom si trovano già su questa lista elseif CustomParameters and CustomParameters.ParameterList then for j = 1, #CustomParameters.ParameterList do if CustomParameters.ParameterList[j].sName == DefaultStrategyParamList.ParameterList[i].sName or CustomParameters.ParameterList[j].sName == DefaultStrategyParamList.ParameterList[i].sNameNge then xParameterValue = CustomParameters.ParameterList[j].sValue break end end end -- se non arriva forzato da strategia, oppure se non è stato configurato da cliente, si prende default if xParameterValue == nil then -- se il parametro strategia è da ereditare da un parametro globale if DefaultStrategyParamList.ParameterList[i].sSource and #DefaultStrategyParamList.ParameterList[i].sSource > 0 then xParameterValue = GetInheritedParameter( Part, DefaultStrategyParamList.ParameterList[i].sSource) else xParameterValue = DefaultStrategyParamList.ParameterList[i].sValue end end if DefaultStrategyParamList.ParameterList[i].sType == 'b' then UpdatedParameters[DefaultStrategyParamList.ParameterList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true elseif DefaultStrategyParamList.ParameterList[i].sType == 'd' then if #DefaultStrategyParamList.ParameterList[i].sValue > 0 then UpdatedParameters[DefaultStrategyParamList.ParameterList[i].sName] = tonumber( xParameterValue) -- stringa vuota equivale a non passare alcun valore (deciderà la strategia) else UpdatedParameters[DefaultStrategyParamList.ParameterList[i].sName] = nil end else --DefaultStrategyParamList[i].sType == 's' or DefaultStrategyParamList[i].sType == 'combo' UpdatedParameters[DefaultStrategyParamList.ParameterList[i].sName] = xParameterValue end end end return UpdatedParameters end ------------------------------------------------------------------------------------------------------------- -- si traduce la tabella dei parametri con tutte le informazioni in una lista contenente i parametri utilizzabili con accesso diretto function BeamLib.LoadGeneralParametersInList( DefaultGeneralParamList) local UpdatedParameters = { PROJECT = {}, BTL = {}} -- aggiornamento parametri PROJECT if DefaultGeneralParamList then local idProjectInfo = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'ProjectInfo') or GDB_ID.NULL UpdatedParameters.PROJECT.sAISetupConfig = EgtGetInfo( idProjectInfo, 'AISETUP', 's') or nil for i = 1, #DefaultGeneralParamList do local sParamNameNGE = DefaultGeneralParamList[i].sNameNge local xParameterValue = EgtGetInfo( idProjectInfo, sParamNameNGE, 's') or DefaultGeneralParamList[i].sValue -- se parametro non trovato si salta tutto. N.B. = I parametri progetto non dovrebbero mai essere nil if xParameterValue then -- salvataggio dato su lista con accesso diretto if DefaultGeneralParamList[i].sType == 'b' then UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true elseif DefaultGeneralParamList[i].sType == 'd' then if #DefaultGeneralParamList[i].sValue > 0 then UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = tonumber( xParameterValue) -- stringa vuota equivale a non passare alcun valore (deciderà la strategia) else UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = nil end else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo' UpdatedParameters.PROJECT[DefaultGeneralParamList[i].sName] = xParameterValue end end end -- aggiornamento parametri BTL local BTLInfo = EgtGetNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL for j = 1, #BTLInfo do local BTLName = EgtGetInfo( BTLInfo[j], 'PROJ', 's') if BTLName then UpdatedParameters.BTL[BTLName] = {} UpdatedParameters.BTL[BTLName].sAISetupConfig = EgtGetInfo( BTLInfo[j], 'AISETUP', 's') or nil for i = 1, #DefaultGeneralParamList do local sParamNameNGE = DefaultGeneralParamList[i].sNameNge local xParameterValue = EgtGetInfo( BTLInfo[j], sParamNameNGE, 's') -- se parametro non trovato si salta tutto if xParameterValue then -- salvataggio dato su lista con accesso diretto if DefaultGeneralParamList[i].sType == 'b' then UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue == 'true' or xParameterValue == '1' or xParameterValue == true elseif DefaultGeneralParamList[i].sType == 'd' then if #DefaultGeneralParamList[i].sValue > 0 then UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = tonumber( xParameterValue) -- stringa vuota equivale a non passare alcun valore (deciderà la strategia) else UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = nil end else --DefaultGeneralParamList[i].sType == 's' or DefaultGeneralParamList[i].sType == 'combo' UpdatedParameters.BTL[BTLName][DefaultGeneralParamList[i].sName] = xParameterValue end end end end end end return UpdatedParameters 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.StringReplaceChar( sOriginal, nPosition, sChar) return sOriginal:sub( 1, nPosition-1) .. sChar .. sOriginal:sub( nPosition+1) 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) -- controllo se oggetto passato è valido, altrimenti errore. Non deve mai succedere if not OriginalTable then error( "TableCopyDeep : can't copy nil object") end 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 ------------------------------------------------------------------------------------------------------------- function BeamLib.MergeTables( OriginalTable, InputTable) local result = {} for k, v in pairs( OriginalTable) do result[k] = v end for k, v in pairs( InputTable) do result[k] = v end return result end ------------------------------------------------------------------------------------------------------------- function BeamLib.FindEdgeBestOrientedAsDirection( Edges, vtDirection) local BestEdge = {} local dMaxDotProduct = GEO.INFINITO for i = 1, #Edges do local dCurrentDotProduct = ( Edges[i].vtN * vtDirection) if ( i == 1) or ( dCurrentDotProduct > dMaxDotProduct + 10 * GEO.EPS_SMALL) then dMaxDotProduct = dCurrentDotProduct BestEdge = Edges[i] end end return BestEdge end ------------------------------------------------------------------------------------------------------------- -- nNearSide : 3=Z+, -3=Z- function BeamLib.PutStartNearestToEdge( nCrvId, b3Raw, dMaxDist, nNearSide) -- verifico che la curva sia chiusa if not EgtCurveIsClosed( nCrvId) then return false end -- recupero il versore normale al piano di lavoro o estrusione local vtN = EgtCurveExtrusion( nCrvId, GDB_ID.ROOT) -- coefficienti per riportare la distanza nel piano di lavoro local dCoeffY = 0 if abs( vtN:getY()) < 0.999 then dCoeffY= 1 / ( sqrt( 1 - vtN:getY() * vtN:getY())) end local dCoeffZ = 0 if abs( vtN:getZ()) < 0.999 then dCoeffZ = 1 / ( sqrt( 1 - vtN:getZ() * vtN:getZ())) end -- cerco l'estremo più vicino al box e lo imposto come inizio (se da sotto escludo Zmax e viceversa) local dUopt = 0 local dDopt = GEO.INFINITO local dSopt = GEO.INFINITO local dUi, dUf = EgtCurveDomain( nCrvId) for dU = dUi, dUf, 0.5 do local ptP = EgtUP( nCrvId, dU, GDB_ID.ROOT) local vtDp = EgtUV( nCrvId, dU, -1, GDB_ID.ROOT) local vtDs = EgtUV( nCrvId, dU, 1, GDB_ID.ROOT) local bTg = ( vtDp and vtDs and vtDp * vtDs > 0.96) if ptP and bTg then local vtMin = ptP - b3Raw:getMin() local vtMax = ptP - b3Raw:getMax() local dD = abs( vtMin:getY()) * dCoeffY dD = min( abs( vtMax:getY()) * dCoeffY, dD) dD = min( abs( vtMin:getZ()) * dCoeffZ, dD) dD = min( abs( vtMax:getZ()) * dCoeffZ, dD) local dS if nNearSide == -3 then dS = abs( vtMin:getZ() * dCoeffZ) else --nNearSide == 3 dS = abs( vtMax:getZ() * dCoeffZ) end if dD < dMaxDist and dS < dSopt + GEO.EPS_SMALL then dUopt = dU dDopt = dD dSopt = dS end end end if abs( dUopt - dUi) > GEO.EPS_ZERO and abs( dUopt - dUf) > GEO.EPS_ZERO then -- TODO. Non utilizzare la funzione EgtChangeClosedCurveStart perchè cambia proprietà della geometria. -- dopo aver trovato l'entità di partenza, calcolare l'offset da aggiungere alla lavorazione per poter cominciare da questa entità (senza modifica della geometria) EgtChangeClosedCurveStart( nCrvId, dUopt) end return true end ------------------------------------------------------------------------------------------------------------- function BeamLib.ImportFileJSON( sFileToImport) local JSON = require( 'JSON') local function readAll( sFileToImport) local f = io.open( sFileToImport, "rb") local content = f:read( "*all") f:close() return content end local content = readAll( sFileToImport) return JSON:decode( content) end ------------------------------------------------------------------------------------------------------------- function BeamLib.GetStrategiesFromList( Proc, StrategyList) -- cerco tra le feature for i = 1, #StrategyList.FEATURE do -- se trovo la feature if Proc.nPrc == StrategyList.FEATURE[i].nPrc then local bGroupIsCompatible = false -- nel JSON il gruppo è sempre 0/1, mente da BTL possono arrivare altri valori. if StrategyList.FEATURE[i].nGrp == 0 then if Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4 then bGroupIsCompatible = true end elseif StrategyList.FEATURE[i].nGrp == 1 then if Proc.nGrp == 1 or Proc.nGrp == 2 then bGroupIsCompatible = true end end -- si controlla gruppo if bGroupIsCompatible then -- cerco tra le topologie for j = 1, #StrategyList.FEATURE[i].TopologyList do -- non si possono mischiare topologie specifiche con topologia 'Feature'. Se presente topologia 'Feature' allora deve essere esclusiva if StrategyList.FEATURE[i].TopologyList[j].sName == 'Feature' and #StrategyList.FEATURE[i].TopologyList > 1 then error( "UNEXPECTED ERROR: topology 'Feature' can't be mixed with others") end -- se trovo la topologia oppure se è 'Feature' if Proc.Topology.sName == StrategyList.FEATURE[i].TopologyList[j].sName or StrategyList.FEATURE[i].TopologyList[j].sName == 'Feature' then local ActiveStrategyList = {} -- aggiungo in lista solo le strategie attive if StrategyList.FEATURE[i].TopologyList[j].StrategyList then for k = 1, #StrategyList.FEATURE[i].TopologyList[j].StrategyList do if ( not StrategyList.FEATURE[i].TopologyList[j].StrategyList[k].nIndexInList) or ( StrategyList.FEATURE[i].TopologyList[j].StrategyList[k].nIndexInList) >= 0 then table.insert( ActiveStrategyList, BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[j].StrategyList[k])) end end end -- ritorno le strategie disponibili per la feature che sto analizzando, altrimenti nil se non ho trovato nulla return EgtIf( #ActiveStrategyList > 0, ActiveStrategyList, nil) end end end end end return nil 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