From 5ad54c18f10a2348fc7bf17c463174aa9bfc702b Mon Sep 17 00:00:00 2001 From: SaraP Date: Mon, 2 Mar 2026 09:29:44 +0100 Subject: [PATCH] 3dPrinting: - sistemato spiral vase completo nel caso multiplanare - sistemata correzione in z per caso multiplanare - migliorie varie nei solidi - gestione multicolore per solidi con strand semplificato. --- LuaLibs/CalcSlices.lua | 3 +- LuaLibs/CalcToolPath.lua | 470 +++++++++++++++++++++++++++++--------- LuaLibs/RunCalcSolids.lua | 448 ++++++++++++++++++++++++++++-------- 3 files changed, 721 insertions(+), 200 deletions(-) diff --git a/LuaLibs/CalcSlices.lua b/LuaLibs/CalcSlices.lua index 39beb6e..abf9436 100644 --- a/LuaLibs/CalcSlices.lua +++ b/LuaLibs/CalcSlices.lua @@ -963,7 +963,8 @@ local function VerifyMultiPlanarStrand() if dDist < dMinStrand - GEO.EPS_SMALL or dDist > dMaxStrand + GEO.EPS_SMALL then EgtOutLog( 'Error on layer ' .. EgtNumToString( i) .. ' : strand height (' .. EgtNumToString( dDist) .. ') outside valid range (' .. EgtNumToString( dMinStrand) .. ' - ' .. EgtNumToString( dMaxStrand) .. ')') - EgtOutBox( 'Strand height outside valid range', 'Error', 'ERROR') + EgtOutBox( 'Strand height value ' .. EgtNumToString( dDist) .. ' in layer ' .. EgtNumToString( i) .. ' is outside valid range (' .. EgtNumToString( dMinStrand) .. + ' - ' .. EgtNumToString( dMaxStrand) .. ')', 'Error', 'ERROR') return false end end diff --git a/LuaLibs/CalcToolPath.lua b/LuaLibs/CalcToolPath.lua index 13c3fb6..f59df84 100644 --- a/LuaLibs/CalcToolPath.lua +++ b/LuaLibs/CalcToolPath.lua @@ -70,55 +70,98 @@ local function GetLayerParamsForToolPathCalc() end ------------------------------------------------------------------ -local function ComputeToolPathBox( nTpathGrpId) - - -- calcolo il box del toolpath (escludendo i wipe) +local function ComputeToolPathBox( nLayerId) + -- calcolo il box di tutti i toolpath del layer escludendo i wipe local b3Box = BBox3d() - local nEntId = EgtGetFirstInGroup( nTpathGrpId) - while nEntId do - if EgtGetInfo( nEntId, KEY_TYPE, 'i') ~= TYPE.WIPE then - local b3Ent = EgtGetBBoxGlob( nEntId, GDB_BB.STANDARD) - b3Box:Add( b3Ent) + local vCrvGrpIds = EgtGetNameInGroup( nLayerId, CONTOUR_GRP .. '*') + for i = 1, #vCrvGrpIds do + -- recupero tutti gli elementi del toolpath + local nTPathGrpId = EgtGetFirstNameInGroup( vCrvGrpIds[i], TOOLPATH_GRP) + local nEntId = EgtGetFirstInGroup( nTPathGrpId) + while nEntId do + if EgtGetInfo( nEntId, KEY_TYPE, 'i') ~= TYPE.WIPE then + local b3Ent = EgtGetBBoxGlob( nEntId, GDB_BB.STANDARD) + b3Box:Add( b3Ent) + end + nEntId = EgtGetNext( nEntId) end - nEntId = EgtGetNext( nEntId) end - return b3Box end ------------------------------------------------------------------ -local function AddZCorrection( b3Box, LayerParams) - -- nel caso multiplanare non è necessaria alcuna correzione +local function AddZCorrection( LayerParams) + + local vLayIds = EgtGetNameInGroup( s_nPartId, SLICE_LAYER.."*") local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') + + -- 1) correzione per il pezzo + local dHBox = EgtGetInfo( s_nPartId, KEY_BOX_MIN_Z, 'i') or 0 + local dCorrZ = 0 + + -- se slicing multiplanare vtSlicing cambia ad ogni layer quindi la correzione deve essere calcolata sul singolo layer if nSlicingType == SLICING_TYPE.MULTIPLANAR then - return + for i = 1, #vLayIds do + -- calcolo i valori legati a vtSlicing per il layer corrente + local vtSlicing = EgtGetInfo( vLayIds[i], KEY_SLICE_DIR, 'v') + local dNxy = sqrt( vtSlicing:getX() * vtSlicing:getX() + vtSlicing:getY() * vtSlicing:getY()) + local dNz = vtSlicing:getZ() + -- altezza necessaria per lo strand non serve perchè l'altezza viene adattata lungo il percorso + -- altezza necessaria per il tool + local dHTool = LayerParams.dTDiam / 2 * dNxy + -- altezza disponibile + local b3Layer = ComputeToolPathBox( vLayIds[i]) + local dHDisp = b3Layer:getMin():getZ() - max( dHBox, 0) + + local dCurrCorrZ = max( 0, dHTool - dHDisp) + dCorrZ = max( dCorrZ, dCurrCorrZ) + end + + -- se slicing standard la correzione può essere calcolata sull'intero pezzo + else + local dNxy = sqrt( LayerParams.vtSlicing:getX() * LayerParams.vtSlicing:getX() + LayerParams.vtSlicing:getY() * LayerParams.vtSlicing:getY()) + local dNz = LayerParams.vtSlicing:getZ() + -- altezza necessaria per lo strand + local dHStrand = 0.5 * LayerParams.dStrand * dNxy + LayerParams.dLayHeight * dNz + -- altezza necessaria per il tool + local dHTool = LayerParams.dTDiam / 2 * dNxy + -- altezza disponibile + -- calcolo il box complessivo dei percorsi + local b3Tot = BBox3d() + for i = 1, #vLayIds do + local b3Curr = ComputeToolPathBox( vLayIds[i]) + b3Tot:Add( b3Curr) + end + local dHDisp = b3Tot:getMin():getZ() - max( dHBox, 0) + + dCorrZ = max( 0, max( dHStrand, dHTool) - dHDisp) + end + + -- applico la correzione al pezzo + if dCorrZ > GEO.EPS_SMALL then + local vtMove = dCorrZ * Z_AX() + EgtMove( s_nPartId, vtMove, GDB_RT.GLOB) + EgtSetInfo( s_nPartId, KEY_MOVED_PART2, vtMove) + -- correggo la posizione del riferimento + local nFrameId = EgtGetFirstNameInGroup( s_nPartId, LAY_FRAME) + EgtMove( nFrameId, - vtMove, GDB_RT.GLOB) end - local dNxy = sqrt( LayerParams.vtSlicing:getX() * LayerParams.vtSlicing:getX() + LayerParams.vtSlicing:getY() * LayerParams.vtSlicing:getY()) - local dNz = LayerParams.vtSlicing:getZ() - -- altezza necessaria per lo strand - local dHStrand = 0.5 * LayerParams.dStrand * dNxy + LayerParams.dLayHeight * dNz - -- altezza necessaria per il tool - local dHTool = LayerParams.dTDiam / 2 * dNxy - -- altezza disponibile - local dHBox = EgtGetInfo( s_nPartId, KEY_BOX_MIN_Z, 'i') or 0 - local dHDisp = b3Box:getMin():getZ() - max( dHBox, 0) + -- 2) correzione per i wipe + -- altezza minima necessaria per i wipe. Se slicing multiplanare l'altezza minima per il wipe cambia ad ogni layer, altrimenti è un valore comune + local dHMinWipe + if nSlicingType ~= SLICING_TYPE.MULTIPLANAR then + local dNxy = sqrt( LayerParams.vtSlicing:getX() * LayerParams.vtSlicing:getX() + LayerParams.vtSlicing:getY() * LayerParams.vtSlicing:getY()) + dHMinWipe = LayerParams.dTDiam / 2 * dNxy + max( dHBox, 0) + s_dHSafeWipe + end - local dCorrZ = max( 0, max( dHStrand, dHTool) - dHDisp) - - -- applico la correzione al pezzo - local vtMove = dCorrZ * Z_AX() - EgtMove( s_nPartId, vtMove, GDB_RT.GLOB) - EgtSetInfo( s_nPartId, KEY_MOVED_PART2, vtMove) - -- correggo la posizione del riferimento - local nFrameId = EgtGetFirstNameInGroup( s_nPartId, LAY_FRAME) - EgtMove( nFrameId, - vtMove, GDB_RT.GLOB) - - -- correzione per i wipe - -- altezza minima necessaria per i wipe - local dHMinWipe = LayerParams.dTDiam / 2 * dNxy + max( dHBox, 0) + s_dHSafeWipe - local vLayIds = EgtGetNameInGroup( s_nPartId, SLICE_LAYER.."*") for i = 1, #vLayIds do + if nSlicingType == SLICING_TYPE.MULTIPLANAR then + local vtSlicing = EgtGetInfo( vLayIds[i], KEY_SLICE_DIR, 'v') + local dNxy = sqrt( vtSlicing:getX() * vtSlicing:getX() + vtSlicing:getY() * vtSlicing:getY()) + dHMinWipe = LayerParams.dTDiam / 2 * dNxy + max( dHBox, 0) + s_dHSafeWipe + end + local vCrvGrps = EgtGetNameInGroup( vLayIds[i], CONTOUR_GRP.."*") for j = 1, #vCrvGrps do local nTPath = EgtGetFirstNameInGroup( vCrvGrps[j], TOOLPATH_GRP) @@ -369,6 +412,7 @@ end -------------------------------------------------------------------- local function AddLeadOut( nCrvId, LayerParams, nGrpId) + local vtSlicing = EgtCurveExtrusion( nCrvId, GDB_ID.ROOT) local ptS = EgtEP( nCrvId, GDB_ID.ROOT) local vtTang = EgtEV( nCrvId, GDB_ID.ROOT) local vtOrtho = Vector3d( vtTang) @@ -378,7 +422,7 @@ local function AddLeadOut( nCrvId, LayerParams, nGrpId) dAng = 90 end - vtOrtho:rotate( LayerParams.vtSlicing, dAng) + vtOrtho:rotate( vtSlicing, dAng) local ptE = ptS + LayerParams.dLeadOutTangDist * vtTang + LayerParams.dLeadOutOrthoDist * vtOrtho local nLeadOutCrv @@ -390,7 +434,7 @@ local function AddLeadOut( nCrvId, LayerParams, nGrpId) if nLeadOutCrv then EgtRelocate( nLeadOutCrv, nCrvId, GDB_IN.AFTER) - EgtModifyCurveExtrusion( nLeadOutCrv, LayerParams.vtSlicing, GDB_RT.GLOB) + EgtModifyCurveExtrusion( nLeadOutCrv, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLeadOutCrv, KEY_TYPE, TYPE.LINK) EgtSetName( nLeadOutCrv, LEAD_OUT_CRV) EgtSetColor( nLeadOutCrv, EgtStdColor('GRAY')) @@ -2020,19 +2064,284 @@ local function AddSpiralVaseLeadOut( nOldId, LayerParams) end end +--------------------------------------------------------------------- +local function SpiralVaseFullMultiPlanar( vLayIds, LayerParams) + -- la differenza in altezza viene distribuita uniformemente lungo tutto il percorso. Tale differenza non è costante per tutti i punti della curva ma varia da punto a punto + -- la continuità tra i layers viene risolta sul layer corrente ( uniformemente su tutto il tratto o solo nella parte iniziale di lunghezza dSpiralVaseInterpLen) + -- gestione speciale per i primi due layers + -- aggiunta passata extra finale piana alla quota dell'ultimo layer + + local nOldId, nOldPathId + local nRealLayer = 1 + + -- ciclo sui layer + for nIdx = 1, #vLayIds do + + -- recupero il piano di slicing + local vtSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_DIR, 'v') + local ptSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_POS, 'p') + + -- cerco i gruppi di contorni + local vCrvGrpIds = EgtGetNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") + if #vCrvGrpIds > 1 then + -- se più di un gruppo di curve errore + EgtOutBox( 'Error in spiral vase : layer ' .. tostring( nIdx) .. ' has more than one toolpath', 'ToolPathCalc') + return false + end + + -- recupero il gruppo dei percorsi + local nPathGrpId = EgtGetFirstNameInGroup( vCrvGrpIds[1], PATH_GRP) + if not nPathGrpId then + EgtOutBox( 'Error missing paths', 'ToolPathCalc') + return + else + EgtSetStatus( nPathGrpId, GDB_ST.OFF) + end + + -- recupero il gruppo dei percorsi utensile + local nTpathGrpId = EgtGetFirstNameInGroup( vCrvGrpIds[1], TOOLPATH_GRP) + if not nTpathGrpId then + nTpathGrpId = EgtGroup( vCrvGrpIds[1]) + EgtSetName( nTpathGrpId, TOOLPATH_GRP) + else + EgtEmptyGroup( nTpathGrpId) + end + + -- creo il percorso di lavoro : + local vEntIds = EgtGetAllInGroup( nPathGrpId) + if #vEntIds > 1 then + EgtOutBox( 'Error in spiral vase : layer ' .. tostring( nIdx) .. ' has more than one toolpath', 'ToolPathCalc') + return false + end + + local nNewEntId = EgtCopyGlob( vEntIds[1] or GDB_ID.NULL, nTpathGrpId, GDB_IN.LAST_SON) + if nNewEntId then + + EgtModifyCurveExtrusion( nNewEntId, vtSlicing, GDB_RT.GLOB) + EgtSetInfo( nNewEntId, KEY_CRV_STRAND, LayerParams.dStrand) + -- eventuale inversione + if LayerParams.bInvert then + EgtInvertCurve( nNewEntId) + EgtSetInfo( nNewEntId, KEY_INVERTED_CRV, 1) + end + EgtSetColor( nNewEntId, EgtStdColor('GRAY')) + + -- se primo layer + if nRealLayer == 1 then + -- mi sposto dell'altezza layer + EgtMove( nNewEntId, LayerParams.dLayHeight * vtSlicing, GDB_RT.GLOB) + + -- eventuale lead in + if LayerParams.nLeadInType ~= LEAD_TYPE.NONE then + EgtTrimCurveStartAtLen( nNewEntId, LayerParams.dOffsetLP) + local nLeadInCrv = AddLeadIn( nNewEntId, LayerParams, nTpathGrpId) + if nLeadInCrv and LayerParams.bLinearApprox then + EgtApproxCurve( nLeadInCrv, GDB_CA.LINES, LayerParams.dLinearApproxTol) + end + end + + else + -- recupero il piano precedente + local vtSlicingPrev = EgtGetInfo( vLayIds[nIdx-1], KEY_SLICE_DIR, 'v') + local ptSlicingPrev = EgtGetInfo( vLayIds[nIdx-1], KEY_SLICE_POS, 'p') + LayerParams.dLayHeight * vtSlicingPrev + local dCosAng = vtSlicing * vtSlicingPrev + + -- a) continuità dei percorsi + local ptEPrev = EgtEP( nOldId, GDB_ID.ROOT) + local ptEProj = ptEPrev - ( ptEPrev - ptSlicing) * vtSlicing * vtSlicing + + -- tento di creare la continuità spostando il punto ( caso in cui ptEProj poggia su nNewEntId) + EgtChangeClosedCurveStartPoint( nNewEntId, ptEProj, GDB_RT.GLOB) + if not AreSamePointApprox( ptEPrev, EgtSP( nNewEntId, GDB_ID.ROOT)) then + -- se i percorsi non sono in continuità modifico percorso corrente usando come guida la proiezione ortogonale del percorso precedente + -- sul piano corrente ( SpiralizeAlongGuide lavora con curve piane complanari) + + local nProjCrv = EgtCopyGlob( nOldPathId, nPathGrpId) + if LayerParams.bInvert then + EgtInvertCurve( nProjCrv) + end + EgtMove( nProjCrv, LayerParams.dLayHeight * vtSlicingPrev, GDB_RT.GLOB) + EgtProjectCurveOnPlane( nProjCrv, ptSlicing, vtSlicing, GDB_RT.GLOB) + EgtChangeClosedCurveStartPoint( nProjCrv, ptEProj, GDB_RT.GLOB) + + -- approssimo con tratti lineari imponendo lunghezza massima per migliorare spiralize + EgtApproxCurve( nProjCrv, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) + EgtApproxCurve( nNewEntId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) + + -- 1) la differenza va distribuita su tutta la curva + local dLen = EgtCurveLength( nNewEntId) + if LayerParams.dSpiralVaseInterpLen < GEO.EPS_SMALL or LayerParams.dSpiralVaseInterpLen > dLen - GEO.EPS_SMALL then + EgtSpiralizeCurveAlongGuide( nNewEntId, nProjCrv) + + -- 2) la differenza va distribuita solo su un sottotratto + else + local dParSplit = EgtCurveParamAtLength( nNewEntId, LayerParams.dSpiralVaseInterpLen) + local nNewEndId2 = EgtSplitCurveAtParam( nNewEntId, dParSplit) + -- trim della curva guida + local _, _, dParMinDist = EgtPointCurveDist( EgtEP( nNewEntId, GDB_ID.ROOT), nProjCrv, GDB_RT.GLOB) + local nGuideId2 = EgtSplitCurveAtParam( nProjCrv, dParMinDist) + EgtErase( nGuideId2) + -- spiralize solo del primo pezzo e riassemblo la curva + EgtSpiralizeCurveAlongGuide( nNewEntId, nProjCrv) + EgtAddCurveCompoCurve( nNewEntId, nNewEndId2) + end + -- forzo il punto + EgtModifyCurveStartPoint( nNewEntId, ptEProj, GDB_RT.GLOB) + EgtErase( nProjCrv) + end + + -- b) spostamento verticale : alzo la curva e, per creare una transizione uniforme dal layer precedente, abbasso i suoi punti in modo graduale sul valore della distanza dal + -- dal layer precedente + EgtMove( nNewEntId, LayerParams.dLayHeight * vtSlicing, GDB_RT.GLOB) + + -- approssimazione lineare per migliorare il calcolo delle quote + EgtApproxCurve( nNewEntId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) + + if nRealLayer == 2 then + -- per non collassare sul layer precedente che è piatto alzo la prima metà della curva sempre di 0.5 * Delta + local dLen = EgtCurveLength( nNewEntId) + local dParMid = EgtCurveParamAtLength( nNewEntId, 0.5 * dLen) + EgtAddCurveCompoJoint( nNewEntId, dParMid) + local vDelta = {} + local _, dE = EgtCurveDomain( nNewEntId) + for dU = 0, dE - 1 do + local ptCurr = EgtUP( nNewEntId, dU, GDB_ID.ROOT) + local dDist = ( ( ptCurr - ptSlicingPrev) * vtSlicingPrev) / dCosAng -- distanza dal piano precedente lungo vtSlicing + local dCurrLen = EgtCurveLengthAtParam( nNewEntId, dU) + if dCurrLen < 0.5 * dLen then + vDelta[dU] = - dDist * 0.5 + else + vDelta[dU] = - dDist * ( dLen - dCurrLen) / dLen + end + end + + EgtModifyCurveStartPoint( nNewEntId, EgtSP( nNewEntId, GDB_ID.ROOT) + vDelta[0] * vtSlicing, GDB_RT.GLOB) + for dU = 1, dE - 1 do + local ptCurr = EgtUP( nNewEntId, dU, GDB_ID.ROOT) + EgtModifyCurveCompoJoint( nNewEntId, dU, ptCurr + vDelta[dU] * vtSlicing, GDB_RT.GLOB) + end + + -- alzo l'ultimo tratto del layer precedente con una proiezione ortogonale "graduale" sul piano corrente + -- ricavo il tratto sulla curva precedente da alzare + local dTrimPar = EgtCurveParamAtLength( nOldId, EgtCurveLength( nOldId) - s_dSpralVaseFirstDelta) + local nLastId = EgtSplitCurveAtParam( nOldId, dTrimPar) + EgtApproxCurve( nLastId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) + -- alzo in maniera graduale + local _, dEOld = EgtCurveDomain( nLastId) + local vDeltaOld = {} + local dLenOld = EgtCurveLength( nLastId) + for dU = 0, dEOld do + local dCurrLen = EgtCurveLengthAtParam( nLastId, dU) + vDeltaOld[dU] = abs( vDelta[0]) * dCurrLen / dLenOld + end + for dU = 0, dEOld - 1 do + local ptCurr = EgtUP( nLastId, dU, GDB_ID.ROOT) + EgtModifyCurveCompoJoint( nLastId, dU, ptCurr + vDeltaOld[dU] * vtSlicing, GDB_RT.GLOB) + end + EgtModifyCurveEndPoint( nLastId, EgtEP( nLastId, GDB_ID.ROOT) + vDeltaOld[dEOld] * vtSlicing, GDB_RT.GLOB) + + -- approssimo + EgtApproxCurve( nLastId, GDB_CA.ARCS, s_dApproxTol) + if LayerParams.bLinearApprox then + EgtApproxCurve( nLastId, GDB_CA.LINES, LayerParams.dLinearApproxTol) + end + EgtModifyCurveEndPoint( nLastId, EgtSP( nNewEntId, GDB_ID.ROOT), GDB_RT.GLOB) + + else + + local dLen = EgtCurveLength( nNewEntId) + local _, dE = EgtCurveDomain( nNewEntId) + local vDelta = {} + for dU = 0, dE - 1 do + local dCurrLen = EgtCurveLengthAtParam( nNewEntId, dU) + local ptCurr = EgtUP( nNewEntId, dU, GDB_ID.ROOT) + local dDist = ( ( ptCurr - ptSlicingPrev) * vtSlicingPrev) / dCosAng -- distanza dal piano precedente lungo vtSlicing + vDelta[dU] = - dDist * ( dLen - dCurrLen) / dLen + end + + EgtModifyCurveStartPoint( nNewEntId, EgtSP( nNewEntId, GDB_ID.ROOT) + vDelta[0] * vtSlicing, GDB_RT.GLOB) + for dU = 1, dE - 1 do + local ptCurr = EgtUP( nNewEntId, dU, GDB_ID.ROOT) + EgtModifyCurveCompoJoint( nNewEntId, dU, ptCurr + vDelta[dU] * vtSlicing, GDB_RT.GLOB) + end + end + + -- c) approssimo + local ptS = EgtSP( nNewEntId, GDB_ID.ROOT) + EgtApproxCurve( nNewEntId, GDB_CA.ARCS, s_dApproxTol) + if LayerParams.bLinearApprox then + EgtApproxCurve( nNewEntId, GDB_CA.LINES, LayerParams.dLinearApproxTol) + end + if EgtCurveIsClosed( nNewEntId) then + EgtChangeClosedCurveStartPoint( nNewEntId, ptS, GDB_RT.GLOB) + end + end + + local vTPathsCrvs = EgtGetAllInGroup( nTpathGrpId) + nOldId = vTPathsCrvs[#vTPathsCrvs] + nOldPathId = vEntIds[1] + nRealLayer = nRealLayer + 1 + end + + if EgtProcessEvents( EgtIf( PRINT, 300, 0) + nIdx / #vLayIds * 100, 0) == 1 then + EgtDraw() + return false + end + end + + -- creo un un layer extra piano alla quota finale + local nLastLay = EgtCopyGlob( vLayIds[#vLayIds], vLayIds[#vLayIds], GDB_IN.AFTER) + -- aggiorno nome e numero slice + local nSliceNbr = EgtGetInfo( nLastLay, KEY_SLICE_NBR, 'i') + 1 + EgtSetName( nLastLay, SLICE_LAYER .. EgtNumToString( nSliceNbr)) + EgtSetInfo( nLastLay, KEY_SLICE_NBR, nSliceNbr) + -- creo la curva di toolpath alla quota finale + local nCrvGrpId = EgtGetFirstNameInGroup( nLastLay, CONTOUR_GRP.."*") + local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) + local nTpathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, TOOLPATH_GRP) + EgtEmptyGroup( nTpathGrpId) + local nId = EgtCopyGlob( EgtGetFirstInGroup( nPathGrpId), nTpathGrpId) + local vtSlicing = EgtGetInfo( nLastLay, KEY_SLICE_DIR, 'v') + EgtMove( nId, LayerParams.dLayHeight * vtSlicing, GDB_RT.GLOB) + + local ptS = EgtEP( nOldId, GDB_ID.ROOT) + EgtChangeClosedCurveStartPoint( nId, ptS, GDB_RT.GLOB) + EgtModifyCurveExtrusion( nId, vtSlicing, GDB_RT.GLOB) + EgtSetInfo( nId, KEY_CRV_STRAND, LayerParams.dStrand) + if LayerParams.bInvert then + EgtInvertCurve( nId) + EgtSetInfo( nId, KEY_INVERTED_CRV, 1) + end + EgtSetColor( nId, EgtStdColor('GRAY')) + + -- approssimo + EgtApproxCurve( nId, GDB_CA.ARCS, s_dApproxTol) + if LayerParams.bLinearApprox then + EgtApproxCurve( nId, GDB_CA.LINES, LayerParams.dLinearApproxTol) + end + if EgtCurveIsClosed( nId) then + EgtChangeClosedCurveStartPoint( nId, ptS, GDB_RT.GLOB) + end + + return true +end + --------------------------------------------------------------------- local function SpiralVaseFull( vLayIds, LayerParams) -- la differenza in altezza tra due layers viene distribuita uniformemente lungo tutto il percorso -- la continuità tra i layers viene risolta sul layer corrente ( uniformemente su tutto il tratto o solo nella parte iniziale di lunghezza dSpiralVaseInterpLen) -- gestione speciale dei primi layers per gestione dell'altezza e feed - -- nel caso di slicing multiplanare viene realizzato un layer extra ( uguale all'ultimo) alla quota finale del pezzo + + local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') + if nSlicingType == SLICING_TYPE.MULTIPLANAR then + return SpiralVaseFullMultiPlanar( vLayIds, LayerParams) + end local nOldId, nOldPathId local nRealLayer = 1 - local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') -- copio ultimo layer - if nSlicingType ~= SLICING_TYPE.MULTIPLANAR and nSlicingType ~= SLICING_TYPE.DEG45_X and nSlicingType ~= SLICING_TYPE.DEG45_Y then + if nSlicingType ~= SLICING_TYPE.DEG45_X and nSlicingType ~= SLICING_TYPE.DEG45_Y then local nNewLay = EgtCopyGlob( vLayIds[#vLayIds], vLayIds[#vLayIds], GDB_IN.AFTER) table.insert( vLayIds, nNewLay) -- aggiorno nome e numero slice @@ -2049,10 +2358,6 @@ local function SpiralVaseFull( vLayIds, LayerParams) -- ciclo sui layer for nIdx = 1, #vLayIds do - if nSlicingType == SLICING_TYPE.MULTIPLANAR then - LayerParams.vtSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_DIR, 'v') - end - -- cerco i gruppi di contorni local vCrvGrpIds = EgtGetNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") if #vCrvGrpIds > 1 then @@ -2246,42 +2551,6 @@ local function SpiralVaseFull( vLayIds, LayerParams) return false end end - - -- se slicing multiplanare creo un un layer extra piano alla quota finale - if nSlicingType == SLICING_TYPE.MULTIPLANAR then - local nLastLay = EgtCopyGlob( vLayIds[#vLayIds], vLayIds[#vLayIds], GDB_IN.AFTER) - -- aggiorno nome e numero slice - local nSliceNbr = EgtGetInfo( nLastLay, KEY_SLICE_NBR, 'i') + 1 - EgtSetName( nLastLay, SLICE_LAYER .. EgtNumToString( nSliceNbr)) - EgtSetInfo( nLastLay, KEY_SLICE_NBR, nSliceNbr) - -- creo la curva di toolpath alla quota finale - local nCrvGrpId = EgtGetFirstNameInGroup( nLastLay, CONTOUR_GRP.."*") - local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) - local nTpathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, TOOLPATH_GRP) - EgtEmptyGroup( nTpathGrpId) - local nId = EgtCopyGlob( EgtGetFirstInGroup( nPathGrpId), nTpathGrpId) - local vtSlicing = EgtGetInfo( nLastLay, KEY_SLICE_DIR, 'v') - EgtMove( nId, LayerParams.dLayHeight * vtSlicing, GDB_RT.GLOB) - - local ptS = EgtEP( nOldId, GDB_ID.ROOT) - EgtChangeClosedCurveStartPoint( nId, ptS, GDB_RT.GLOB) - EgtModifyCurveExtrusion( nId, LayerParams.vtSlicing, GDB_RT.GLOB) - EgtSetInfo( nId, KEY_CRV_STRAND, LayerParams.dStrand) - if LayerParams.bInvert then - EgtInvertCurve( nId) - EgtSetInfo( nId, KEY_INVERTED_CRV, 1) - end - EgtSetColor( nId, EgtStdColor('GRAY')) - - -- approssimo - EgtApproxCurve( nId, GDB_CA.ARCS, s_dApproxTol) - if LayerParams.bLinearApprox then - EgtApproxCurve( nId, GDB_CA.LINES, LayerParams.dLinearApproxTol) - end - if EgtCurveIsClosed( nId) then - EgtChangeClosedCurveStartPoint( nId, ptS, GDB_RT.GLOB) - end - end return true end @@ -2364,10 +2633,10 @@ local function SpiralVasePartialMultiPlanar( vLayIds, LayerParams) local ptSProj = ptSOld + ( ( ptSOld - ptSlicing) * vtSlicing) * vtSlicing local ptEProj = ptEOld + ( ( ptEOld - ptSlicing) * vtSlicing) * vtSlicing + -- a) continuità tra i layers -- modifico il punto iniziale corrente per avvicinarmi il più possibile alla fine del percorso precedente EgtChangeClosedCurveStartPoint( nNewEntId, ptEProj, GDB_RT.GLOB) local ptCurrStart = EgtSP( nNewEntId, GDB_ID.ROOT) - -- a) verifico continuità tra i layers if not AreSamePointApprox( ptEProj, ptCurrStart) then -- se i percorsi non sono in continuità modifico il tratto finale del percorso precedente in modo da farlo arrivare sul punto di inizio del percorso corrente -- usando come guida la proiezione obliqua del percorso corrente sul piano precedente ( SpiralizeAlongGuide lavora con curve piane complanari) @@ -2389,16 +2658,16 @@ local function SpiralVasePartialMultiPlanar( vLayIds, LayerParams) local dDist = ( pt - ptSlicingPrev) * vtSlicingPrev / ( vtSlicingPrev * vtSlicing) EgtModifyCurveCompoJoint( nProjCrv, dU, pt - dDist * vtSlicing, GDB_RT.GLOB) end - -- approssimazione dei tratti per migliorare la qualità dello spiralize EgtApproxCurve( nProjCrv, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) EgtApproxCurve( nOldId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) - -- spiralize EgtInvertCurve( nProjCrv) EgtInvertCurve( nOldId) EgtSpiralizeCurveAlongGuide( nOldId, nProjCrv) EgtInvertCurve( nOldId) + + EgtErase( nProjCrv) end -- b) proiezione ortogonale graduale sul piano corrente @@ -2499,11 +2768,7 @@ local function SpiralVasePartial( vLayIds, LayerParams) -- ciclo sui layer local nOldId for nIdx = 1, #vLayIds do - - -- if nSlicingType == SLICING_TYPE.MULTIPLANAR then - -- LayerParams.vtSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_DIR, 'v') - -- end - + -- cerco i gruppi di contorni local vCrvGrpIds = EgtGetNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") if #vCrvGrpIds > 1 then @@ -2654,24 +2919,16 @@ local function SpiralVase( vLayIds, LayerParams) return false end end - - -- calcolo il box dei percorsi - local b3Tot = BBox3d() - local nLastTPath - local vLayers = EgtGetNameInGroup( s_nPartId, SLICE_LAYER .. '*') - for i = 1, #vLayers do - local vCrvGrpIds = EgtGetNameInGroup( vLayers[i], CONTOUR_GRP.."*") - local nTpathGrpId = EgtGetFirstNameInGroup( vCrvGrpIds[1], TOOLPATH_GRP) - nLastTPath = EgtGetLastInGroup( nTpathGrpId) - local b3Box = ComputeToolPathBox( nTpathGrpId) - b3Tot:Add( b3Box) - end - + -- aggiungo uscita, coasting e wipe su ultima curva + local nLastLayer = EgtGetLastNameInGroup( s_nPartId, SLICE_LAYER .. '*') + local vCrvGrpIds = EgtGetNameInGroup( nLastLayer, CONTOUR_GRP.."*") + local nTpathGrpId = EgtGetFirstNameInGroup( vCrvGrpIds[1], TOOLPATH_GRP) + local nLastTPath = EgtGetLastInGroup( nTpathGrpId) AddSpiralVaseLeadOut( nLastTPath, LayerParams) -- correzione in z - AddZCorrection( b3Tot, LayerParams) + AddZCorrection( LayerParams) return true end @@ -2697,7 +2954,6 @@ function CalcToolPath.Exec( nPartId) return SpiralVase( vLayIds, LayerParams) end - local b3Tot = BBox3d() -- box dei toolpath local nLayCnt = 1 -- Ciclo sui layer for nIdx = 1, #vLayIds do @@ -2783,10 +3039,6 @@ function CalcToolPath.Exec( nPartId) end end - -- aggiorno il box dei toolpath - local b3Box = ComputeToolPathBox( nTpathGrpId) - b3Tot:Add( b3Box) - -- verifico non sia vuoto per aggiornare il numero di layers if EgtGetFirstInGroup( nTpathGrpId) then nLayCnt = nIdx @@ -2812,7 +3064,7 @@ function CalcToolPath.Exec( nPartId) end -- correzione in z - AddZCorrection( b3Tot, LayerParams) + AddZCorrection( LayerParams) -- setto info con numero di layers effettivi EgtSetInfo( nPartId, KEY_LAYER_CNT, nLayCnt) diff --git a/LuaLibs/RunCalcSolids.lua b/LuaLibs/RunCalcSolids.lua index c8e5da0..c0f045d 100644 --- a/LuaLibs/RunCalcSolids.lua +++ b/LuaLibs/RunCalcSolids.lua @@ -16,6 +16,8 @@ local AMD = require( 'AddManData') local s_dTol = 0.1 local s_nSimplifiedSection = 0 local s_dMultiPlanarH = 0 +local s_dColorFactor = 0.9 +local s_nPartId --------------------------------------------------------------------- local function GetLayerParamsForSolidCalc( nPartId) @@ -106,9 +108,7 @@ local function CreateSpiralVaseCap( nSectId, vtDir, nSolidGrp) local nCapSrf = EgtSurfTmByTriangles( nSolidGrp, vSurfs) -- cancello curve di costruzione - for i = 1, #vCrvs do - EgtErase( vCrvs[i]) - end + EgtErase( vCrvs) EgtErase( nCrvTop) EgtErase( nCrvBottom) @@ -187,19 +187,19 @@ local function CreateSpiralVaseSolid( nCrvId, nSolidGrp, vtSlicing, dH, dStrand) return nil end end - - local nSrfId = EgtSurfTmByTriangles( nSolidGrp, vSurfs) - + -- creazione del mezzo disco iniziale - local nCap1 = CreateSpiralVaseCap( nSectId, - vtS, nSolidGrp) + vSurfs[#vCrvs] = CreateSpiralVaseCap( nSectId, - vtS, nSolidGrp) -- creazione del mezzo disco finale - local nCap2 = CreateSpiralVaseCap( nSectE, vtE, nSolidGrp) - EgtInvertSurf( nCap2) + vSurfs[#vCrvs+1] = CreateSpiralVaseCap( nSectE, vtE, nSolidGrp) + EgtInvertSurf( vSurfs[#vCrvs+1]) + local nSolidId = EgtSurfTmByTriangles( nSolidGrp, vSurfs) + -- cancello le curve usate per la costruzione EgtErase( nGrpTmp) - return EgtSurfTmByTriangles( nSolidGrp, { nSrfId, nCap1, nCap2}) + return nSolidId end -------------------------------------------------------------------------------------- @@ -212,7 +212,7 @@ local function CreateSolid( nCrvId, nSolidGrp, LayerParams, dH, dStrand) end --------------------------------------------------------------------- -local function CreateDirectionArrow( nCrvId, nSolidGrp, vtSlicing, dStrand, nLayer) +local function CreateDirectionArrow( nCrvId, nSolidGrp, vtSlicing, dStrand, nSliceNbr) local ptS = EgtSP( nCrvId, GDB_RT.GLOB) local vtS = EgtSV( nCrvId, GDB_RT.GLOB) @@ -234,7 +234,7 @@ local function CreateDirectionArrow( nCrvId, nSolidGrp, vtSlicing, dStrand, nLay local nSrf = EgtSurfFlatRegion( nSolidGrp, { nCompo}) EgtErase( nCompo) EgtSetColor( nSrf, RED()) - EgtSetInfo( nSrf, KEY_SLICE_NBR, nLayer) + EgtSetInfo( nSrf, KEY_SLICE_NBR, nSliceNbr) EgtSetStatus( nSrf, GDB_ST.OFF) EgtSetMode( nSrf, GDB_MD.HIDDEN) EgtSetName( nSrf, DIR_ARROW) @@ -272,7 +272,57 @@ local function CreateRecursiveSolid( nCrvId, vSurfs, nSolidGrp, LayerParams, dH, end --------------------------------------------------------------------- -local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nLayer, dLayerH) +local function CalcSolidGuides( nCrvId, dStrand, nSolidGrp) + + -- suddivido la curva in modo opportuno + local nCopyId = EgtCopyGlob( nCrvId, nSolidGrp) + local nId + 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 + + if not nId then return end + + -- verifico in modo euristico se la curva torna indietro su se stessa come se fossero due shell collegate ( verifico se è presente un sottotratto di lunghezza + -- circa pari allo strand non in tangenza con i sottotratti vicini). Nel caso la spezzo per evitare problemi nel calcolo di solidi swept + local vGuideIds = {} + for nInd = 0, nParts - 1 do + local nGuideId = nId + nInd + table.insert( vGuideIds, nGuideId) + if EgtGetType( nGuideId) == GDB_TY.CRV_COMPO then + local _, dE = EgtCurveDomain( nGuideId) + for dU = 1, dE - 2 do + local dLen = EgtCurveCompoLength( nGuideId, dU) + if abs( dLen - dStrand) < 500 * GEO.EPS_SMALL then + -- verifico gli angoli + local vtPrev = EgtUV( nGuideId, dU, -1, GDB_ID.ROOT) + local vtCurrS = EgtUV( nGuideId, dU, 1, GDB_ID.ROOT) + local vtCurrE = EgtUV( nGuideId, dU + 1, -1, GDB_ID.ROOT) + local vtNext = EgtUV( nGuideId, dU + 1, 1, GDB_ID.ROOT) + if vtPrev * vtCurrS < GEO.EPS_SMALL or vtCurrE * vtNext < GEO.EPS_SMALL then + local nNewId = EgtSplitCurveAtParam( nGuideId, dU + 0.5) + table.insert( vGuideIds, nNewId) + break + end + end + end + end + end + + return vGuideIds +end + +--------------------------------------------------------------------- +local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nSliceNbr, dLayerH) local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i') if nType == TYPE.WIPE then return true end @@ -294,54 +344,47 @@ local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nLayer, dLa Color = EgtStdColor( 'AQUA') end + if s_nSimplifiedSection == 1 and nSliceNbr % 2 == 0 then + Color = Color3d( s_dColorFactor * Color:getRed(), s_dColorFactor * Color:getGreen(), s_dColorFactor * Color:getBlue()) + end + -- parametri della passata local dStrand = EgtGetInfo( nCrvId, KEY_CRV_STRAND, 'd') or LayerParams.dStrand local dH = dLayerH or LayerParams.dLayHeight - - 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) + CreateDirectionArrow( nCrvId, nSolidGrp, LayerParams.vtSlicing, dStrand, nSliceNbr) end - if nId == GDB_ID.NULL then return false end + -- spezzo la curva guida in diversi sottotratti per i quali calcolare i solidi + local vGuideIds = CalcSolidGuides( nCrvId, dStrand, nSolidGrp) + if not vGuideIds then + return false + end + local bOk = true - for nInd = 0, nParts - 1 do - local nGuideId = nId + nInd - local nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dH, dStrand - 5 * GEO.EPS_SMALL) + for i = 1, #vGuideIds do + local nSrfId = CreateSolid( vGuideIds[i], nSolidGrp, LayerParams, dH, dStrand - 5 * GEO.EPS_SMALL) if not nSrfId then - EgtOutLog( 'Warning : CreateSolid failed '.. '(layer '..tostring( nLayer)..', curve '..tostring( nCrvId)..')') + EgtOutLog( 'Warning : CreateSolid failed '.. '(layer '..tostring( nSliceNbr)..', curve '..tostring( nCrvId)..')') -- ritento con strand più piccolo - nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dH, dStrand - 50 * GEO.EPS_SMALL) + nSrfId = CreateSolid( vGuideIds[i], nSolidGrp, LayerParams, dH, dStrand - 50 * GEO.EPS_SMALL) if not nSrfId then - EgtOutLog( 'Warning : CreateSolid_1 failed '.. '(layer '..tostring( nLayer)..', curve '..tostring( nCrvId)..')') + EgtOutLog( 'Warning : CreateSolid_1 failed '.. '(layer '..tostring( nSliceNbr)..', 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 i < #vGuideIds then + local nCopyId = EgtCopy( vGuideIds[i] + 1, vGuideIds[i], 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, dH, dStrand - 5 * GEO.EPS_SMALL) + local bOk2 = EgtAddCurveCompoCurve( vGuideIds[i], nCopyId) + local bOk3 = EgtTrimCurveStartAtLen( vGuideIds[i] + 1, LEN_TRIM) + nSrfId = CreateSolid( vGuideIds[i], nSolidGrp, LayerParams, dH, dStrand - 5 * GEO.EPS_SMALL) if not nSrfId then - nSrfId = CreateSolid( nGuideId, nSolidGrp, LayerParams, dH, dStrand - 50 * GEO.EPS_SMALL) + nSrfId = CreateSolid( vGuideIds[i], nSolidGrp, LayerParams, dH, dStrand - 50 * GEO.EPS_SMALL) end end end @@ -351,12 +394,12 @@ local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nLayer, dLa 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) + EgtRelocateGlob( vGuideIds[i], nGrp) + EgtApproxCurve( vGuideIds[i], GDB_CA.LINES, 100 * GEO.EPS_SMALL) + EgtRelocateGlob( vGuideIds[i], nSolidGrp) local vSurfs = {} - local bOk = CreateRecursiveSolid( nGuideId, vSurfs, nSolidGrp, LayerParams, dH, dStrand) + local bOk = CreateRecursiveSolid( vGuideIds[i], vSurfs, nSolidGrp, LayerParams, dH, dStrand) if #vSurfs > 0 then nSrfId = EgtSurfTmByTriangles( nSolidGrp, vSurfs) end @@ -370,14 +413,14 @@ local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nLayer, dLa if nSrfId then EgtSetColor( nSrfId, Color) EgtSetInfo( nSrfId, KEY_TYPE, nType) - EgtSetInfo( nSrfId, KEY_SLICE_NBR, nLayer) + EgtSetInfo( nSrfId, KEY_SLICE_NBR, nSliceNbr) else bOk = false EgtOutLog( 'Warning : CreateSolid_Sewing failed') end - EgtErase( nGuideId) - end - + EgtErase( vGuideIds[i]) + end + return bOk end @@ -399,6 +442,7 @@ local function CreateMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, nLayerId local nPrevLayerId = EgtGetPrev( nLayerId) local vtSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_DIR, 'v') local ptSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_POS, 'p') + vtSlicingPrev * LayerParams.dLayHeight + local dCosAng = vtSlicingPrev * LayerParams.vtSlicing local vSolids = EgtGetAllInGroup( nSolidGrpId) for i = 1, #vSolids do @@ -407,7 +451,7 @@ local function CreateMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, nLayerId local ptVertex = EgtSurfTmGetVertex( vSolids[i], j, GDB_RT.GLOB) -- distanza dal piano di slicing corrente e precedente lungo vtSlicing local dDistCurr = abs( ( ptVertex - ptSlicing) * LayerParams.vtSlicing) - local dDistPrev = ( ptVertex - ptSlicingPrev) * vtSlicingPrev / ( vtSlicingPrev * LayerParams.vtSlicing) + local dDistPrev = ( ptVertex - ptSlicingPrev) * vtSlicingPrev / dCosAng -- calcolo la nuova posizione sapendo che l'altezza dello strand passa da s_dMultiPlanarH a dNewH local dNewH = dDistCurr + dDistPrev local dDelta = dDistCurr - dDistCurr * dNewH / s_dMultiPlanarH @@ -421,16 +465,16 @@ end --------------------------------------------------------------------- local function CreatePartialSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, nLayerId) - -- 1) le prima curve sono solidi multiplanari standard + -- 1) le prime curve sono solidi multiplanari standard for i = 1, #vIds - 1 do CreateMultiPlanarSolids( { vIds[i]}, nSolidGrpId, LayerParams, nLayerId) end - -- 2) l'ultima è il tratto che si alza fino al layer successivo + -- 2) l'ultima curva è il tratto che si alza fino al layer successivo + local nGrpTmp = EgtGroup( nSolidGrpId) local dStrand = EgtGetInfo( vIds[#vIds], KEY_CRV_STRAND, 'd') or LayerParams.dStrand - -- gruppo temporaneo per conti - local nGrpTmp = EgtGroup( nSolidGrpId, Frame3d( ORIG(), LayerParams.vtSlicing, GDB_RT.GLOB)) - + + -- a) calcolo il solido -- appiattisco la curva ( proiezione obliqua sul piano corrente lungo vtSlicing del piano successivo) local nNextLayerId = EgtGetNext( nLayerId) local vtSlicingNext = EgtGetInfo( nNextLayerId, KEY_SLICE_DIR, 'v') @@ -454,7 +498,7 @@ local function CreatePartialSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, Laye vtDir2:rotate( LayerParams.vtSlicing, 90) local nSectE = CreateSection( ptE, vtDir2, dStrand, s_dMultiPlanarH, LayerParams.vtSlicing, nGrpTmp) - -- creo il solido aperto ( tubo) + -- creo le guide per il solido aperto ( tubo) local dMaxDist = ( EgtEP( vIds[#vIds], GDB_ID.ROOT) - ptSlicing) * LayerParams.vtSlicing / ( vtSlicingNext * LayerParams.vtSlicing) local vCrvs = {} local _, dParE = EgtCurveDomain( nSectId) @@ -484,53 +528,264 @@ local function CreatePartialSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, Laye local dMove = ( ptRef - ptS) * LayerParams.vtSlicing EgtMove( vCrvs[i+1], LayerParams.vtSlicing * dMove, GDB_RT.GLOB) end + -- creazione delle superfici del tubo 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 + return false end end - local nSrfId = EgtSurfTmByTriangles( nSolidGrpId, vSurfs) - - -- creazione del mezzo disco iniziale - local nCap1 = CreateSpiralVaseCap( nSectId, - EgtSV( vIds[#vIds], GDB_ID.ROOT), nSolidGrpId) - -- creazione del mezzo disco finale - local nCap2 = CreateSpiralVaseCap( nSectE, EgtEV( vIds[#vIds], GDB_ID.ROOT), nSolidGrpId) - EgtInvertSurf( nCap2) - - -- solido finale - local nSolidId = EgtSurfTmByTriangles( nSolidGrpId, { nSrfId, nCap1, nCap2}) + -- creazione del mezzo disco iniziale e finale + vSurfs[#vCrvs] = CreateSpiralVaseCap( nSectId, - EgtSV( vIds[#vIds], GDB_ID.ROOT), nSolidGrpId) + vSurfs[#vCrvs + 1] = CreateSpiralVaseCap( nSectE, EgtEV( vIds[#vIds], GDB_ID.ROOT), nSolidGrpId) + EgtInvertSurf( vSurfs[#vSurfs]) + local nSolidId = EgtSurfTmByTriangles( nSolidGrpId, vSurfs) - -- limito il solido al piano di slicing precedente - local ptPrev - local vtPrev - if EgtGetInfo( nLayerId, KEY_SLICE_NBR, 'i') == 1 then - ptPrev = ptSlicing - LayerParams.dLayHeight * LayerParams.vtSlicing - vtPrev = LayerParams.vtSlicing + -- b) deformo il solido per limitarlo al piano di slicing precedente + local ptSlicingPrev + local vtSlicingPrev + local nSliceNbr = EgtGetInfo( nLayerId, KEY_SLICE_NBR, 'i') + if nSliceNbr == 1 then + vtSlicingPrev = LayerParams.vtSlicing + ptSlicingPrev = ptSlicing - LayerParams.dLayHeight * LayerParams.vtSlicing else local nPrevLayId = EgtGetPrev( nLayerId) - vtPrev = EgtGetInfo( nPrevLayId, KEY_SLICE_DIR, 'v') - ptPrev = EgtGetInfo( nPrevLayId, KEY_SLICE_POS, 'p') + vtPrev * LayerParams.dLayHeight + vtSlicingPrev = EgtGetInfo( nPrevLayId, KEY_SLICE_DIR, 'v') + ptSlicingPrev = EgtGetInfo( nPrevLayId, KEY_SLICE_POS, 'p') + vtSlicingPrev * LayerParams.dLayHeight end + local dCosAng = vtSlicingPrev * LayerParams.vtSlicing + -- estendo la curva proiettata per gestire correttamente la deformazione dei caps + local nProjExtCrv = EgtCopyGlob( nProjCrv, nGrpTmp) + EgtExtendCurveStartByLen( nProjExtCrv, dStrand) + EgtExtendCurveEndByLen( nProjExtCrv, dStrand) + local dLen = EgtCurveLength( nProjCrv) + local nVertexCnt = EgtSurfTmVertexCount( nSolidId) for j = 0, nVertexCnt - 1 do + local ptVertex = EgtSurfTmGetVertex( nSolidId, j, GDB_RT.GLOB) - local _, ptMinDist = EgtPointCurveDist( ptVertex, vIds[#vIds], GDB_ID.ROOT) - local dDistCrv = abs( ( ptVertex - ptMinDist) * LayerParams.vtSlicing) - local dDistPlane = ( ptVertex - ptPrev) * vtPrev / ( vtPrev * LayerParams.vtSlicing) + + -- calcolo la distanza dal piano precedente lungo vtSlicing + local dDistPrevPlane = ( ptVertex - ptSlicingPrev) * vtSlicingPrev / dCosAng + -- calcolo la distanza approssimata dalla curva del toolpath + local _, ptMinDist, dMinPar = EgtPointCurveDist( ptVertex, nProjExtCrv, GDB_ID.ROOT) + local dCurrLen = EgtCurveLengthAtParam( nProjExtCrv, dMinPar) - dStrand + local ptRef = ptMinDist + dMaxDist * dCurrLen / dLen * vtSlicingNext + local dDistCrv = ( ptRef - ptVertex) * LayerParams.vtSlicing + -- calcolo la nuova posizione sapendo che l'altezza dello strand passa da s_dMultiPlanarH a dNewH - local dNewH = dDistCrv + dDistPlane + local dNewH = dDistCrv + dDistPrevPlane local dDelta = dDistCrv - dDistCrv * dNewH / s_dMultiPlanarH local ptNew = ptVertex + dDelta * LayerParams.vtSlicing EgtSurfTmMoveVertex( nSolidId, j, ptNew, GDB_RT.GLOB, ( j == nVertexCnt - 1)) end - EgtSetColor( nSolidId, EgtStdColor( 'TEAL')) + local Color = EgtStdColor( 'TEAL') + if s_nSimplifiedSection == 1 and nSliceNbr % 2 == 0 then + Color = Color3d( s_dColorFactor * Color:getRed(), s_dColorFactor * Color:getGreen(), s_dColorFactor * Color:getBlue()) + end + EgtSetColor( nSolidId, Color) + + EgtErase( nGrpTmp) +end + +--------------------------------------------------------------------- +local function CreateFullSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, nLayerId) + + local nSliceNbr = EgtGetInfo( nLayerId, KEY_SLICE_NBR, 'i') + local ptSlicing = EgtGetInfo( nLayerId, KEY_SLICE_POS, 'p') + LayerParams.dLayHeight * LayerParams.vtSlicing + + -- recupero il piano precedente e il suo toolpath + local nPrevLayerId = EgtGetPrev( nLayerId) + local vtSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_DIR, 'v') + local ptSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_POS, 'p') + LayerParams.dLayHeight * vtSlicingPrev + local dCosAng = vtSlicingPrev * LayerParams.vtSlicing + local nPrevCrvGrp = EgtGetFirstNameInGroup( nPrevLayerId, CONTOUR_GRP .. '*') + local nPrevTPathGrp = EgtGetFirstNameInGroup( nPrevCrvGrp, TOOLPATH_GRP) + local nPrevTPath = EgtGetFirstNameInGroup( nPrevTPathGrp, SHELL_CRV .. '*') + + -- gruppo temporaneo per conti + local nGrpTmp = EgtGroup( nSolidGrpId) + + for i = 1, #vIds do + local dStrand = EgtGetInfo( vIds[i], KEY_CRV_STRAND, 'd') or LayerParams.dStrand + + -- creo la freccia direzionale + CreateDirectionArrow( vIds[i], nSolidGrpId, LayerParams.vtSlicing, dStrand, nSliceNbr) + + -- appiattisco la curva ( proiezione sul piano di slicing) + local nProjCrv = EgtCopyGlob( vIds[i], nGrpTmp) + EgtProjectCurveOnPlane( nProjCrv, ptSlicing, LayerParams.vtSlicing, GDB_RT.GLOB) + local dLen = EgtCurveLength( nProjCrv) + + -- suddivido la curva piana + local vGuideIds = CalcSolidGuides( nProjCrv, dStrand, nGrpTmp) + local dCumLen = 0 + for k = 1, #vGuideIds do + + -- calcolo il solido sulla porzione della curva di proiezione + local nSolidId = CreateStandardSolid( vGuideIds[k], nSolidGrpId, s_dMultiPlanarH, dStrand) + + -- estendo la guida per gestire al meglio i caps + local nCrvRef = EgtCopyGlob( vGuideIds[k], nGrpTmp) + EgtExtendCurveStartByLen( nCrvRef, dStrand) + EgtExtendCurveEndByLen( nCrvRef, dStrand) + + -- recupero la curva precedente. Se estremi la limito per gestire al meglio la corrispondenza tra i toolpath + local nPrevTPathRef = nPrevTPath + if k == 1 then + nPrevTPathRef = EgtCopyGlob( nPrevTPath, nGrpTmp) + EgtTrimCurveEndAtLen( nPrevTPathRef, 0.5 * EgtCurveLength( nPrevTPathRef)) + elseif k == #vGuideIds then + nPrevTPathRef = EgtCopyGlob( nPrevTPath, nGrpTmp) + EgtTrimCurveStartAtLen( nPrevTPathRef, 0.5 * EgtCurveLength( nPrevTPathRef)) + end + + -- deformo i solidi : + -- 1) traslazione dei vertici per portarli alla quota corretta del toolpath corrente + -- 2) deformazione della sezione in base alla distanza dal toolpath precedente + local nVertexCnt = EgtSurfTmVertexCount( nSolidId) + for j = 0, nVertexCnt - 1 do + local ptVertex = EgtSurfTmGetVertex( nSolidId, j, GDB_RT.GLOB) + + -- ricavo il punto di riferimento sulla proiezione del toolpath + local _, ptMinDist, dParMinDist = EgtPointCurveDist( ptVertex, nCrvRef, GDB_ID.ROOT) + local dCurrLen = EgtCurveLengthAtParam( nCrvRef, dParMinDist) - dStrand + dCumLen + + -- 1) proietto il punto sul piano corrente e calcolo la traslazione da applicare in base alla distanza dal piano precedente ( analogamente a CalcToolPath) + local dDistCrv = ( ptSlicing - ptVertex) * LayerParams.vtSlicing + local ptProj = ptVertex + dDistCrv * LayerParams.vtSlicing + local dDistPlanePrev = ( ptProj - ptSlicingPrev) * vtSlicingPrev / dCosAng + local dDeltaPos + if nSliceNbr == 2 and dCurrLen < 0.5 * dLen then + dDeltaPos = 0.5 * dDistPlanePrev + else + dDeltaPos = dDistPlanePrev * ( dLen - dCurrLen) / dLen + end + + -- 2) per calcolare la vera altezza del solido calcolo la distanza dal toolpath precedente guardando il punto di riferimento sul percorso corrente + local dNewH + if nSliceNbr == 2 then + -- il primo layer è ad altezza costante quindi è semplice distanza dal piano precedente lungo vtSlicing + dNewH = ( ptProj - ptSlicingPrev) * vtSlicingPrev / dCosAng - dDeltaPos + else + local _, ptMinDistPrev = EgtPointCurveDist( ptMinDist, nPrevTPathRef, GDB_ID.ROOT) + local dDistPlanePrev2 = ( ptMinDist - ptSlicingPrev) * vtSlicingPrev / dCosAng + local dDeltaPos2 + if nSliceNbr == 2 and dCurrLen < 0.5 * dLen then + dDeltaPos2 = 0.5 * dDistPlanePrev2 + else + dDeltaPos2 = dDistPlanePrev2 * ( dLen - dCurrLen) / dLen + end + dNewH = ( ptMinDist - ptMinDistPrev) * LayerParams.vtSlicing - dDeltaPos2 + -- aggiungo un piccolo extra per tener conto che la distanza è stata calcolata sulle curve centrali del solido + local dExtra = ( LayerParams.vtSlicing ^ vtSlicingPrev):len() / dCosAng * dStrand * 0.5 + dNewH = dNewH + dExtra + end + + local dDelta = dDistCrv - dDistCrv * dNewH / s_dMultiPlanarH + local ptNew = ptVertex + ( dDelta - dDeltaPos) * LayerParams.vtSlicing + EgtSurfTmMoveVertex( nSolidId, j, ptNew, GDB_RT.GLOB, ( j == nVertexCnt - 1)) + end + + -- imposto colore + local Color = EgtStdColor( 'TEAL') + if s_nSimplifiedSection == 1 and nSliceNbr % 2 == 0 then + Color = Color3d( s_dColorFactor * Color:getRed(), s_dColorFactor * Color:getGreen(), s_dColorFactor * Color:getBlue()) + end + EgtSetColor( nSolidId, Color) + + dCumLen = dCumLen + EgtCurveLength( vGuideIds[i]) + end + end + + EgtErase( nGrpTmp) +end + +--------------------------------------------------------------------- +local function CreateFullSpiralVaseMultiPlanarSolidsLastLayer( vIds, nSolidGrpId, LayerParams, nLayerId) + -- le curve sono piane quindi i solidi possono essere calcolati nel modo classico + -- i solidi della shell sono deformati in base alla distanza dalla curva precedente + -- eventuali solidi di lead out e coasting sono calcolati con un valore di altezza costante pari all'ultimo valore di altezza dei solidi della shell + + local nSliceNbr = EgtGetInfo( nLayerId, KEY_SLICE_NBR, 'i') + + local nPrevLayerId = EgtGetPrev( EgtGetPrev( nLayerId)) + local vtSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_DIR, 'v') + local ptSlicingPrev = EgtGetInfo( nPrevLayerId, KEY_SLICE_POS, 'p') + vtSlicingPrev * LayerParams.dLayHeight + local ptSlicing = EgtGetInfo( nLayerId, KEY_SLICE_POS, 'p') + LayerParams.vtSlicing * LayerParams.dLayHeight + local dCosAng = vtSlicingPrev * LayerParams.vtSlicing + + -- 1) curva shell + local nGrpTmp = EgtGroup( nSolidGrpId) + local dStrand = EgtGetInfo( vIds[1], KEY_CRV_STRAND, 'd') or LayerParams.dStrand + local vShellGuides = CalcSolidGuides( vIds[1], dStrand, nGrpTmp) + + local dLen = EgtCurveLength( vIds[1]) + -- se non c'è lead out alla lunghezza totale della shell devo aggiungere anche quella del coasting + if EgtGetInfo( s_nPartId, KEY_LEAD_OUT_TYPE, 'i') == LEAD_TYPE.NONE then + dLen = dLen + EgtGetInfo( s_nPartId, KEY_COASTING_LEN, 'd') + end + local dCumLen = 0 + + -- creo la freccia direzionale + CreateDirectionArrow( vIds[1], nSolidGrpId, LayerParams.vtSlicing, dStrand, nSliceNbr) + + for i = 1, #vShellGuides do + + -- calcolo il solido associato + local nSolidId = CreateStandardSolid( vShellGuides[i], nSolidGrpId, s_dMultiPlanarH, dStrand) + + -- estensione della guida per gestire meglio i caps + local nCrvRef = EgtCopyGlob( vShellGuides[i], nGrpTmp) + EgtExtendCurveStartByLen( nCrvRef, dStrand) + EgtExtendCurveEndByLen( nCrvRef, dStrand) + + -- deformo in base alla distanza dalla curva precedente + local nVertexCnt = EgtSurfTmVertexCount( nSolidId) + for j = 0, nVertexCnt - 1 do + local ptVertex = EgtSurfTmGetVertex( nSolidId, j, GDB_RT.GLOB) + + -- ricavo il punto di riferimento sulla guida + local _, _, dParMinDist = EgtPointCurveDist( ptVertex, nCrvRef, GDB_ID.ROOT) + local dCurrLen = EgtCurveLengthAtParam( nCrvRef, dParMinDist) - dStrand + dCumLen + + -- calcolo la nuova altezza del solido in base alla distanza dalla curva precedente + local dDistCurr = ( ptSlicing - ptVertex) * LayerParams.vtSlicing + local ptProj = ptVertex + dDistCurr * LayerParams.vtSlicing + local dDistPrev = ( ptProj - ptSlicingPrev) * vtSlicingPrev / dCosAng + local dNewH = dDistPrev * ( dLen - dCurrLen) / dLen + dNewH = max( dNewH, 500 * GEO.EPS_SMALL) + + -- calcolo la nuova posizione sapendo che l'altezza dello strand passa da s_dMultiPlanarH a dNewH + local dDelta = dDistCurr - dDistCurr * dNewH / s_dMultiPlanarH + local ptNew = ptVertex + dDelta * LayerParams.vtSlicing + EgtSurfTmMoveVertex( nSolidId, j, ptNew, GDB_RT.GLOB, ( j == nVertexCnt - 1)) + end + + dCumLen = dCumLen + EgtCurveLength( vShellGuides[i]) + + -- imposto colore + local Color = EgtStdColor( 'TEAL') + if s_nSimplifiedSection == 1 and nSliceNbr % 2 == 0 then + Color = Color3d( s_dColorFactor * Color:getRed(), s_dColorFactor * Color:getGreen(), s_dColorFactor * Color:getBlue()) + end + EgtSetColor( nSolidId, Color) + end + + -- 2) curve di uscita + -- calcolo altezza finale del solido shell + local ptE = EgtEP( vIds[1], GDB_ID.ROOT) + local dH = ( ( ptE - ptSlicingPrev) * vtSlicingPrev / dCosAng) * ( dLen - EgtCurveLength( vIds[1])) / dLen + dH = max( dH, 500 * GEO.EPS_SMALL) + for i = 2, #vIds do + CreateSolidFromCurve( vIds[i], nSolidGrpId, LayerParams, nSliceNbr, dH) + end + EgtErase( nGrpTmp) - return true end --------------------------------------------------------------------- @@ -547,6 +802,7 @@ function RunCalcSolids.Exec() local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) or EgtGetFirstNameInGroup( GDB_ID.ROOT, PART) while nPartId do + s_nPartId = nPartId 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 @@ -582,7 +838,7 @@ function RunCalcSolids.Exec() -- flag di interruzione perchè trovati solidi già ok local bSolidsOk = false -- indice layer ( per log) - local nLayer = EgtGetInfo( vLayIds[ nIdx], KEY_SLICE_NBR, 'i') + local nSliceNbr = 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 @@ -603,22 +859,34 @@ function RunCalcSolids.Exec() local vIds = EgtGetAllInGroup( nTPathGrpId) - -- multiplanare + -- slicing multiplanare if nSlicingType == SLICING_TYPE.MULTIPLANAR then LayerParams.vtSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_DIR, 'v') if LayerParams.bSpiralVase then local dTransitionLen = EgtGetInfo( nPartId, KEY_SPIRAL_VASE_LEN, 'd') or 0 + -- a) spiral vase completo ( con transizione in altezza su tutto il layer) if dTransitionLen < GEO.EPS_SMALL then - -- TO DO + if nIdx == 1 then + -- il primo layer va gestito come uno spiral vase con transizione parziale ( curva a quota costante e ultimo tratto che si alza) + CreatePartialSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) + elseif nIdx == #vLayIds then + -- gestione speciale per lead out e coasting + CreateFullSpiralVaseMultiPlanarSolidsLastLayer( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) + else + CreateFullSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) + end + + -- b) spiral vase con transizione parziale else if nIdx == #vLayIds then - -- ultimo layer non ha tratto finale rialzato quindi è un multiplanare standard + -- ultimo layer è un multiplanare standard perchè non ha tratto finale che si alza CreateMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) else CreatePartialSpiralVaseMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) end end + -- c) multiplanare standard else CreateMultiPlanarSolids( vIds, nSolidGrpId, LayerParams, vLayIds[nIdx]) end @@ -650,13 +918,13 @@ function RunCalcSolids.Exec() for i = 1, #vChainedIds do if #vChainedIds[i] == 1 then - CreateSolidFromCurve( vChainedIds[i][1], nSolidGrpId, LayerParams, nLayer) + CreateSolidFromCurve( vChainedIds[i][1], nSolidGrpId, LayerParams, nSliceNbr) else local nNewCrv = EgtCurveCompo( nSolidGrpId, vChainedIds[i], false) local dStrand = EgtGetInfo( vChainedIds[i][1], KEY_CRV_STRAND, 'd') or LayerParams.dStrand EgtSetInfo( nNewCrv, KEY_CRV_STRAND, dStrand) EgtSetInfo( nNewCrv, KEY_TYPE, TYPE.OUTER_SHELL) - CreateSolidFromCurve( nNewCrv, nSolidGrpId, LayerParams, nLayer) + CreateSolidFromCurve( nNewCrv, nSolidGrpId, LayerParams, nSliceNbr) EgtErase( nNewCrv) end end @@ -664,7 +932,7 @@ function RunCalcSolids.Exec() -- slicing standard else for i = 1, #vIds do - CreateSolidFromCurve( vIds[i], nSolidGrpId, LayerParams, nLayer) + CreateSolidFromCurve( vIds[i], nSolidGrpId, LayerParams, nSliceNbr) end end else