fa36c51de0
- Paramtri generali sono pre-processati quindi si deve controllare che non siano nil, perchè potrebbero esserci, ma essere falsi
946 lines
39 KiB
Lua
946 lines
39 KiB
Lua
-- 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
|
|
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.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)
|
|
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
|
|
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.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, 25))
|
|
|
|
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#")
|
|
EgtSetLevel( idTempGroup, GDB_LV.TEMP)
|
|
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
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
-- 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] 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
|
|
-- 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
|
|
|
|
-- 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')
|
|
-- 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
|
|
|
|
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.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
|
|
if #StrategyList.FEATURE[i].TopologyList == 1 and StrategyList.FEATURE[i].TopologyList[1].sName == 'Feature' then
|
|
return BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[1].StrategyList)
|
|
else
|
|
-- cerco tra le topologie
|
|
for j = 1, #StrategyList.FEATURE[i].TopologyList do
|
|
-- se trovo la topologia
|
|
if Proc.Topology.sName == StrategyList.FEATURE[i].TopologyList[j].sName then
|
|
-- ritorno le strategie disponibili per la feature che sto analizzando
|
|
return BeamLib.TableCopyDeep( StrategyList.FEATURE[i].TopologyList[j].StrategyList)
|
|
end
|
|
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
|