Files
3dprinting/LuaLibs/RunCalcSolids.lua
T
SaraP 68caeb21b2 3dPrinting :
- correzioni spiral vase.
2024-05-16 15:38:34 +02:00

499 lines
19 KiB
Lua

-- RunCalcSolids.lua by Egaltech s.r.l. 2022/11/02
-- Calcolo percorsi di lavoro per Stampa 3d
-- Tabella per definizione modulo
local RunCalcSolids = {}
-- Intestazioni
require( 'EgtBase')
EgtOutLog( ' RunCalcSolids started', 1)
-- Dati
local AMD = require( 'AddManData')
--------------------------------------------------------------------
local s_dTol = 0.1
local s_nSimplifiedSection = 0
---------------------------------------------------------------------
local function GetLayerParamsForSolidCalc( nPartId)
local LayerParams = {}
LayerParams.bSpiralVase = EgtGetInfo( nPartId, KEY_SPIRAL_VASE, 'b') or false
LayerParams.dLayHeight = EgtGetInfo( nPartId, KEY_SLICE_STEP, 'd')
LayerParams.vtSlicing = EgtGetInfo( nPartId, KEY_SLICING_DIR, 'v')
LayerParams.dStrand = EgtGetInfo( nPartId, KEY_STRAND, 'd')
return LayerParams
end
---------------------------------------------------------------------
local function CalcSectionParams( dStrand, dH)
local dBevelX = 0
local dBevelY = 0
if s_nSimplifiedSection == 0 then
-- sezione ottagonale
dBevelX = dStrand / 10
dBevelY = dH / 6
end
return dBevelX, dBevelY
end
---------------------------------------------------------------------
local function CreateSection( ptS, vtDir, dStrand, dH, vtSlicing, nSolidGrp)
local dBevelX, dBevelY = CalcSectionParams( dStrand, dH)
local ptA = ptS - dH * vtSlicing + ( 0.5 * dStrand - dBevelX) * vtDir
local ptB = ptA + dBevelY * vtSlicing + dBevelX * vtDir
local ptC = ptB + ( dH - 2 * dBevelY) * vtSlicing
local ptD = ptA + dH * vtSlicing
local ptE = ptD - ( dStrand - 2 * dBevelX) * vtDir
local ptF = ptC - dStrand * vtDir
local ptG = ptB - dStrand * vtDir
local ptH = ptA - ( dStrand - 2 * dBevelX) * vtDir
local nId = EgtCurveCompoFromPoints( nSolidGrp, {ptA, ptB, ptC, ptD, ptE, ptF, ptG, ptH, ptA}, GDB_RT.GLOB)
EgtInvertCurve( nId)
return nId
end
------------------------------------------------------------------------------
local function CreateSpiralVaseCap( nSectId, vtDir, nSolidGrp)
local vPt = {}
local nLast = EgtIf( s_nSimplifiedSection == 1, 3, 7)
for i = 0, nLast do
vPt[i + 1] = EgtUP( nSectId, i, GDB_ID.ROOT)
end
local vCrvs = {}
-- calcolo gli archi che definiscono la superficie laterale
if s_nSimplifiedSection == 1 then
-- sezione quadrata
vCrvs[1] = EgtArc2PV( nSolidGrp, vPt[1], vPt[2], vtDir, GDB_RT.GLOB)
vCrvs[2] = EgtArc2PV( nSolidGrp, vPt[4], vPt[3], vtDir, GDB_RT.GLOB)
else
-- sezione ottagonale
vCrvs[1] = EgtArc2PV( nSolidGrp, vPt[1], vPt[2], vtDir, GDB_RT.GLOB)
vCrvs[2] = EgtArc2PV( nSolidGrp, vPt[8], vPt[3], vtDir, GDB_RT.GLOB)
vCrvs[3] = EgtArc2PV( nSolidGrp, vPt[7], vPt[4], vtDir, GDB_RT.GLOB)
vCrvs[4] = EgtArc2PV( nSolidGrp, vPt[6], vPt[5], vtDir, GDB_RT.GLOB)
end
-- creo le rigate
local vSurfs = {}
for i = 1, #vCrvs - 1 do
vSurfs[i] = EgtSurfTmRuled( nSolidGrp, vCrvs[i], vCrvs[i+1], GDB_RUL.ISOPAR, s_dTol)
end
-- calcolo le superfici top e bottom del cap
local nCrvBottom = EgtCurveCompo( nSolidGrp, {vCrvs[1]}, false, GDB_RT.GLOB)
EgtCloseCurveCompo( nCrvBottom)
local nSurfBottom = EgtSurfTmByRegion( nSolidGrp, nCrvBottom, s_dTol)
local nCrvTop = EgtCurveCompo( nSolidGrp, {vCrvs[#vCrvs]}, false, GDB_RT.GLOB)
EgtCloseCurveCompo( nCrvTop)
local nSurfTop = EgtSurfTmByRegion( nSolidGrp, nCrvTop, s_dTol)
table.insert( vSurfs, nSurfTop)
table.insert( vSurfs, nSurfBottom)
local nCapSrf = EgtSurfTmByTriangles( nSolidGrp, vSurfs)
-- cancello curve di costruzione
for i = 1, #vCrvs do
EgtErase( vCrvs[i])
end
EgtErase( nCrvTop)
EgtErase( nCrvBottom)
return nCapSrf
end
-------------------------------------------------------------------------------
local function CreateSpiralVaseSolid( nCrvId, nSolidGrp, LayerParams, dStrand)
-- gruppo temporaneo per conti
local nGrpTmp = EgtGroup( nSolidGrp, Frame3d( ORIG(), LayerParams.vtSlicing, GDB_RT.GLOB))
-- accorcio leggermente la curva per evitare problemi di inconsistent orientation nel solido
local dLen = EgtCurveLength( nCrvId)
EgtTrimCurveEndAtLen( nCrvId, dLen - 20 * GEO.EPS_SMALL)
local ptS = EgtSP( nCrvId, GDB_ID.ROOT)
local vtS = EgtSV( nCrvId, GDB_ID.ROOT)
local ptE = EgtEP( nCrvId, GDB_ID.ROOT)
local vtE = EgtEV( nCrvId, GDB_ID.ROOT)
local dDelta = ( ptE - ptS) * LayerParams.vtSlicing
-- appiattisco la curva
local nCrvCopy = EgtCopyGlob( nCrvId, nGrpTmp)
EgtModifyCurveExtrusion( nCrvCopy, LayerParams.vtSlicing, GDB_RT.GLOB)
EgtProjectCurveOnPlane( nCrvCopy, ptS, LayerParams.vtSlicing, GDB_RT.GLOB)
EgtMergeCurvesInCurveCompo( nCrvCopy)
EgtChangeClosedCurveStartPoint( nCrvCopy, ptS, GDB_RT.GLOB)
-- calcolo la sezione iniziale
local vtDir = EgtSV( nCrvCopy, GDB_ID.ROOT)
vtDir:rotate( LayerParams.vtSlicing, 90)
local nSectId = CreateSection( ptS, vtDir, dStrand, LayerParams.dLayHeight, LayerParams.vtSlicing, nGrpTmp)
-- creo la sezione finale
local vtDir2 = EgtEV( nCrvCopy, GDB_ID.ROOT)
vtDir2:rotate( LayerParams.vtSlicing, 90)
local nSectE = CreateSection( ptE, vtDir2, dStrand, LayerParams.dLayHeight, LayerParams.vtSlicing, nGrpTmp)
-- creo il solido aperto (tubo)
local vCrvs = {}
local _, dParE = EgtCurveDomain( nSectId)
for i = 0, dParE do
local ptRef = EgtUP( nSectId, i, GDB_ID.ROOT)
local dOffs = ( ptS - ptRef) * vtDir
vCrvs[i+1] = EgtOffsetCurveAdv( nCrvCopy, dOffs)
if not vCrvs[i+1] or vCrvs[i+1] == GDB_ID.NULL then
EgtErase( nGrpTmp)
return nil
end
local dMove = ( ptRef - ptS) * LayerParams.vtSlicing
EgtMove( vCrvs[i+1], LayerParams.vtSlicing * dMove, GDB_RT.GLOB)
EgtSpiralizeCurveAlongExtrusion( vCrvs[i+1], dDelta)
-- modifico la curva per congiungerla ai caps
EgtApproxCurve( vCrvs[i+1], GDB_CA.LINES, s_dTol)
EgtModifyCurveStartPoint( vCrvs[i+1], ptRef, GDB_RT.GLOB)
local ptRefEnd = EgtUP( nSectE, i, GDB_ID.ROOT)
local _, _, dParMinDist = EgtPointCurveDist( ptRefEnd, vCrvs[i+1], GDB_ID.ROOT)
local _, dParE = EgtCurveDomain( vCrvs[i+1])
if abs( dParE - dParMinDist) > GEO.EPS_SMALL then
EgtTrimCurveEndAtParam( vCrvs[i+1], dParMinDist)
end
EgtModifyCurveEndPoint( vCrvs[i+1], ptRefEnd, GDB_RT.GLOB)
end
local vSurfs = {}
for i = 1, #vCrvs - 1 do
vSurfs[i] = EgtSurfTmRuled( nGrpTmp, vCrvs[i], vCrvs[i+1], GDB_RUL.MINDIST, s_dTol)
if not vSurfs[i] or vSurfs[i] == GDB_ID.NULL then
EgtErase( nGrpTmp)
return nil
end
end
local nSrfId = EgtSurfTmByTriangles( nSolidGrp, vSurfs)
-- creazione del mezzo disco iniziale
local nCap1 = CreateSpiralVaseCap( nSectId, - vtS, nSolidGrp)
-- creazione del mezzo disco finale
local nCap2 = CreateSpiralVaseCap( nSectE, vtE, nSolidGrp)
EgtInvertSurf( nCap2)
-- cancello le curve usate per la costruzione
EgtErase( nGrpTmp)
return EgtSurfTmByTriangles( nSolidGrp, { nSrfId, nCap1, nCap2})
end
----------------------------------------------------------------------
local function CreateStandardSolid( nCrvId, nSolidGrp, LayerParams, dStrand)
local dBevelX, dBevelY = CalcSectionParams( dStrand, LayerParams.dLayHeight)
local nSrfId = EgtSurfTmRectSwept( nSolidGrp, dStrand, LayerParams.dLayHeight, dBevelX, dBevelY, nCrvId, GDB_RSCT.BEVEL, s_dTol)
return nSrfId
end
--------------------------------------------------------------------------------------
local function CreateSolid( nCrvId, nSolidGrp, LayerParams, dStrand)
if LayerParams.bSpiralVase then
return CreateSpiralVaseSolid( nCrvId, nSolidGrp, LayerParams, dStrand)
else
return CreateStandardSolid( nCrvId, nSolidGrp, LayerParams, dStrand)
end
end
---------------------------------------------------------------------
local function CreateDirectionArrow( nCrvId, nSolidGrp, vtSlicing, dStrand, nLayer)
local ptS = EgtSP( nCrvId, GDB_RT.GLOB)
local vtS = EgtSV( nCrvId, GDB_RT.GLOB)
local dCrvLen = EgtCurveLength( nCrvId)
if dCrvLen > 2 * dStrand then
local dPar = EgtCurveParamAtLength( nCrvId, 4/5 * dStrand)
ptS = EgtUP( nCrvId, dPar, GDB_RT.GLOB)
vtS = EgtUV( nCrvId, dPar, -1, GDB_RT.GLOB)
end
local vt2 = Vector3d( vtS)
vt2:rotate( vtSlicing, 90)
local dLen = 4/5 * dStrand
local pt1 = ptS + 0.5 * dLen * vt2
local pt2 = ptS - 0.5 * dLen * vt2
local pt3 = ptS + vtS * dLen
local nCompo = EgtCurveCompoFromPoints( nSolidGrp, { pt1, pt2, pt3, pt1}, GDB_RT.GLOB)
EgtMove( nCompo, 100 * GEO.EPS_SMALL * vtSlicing, GDB_RT.GLOB)
local nSrf = EgtSurfFlatRegion( nSolidGrp, { nCompo})
EgtErase( nCompo)
EgtSetColor( nSrf, RED())
EgtSetInfo( nSrf, KEY_SLICE_NBR, nLayer)
EgtSetStatus( nSrf, GDB_ST.OFF)
EgtSetMode( nSrf, GDB_MD.HIDDEN)
EgtSetName( nSrf, DIR_ARROW)
end
---------------------------------------------------------------------
local function CreateRecursiveSolid( nCrvId, vSurfs, nSolidGrp, LayerParams, dStrand)
-- tento la creazione del solido
local nSurf = CreateSolid( nCrvId, nSolidGrp, LayerParams, dStrand - 50 * GEO.EPS_SMALL)
if nSurf then
EgtErase( nCrvId)
table.insert( vSurfs, nSurf)
return true
else
-- se curva singola esco perchè non è possibile spezzare ulteriormente
local _, dParE = EgtCurveDomain( nCrvId)
if abs( dParE - 1) < GEO.EPS_SMALL then
EgtErase( nCrvId)
return false
end
-- se non si tratta di curva singola, spezzo a metà e tento sulle due sottocurve
local dParSplit = floor( dParE / 2 + 0.5)
local nCrvSplit = EgtSplitCurveAtParam( nCrvId, dParSplit)
if not nCrvSplit then
-- errore nello split
EgtErase( nCrvId)
return false
end
local bOk = CreateRecursiveSolid( nCrvId, vSurfs, nSolidGrp, LayerParams, dStrand)
bOk = bOk and CreateRecursiveSolid( nCrvSplit, vSurfs, nSolidGrp, LayerParams, dStrand)
return bOk
end
end
---------------------------------------------------------------------
local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nLayer)
local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i')
if nType == TYPE.WIPE then return true end
-- scelta del colore
local Color = EgtStdColor( 'GRAY')
if nType == TYPE.OUTER_SHELL or nType == TYPE.EXTRA_OUTER_SHELL then
Color = EgtStdColor( 'TEAL')
elseif nType == TYPE.INNER_SHELL or nType == TYPE.EXTRA_SHELL then
Color = EgtStdColor( 'ORANGE')
elseif nType == TYPE.LINK then
Color = EgtStdColor( 'GRAY')
elseif nType == TYPE.INFILL then
Color = EgtStdColor( 'YELLOW')
elseif nType == TYPE.COASTING then
Color = EgtStdColor( 'BLUE')
elseif nType == TYPE.RIB then
Color = EgtStdColor( 'OLIVE')
elseif nType == TYPE.AUX_SOLID then
Color = EgtStdColor( 'AQUA')
end
local dStrand = EgtGetInfo( nCrvId, KEY_CRV_STRAND, 'd') or LayerParams.dStrand
local nCopyId = EgtCopyGlob( nCrvId, nSolidGrp)
local nId = GDB_ID.NULL
local nParts = 1
local LEN_REF = 100
local bZigZagInfill = EgtGetInfo( nCopyId, KEY_ZIG_ZAG_INFILL, 'b') or false
if bZigZagInfill then
nId, nParts = EgtSplitCurveAtCorners( nCopyId, 80)
else
local dLen = EgtCurveLength( nCrvId)
if dLen > LEN_REF and nType ~= TYPE.LINK and nType ~= TYPE.COASTING then
nParts = EgtClamp( floor( dLen / LEN_REF), 1, 10)
end
nId = EgtSplitCurve( nCopyId, nParts)
end
-- freccia direzionale
local sName = EgtGetName( nCrvId)
if nType ~= TYPE.COASTING and nType ~= TYPE.LINK and sName ~= LEAD_IN_CRV and sName ~= LEAD_OUT_CRV and sName ~= LINK_CRV then
CreateDirectionArrow( nCrvId, nSolidGrp, LayerParams.vtSlicing, dStrand, nLayer)
end
if nId == GDB_ID.NULL then return false end
local bOk = true
for nInd = 0, nParts - 1 do
local nGuideId = nId + nInd
local nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dStrand - 5 * GEO.EPS_SMALL)
if not nSrfId then
EgtOutLog( 'Warning : CreateSolid failed '.. '(layer '..tostring( nLayer)..', curve '..tostring( nCrvId)..')')
-- ritento con strand più piccolo
nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dStrand - 50 * GEO.EPS_SMALL)
if not nSrfId then
EgtOutLog( 'Warning : CreateSolid_1 failed '.. '(layer '..tostring( nLayer)..', curve '..tostring( nCrvId)..')')
-- se non ultima, provo a spostare l'estremità finale
if nInd < nParts - 1 then
local nCopyId = EgtCopy( nGuideId + 1, nGuideId, GDB_IN.AFTER)
if nCopyId then
local LEN_TRIM = 10
local bOk1 = EgtTrimCurveEndAtLen( nCopyId, LEN_TRIM)
local bOk2 = EgtAddCurveCompoCurve( nGuideId, nCopyId)
local bOk3 = EgtTrimCurveStartAtLen( nGuideId + 1, LEN_TRIM)
nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dStrand - 5 * GEO.EPS_SMALL)
if not nSrfId then
nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dStrand - 50 * GEO.EPS_SMALL)
end
end
end
end
-- ritento spezzando la curva in modo ricorsivo fino ad inidividuare delle sottocurve su cui è possibile calcolare il solido
if not nSrfId then
EgtOutLog( 'Warning : CreateSolid_2 failed')
local nGrp = EgtGroup( nSolidGrp, Frame3d( ORIG(), LayerParams.vtSlicing), GDB_RT.GLOB)
EgtRelocateGlob( nGuideId, nGrp)
EgtApproxCurve( nGuideId, GDB_CA.LINES, 100 * GEO.EPS_SMALL)
EgtRelocateGlob( nGuideId, nSolidGrp)
local vSurfs = {}
local bOk = CreateRecursiveSolid( nGuideId, vSurfs, nSolidGrp, LayerParams, dStrand)
if #vSurfs > 0 then
nSrfId = EgtSurfTmByTriangles( nSolidGrp, vSurfs)
end
if not nSrfId or bOk == false then
EgtOutLog( 'Warning : CreateSolid_3 failed')
end
EgtErase( nGrp)
end
end
if nSrfId then
EgtSetColor( nSrfId, Color)
EgtSetInfo( nSrfId, KEY_TYPE, nType)
EgtSetInfo( nSrfId, KEY_SLICE_NBR, nLayer)
else
bOk = false
EgtOutLog( 'Warning : CreateSolid_Sewing failed')
end
EgtErase( nGuideId)
end
return bOk
end
---------------------------------------------------------------------
function RunCalcSolids.Exec()
-- per determinare il tempo di calcolo
EgtStartCounter()
-- verifico se richiesta sezione semplificata ( rettangolare)
local sIniFile = EgtGetIniFile()
s_nSimplifiedSection = EgtGetNumberFromIni( 'Solids', 'SimplifiedSection', 0, sIniFile)
local nPartIndex = 1
local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) or EgtGetFirstNameInGroup( GDB_ID.ROOT, PART)
while nPartId do
if EgtGetInfo( nPartId, KEY_PART_ON_TABLE, 'b') then
-- verifico se necessario calcolare il solido
local bCalcSolid = EgtGetInfo( nPartId, KEY_CALC_SOLIDS, 'b') or false
if bCalcSolid then
-- recupero il suo frame
local nFrameId = EgtGetFirstNameInGroup( EgtGetFirstNameInGroup( nPartId, 'Frame'), 'FramePart')
local ptOrig = EgtSP( nFrameId or GDB_ID.NULL, GDB_ID.ROOT)
EgtSetInfo( nPartId, KEY_ORIG_REF, ptOrig)
-- recupero i suoi slice
local vLayIds = EgtGetNameInGroup( nPartId, SLICE_LAYER .. '*')
if not vLayIds then
EgtOutBox( 'No sliced part in this project!', 'Error', 'ERROR')
return
end
EgtSetInfo( nPartId, KEY_HAS_SOLIDS, 1)
-- recupero i parametri necessari al calcolo dei solidi
local LayerParams = GetLayerParamsForSolidCalc( nPartId)
for nIdx = 1, #vLayIds do
-- flag di interruzione perchè trovati solidi già ok
local bSolidsOk = false
-- indice layer (per log)
local nLayer = EgtGetInfo( vLayIds[ nIdx], KEY_SLICE_NBR, 'i')
-- scorro tutti i gruppi di contorni
local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") or GDB_ID.NULL
while nCrvGrpId ~= GDB_ID.NULL do
-- recupero il gruppo dei percorsi utensile
local nTPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, TOOLPATH_GRP) or GDB_ID.NULL
if nTPathGrpId == GDB_ID.NULL then
EgtOutBox( 'Error no tool paths', 'SolidCalc')
return
end
-- recupero il gruppo dei solidi
local nSolidGrpId = EgtGetFirstNameInGroup( nCrvGrpId, SOLID_GRP) or GDB_ID.NULL
if nSolidGrpId == GDB_ID.NULL then
nSolidGrpId = EgtGroup( nCrvGrpId)
EgtSetName( nSolidGrpId, SOLID_GRP)
EgtSetLevel( nSolidGrpId, GDB_LV.TEMP)
-- scorro le curve del percorso utensile
local nId = EgtGetFirstInGroup( nTPathGrpId)
while nId do
local bOk = CreateSolidFromCurve( nId, nSolidGrpId, LayerParams, nLayer)
nId = EgtGetNext( nId)
end
else
bSolidsOk = true
break
end
--passo al gruppo di contorni successivo
nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL
end
if bSolidsOk then
break
end
local nStep = 10
if nIdx > 400 then
nStep = 80
elseif nIdx > 200 then
nStep = 40
elseif nIdx > 100 then
nStep = 20
end
if ( nIdx % nStep) == 0 then
EgtDraw()
end
if EgtProcessEvents( EgtIf( PRINT, 400, 0) + nIdx / #vLayIds * 100, 0) == 1 then
-- se interrompo cancello i solidi realizzati
for i = 1, #vLayIds do
local vGrpId = EgtGetNameInGroup( vLayIds[i], CONTOUR_GRP .. '*') or {}
for j = 1, #vGrpId do
local nSolidId = EgtGetNameInGroup( vGrpId[j], SOLID_GRP .. '*') or GDB_ID.NULL
EgtErase( nSolidId)
end
end
-- rimuovo info della presenza solidi
EgtSetInfo( nPartId, KEY_HAS_SOLIDS, false)
EgtDraw()
return
end
end
-- eventuale aggiornamento delle ViewInfo
local nViewId = EgtGetFirstNameInGroup( GDB_ID.ROOT, VIEWPARAMS)
if nViewId then
EgtSetInfo( nViewId, SOLID_GRP, true)
end
end
end
nPartIndex = nPartIndex + 1
nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) or EgtGetNextName( nPartId, PART)
end
EgtDraw()
-- report tempo di calcolo in log
EgtOutLog( string.format( ' CalcSolidsTime = %.2f ms', EgtStopCounter()))
end
---------------------------------------------------------------------
return RunCalcSolids