-- CalcToolPath.lua by Egaltech s.r.l. 2026/02/16 -- Calcolo percorsi di lavoro per Stampa 3d -- Tabella per definizione modulo local CalcToolPath = {} -- Intestazioni require( 'EgtBase') EgtOutLog( ' CalcToolPath started', 1) -- Dati local AMD = require( 'AddManData') --------------------------------------------------------------------- local s_nPartId local s_nDefaultWipeAng = -90 -- angolo = 0° per wipe significa che esce ortogonalmente alla direzione del movimento local s_dApproxTol = 0.1 local s_dHSafeWipe = 2 local s_nCurrIdx local s_dSpiralVaseMaxLen = 10 -- lunghezza massima dei tratti per calcolo SpiralizeAlongGuide local s_dSpralVaseFirstDelta = 30 -- lunghezza del tratto sul primo layer che va alzato nella modalità SpiralVaseFull --------------------------------------------------------------------- local function GetLayerParamsForToolPathCalc() local LayerParams = {} LayerParams.bSpiralVase = EgtGetInfo( s_nPartId, KEY_SPIRAL_VASE, 'b') or false LayerParams.dSpiralVaseLen = EgtGetInfo( s_nPartId, KEY_SPIRAL_VASE_LEN, 'd') or 0 LayerParams.dStrand = EgtGetInfo( s_nPartId, KEY_STRAND, 'd') LayerParams.dInnerStrand = EgtGetInfo( s_nPartId, KEY_INNER_STRAND, 'd') or LayerParams.dStrand if LayerParams.dInnerStrand < GEO.EPS_SMALL then LayerParams.dInnerStrand = LayerParams.dStrand end LayerParams.dLayHeight = EgtGetInfo( s_nPartId, KEY_SLICE_STEP, 'd') LayerParams.dOffs = EgtGetInfo( s_nPartId, KEY_OFFSET_SLICE, 'd') LayerParams.bInvert = ( EgtGetInfo( s_nPartId, KEY_PRINT_DIRECTION, 'i') == PRINT_DIRECTION.CW) LayerParams.nOrder = EgtGetInfo( s_nPartId, KEY_STRAND_ORDER, 'i') LayerParams.vPrintOrder = EgtGetInfo( s_nPartId, KEY_PRINT_ORDER, 'vi') or { 1, 2, 3, 4, 5, 6, 7, 8} LayerParams.nLinkType = EgtGetInfo( s_nPartId, KEY_LINK_TYPE, 'i') LayerParams.dLinkParam = EgtGetInfo( s_nPartId, KEY_LINK_PARAM, 'd') LayerParams.nLeadInType = EgtGetInfo( s_nPartId, KEY_LEAD_IN_TYPE, 'i') LayerParams.bSingleLeadIn = EgtGetInfo( s_nPartId, KEY_SINGLE_LEAD_IN, 'b') or false LayerParams.dLeadInTangDist = EgtGetInfo( s_nPartId, KEY_LEAD_IN_TANG_DIST, 'd') LayerParams.dLeadInOrthoDist = EgtGetInfo( s_nPartId, KEY_LEAD_IN_ORTHO_DIST, 'd') LayerParams.nLeadOutType = EgtGetInfo( s_nPartId, KEY_LEAD_OUT_TYPE, 'i') LayerParams.dLeadOutTangDist = EgtGetInfo( s_nPartId, KEY_LEAD_OUT_TANG_DIST, 'd') LayerParams.dLeadOutOrthoDist = EgtGetInfo( s_nPartId, KEY_LEAD_OUT_ORTHO_DIST, 'd') LayerParams.dOffsetLP = EgtGetInfo( s_nPartId, KEY_OFFSET_LEAD_POINT, 'd') LayerParams.dSPOffs = EgtGetInfo( s_nPartId, KEY_SP_OFFSET_ON_SLICE, 'd') LayerParams.dCoastingLen = EgtGetInfo( s_nPartId, KEY_COASTING_LEN, 'd') LayerParams.dWipeLen = EgtGetInfo( s_nPartId, KEY_WIPE_LEN, 'd') LayerParams.dWipeDir = EgtGetInfo( s_nPartId, KEY_WIPE_DIR, 'd') or 0.0 LayerParams.vtSlicing = EgtGetInfo( s_nPartId, KEY_SLICE_DIR, 'v') LayerParams.dTDiam = EgtGetInfo( s_nPartId, KEY_TOOL_DIAM, 'd') -- parametri infill LayerParams.dInfillStrand = EgtGetInfo( s_nPartId, KEY_INFILL_STRAND, 'd') or LayerParams.dStrand if LayerParams.dInfillStrand < GEO.EPS_SMALL then LayerParams.dInfillStrand = LayerParams.dStrand end LayerParams.bInfillLink = EgtGetInfo( s_nPartId, KEY_INFILL_LINK, 'b') or false LayerParams.dInfillCoasting = EgtGetInfo( s_nPartId, KEY_INFILL_COASTING, 'd') or 0 LayerParams.dInfillWipe = EgtGetInfo( s_nPartId, KEY_INFILL_WIPE, 'd') or 0 LayerParams.dInfillWipeDir = EgtGetInfo( s_nPartId, KEY_INFILL_WIPE_DIR, 'd') or 0 -- parametri dal file macchina per eventuale approssimazione lineare dei percorsi local sMachIni = EgtGetCurrMachineDir() .. '\\' .. EgtGetCurrMachineName() .. '.ini' LayerParams.bLinearApprox = ( EgtGetNumberFromIni( SEC_3DPRINTING, KEY_LINEAR_APPROX, 0, sMachIni) == 1) LayerParams.dLinearApproxTol = EgtGetNumberFromIni( SEC_3DPRINTING, KEY_LINEAR_TOL, 0.1, sMachIni) -- parametri da file ini del programma local sIniFile = EgtGetIniFile() LayerParams.dSpiralVaseInterpLen = EgtGetNumberFromIni( '3dPrinting', KEY_SPIRAL_VASE_INTERP_LEN, 100.0, sIniFile) return LayerParams end ------------------------------------------------------------------ local function ComputeToolPathBox( nLayerId) -- calcolo il box di tutti i toolpath del layer escludendo i wipe local b3Box = BBox3d() 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 end return b3Box end ------------------------------------------------------------------ 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, 'd') 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 or nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 or nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR then 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() local b3Layer = ComputeToolPathBox( vLayIds[i]) if not b3Layer:isEmpty() then -- altezza necessaria per lo strand local dHStrand = 0 -- nel caso multiplanar con partenza verticale l'altezza necessaria per lo strand non serve perchè l'altezza viene adattata lungo il percorso if nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 then -- nel caso multiplanar 45° si considera come altezza strand quella settata nei parametri visto che varia lungo il percorso ( euristico) dHStrand = 0.5 * LayerParams.dStrand * dNxy + LayerParams.dLayHeight * dNz elseif nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR then dHStrand = 0.5 * LayerParams.dStrand end -- altezza necessaria per il tool local dHTool = LayerParams.dTDiam / 2 * dNxy -- altezza disponibile local dHDisp = b3Layer:getMin():getZ() - max( dHBox, 0) local dCurrCorrZ = max( 0, max( dHStrand, dHTool) - dHDisp) dCorrZ = max( dCorrZ, dCurrCorrZ) end 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 -- 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 and nSlicingType ~= SLICING_TYPE.MULTIPLANAR_DEG45 and nSlicingType ~= SLICING_TYPE.MULTIPLANAR_HOR 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 for i = 1, #vLayIds do if nSlicingType == SLICING_TYPE.MULTIPLANAR or nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 or nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR 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) if nTPath then local vIds = EgtGetAllInGroup( nTPath) for k = 1, #vIds do -- se wipe verifico se ha lunghezza sensata per non finire nella tavola if EgtGetInfo( vIds[k], KEY_TYPE, 'i') == TYPE.WIPE then -- da controllare solo se non segue l'andamento di una curva chiusa local bOnCurve = EgtGetInfo( vIds[k], KEY_WIPE_ON_CRV, 'b') or false if not bOnCurve then local dLen = EgtCurveLength( vIds[k]) local vtDir = EgtSV( vIds[k], GDB_ID.ROOT) local ptE = EgtEP( vIds[k], GDB_ID.ROOT) if ptE:getZ() < dHMinWipe then -- modifico la lunghezza per non finire nella tavola local dDiffLen = abs( ( dHMinWipe - ptE:getZ()) / vtDir:getZ()) if dDiffLen > dLen - GEO.EPS_SMALL then -- l'intero tratto di wipe va eliminato EgtErase( vIds[k]) EgtOutLog( 'Warning : wipe was removed due to wrong direction (layer '..tostring( i)..') - CalcToolPath') else EgtTrimCurveEndAtLen( vIds[k], dLen - dDiffLen) end end end end end end end end end ------------------------------------------------------------------- local function AddCurvesToToolPath( vEntIds, nTpathGrpId, nOrder, bInvert, vtSlicing, dLayHeight) local vIds = {} -- vettore con gli id ordinati delle curve nel gruppo dei ToolPath local nStart = EgtIf( nOrder == PRINT_ORDER.EXT_INT, 1, #vEntIds) local nEnd = EgtIf( nOrder == PRINT_ORDER.EXT_INT, #vEntIds, 1) local nStep = EgtIf( nOrder == PRINT_ORDER.EXT_INT, 1, -1) local nIdx = 1 for i = nStart, nEnd, nStep do -- copio nel gruppo toolpath if i == nStart then vIds[nIdx] = EgtCopyGlob( vEntIds[i], nTpathGrpId, GDB_IN.LAST_SON) else vIds[nIdx] = EgtCopyGlob( vEntIds[i], vIds[nIdx-1], GDB_IN.AFTER) end -- mi sposto dell'altezza layer EgtMove( vIds[nIdx], dLayHeight * vtSlicing, GDB_RT.GLOB) if EgtCurveIsClosed( vIds[nIdx]) then EgtSetInfo( vIds[nIdx], KEY_CLOSED_CRV, 1) -- eventuale inversione if bInvert then EgtInvertCurve( vIds[nIdx]) EgtSetInfo( vIds[nIdx], KEY_INVERTED_CRV, 1) end end -- approssimo la curva e ne risetto il punto iniziale local ptS = EgtSP( vIds[nIdx], GDB_ID.ROOT) EgtApproxCurve( vIds[nIdx], GDB_CA.ARCS, s_dApproxTol) if EgtCurveIsClosed( vIds[nIdx]) then EgtChangeClosedCurveStartPoint( vIds[nIdx], ptS, GDB_RT.GLOB) end EgtSetInfo( vEntIds[i], KEY_ASSOCIATED_TP_CRV, vIds[nIdx]) EgtSetInfo( vIds[nIdx], KEY_ASSOCIATED_P_CRV, vEntIds[i]) EgtModifyCurveExtrusion( vIds[nIdx], vtSlicing, GDB_RT.GLOB) EgtSetColor( vIds[nIdx], EgtStdColor('GRAY')) EgtSetStatus( vIds[nIdx], GDB_ST.ON) nIdx = nIdx + 1 end return vIds end ------------------------------------------------------------------------- local function AddStartPointOffsetOnLayer( nCrv, nCrvPrev, dSPOffs, nOrder, vtSlicing, dLayH) if not EgtCurveIsClosed( nCrv) then return end local dStrand = EgtGetInfo( nCrv, KEY_CRV_STRAND, 'd') -- individuo eventuale curva di toolpath precendente da cui prendere il punto di partenza local nPrev local vPrevPath = EgtGetInfo( nCrv, EgtIf( nOrder == PRINT_ORDER.EXT_INT, KEY_PREV_CRV, KEY_NEXT_CRVS), 'vi') if vPrevPath then local nAssociatedPathCrv = EgtGetInfo( nCrv, KEY_ASSOCIATED_P_CRV, 'i') local nPrevFirst = EgtGetInfo( vPrevPath[1], KEY_ASSOCIATED_TP_CRV, 'i') local dOtherStrand = EgtGetInfo( nPrevFirst, KEY_CRV_STRAND, 'd') for j = 1, #vPrevPath do -- verifico se gli start point delle path curve sono sufficientemente vicini if dist( EgtSP( vPrevPath[j], GDB_ID.ROOT), EgtSP( nAssociatedPathCrv, GDB_ID.ROOT)) < ( dStrand + dOtherStrand) * 0.5 + 100 * GEO.EPS_SMALL then nPrev = EgtGetInfo( vPrevPath[j], KEY_ASSOCIATED_TP_CRV, 'i') break end end elseif nCrvPrev then -- caso ribs chiuse in cui manca info sul precedente/successivo ( TODO da migliorare!) nPrev = nCrvPrev end if not nPrev then return end -- recupero punto di partenza originale prima di eventuale OffsetLeadPoint local ptS = EgtGetInfo( nPrev, KEY_ORIGINAL_START_POINT, 'p') or EgtSP( nPrev, GDB_ID.ROOT) EgtChangeClosedCurveStartPoint( nCrv, ptS, GDB_RT.GLOB) local dLen = dSPOffs if dSPOffs < 0 then dLen = EgtCurveLength( nCrv) + dLen end local dPar = EgtCurveParamAtLength( nCrv, dLen) if dPar then EgtChangeClosedCurveStart( nCrv, dPar) end end ------------------------------------------------------------------- local function AddLink( vCrv, nTpathGrpId, nLinkType, dLinkParam, dSPOffs, nOrder, vtSlicing) if not vCrv or #vCrv == 0 then return end if nLinkType == LINK_TYPE.NONE and abs( dSPOffs) > GEO.EPS_SMALL then -- se nessun raccordo modifico solo lo start point delle curve for i = 1, #vCrv do AddStartPointOffsetOnLayer( vCrv[i], vCrv[i-1], dSPOffs, nOrder) end elseif nLinkType ~= LINK_TYPE.NONE then -- modifico lo start point della prima curva AddStartPointOffsetOnLayer( vCrv[1], nil, dSPOffs, nOrder) local dPrevStrand = EgtGetInfo( vCrv[1], KEY_CRV_STRAND, 'd') -- creo i raccordi for i = 2, #vCrv do -- il link ha senso solo su curva chiusa if EgtCurveIsClosed( vCrv[i]) then -- verifico se ha senso creare raccordo local dDist = EgtPointCurveDist( EgtEP( vCrv[i-1]), vCrv[i]) local dCurrStrand = EgtGetInfo( vCrv[i], KEY_CRV_STRAND, 'd') if dDist < ( dCurrStrand + dPrevStrand) * 0.5 + 10 * GEO.EPS_SMALL then local nLinkId -- modifico lo start point local dLen = EgtCurveLength( vCrv[i-1]) - EgtIf( i > 2, abs( dSPOffs), 0) EgtTrimCurveEndAtLen( vCrv[i-1], dLen) EgtChangeClosedCurveStartPoint( vCrv[i], EgtEP( vCrv[i-1])) -- aggiungo il raccordo EgtTrimCurveEndAtLen( vCrv[i-1], EgtCurveLength( vCrv[i-1]) - dLinkParam / 2) EgtTrimCurveStartAtLen( vCrv[i], dLinkParam / 2) if nLinkType == LINK_TYPE.LINEAR then nLinkId = EgtCurveCompoFromPoints( nTpathGrpId, {EgtEP( vCrv[i-1]), EgtSP( vCrv[i])}) elseif nLinkType == LINK_TYPE.BIARC then local frLoc = Frame3d( ORIG(), vtSlicing) local nGrpTmp = EgtGroup( nTpathGrpId, frLoc, GDB_RT.GLOB) local _, _, dAngIni = SphericalFromVector( EgtEV( vCrv[i-1], nGrpTmp)) local _, _, dAngFin = SphericalFromVector( EgtSV( vCrv[i], nGrpTmp)) nLinkId = EgtBiArc( nGrpTmp, EgtEP( vCrv[i-1], nGrpTmp), EgtSP( vCrv[i], nGrpTmp), dAngIni, dAngFin, 0.5) EgtRelocateGlob( nLinkId, nTpathGrpId, GDB_IN.LAST_SON) EgtErase( nGrpTmp) end if nLinkId then EgtRelocate( nLinkId, vCrv[i], GDB_IN.BEFORE) EgtModifyCurveExtrusion( nLinkId, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLinkId, KEY_TYPE, TYPE.LINK) EgtSetName( nLinkId, LINK_CRV) EgtSetInfo( nLinkId, KEY_CRV_STRAND, max( dCurrStrand, dPrevStrand)) end dPrevStrand = dCurrStrand else -- se raccordo non sensato perchè curve troppo distanti modifico lo start point AddStartPointOffsetOnLayer( vCrv[i], vCrv[i-1], dSPOffs, nOrder) end end end end end --------------------------------------------------------------------- local function AddOffsetLeadPoint( vIds, nFirstCopy, dOffsetLP, nLinkType) -- se link va fatto solo sulla shell esterna local nLast = EgtIf( nLinkType == LINK_TYPE.NONE, #vIds, 1) if abs( dOffsetLP) > GEO.EPS_SMALL then for i = 1, nLast do -- conservo lo start point originale per AddStartPointOffsetOnLayer EgtSetInfo( vIds[i], KEY_ORIGINAL_START_POINT, EgtSP( vIds[i], GDB_ID.ROOT)) if dOffsetLP > GEO.EPS_SMALL then -- taglio curva EgtTrimCurveStartAtLen( vIds[i], dOffsetLP) else -- è necessario aggiungere un tratto local nAddCrv = EgtCopyGlob( EgtIf( i == 1 and nLinkType ~= LINK_TYPE.NONE, nFirstCopy, vIds[i]), vIds[1], GDB_IN.AFTER) EgtTrimCurveStartAtLen( nAddCrv, EgtCurveLength( nAddCrv) - abs( dOffsetLP)) if not EgtAddCurveCompoCurve( vIds[i], nAddCrv, true, false) then -- se fallisce cancello il tratto da aggiungere EgtErase( nAddCrv) end end end end -- elimino curva aux usata per prima shell EgtErase( nFirstCopy) end -------------------------------------------------------------------- local function AddLeadIn( nCrvId, LayerParams, nGrpId) local ptE = EgtSP( nCrvId, GDB_ID.ROOT) local vtTang = EgtSV( nCrvId, GDB_ID.ROOT) local vtOrtho = Vector3d( vtTang) local dAng = 90 if ( LayerParams.bInvert and LayerParams.nOrder == PRINT_ORDER.INT_EXT) or ( not LayerParams.bInvert and LayerParams.nOrder == PRINT_ORDER.EXT_INT) then dAng = - 90 end vtOrtho:rotate( LayerParams.vtSlicing, dAng) local ptS = ptE - LayerParams.dLeadInTangDist * vtTang + LayerParams.dLeadInOrthoDist * vtOrtho local nLeadInCrv if LayerParams.nLeadInType == LEAD_TYPE.LINEAR then nLeadInCrv = EgtCurveCompoFromPoints( nGrpId, {ptS, ptE}, GDB_RT.GLOB) elseif LayerParams.nLeadInType == LEAD_TYPE.ARC then nLeadInCrv = EgtArc2PV( nGrpId, ptE, ptS, -vtTang, GDB_RT.GLOB) EgtInvertCurve( nLeadInCrv) end if nLeadInCrv then EgtRelocate( nLeadInCrv, nCrvId, GDB_IN.BEFORE) EgtModifyCurveExtrusion( nLeadInCrv, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLeadInCrv, KEY_TYPE, TYPE.LINK) EgtSetName( nLeadInCrv, LEAD_IN_CRV) EgtSetColor( nLeadInCrv, EgtStdColor('GRAY')) local dStrand = EgtGetInfo( nCrvId, KEY_CRV_STRAND, 'd') EgtSetInfo( nLeadInCrv, KEY_CRV_STRAND, dStrand) end return nLeadInCrv 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) local dAng = - 90 if ( LayerParams.bInvert and LayerParams.nOrder == PRINT_ORDER.INT_EXT) or ( not LayerParams.bInvert and LayerParams.nOrder == PRINT_ORDER.EXT_INT) then dAng = 90 end vtOrtho:rotate( vtSlicing, dAng) local ptE = ptS + LayerParams.dLeadOutTangDist * vtTang + LayerParams.dLeadOutOrthoDist * vtOrtho local nLeadOutCrv if LayerParams.nLeadOutType == LEAD_TYPE.LINEAR then nLeadOutCrv = EgtCurveCompoFromPoints( nGrpId, {ptS, ptE}, GDB_RT.GLOB) elseif LayerParams.nLeadOutType == LEAD_TYPE.ARC then nLeadOutCrv = EgtArc2PV( nGrpId, ptS, ptE, vtTang, GDB_RT.GLOB) end if nLeadOutCrv then EgtRelocate( nLeadOutCrv, nCrvId, GDB_IN.AFTER) EgtModifyCurveExtrusion( nLeadOutCrv, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLeadOutCrv, KEY_TYPE, TYPE.LINK) EgtSetName( nLeadOutCrv, LEAD_OUT_CRV) EgtSetColor( nLeadOutCrv, EgtStdColor('GRAY')) local dStrand = EgtGetInfo( nCrvId, KEY_CRV_STRAND, 'd') EgtSetInfo( nLeadOutCrv, KEY_CRV_STRAND, dStrand) end return nLeadOutCrv end -------------------------------------------------------------------- local function AddRetraction( nCrvId, dCoastingLen, dWipeLen, dWipeDir) -- recupero i parametri per retrazione local vtSlicing = EgtCurveExtrusion( nCrvId, GDB_ID.ROOT) local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i') local bClosed = EgtGetInfo( nCrvId, KEY_CLOSED_CRV, 'b') or false local bInverted = EgtGetInfo( nCrvId, KEY_INVERTED_CRV, 'b') or false local dStrand = EgtGetInfo( nCrvId, KEY_CRV_STRAND, 'd') -- curva ausiliaria per generare correttamente wipe local nCopyId = EgtCopyGlob( nCrvId, nCrvId, GDB_IN.AFTER) if not EgtCurveIsClosed( nCopyId) and EgtCurveIsFlat( nCopyId) then local ptNewStart = EgtEP( nCopyId, GDB_ID.ROOT) -- mi posiziono in un frame locale per fare i conti local nGrp = EgtGroup( EgtGetParent( nCrvId), Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB) EgtRelocateGlob( nCopyId, nGrp) local nInters = EgtCurveSelfIntersCount( nCopyId) local nCrvCnt if nInters > 0 then -- caso con sovrapposizione nCopyId, nCrvCnt = EgtSplitCurveAtSelfInters( nCopyId) for nIdx = 1, nCrvCnt - 2 do EgtAddCurveCompoCurve( nCopyId, nCopyId + nIdx) end if nCrvCnt > 1 then EgtErase( nCopyId + nCrvCnt - 1) end end EgtCloseCurveCompo( nCopyId) EgtChangeClosedCurveStartPoint( nCopyId, ptNewStart, GDB_RT.GLOB) EgtRelocateGlob( nCopyId, nCrvId, GDB_IN.AFTER) EgtErase( nGrp) end local nCoastingId if dCoastingLen > GEO.EPS_SMALL then nCoastingId = EgtCopyGlob( nCrvId, nCrvId, GDB_IN.AFTER) local dLenTrim = EgtCurveLength( nCoastingId) - dCoastingLen dLenTrim = max( dLenTrim, MIN_LEN) local dPar = EgtCurveParamAtLength( nCoastingId, dLenTrim) if not dPar then dPar = EgtCurveParamAtLength( nCoastingId, MIN_LEN) or 0 end EgtTrimCurveStartAtParam( nCoastingId, dPar) -- aggiorno la curva originale if dPar > GEO.EPS_SMALL then EgtTrimCurveEndAtParam( nCrvId, dPar) else EgtErase( nCrvId) end EgtModifyCurveExtrusion( nCoastingId, vtSlicing, GDB_RT.GLOB) EgtSetName( nCoastingId, COASTING_CRV) EgtSetInfo( nCoastingId, KEY_TYPE, TYPE.COASTING) EgtSetColor( nCoastingId, EgtStdColor('ORANGE')) end if dWipeLen > GEO.EPS_SMALL then local nWipeId if bClosed then -- se chiusa ( shell, SolidFill di tipo offset, ribs chiusi) nWipeId = nCopyId nCopyId = nil EgtTrimCurveEndAtLen( nWipeId, dWipeLen) EgtSetInfo( nWipeId, KEY_WIPE_ON_CRV, true) else -- se extra shell, infill, spiral vase o rib che non termina sulla parete local ptS = EgtEP( nCoastingId or nCrvId, GDB_ID.ROOT) local vtDir = EgtEV( nCoastingId or nCrvId, GDB_ID.ROOT) local dAng = dWipeDir + s_nDefaultWipeAng -- verifico se necessario cambiare il segno all'angolo local bChangeSign = false -- riempimento if nType == TYPE.INFILL or nType == TYPE.AUX_SOLID then local vtS = EgtGetInfo( nCrvId, KEY_ZIG_ZAG_DIR, 'v') if vtS then -- solidfill a zigzag if AreOppositeVectorApprox( vtS, vtDir) then bChangeSign = true end else -- riempimento generico ( linee, griglie, nido d'ape) local nGrpLoc = EgtGroup( EgtGetParent( nCopyId), Frame3d( ORIG(), vtSlicing)) local nAuxSurf = EgtGetInfo( nCrvId, KEY_ASSOCIATED_SURF, 'i') or GDB_ID.NULL -- verifico se direzione di default punta verso esterno del solido local vtDirTest = Vector3d( vtDir) vtDirTest:rotate( vtSlicing, s_nDefaultWipeAng) local nCrvTest = EgtCurveCompoFromPoints( nGrpLoc, { ptS + 10 * GEO.EPS_SMALL * vtDirTest, ptS + vtDirTest}, GDB_RT.GLOB) local nRes = EgtCurveWithRegionClassify( nCrvTest, nAuxSurf) if nRes ~= GDB_CRC.OUT then -- se non punta verso esterno provo con la direzione opposta EgtRotate( nCrvTest, ptS, vtSlicing, 180, GDB_RT.GLOB) nRes = EgtCurveWithRegionClassify( nCrvTest, nAuxSurf) if nRes == GDB_CRC.OUT then bChangeSign = true end end EgtErase( nGrpLoc) end -- rib elseif nType == TYPE.RIB then local bInvertStrandOrder = EgtGetInfo( nCrvId, KEY_RIBS_INVERT_STRAND_ORDER, 'b') or false local bInvertDir = EgtGetInfo( nCrvId, KEY_RIBS_INVERT_DIR, 'b') or false bChangeSign = ( bInvertDir ~= bInvertStrandOrder) -- extra shell elseif nType == TYPE.EXTRA_SHELL or nType == TYPE.EXTRA_OUTER_SHELL then bChangeSign = bInverted end vtDir:rotate( vtSlicing, EgtIf( bChangeSign, - dAng, dAng)) local ptE = ptS + vtDir * dWipeLen nWipeId = EgtCurveCompoFromPoints( EgtGetParent( nCoastingId or nCrvId), {ptS, ptE}, GDB_RT.GLOB) EgtModifyCurveExtrusion( nWipeId, vtSlicing, GDB_RT.GLOB) EgtRelocateGlob( nWipeId, nCoastingId or nCrvId, GDB_IN.AFTER) end if nWipeId then EgtSetName( nWipeId, WIPE_CRV) EgtSetInfo( nWipeId, KEY_TYPE, TYPE.WIPE) EgtSetInfo( nWipeId, KEY_CRV_STRAND, dStrand) EgtSetColor( nWipeId, EgtStdColor('AQUA')) end end if nCopyId then EgtErase( nCopyId) end return nCoastingId end -------------------------------------------------------------------- local function AddRetractionOnLastCrv( nCrvId, nTpathGrpId, LayerParams, dCoastingLen, dWipeLen, dWipeDir) if LayerParams.nLeadOutType == LEAD_TYPE.NONE then AddRetraction( nCrvId, dCoastingLen, dWipeLen, dWipeDir) else local nLeadOutId = EgtGetLastInGroup( nTpathGrpId) local dLen = EgtCurveLength( nLeadOutId) if dLen > dCoastingLen - 500 * GEO.EPS_SMALL then -- coinvolge solo la curva di lead out local dNewCoastingLen = EgtIf( abs( dCoastingLen - dLen) < 500 * GEO.EPS_SMALL, dLen, dCoastingLen) -- verifico se interamente coinvolta AddRetraction( nLeadOutId, dNewCoastingLen, dWipeLen, dWipeDir) else -- coinvolge parte dell'ultima shell crv local dNewCoastingLen = dCoastingLen - dLen local nCoastingId = AddRetraction( nCrvId, dNewCoastingLen, 0.0, dWipeDir) EgtAddCurveCompoCurve( nCoastingId, nLeadOutId) EgtSetInfo( nCoastingId, KEY_CLOSED_CRV, 0) -- wipe AddRetraction( nCoastingId, 0, dWipeLen, dWipeDir) end end end --------------------------------------------------------------------- local function CalcShellsToolPath( vEntIds, nTpathGrpId, bFirst, LayerParams) if not vEntIds or #vEntIds == 0 then return end -- aggiungo le curve nel toolpath local vIds = AddCurvesToToolPath( vEntIds, nTpathGrpId, LayerParams.nOrder, LayerParams.bInvert, LayerParams.vtSlicing, LayerParams.dLayHeight) local nFirstCopy = EgtCopyGlob( vIds[1], nTpathGrpId) -- necessaria per corretto offset lead point sulla shell esterna -- assegno lo strand for i = 1, #vIds do local nType = EgtGetInfo( vIds[i], KEY_TYPE, 'i') if nType == TYPE.OUTER_SHELL then EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dStrand) elseif nType == TYPE.INNER_SHELL then EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dInnerStrand) else -- infill EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dInfillStrand) end end -- aggiungo gli opportuni raccordi AddLink( vIds, nTpathGrpId, LayerParams.nLinkType, LayerParams.dLinkParam, LayerParams.dSPOffs, LayerParams.nOrder, LayerParams.vtSlicing) -- offset lead point AddOffsetLeadPoint( vIds, nFirstCopy, LayerParams.dOffsetLP, LayerParams.nLinkType) -- aggiungo leadin/leadout if LayerParams.nLeadInType ~= LEAD_TYPE.NONE then if bFirst or not LayerParams.bSingleLeadIn then AddLeadIn( vIds[1], LayerParams, nTpathGrpId) end end if LayerParams.nLeadOutType ~= LEAD_TYPE.NONE then EgtTrimCurveEndAtLen( vIds[#vIds], EgtCurveLength( vIds[#vIds]) - LayerParams.dOffsetLP) AddLeadOut( vIds[#vIds], LayerParams, nTpathGrpId) end -- aggiungo coasting/wipe for i = 1, #vIds - 1 do local nNextId = EgtGetNext( vIds[i]) if EgtGetInfo( nNextId, KEY_TYPE, 'i') ~= TYPE.LINK then AddRetraction( vIds[i], LayerParams.dCoastingLen, LayerParams.dWipeLen, LayerParams.dWipeDir) end end -- sull'ultima curva gestione speciale per eventuale lead out AddRetractionOnLastCrv( vIds[#vIds], nTpathGrpId, LayerParams, LayerParams.dCoastingLen, LayerParams.dWipeLen, LayerParams.dWipeDir) end --------------------------------------------------------------------- local function CalcExtraShellToolPath( vEntIds, nTpathGrpId, LayerParams) if not vEntIds or #vEntIds == 0 then return end -- aggiungo le curve nel toolpath local vIds = AddCurvesToToolPath( vEntIds, nTpathGrpId, PRINT_ORDER.EXT_INT, false, LayerParams.vtSlicing, LayerParams.dLayHeight) -- assegno strand for i = 1, #vIds do local nType = EgtGetInfo( vIds[i], KEY_TYPE, 'i') if nType == TYPE.EXTRA_OUTER_SHELL then EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dStrand) else EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dInnerStrand) end end -- aggiungo gli opportuni raccordi local sPrevName = EgtGetName( vIds[1]) for i = 2, #vIds do local sCurrName = EgtGetName( vIds[i]) -- se hanno lo stesso nome vanno collegate if sCurrName == sPrevName then local ptS = EgtEP( vIds[i-1]) local ptE = EgtSP( vIds[i]) local nLinkId = EgtCurveCompoFromPoints( nTpathGrpId, {ptS, ptE}) if nLinkId then EgtRelocateGlob( nLinkId, vIds[i], GDB_IN.BEFORE) EgtModifyCurveExtrusion( nLinkId, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLinkId, KEY_TYPE, TYPE.LINK) EgtSetName( nLinkId, LINK_CRV) local dStrand1 = EgtGetInfo( vIds[i], KEY_CRV_STRAND, 'd') local dStrand2 = EgtGetInfo( vIds[i-1], KEY_CRV_STRAND, 'd') EgtSetInfo( nLinkId, KEY_CRV_STRAND, max( dStrand1, dStrand2)) end else -- se nome diverso ma chiuse applico lo start point if EgtCurveIsClosed( vIds[i]) and EgtCurveIsClosed( vIds[i-1]) then AddStartPointOffsetOnLayer( vIds[i], vIds[i-1], LayerParams.dSPOffs, PRINT_ORDER.EXT_INT, LayerParams.vtSlicing, LayerParams.dLayHeight) end end sPrevName = sCurrName end -- aggiungo offset lead point sulle extra shell chiuse for i = 1, #vIds do if EgtCurveIsClosed( vIds[i]) then local nCopy = EgtCopyGlob( nTpathGrpId, vIds[i]) AddOffsetLeadPoint( {vIds[i]}, nCopy, LayerParams.dOffsetLP, LINK_TYPE.NONE) end end -- aggiungo coasting/wipe for i = 1, #vIds do -- verifico non sia collegato al successivo tramite link local nNextId = EgtGetNext( vIds[i]) if not nNextId or EgtGetInfo( nNextId, KEY_TYPE, 'i') ~= TYPE.LINK then -- recupero i parametri local dCoastingLen, dWipeLen, dWipeDir local bClosed = EgtGetInfo( vIds[i], KEY_CLOSED_CRV, 'b') or false if not bClosed then local bInverted = EgtGetInfo( vIds[i], KEY_INVERTED_CRV, 'b') or false local vCoastLen = EgtGetInfo( vIds[i], KEY_EXTRA_SHELL_COASTING, 'vd') local vWipeLen = EgtGetInfo( vIds[i], KEY_EXTRA_SHELL_WIPE, 'vd') local vWipeDir = EgtGetInfo( vIds[i], KEY_EXTRA_SHELL_WIPE_DIR, 'vd') -- se curva è stata invertita devo prendere le info legate a quello che era il suo punto di inizio, altrimenti prendo le info legate al punto finale dCoastingLen = EgtIf( bInverted, vCoastLen[1], vCoastLen[2]) dWipeLen = EgtIf( bInverted, vWipeLen[1], vWipeLen[2]) dWipeDir = EgtIf( bInverted, vWipeDir[1], vWipeDir[2]) else -- se chiusa considero i parametri delle shell complete dCoastingLen = LayerParams.dCoastingLen dWipeLen = LayerParams.dWipeLen dWipeDir = LayerParams.dWipeDir end AddRetraction( vIds[i], dCoastingLen, dWipeLen, dWipeDir) end end end --------------------------------------------------------------------- ----------------------- INFILL -------------------------------------- --------------------------------------------------------------------- local function ComputeShortestCrv( nCrvId, dParS, dParE) local nParentId = EgtGetParent( nCrvId) -- verifico i due percorsi possibili dParS->dParE e dParE->dParS local nCopyId1 = EgtCopyGlob( nCrvId, nParentId, GDB_IN.AFTER) local nCopyId2 = EgtCopyGlob( nCrvId, nParentId, GDB_IN.AFTER) EgtTrimCurveStartEndAtParam( nCopyId1, dParS, dParE) EgtTrimCurveStartEndAtParam( nCopyId2, dParE, dParS) EgtInvertCurve( nCopyId2) local dLen1 = EgtCurveLength( nCopyId1) local dLen2 = EgtCurveLength( nCopyId2) if dLen1 > dLen2 then EgtErase( nCopyId1) return nCopyId2 else EgtErase( nCopyId2) return nCopyId1 end end ----------------------------------------------------------------------- local function VerifyInfillLink( nLinkId, nCurr, nNext, vIds, dStrand, nGrpTmp) -- regione occupata dal link local dOffs = dStrand * 0.5 local nLinkSurf = EgtSurfFrFatCurve( nGrpTmp, nLinkId, dOffs, false) if not nLinkSurf then return true end -- verifico non intersechi altre curve di infill for i = 1, #vIds do if vIds[i] ~= nCurr and vIds[i] ~= nNext then -- con curva local nRes = EgtCurveCurveInters( vIds[i], nLinkId, nGrpTmp) if nRes then return false end -- con regione occupata local nClassif = EgtCurveWithRegionClassify( vIds[i], nLinkSurf) if nClassif == GDB_CRC.INTERS or nClassif == GDB_CRC.IN then return false end end end -- verifica con le curve coinvolte dal link if nLinkSurf then local nCurrCopy = EgtCopyGlob( nCurr, nGrpTmp) local _, nCnt = EgtTrimCurveWithRegion( nCurrCopy, nLinkSurf, true, false) if nCnt > 1 then return false end local nNextCopy = EgtCopyGlob( nNext, nGrpTmp) _, nCnt = EgtTrimCurveWithRegion( nNextCopy, nLinkSurf, true, false) if nCnt > 1 then return false end -- verifico se tratti lineari paralleli al setto sono sufficientemente lontani local dMinDist = dStrand * 0.5 local nLinkLoc = EgtCopyGlob( nLinkId, nGrpTmp) local _, dParELink = EgtCurveDomain( nLinkLoc) local nCurrLoc = EgtCopyGlob( nCurr, nGrpTmp) local _, dParE = EgtCurveDomain( nCurrLoc) for dPar = dParE, max( 1, dParE - 3), -1 do local vtDirCurr = EgtUV( nCurrLoc, dPar - 0.5, -1) for dParCrv = 1, dParELink do local vtS = EgtUV( nLinkLoc, dParCrv - 1, 1) local vtE = EgtUV( nLinkLoc, dParCrv, -1) -- se tratto lineare allineato come curva corrente if AreSameVectorApprox( vtS, vtE) and vtS * vtDirCurr < - 1 + GEO.EPS_SMALL then -- verifico distanza local nCrvTest = EgtCurveCompoFromPoints( nGrpTmp, { EgtUP( nCurrLoc, dPar-1), EgtUP( nCurrLoc, dPar)}) local dDist = EgtPointCurveDist( EgtUP( nLinkLoc, dParCrv - 0.5), nCrvTest) if dDist < dMinDist + GEO.EPS_SMALL then return false end end end end local nNextLoc = EgtCopyGlob( nNext, nGrpTmp) _, dParE = EgtCurveDomain( nNextLoc) for dPar = 0, min( dParE - 1, 3) do local vtDirCurr = EgtUV( nNextLoc, dPar + 0.5, -1) for dParCrv = 1, dParELink do local vtS = EgtUV( nLinkLoc, dParCrv - 1, 1) local vtE = EgtUV( nLinkLoc, dParCrv, -1) -- se tratto lineare allineato come curva corrente if AreSameVectorApprox( vtS, vtE) and vtS * vtDirCurr < - 1 + GEO.EPS_SMALL then -- verifico distanza local nCrvTest = EgtCurveCompoFromPoints( nGrpTmp, { EgtUP( nNextLoc, dPar), EgtUP( nNextLoc, dPar + 1)}) local dDist = EgtPointCurveDist( EgtUP( nLinkLoc, dParCrv - 0.5), nCrvTest) if dDist < dMinDist + GEO.EPS_SMALL then return false end end end end end return true end --------------------------------------------------------------------- local function CalcInfillLink( vIds, nInfillGrp, dStrand, LayerParams) if #vIds == 0 then return end -- estraggo i loop delle superfici usate per trim local nLoopGrp = EgtGroup( nInfillGrp) local tSurfs = {} for i = 1, #vIds do local nTrimSurf = EgtGetInfo( vIds[i], KEY_ASSOCIATED_SURF, 'i') -- controllo di non aver già estratto il suo loop if not tSurfs[nTrimSurf] then EgtMove( nTrimSurf, LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) local nChunks = EgtSurfFrChunkCount( nTrimSurf) for i = 0, nChunks - 1 do EgtExtractSurfFrChunkLoops( nTrimSurf, i, nLoopGrp) end tSurfs[nTrimSurf] = 1 end end local vCrvIds = EgtGetAllInGroup( nLoopGrp) -- creo gruppo temporaneo per conti local frLoc = Frame3d( ORIG(), LayerParams.vtSlicing) local nGrpTmp = EgtGroup( nInfillGrp, frLoc, GDB_RT.GLOB) -- creo vettore corrispondente a vIds per indicare quando la curva viene utilizzata nei link local vUsed = {} for i = 1, #vIds do vUsed[i] = false end -- scorro le curve per creare link local nCurr = vIds[1] vUsed[1] = true while nCurr do local bFound = false -- cerco tra le curve non utilizzate quale può essere usata per link for i = 1, #vIds do if bFound then break end if not vUsed[i] then local nNext = vIds[i] local ptS = EgtEP( nCurr) local ptE = EgtSP( nNext) if not AreSamePointApprox( ptS, ptE) then -- cerco di creare il link for k = 1, #vCrvIds do local dParS = EgtCurveParamAtPoint( vCrvIds[k], ptS, 10 * GEO.EPS_SMALL) local dParE = EgtCurveParamAtPoint( vCrvIds[k], ptE, 10 * GEO.EPS_SMALL) if dParS and dParE then local nLinkId = ComputeShortestCrv( vCrvIds[k], dParS, dParE) if nLinkId then local bValid = VerifyInfillLink( nLinkId, nCurr, nNext, vIds, dStrand, nGrpTmp) if not bValid then EgtErase( nLinkId) else bFound = true -- riposiziono le curve collegate EgtRelocateGlob( nLinkId, nCurr, GDB_IN.AFTER) EgtRelocateGlob( nNext, nLinkId, GDB_IN.AFTER) -- sistemo le info del link EgtSetInfo( nLinkId, KEY_TYPE, TYPE.INFILL) EgtSetName( nLinkId, LINK_CRV) EgtModifyCurveExtrusion( nLinkId, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLinkId, KEY_CRV_STRAND, dStrand) -- aggiorno per iterazione successiva nCurr = vIds[i] vUsed[i] = true break end end end end end end end -- se link non è stato realizzato cerco il primo tratto non utilizzato da cui ripartire if not bFound then for i = 1, #vIds do if not vUsed[i] then nCurr = vIds[i] vUsed[i] = true bFound = true break end end -- se tutti i tratti utilizzati ho finito if not bFound then nCurr = nil end end end EgtErase( nGrpTmp) end --------------------------------------------------------------------- local function CalcInfillToolPath( nInfillGrp, nTpathGrpId, LayerParams) local vEntIds = EgtGetNameInGroup( nInfillGrp, INFILL_CRV ..'*') if not vEntIds or #vEntIds == 0 then return end -- aggiungo le curve nel toolpath local vIds = AddCurvesToToolPath( vEntIds, nTpathGrpId, PRINT_ORDER.EXT_INT, false, LayerParams.vtSlicing, LayerParams.dLayHeight) -- assegno strand for i = 1, #vIds do EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dInfillStrand) end -- eventuale creazione dei link if LayerParams.bInfillLink then CalcInfillLink( vIds, nInfillGrp, LayerParams.dInfillStrand, LayerParams) end -- aggiungo coasting e wipe for i = 1, #vIds do local nNext = EgtGetNext( vIds[i]) if not nNext or EgtGetName( nNext) ~= LINK_CRV then AddRetraction( vIds[i], LayerParams.dInfillCoasting, LayerParams.dInfillWipe, LayerParams.dInfillWipeDir) end end end --------------------------------------------------------------------- ----------------------- SOLID FILL ---------------------------------- --------------------------------------------------------------------- local function CalcSolidFillToolPath( nInfillGrp, nTpathGrpId, LayerParams) local vEntIds = EgtGetNameInGroup( nInfillGrp, INFILL_CRV ..'*') if not vEntIds or #vEntIds == 0 then return end local nSolidFillType = EgtGetInfo( nInfillGrp, KEY_FILL_TYPE, 'i') or FILL_TYPE.ZIG_ZAG local nOrder = PRINT_ORDER.EXT_INT local bInvert = false if nSolidFillType == FILL_TYPE.OFFSET then -- copio i valori per le shell nOrder = LayerParams.nOrder bInvert = LayerParams.bInvert end -- aggiungo le curve nel toolpath local vIds = AddCurvesToToolPath( vEntIds, nTpathGrpId, nOrder, bInvert, LayerParams.vtSlicing, LayerParams.dLayHeight) -- assegno strand for i = 1, #vIds do EgtSetInfo( vIds[i], KEY_CRV_STRAND, LayerParams.dInfillStrand) end -- se riempimento ad offset sistemo come nel caso delle shell if nSolidFillType == FILL_TYPE.OFFSET then local nFirstCopy = EgtCopyGlob( vIds[1], nTpathGrpId) -- aggiungo gli opportuni raccordi AddLink( vIds, nTpathGrpId, LayerParams.nLinkType, LayerParams.dLinkParam, LayerParams.dSPOffs, LayerParams.nOrder, LayerParams.vtSlicing) -- offset lead point AddOffsetLeadPoint( vIds, nFirstCopy, LayerParams.dOffsetLP, LayerParams.nLinkType) end -- aggiungo coasting/wipe for i = 1, #vIds do local nNextId = EgtGetNext( vIds[i]) if not nNextId or EgtGetInfo( nNextId, KEY_TYPE, 'i') ~= TYPE.LINK then AddRetraction( vIds[i], LayerParams.dInfillCoasting, LayerParams.dInfillWipe, LayerParams.dInfillWipeDir) end end end -------------------------------------------------------------------------------------- local function JoinShellsAndSolidFills( nInfillGrp, vShellIds, vExtraShells, LayerParams, tabRibs) local nFillType = EgtGetInfo( nInfillGrp, KEY_FILL_TYPE, 'i') or FILL_TYPE.NONE if nFillType == FILL_TYPE.OFFSET and vShellIds and #vShellIds > 0 then -- cerco indice di realizzazione dei vari elementi di stampa local vTypeSequence = {} for i = 1, #LayerParams.vPrintOrder do vTypeSequence[LayerParams.vPrintOrder[i]] = i end local nMin = vTypeSequence[PRINT_ELEMENT.SHELL] local nMax = vTypeSequence[PRINT_ELEMENT.INFILL] local bShellFirst = true if nMin > nMax then nMin, nMax = nMax, nMin bShellFirst = false end -- verifico se extra shell realizzate tra shell e infill if vExtraShells and #vExtraShells > 0 and nMin < vTypeSequence[PRINT_ELEMENT.EXTRA_SHELL] and vTypeSequence[PRINT_ELEMENT.EXTRA_SHELL] < nMax then return end -- verifico se esistono setti esterni o unbounded realizzati tra le shell e gli infill if #tabRibs[RIB_TYPE.UNBOUNDED] > 0 and nMin < vTypeSequence[PRINT_ELEMENT.RIB_UNBOUNDED] and vTypeSequence[PRINT_ELEMENT.RIB_UNBOUNDED] < nMax then return elseif #tabRibs[RIB_TYPE.EXTERNAL] > 0 and nMin < vTypeSequence[PRINT_ELEMENT.RIB_EXTERNAL] and vTypeSequence[PRINT_ELEMENT.RIB_EXTERNAL] < nMax then return end -- verifico se ordinamento di shell e infill è coerente con PrintOrder if ( bShellFirst and LayerParams.nOrder == PRINT_ORDER.INT_EXT) or ( not bShellFirst and LayerParams.nOrder == PRINT_ORDER.EXT_INT) then return end -- aggiungo le curve di infill a quelle di shell local nPathGrp = EgtGetParent( vShellIds[1]) local vInfillCrvs = EgtGetNameInGroup( nInfillGrp, INFILL_CRV ..'*') or {} for k = 1, #vInfillCrvs do table.insert( vShellIds, vInfillCrvs[k]) -- le sposto nel PathGrp in modo da non gestirle una seconda volta quando vengono trattati gli infill EgtRelocateGlob( vInfillCrvs[k], nPathGrp) end end end ------------------------------------------------------------------- ----------------------- AUX SOLIDS ------------------------------- ------------------------------------------------------------------- local function CalcAuxSolidsToolPath( nAuxSolidsGrp, nAuxSolidsPathGrp, nTpathGrpId, LayerParams) if not nAuxSolidsGrp or not nAuxSolidsPathGrp then return end -- recupero le curve di slicing relative al primo solido ausiliario local nSolidId = EgtGetFirstNameInGroup( nAuxSolidsGrp, AUX_SOLIDS_CRV .. '*') while nSolidId do -- recupero tutti i percorsi relativi a quel solido local sName = EgtGetName( nSolidId) local vEntIds = EgtGetNameInGroup( nAuxSolidsPathGrp, sName .. '*') if vEntIds and #vEntIds > 0 then -- recupero i parametri relativi al solido dalla curva di slicing local nFillType = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_INFILL, 'i') local dStrand = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_STRAND, 'd') local nOrder = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_PRINT_ORDER, 'i') local dCoastingLen = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_COASTING_LEN, 'd') local dWipeLen = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_WIPE_LEN, 'd') local dWipeDir = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_WIPE_DIR, 'd') -- copio i percorsi nel gruppo toolpath local vIds = AddCurvesToToolPath( vEntIds, nTpathGrpId, nOrder, LayerParams.bInvert, LayerParams.vtSlicing, LayerParams.dLayHeight) -- assegno strand for i = 1, #vIds do EgtSetInfo( vIds[i], KEY_CRV_STRAND, dStrand) end -- distinguo le shell dal riempimento local vShells = {} local vInfill = {} for i = 1, #vIds do local nType = EgtGetInfo( vIds[i], KEY_TYPE, 'i') local bZigZag = EgtGetInfo( vIds[i], KEY_ZIG_ZAG_INFILL, 'b') or false if nType == TYPE.INFILL or bZigZag then table.insert( vInfill, vIds[i]) else table.insert( vShells, vIds[i]) end end -- aggiungo link e offset lead point sulle shell if #vShells > 0 then local nLinkType = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_LINK_TYPE, 'i') local dLinkParam = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_LINK_PARAM, 'd') local dSPOffset = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_SP_OFFSET, 'd') local dLPOffset = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_LP_OFFSET, 'd') local nFirstCopy = EgtCopyGlob( vShells[1], nTpathGrpId) -- necessaria per avere il corretto offset lead point sulla shell esterna nel caso di link AddLink( vShells, nTpathGrpId, nLinkType, dLinkParam, dSPOffset, nOrder, LayerParams.vtSlicing) AddOffsetLeadPoint( vShells, nFirstCopy, dLPOffset, nLinkType) end -- aggiungo eventuale link su infill if nFillType & FILL_CATEGORY.INFILL ~= 0 then local bInfillLink = EgtGetInfo( nSolidId, KEY_AUX_SOLIDS_INFILL_LINK, 'b') if bInfillLink then CalcInfillLink( vInfill, nAuxSolidsPathGrp, dStrand, LayerParams) end end -- coasting e wipe for i = 1, #vIds do local nNextId = EgtGetNext( vIds[i]) if not nNextId or EgtGetName( nNextId) ~= LINK_CRV then AddRetraction( vIds[i], dCoastingLen, dWipeLen, dWipeDir) end end end -- recupero il solido successivo local nLastSolidId = EgtGetLastNameInGroup( nAuxSolidsGrp, sName) nSolidId = EgtGetNextName( nLastSolidId, AUX_SOLIDS_CRV .. '*') end end -------------------------------------------------------------------- --------------------------- RIBS ----------------------------------- -------------------------------------------------------------------- local function AddFillet( nCrv1, nCrv2, dFillet, vtSlicing) if dFillet < GEO.EPS_SMALL then return end local nRefPosId = EgtGetPrev( nCrv1) local nRefGrpId = EgtGetParent( nCrv1) local vsInfo1 = EgtGetAllInfo( nCrv1) local vsInfo2 = EgtGetAllInfo( nCrv2) -- creo un gruppo con riferimento locale allo slicing per i conti del fillet local nGrpTmp = EgtGroup( EgtGetParent( nCrv1), Frame3d( ORIG(), vtSlicing), GDB_RT.GLOB) -- creo il fillet local dParRef1 = EgtCurveParamAtLength( nCrv1, EgtCurveLength( nCrv1) - 100 * GEO.EPS_SMALL) local dParRef2 = EgtCurveParamAtLength( nCrv2, 100 * GEO.EPS_SMALL) local nFillet = EgtCurveFillet( nGrpTmp, nCrv1, EgtUP( nCrv1, dParRef1, nGrpTmp), nCrv2, EgtUP( nCrv2, dParRef2, nGrpTmp), dFillet, true, GDB_RT.LOC) if not nFillet then -- ritento con valore di fillet leggermente inferiore nFillet = EgtCurveFillet( nGrpTmp, nCrv1, EgtUP( nCrv1, dParRef1, nGrpTmp), nCrv2, EgtUP( nCrv2, dParRef2, nGrpTmp), dFillet - 50 * GEO.EPS_SMALL, true, GDB_RT.LOC) end -- spezzo a metà il fillet per assegnarlo alle due curve if nFillet then local nNewFillet = EgtSplitCurve( nFillet, 2) -- aggiungo a nCrv1 if EgtExistsObj( nCrv1) then EgtAddCurveCompoArcTg( nCrv1, EgtEP( nNewFillet, GDB_ID.ROOT), true, GDB_RT.GLOB) EgtErase( nNewFillet) else -- nCrv1 viene sostituita completamente dal fillet local nNewCrv = EgtCurveCompo( nRefGrpId, {nNewFillet}) -- riposiziono dopo il precedente di nCrv1 ( se esiste) oppure in testa al gruppo if nRefPosId ~= GDB_ID.NULL then EgtRelocateGlob( nNewFillet, nRefPosId, GDB_IN.AFTER) else EgtRelocateGlob( nNewFillet, nRefGrpId, GDB_IN.FIRST_SON) end -- modifico l'id per conservare quello di nCrv1 EgtChangeId( nNewCrv, nCrv1) -- riassegno le info for i = 1, #vsInfo1 do local vsInfo = EgtSplitString( vsInfo1[i], '=') EgtSetInfo( nCrv1, vsInfo[1], vsInfo[2]) end end -- aggiungo a nCrv2 if EgtExistsObj( nCrv2) then EgtAddCurveCompoArcTg( nCrv2, EgtSP( nNewFillet + 1, GDB_ID.ROOT), false, GDB_RT.GLOB) EgtErase( nNewFillet + 1) else -- nCrv2 viene sostituita completamente dal fillet local nNewCrv = EgtCurveCompo( nRefGrpId, {nNewFillet + 1}) EgtRelocateGlob( nNewCrv, nCrv1, GDB_IN.AFTER) EgtChangeId( nNewCrv, nCrv2) for i = 1, #vsInfo2 do local vsInfo = EgtSplitString( vsInfo2[i], '=') EgtSetInfo( nCrv2, vsInfo[1], vsInfo[2]) end end else EgtOutLog( 'Warning : ribs fillet not possible (layer '..tostring( s_nCurrIdx)..') - CalcToolPath') end EgtErase( nGrpTmp) end -------------------------------------------------------------------- local function VerifyRibsLink( nLinkId, nCurr, nNext, nGrpTmp, dStrand) local dOverlap1 = EgtGetInfo( nCurr, KEY_RIBS_OVERLAP, 'd') local dOverlap2 = EgtGetInfo( nNext, KEY_RIBS_OVERLAP, 'd') local dOverlap = max( dOverlap1, dOverlap2) local dLen = EgtCurveLength( nLinkId) -- 1) verifico che non entri nella tavola local b3Box = EgtGetBBoxGlob( nLinkId, GDB_BB.STANDARD) if b3Box:getMin():getZ() < - GEO.EPS_SMALL then return false end -- 2) verifica con setti coinvolti dal link if nCurr ~= nNext then -- verifico non passi per estremo errato local dParTest1 = EgtCurveParamAtPoint( nLinkId, EgtSP( nCurr, GDB_ID.ROOT), 100 * GEO.EPS_SMALL, GDB_RT.GLOB) local dParTest2 = EgtCurveParamAtPoint( nLinkId, EgtEP( nNext, GDB_ID.ROOT), 100 * GEO.EPS_SMALL, GDB_RT.GLOB) if dParTest1 or dParTest2 then return false end -- verifico non intersechi i setti in altri punti oltre agli estremi local nCurrLoc = EgtCopyGlob( nCurr, nGrpTmp) local nNextLoc = EgtCopyGlob( nNext, nGrpTmp) local nLinkLoc = EgtCopyGlob( nLinkId, nGrpTmp) EgtTrimCurveEndAtLen( nLinkLoc, EgtCurveLength( nLinkLoc) - 100 * GEO.EPS_SMALL) EgtTrimCurveStartAtLen( nLinkLoc, 100 * GEO.EPS_SMALL) if EgtIP( nLinkLoc, nCurrLoc, ORIG()) or EgtIP( nLinkLoc, nNextLoc, ORIG()) then return false end -- se collegamento non ottimale verifico che abbia una parte esterna alla regione occupata dai setti abbsatanza lunga ( > 20% della lunghezza totale) if dist( EgtEP( nCurr, GDB_ID.ROOT), EgtSP( nNext, GDB_ID.ROOT)) > dist( EgtEP( nCurr, GDB_ID.ROOT), EgtEP( nNext, GDB_ID.ROOT)) + 1000 * GEO.EPS_SMALL then local nSrfRibs = EgtSurfFrFatCurve( nGrpTmp, nCurr, dStrand, false) or GDB_ID.NULL local nSrfRibs2 = EgtSurfFrFatCurve( nGrpTmp, nNext, dStrand, false) or GDB_ID.NULL EgtSurfFrAdd( nSrfRibs, nSrfRibs2) -- EgtSetStatus( nSrfRibs, GDB_ST.OFF) -- EgtSetStatus( nSrfRibs2, GDB_ST.OFF) local nLinkLoc = EgtCopyGlob( nLinkId, nGrpTmp) local nRes, nCnt = EgtTrimCurveWithRegion( nLinkLoc, nSrfRibs, false, false) if nCnt == 0 then return false end local dResLen = EgtCurveLength( nRes) if dResLen < 0.2 * dLen - GEO.EPS_SMALL then return false end end end -- 3) verifiche con altri setti ( considerando anche le tipologie del PathGrp non ancora realizzate) local nLinkLoc = EgtCopyGlob( nLinkId, nGrpTmp) local nOrigCurr = EgtGetInfo( nCurr, KEY_ORIGINAL_RIB, 'i') local nOrigNext = EgtGetInfo( nNext, KEY_ORIGINAL_RIB, 'i') local vRibsIds = EgtGetNameInGroup( EgtGetParent( nCurr), RIBS_CRV .. '*') local nCrvGrp = EgtGetParent( EgtGetParent( nCurr)) local nRibsPathGrp = EgtGetFirstNameInGroup( nCrvGrp, RIBS_GRP) local vRibsPaths = EgtGetNameInGroup( nRibsPathGrp, RIBS_CRV .. '*') for i = 1, #vRibsPaths do local nTPath = EgtGetInfo( vRibsPaths[i], KEY_ASSOCIATED_TP_CRV, 'i') if not nTPath then table.insert( vRibsIds, vRibsPaths[i]) end end for i = 1, #vRibsIds do if vRibsIds[i] ~= nCurr and vRibsIds[i] ~= nNext then -- verifico se sovrapposizione tra le passate local dCurrStrand = EgtGetInfo( vRibsIds[i], KEY_RIBS_STRAND, 'd') local nOrigId = EgtGetInfo( vRibsIds[i], KEY_ORIGINAL_RIB, 'i') local dOffs if nOrigId == nOrigCurr or nOrigId == nOrigNext then -- se passata relativa ad un setto coinvolto nel link verifico soltanto che il percorso del link non entri nella regione occupata dal setto local dStrandOverlap = EgtGetInfo( vRibsIds[i], KEY_RIBS_STRAND_OVERLAP, 'd') dOffs = dCurrStrand * ( 0.5 - dStrandOverlap / 100) else -- altrimenti verifico che le regioni del link e del setto non si sovrappongono ( a meno dell'overlap fissato) dOffs = dCurrStrand * 0.5 + ( 0.5 - dOverlap / 100) * dStrand - 50 * GEO.EPS_SMALL end if dOffs > GEO.EPS_SMALL then local nSrfCurr = EgtSurfFrFatCurve( nGrpTmp, vRibsIds[i], dOffs, false) if nSrfCurr then -- EgtSetStatus( nSrfCurr, GDB_ST.OFF) local nRes = EgtCurveWithRegionClassify( nLinkLoc, nSrfCurr) if nRes ~= GDB_CRC.OUT then return false end end end end end -- 4) verifico se si trova in almeno una regione ammissibile ( per caso ForcedLink) local nType = EgtGetInfo( nCurr, KEY_RIBS_TYPE, 'i') local nOut = 0 for i = 1, 2 do local nSurfId = EgtGetInfo( EgtIf( i == 1, nCurr, nNext), KEY_ASSOCIATED_SURF, 'i') if nSurfId and nSurfId ~= -1 then local nSrfLoc = EgtCopyGlob( nSurfId, nGrpTmp) -- EgtSetStatus( nSrfLoc, GDB_ST.OFF) local nRes = EgtCurveWithRegionClassify( nLinkId, nSrfLoc) if ( ( nType == RIB_TYPE.INTERNAL or nType == RIB_TYPE.SUPPORT) and ( nRes == GDB_CRC.OUT or nRes == GDB_CRC.INTERS)) or ( nType == RIB_TYPE.EXTERNAL and ( nRes == GDB_CRC.IN or nRes == GDB_CRC.INTERS)) then nOut = nOut + 1 end end end local nType1 = EgtGetInfo( nCurr, KEY_RIBS_TYPE, 'i') local nType2 = EgtGetInfo( nNext, KEY_RIBS_TYPE, 'i') if nType1 == RIB_TYPE.UNBOUNDED or nType2 == RIB_TYPE.UNBOUNDED then -- deve essere nella regione ammissibile dell'altro setto if nOut == 1 then return false end else -- deve essere nella regione ammissibile di uno dei due if nOut == 2 then return false end end return true end -------------------------------------------------------------------- local function ComputeRibsLinkOnSameCrv( nCrvId, dParS, dParE, nCurr, nNext, nGrpTmp, dStrand) local nParentId = EgtGetParent( nCrvId) local nShortest = EgtCopyGlob( nCrvId, nParentId, GDB_IN.AFTER) local nLongest = EgtCopyGlob( nCrvId, nParentId, GDB_IN.AFTER) EgtTrimCurveStartEndAtParam( nShortest, dParS, dParE) EgtTrimCurveStartEndAtParam( nLongest, dParE, dParS) EgtInvertCurve( nLongest) if EgtCurveLength( nShortest) > EgtCurveLength( nLongest) + GEO.EPS_SMALL then nShortest, nLongest = nLongest, nShortest end -- verifico il percorso più corto if VerifyRibsLink( nShortest, nCurr, nNext, nGrpTmp, dStrand) then EgtErase( nLongest) return nShortest else -- se non valido tento con il percorso più lungo EgtErase( nShortest) if VerifyRibsLink( nLongest, nCurr, nNext, nGrpTmp, dStrand) then return nLongest else EgtErase( nLongest) return end end end -------------------------------------------------------------------- local function ComputeRibsLinkOnDiffCrvs( nCrvS, nCrvE, dParS, dParE, nCurr, nNext, nGrpTmp, dStrand) local nParentId = EgtGetParent( nCrvS) local _, _, dParFinal = EgtPointCurveDist( EgtUP( nCrvE, dParE, GDB_ID.ROOT), nCrvS, GDB_ID.ROOT) local _, _, dParStart = EgtPointCurveDist( EgtUP( nCrvS, dParS, GDB_ID.ROOT), nCrvE, GDB_ID.ROOT) -- tento con il tratto dParS->dParE -- recupero il tratto interessato sulla curva1 local nCrv1 = EgtCopyGlob( nCrvS, nParentId, GDB_IN.AFTER) EgtTrimCurveStartEndAtParam( nCrv1, dParS, dParFinal) -- recupero il tratto interessato sulla curva2 local nCrv2 = EgtCopyGlob( nCrvE, nParentId, GDB_IN.AFTER) EgtTrimCurveStartEndAtParam( nCrv2, dParStart, dParE) -- modifico nCrv2 per avere una transizione uniforme da nCrv1 EgtSpiralizeCurveAlongGuide( nCrv2, nCrv1) EgtErase( nCrv1) -- verifico se valida if VerifyRibsLink( nCrv2, nCurr, nNext, nGrpTmp, dStrand) then return nCrv2 else -- tento con il tratto dParE->dParS EgtErase( nCrv2) nCrv1 = EgtCopyGlob( nCrvS, nParentId, GDB_IN.AFTER) -- tratto interessato sulla curva1 EgtTrimCurveStartEndAtParam( nCrv1, dParFinal, dParS) EgtInvertCurve( nCrv1) nCrv2 = EgtCopyGlob( nCrvE, nParentId, GDB_IN.AFTER) -- tratto interessato sulla curva2 EgtTrimCurveStartEndAtParam( nCrv2, dParE, dParStart) EgtInvertCurve( nCrv2) EgtSpiralizeCurveAlongGuide( nCrv2, nCrv1) -- transizione uniforme da nCrv1 EgtErase( nCrv1) if VerifyRibsLink( nCrv2, nCurr, nNext, nGrpTmp, dStrand) then return nCrv2 else EgtErase( nCrv2) return end end end -------------------------------------------------------------------- local function CalcRibsLink( nCurr, nNext, nLoopGrp, bForceLink, vtSlicing, nGrpTmp) local ptS = EgtEP( nCurr) local ptE = EgtSP( nNext) if AreSamePointApprox( ptS, ptE) then return end local dStrand1 = EgtGetInfo( nCurr, KEY_CRV_STRAND, 'd') local dStrand2 = EgtGetInfo( nNext, KEY_CRV_STRAND, 'd') local dStrand = max( dStrand1, dStrand2) local dFillet1 = EgtGetInfo( nCurr, KEY_RIBS_LINK_FILLET, 'd') local dFillet2 = EgtGetInfo( nNext, KEY_RIBS_LINK_FILLET, 'd') if bForceLink then local dStrandOverlap1 = EgtGetInfo( nCurr, KEY_RIBS_STRAND_OVERLAP, 'd') local dStrandOverlap2 = EgtGetInfo( nNext, KEY_RIBS_STRAND_OVERLAP, 'd') dFillet1 = min( dFillet1, ( 1 - dStrandOverlap1 / 100) * dStrand1 * 0.5) dFillet2 = min( dFillet2, ( 1 - dStrandOverlap2 / 100) * dStrand2 * 0.5) end local vCrvIds = EgtGetAllInGroup( nLoopGrp) -- recupero le curve di bordo su cui poggiano i setti e i corrispondenti parametri local vIdsS, vIdsE = {}, {} local vParS, vParE = {}, {} for i = 1, #vCrvIds do local dParS = EgtCurveParamAtPoint( vCrvIds[i], ptS, 10 * GEO.EPS_SMALL) if dParS then table.insert( vIdsS, i) table.insert( vParS, dParS) end local dParE = EgtCurveParamAtPoint( vCrvIds[i], ptE, 10 * GEO.EPS_SMALL) if dParE then table.insert( vIdsE, i) table.insert( vParE, dParE) end end -- verifico se possibile creare link basandosi sulle curve di bordo for i = 1, #vIdsS do for j = 1, #vIdsE do local nLinkId if vIdsS[i] == vIdsE[j] then -- link su una sola curva nLinkId = ComputeRibsLinkOnSameCrv( vCrvIds[vIdsS[i]], vParS[i], vParE[j], nCurr, nNext, nGrpTmp, dStrand) else -- link tra due curve distinte nLinkId = ComputeRibsLinkOnDiffCrvs( vCrvIds[vIdsS[i]], vCrvIds[vIdsE[j]], vParS[i], vParE[j], nCurr, nNext, nGrpTmp, dStrand) end if nLinkId then -- fillet AddFillet( nCurr, nLinkId, dFillet1, vtSlicing) AddFillet( nLinkId, nNext, dFillet2, vtSlicing) -- assegno le info EgtRelocateGlob( nLinkId, nCurr, GDB_IN.AFTER) EgtSetInfo( nLinkId, KEY_TYPE, TYPE.RIB) EgtSetName( nLinkId, LINK_CRV) EgtModifyCurveExtrusion( nLinkId, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLinkId, KEY_CRV_STRAND, dStrand) return nLinkId end end end -- se non ho trovato un collegamento lungo bordi ma link deve esserci creo una linea tra ptS e ptE if bForceLink then local nLinkId = EgtCurveCompoFromPoints( EgtGetParent( nCurr), {ptS, ptE}) -- assegno le info EgtSetInfo( nLinkId, KEY_TYPE, TYPE.RIB) EgtSetName( nLinkId, LINK_CRV) EgtModifyCurveExtrusion( nLinkId, vtSlicing, GDB_RT.GLOB) EgtRelocateGlob( nLinkId, nCurr, GDB_IN.AFTER) EgtSetInfo( nLinkId, KEY_CRV_STRAND, dStrand) local bValid = VerifyRibsLink( nLinkId, nCurr, nNext, nGrpTmp, dStrand) if bValid then -- fillet AddFillet( nCurr, nLinkId, dFillet1, vtSlicing) AddFillet( nLinkId, nNext, dFillet2, vtSlicing) return nLinkId else EgtErase( nLinkId) return end end return end -------------------------------------------------------------------- local function CalcLoopRibLink( nCurr, nNext, nLoopGrp, vtSlicing, nGrpTmp, bForceLink) local ptS = EgtEP( nCurr) local ptE = EgtSP( nNext) if AreSamePointApprox( ptS, ptE) then return end local dStrand = EgtGetInfo( nCurr, KEY_CRV_STRAND, 'd') local dFillet = EgtGetInfo( nCurr, KEY_RIBS_LINK_FILLET, 'd') local vCrvIds = EgtGetAllInGroup( nLoopGrp) -- scorro le curve di bordo e verifico se posso creare il link for i = 1, #vCrvIds do local dParS = EgtCurveParamAtPoint( vCrvIds[i], ptS, 10 * GEO.EPS_SMALL) local dParE = EgtCurveParamAtPoint( vCrvIds[i], ptE, 10 * GEO.EPS_SMALL) if dParS and dParE then local nLinkId = ComputeShortestCrv( vCrvIds[i], dParS, dParE) if nLinkId then EgtRelocateGlob( nLinkId, nCurr, GDB_IN.AFTER) EgtSetInfo( nLinkId, KEY_TYPE, TYPE.RIB) EgtSetName( nLinkId, LINK_CRV) EgtModifyCurveExtrusion( nLinkId, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLinkId, KEY_CRV_STRAND, dStrand) if VerifyRibsLink( nLinkId, nCurr, nNext, nGrpTmp, dStrand) then -- fillet if bForceLink then dFillet = min( dFillet, dStrand * 0.5) end AddFillet( nCurr, nLinkId, dFillet, vtSlicing) AddFillet( nLinkId, nNext, dFillet, vtSlicing) return nLinkId else EgtErase( nLinkId) end end end end return end -------------------------------------------------------------------- local function VerifyRibsLead( nId, nRibId, bInVsOut, nGrpTmp) local dStrand = EgtGetInfo( nRibId, KEY_CRV_STRAND, 'd') local dShellOverlap = EgtGetInfo( nRibId, KEY_RIBS_OVERLAP, 'd') local dStrandOverlap = EgtGetInfo( nRibId, KEY_RIBS_STRAND_OVERLAP, 'd') local dOverlap = max( dShellOverlap, dStrandOverlap) local nOrigRib = EgtGetInfo( nRibId, KEY_ORIGINAL_RIB, 'i') local dLen = EgtCurveLength( nId) local nParentId = EgtGetParent( nId) -- porto il lead nel gruppo locale EgtRelocateGlob( nId, nGrpTmp) -- 1) verifico se interseca altri setti, lead in, lead out o collegamenti -- recupero gli id degli elementi da controllare local vCheckIds = {} local nCurrId = EgtGetFirstInGroup( EgtGetParent( nRibId)) while nCurrId do if nCurrId ~= nRibId and nCurrId ~= nId then -- considero solo i setti e gli elementi a loro associati ( tranne i wipe perchè non corrispondono a materiale depositato) local nType = EgtGetInfo( nCurrId, KEY_TYPE, 'i') if nType == TYPE.RIB or ( nType == TYPE.COASTING and EgtGetInfo( EgtGetPrev( nCurrId), KEY_TYPE, 'i') == TYPE.RIB) then -- controllo che non sia un elemento relativo ad un'altra passata del setto corrente if EgtGetName( nCurrId) == LEAD_IN_CRV then -- il setto di riferimento è l'elemento successivo local nCurrOrigRib = EgtGetInfo( EgtGetNext( nCurrId), KEY_ORIGINAL_RIB, 'i') or -1 if nOrigRib ~= nCurrOrigRib then table.insert( vCheckIds, nCurrId) end elseif EgtGetName( nCurrId) == LINK_CRV then -- il link va controllato se non congiunge due passate del setto corrente local nOrigRib1 = EgtGetInfo( EgtGetPrev( nCurrId), KEY_ORIGINAL_RIB, 'i') or -1 local nOrigRib2 = EgtGetInfo( EgtGetNext( nCurrId), KEY_ORIGINAL_RIB, 'i') or -1 if nOrigRib ~= nOrigRib1 or nOrigRib ~= nOrigRib2 then table.insert( vCheckIds, nCurrId) end else local nRibType = EgtGetInfo( nCurrId, KEY_RIBS_TYPE, 'i') if nRibType ~= RIB_TYPE.UNBOUNDED then local nCurrOrigRib = EgtGetInfo( nCurrId, KEY_ORIGINAL_RIB, 'i') if nOrigRib ~= nCurrOrigRib then table.insert( vCheckIds, nCurrId) end end end end end nCurrId = EgtGetNext( nCurrId) end -- tra gli id da controllare devo aggiungere anche altri setti non ancora presenti nel toolpath ( tipologie di setti realizzate in seguito) local nCrvGrp = EgtGetParent( EgtGetParent( nRibId)) local nRibsPathGrp = EgtGetFirstNameInGroup( nCrvGrp, RIBS_GRP) local vRibsPaths = EgtGetNameInGroup( nRibsPathGrp, RIBS_CRV .. '*') for i = 1, #vRibsPaths do local nTPath = EgtGetInfo( vRibsPaths[i], KEY_ASSOCIATED_TP_CRV, 'i') if not nTPath then table.insert( vCheckIds, vRibsPaths[i]) end end -- creo la superficie occupata dagli id da controllare local nSrf for i = 1, #vCheckIds do local dCurrStrand = EgtGetInfo( vCheckIds[i], KEY_CRV_STRAND, 'd') or EgtGetInfo( vCheckIds[i], KEY_RIBS_STRAND, 'd') local dCurrOffs = dCurrStrand * 0.5 + ( 0.5 - dOverlap / 100) * dStrand - 50 * GEO.EPS_SMALL if dCurrOffs > GEO.EPS_SMALL then local nSrfCurr = EgtSurfFrFatCurve( nGrpTmp, vCheckIds[i], dCurrOffs, false) if not nSrf then nSrf = nSrfCurr else EgtSurfFrAdd( nSrf, nSrfCurr) end end end -- verifico di avere un tratto esterno consecutivo al setto if nSrf then local nOrigLead = EgtCopyGlob( nId, nGrpTmp) local nRes, nCnt = EgtTrimCurveWithRegion( nId, nSrf, false, false) if not nRes or nCnt == 0 then return false end -- la curva di interesse è la prima se lead out o l'ultima se lead in local nNewCrv = EgtIf( bInVsOut, nRes + nCnt - 1, nRes) local ptRes = EgtIf( bInVsOut, EgtEP( nNewCrv, GDB_ID.ROOT), EgtSP( nNewCrv, GDB_ID.ROOT)) local ptRib = EgtIf( bInVsOut, EgtSP( nRibId, GDB_ID.ROOT), EgtEP( nRibId, GDB_ID.ROOT)) if not AreSamePointApprox( ptRes, ptRib) then return false end EgtChangeId( nNewCrv, nId) end -- 2) verifiche con il setto corrente -- verifico non passi da altro estremo local dParTest = EgtCurveParamAtPoint( nId, EgtIf( bInVsOut, EgtEP( nRibId, GDB_ID.ROOT), EgtSP( nRibId, GDB_ID.ROOT)), 100 * GEO.EPS_SMALL, GDB_RT.GLOB) if dParTest then return false end -- verifico se interrompere in corrispondenza di tratti lineari paralleli al setto che non sono sufficientemente lontani local _, dParE = EgtCurveDomain( nId) local nRibLoc = EgtCopyGlob( nRibId, nGrpTmp) local vtDir = EgtMV( nRibLoc) local dParRef = -1 local dParCrv = 1 for dParCrv = 0, dParE - 1 do local vtS = EgtUV( nId, dParCrv, 1) local vtE = EgtUV( nId, dParCrv + 1, -1) local dLenCrv = EgtCurveCompoLength( nId, dParCrv) if AreSameVectorApprox( vtS, vtE) and vtS * vtDir < - 1 + GEO.EPS_SMALL and dLenCrv > dStrand + GEO.EPS_SMALL then local vtDist = EgtUP( nId, dParCrv + 0.5) - EgtMP( nRibLoc) local vtOrthoDist = vtDist - ( vtDist * vtDir) * vtDir local dDist = vtOrthoDist:len() if dDist < dStrand + GEO.EPS_SMALL then dParRef = dParCrv if not bInVsOut then break end end end end if dParRef > - GEO.EPS_SMALL then if bInVsOut then local _, dE = EgtCurveDomain( nId) if abs( dParRef + 1 - dE) < GEO.EPS_SMALL then -- la curva si cancella completamente return false end EgtTrimCurveStartAtParam( nId, dParRef + 1) else if dParRef < GEO.EPS_SMALL then -- la curva si cancella completamente return false end EgtTrimCurveEndAtParam( nId, dParRef) end end -- 3) verifiche con eventuale lead in if not bInVsOut then local nCurrLI = EgtGetPrev( nRibId) if nCurrLI and EgtGetName( nCurrLI) == LEAD_IN_CRV then local nLeadInLoc = EgtCopyGlob( nCurrLI, nGrpTmp) -- verifico se intersezione fra curve local _, nPnt, nCrv = EgtCurveCurveInters( nId, nLeadInLoc, nGrpTmp) if nPnt ~= 0 or nCrv ~= 0 then return false end local dLeadInLen = EgtCurveLength( nLeadInLoc) if dLeadInLen > dStrand + GEO.EPS_SMALL then local nSrfLeadIn = EgtSurfFrFatCurve( nGrpTmp, nId, dStrand * ( 1 - dOverlap / 100), false) if nSrfLeadIn then -- EgtSetStatus( nSrfLeadIn, GDB_ST.OFF) -- verifico di avere un solo tratto esterno di lunghezza sufficiente local nRes, nCnt = EgtTrimCurveWithRegion( nLeadInLoc, nSrfLeadIn, false, false) if nCnt ~= 1 then return false else local dLen = EgtCurveLength( nRes) if dLen < dStrand / 2 + GEO.EPS_SMALL then return false end end end end end end local dNewLen = EgtCurveLength( nId) if dNewLen < 100 * GEO.EPS_SMALL then return false end if abs( dLen - dNewLen) > GEO.EPS_SMALL then EgtOutLog( 'Warning : ' .. EgtGetName( nRibId) .. ' Lead' .. EgtIf( bInVsOut, 'In', 'Out') .. ' is shortened. Len = ' .. EgtNumToString( dNewLen) .. ', SetLen = ' .. EgtNumToString( dLen) .. ' ( layer '.. tostring( s_nCurrIdx)..') - CalcToolPath' ) end EgtRelocateGlob( nId, nParentId) return true end --------------------------------------------------------------------------------- local function PrepareRibLead( nCrvOffs, nRib, bInvert, bInVsOut, dPar, dLeadLen) local nLeadId = EgtCopyGlob( nCrvOffs, nRib, GDB_IN.AFTER) EgtChangeClosedCurveStart( nLeadId, dPar) -- oriento in modo che la curva parta da nRib if bInvert then EgtInvertCurve( nLeadId) end EgtTrimCurveEndAtLen( nLeadId, dLeadLen) if bInVsOut then -- se lead in la curva deve terminare in nRib EgtInvertCurve( nLeadId) end return nLeadId end --------------------------------------------------------------------------------- local function FindCorrectRibLead( dPar, nRib, nCrvOffs, bLeadInvert, dLeadLen, bInVsOut, nGrpTmp, bSpecialCase) if dLeadLen < GEO.EPS_SMALL then return end local nLeadId local bInvert = bLeadInvert -- valore di default è quello dei parametri local bOnlyOneSide = false local dParE -- verifico se ho un solo lato possibile per la presenza di altre passate local nOtherRib if bSpecialCase then local sName = EgtGetName( nRib) local nFirst = EgtGetFirstNameInGroup( EgtGetParent( nRib), sName) local nLast = EgtGetLastNameInGroup( EgtGetParent( nRib), sName) if bInVsOut and nRib == nFirst then nOtherRib = nLast elseif not bInVsOut and nRib == nLast then nOtherRib = nFirst end else local nLinkId = EgtIf( bInVsOut, EgtGetNext( nRib), EgtGetPrev( nRib)) if nLinkId and EgtGetName( nLinkId) == LINK_CRV then nOtherRib = EgtIf( bInVsOut, EgtGetNext( nLinkId), EgtGetPrev( nLinkId)) local nOrigRib1 = EgtGetInfo( nRib, KEY_ORIGINAL_RIB, 'i') local nOrigRib2 = EgtGetInfo( nOtherRib, KEY_ORIGINAL_RIB, 'i') local nSplitId1 = EgtGetInfo( nRib, KEY_SPLIT_ID, 'i') or 0 local nSplitId2 = EgtGetInfo( nOtherRib, KEY_SPLIT_ID, 'i') or 0 if nOrigRib1 ~= nOrigRib2 or ( nOrigRib1 == nOrigRib2 and nSplitId1 ~= nSplitId2) then nOtherRib = nil end end end if nOtherRib then local ptOther = EgtIf( bInVsOut, EgtEP( nOtherRib, GDB_ID.ROOT), EgtSP( nOtherRib, GDB_ID.ROOT)) dParE = EgtCurveParamAtPoint( nCrvOffs, ptOther, 100 * GEO.EPS_SMALL, GDB_RT.GLOB) if dParE then bOnlyOneSide = true end end -- se un solo lato possibile if bOnlyOneSide then -- verifico a quale valore di bInvert corrisponde l'unico lato possibile local nCopyId1 = EgtCopyGlob( nCrvOffs, nGrpTmp) local nCopyId2 = EgtCopyGlob( nCrvOffs, nGrpTmp) EgtTrimCurveStartEndAtParam( nCopyId1, dPar, dParE) EgtTrimCurveStartEndAtParam( nCopyId2, dParE, dPar) local dLen1 = EgtCurveLength( nCopyId1) local dLen2 = EgtCurveLength( nCopyId2) bInvert = dLen1 < dLen2 nLeadId = PrepareRibLead( nCrvOffs, nRib, bInvert, bInVsOut, dPar, dLeadLen) -- verifico se lead sensato if not VerifyRibsLead( nLeadId, nRib, bInVsOut, nGrpTmp) then EgtErase( nLeadId) return end -- se due lati possibili else -- primo tentativo nella direzione individuata dal parametro bInvert nLeadId = PrepareRibLead( nCrvOffs, nRib, bInvert, bInVsOut, dPar, dLeadLen) if not VerifyRibsLead( nLeadId, nRib, bInVsOut, nGrpTmp) then -- secondo tentativo nell'altra direzione EgtErase( nLeadId) bInvert = not bInvert nLeadId = PrepareRibLead( nCrvOffs, nRib, bInvert, bInVsOut, dPar, dLeadLen) if not VerifyRibsLead( nLeadId, nRib, bInVsOut, nGrpTmp) then EgtErase( nLeadId) return end end end EgtRelocateGlob( nLeadId, nRib, EgtIf( bInVsOut, GDB_IN.BEFORE, GDB_IN.AFTER)) return nLeadId, bInvert end -------------------------------------------------------------------- local function AddRibsLeadIn( nCrv, nLoopsGrp, vtSlicing, nGrpTmp, bForceNoSolidBorder, bSpecialCase) local dLILen = EgtGetInfo( nCrv, KEY_RIBS_LEAD_IN_LEN, 'd') local bLIInvert = EgtGetInfo( nCrv, KEY_RIBS_LEAD_IN_INVERT, 'b') local dStrand = EgtGetInfo( nCrv, KEY_CRV_STRAND, 'd') local dFillet = EgtGetInfo( nCrv, KEY_RIBS_LEAD_FILLET, 'd') if dLILen < GEO.EPS_SMALL then return end -- recupero la curva di offset su cui calcolare leadin local ptS = EgtSP( nCrv) local vCrvOffs = {} if bForceNoSolidBorder then vCrvOffs = EgtGetNameInGroup( nLoopsGrp, SURF_LOOP .. '*') or {} else vCrvOffs = EgtGetAllInGroup( nLoopsGrp) or {} end for i = 1, #vCrvOffs do local dParS = EgtCurveParamAtPoint( vCrvOffs[i], ptS, 100 * GEO.EPS_SMALL) if dParS then local nLeadIn = FindCorrectRibLead( dParS, nCrv, vCrvOffs[i], bLIInvert, dLILen, true, nGrpTmp, bSpecialCase) -- se lead in possibile if nLeadIn then AddFillet( nLeadIn, nCrv, dFillet, vtSlicing) EgtModifyCurveExtrusion( nLeadIn, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nLeadIn, KEY_TYPE, TYPE.RIB) EgtSetName( nLeadIn, LEAD_IN_CRV) EgtSetInfo( nLeadIn, KEY_CRV_STRAND, dStrand) return end end end end -------------------------------------------------------------------- local function AddRibsLeadOut( nCrv, nLoopsGrp, vtSlicing, nGrpTmp, bForceNoSolidBorder, bSpecialCase) local dRibsLOLen = EgtGetInfo( nCrv, KEY_RIBS_LEAD_OUT_LEN, 'd') local dRibsLOCoasting = EgtGetInfo( nCrv, KEY_RIBS_LEAD_OUT_COASTING, 'd') local dRibsLOWipe = EgtGetInfo( nCrv, KEY_RIBS_LEAD_OUT_WIPE, 'd') local dRibsLOWipeAng = EgtGetInfo( nCrv, KEY_RIBS_LEAD_OUT_WIPE_DIR, 'd') local bRibsLOInvert = EgtGetInfo( nCrv, KEY_RIBS_LEAD_OUT_INVERT, 'b') local dStrand = EgtGetInfo( nCrv, KEY_CRV_STRAND, 'd') local dFillet = EgtGetInfo( nCrv, KEY_RIBS_LEAD_FILLET, 'd') if abs( dRibsLOLen) < GEO.EPS_SMALL and abs( dRibsLOCoasting) < GEO.EPS_SMALL and abs( dRibsLOWipe) < GEO.EPS_SMALL then return end -- se setto chiuso applico la stessa uscita delle shell if EgtCurveIsClosed( nCrv) then return AddRetraction( nCrv, dRibsLOCoasting, dRibsLOWipe, dRibsLOWipeAng) end local ptE = EgtEP( nCrv, GDB_ID.ROOT) local vtE = EgtEV( nCrv, GDB_ID.ROOT) -- recupero la curva di offset su cui calcolare lead out local vCrvOffs = {} if bForceNoSolidBorder then vCrvOffs = EgtGetNameInGroup( nLoopsGrp, SURF_LOOP .. '*') or {} else vCrvOffs = EgtGetAllInGroup( nLoopsGrp) or {} end for i = 1, #vCrvOffs do local dParE = EgtCurveParamAtPoint( vCrvOffs[i], ptE, GEO.EPS_SMALL, GDB_RT.GLOB) if dParE then local nCrvLO local nCoasting local nWipe -- trovo curva opportuna per lead out local nCrvRef, bInvert = FindCorrectRibLead( dParE, nCrv, vCrvOffs[i], bRibsLOInvert, dRibsLOLen + dRibsLOCoasting, false, nGrpTmp, bSpecialCase) if nCrvRef then -- aggiungo il fillet ( potrebbe coinvolgere sia lead out sia coasting) AddFillet( nCrv, nCrvRef, dFillet, vtSlicing) -- calcolo la nuova lunghezza per il lead out per conservare la lunghezza del coasting dopo il fillet dRibsLOLen = EgtCurveLength( nCrvRef) - dRibsLOCoasting -- primo tratto ( segue offset con flusso aperto) if dRibsLOLen > GEO.EPS_SMALL then nCrvLO = EgtCopyGlob( nCrvRef, nCrv, GDB_IN.AFTER) EgtTrimCurveEndAtLen( nCrvLO, dRibsLOLen) EgtModifyCurveExtrusion( nCrvLO, vtSlicing, GDB_RT.GLOB) EgtSetInfo( nCrvLO, KEY_TYPE, TYPE.RIB) EgtSetName( nCrvLO, LEAD_OUT_CRV) EgtSetInfo( nCrvLO, KEY_CRV_STRAND, dStrand) -- aggiorno ptE e vtE ptE = EgtEP( nCrvLO, GDB_ID.ROOT) vtE = EgtEV( nCrvLO, GDB_ID.ROOT) end -- secondo tratto ( segue offset con flusso chiuso) if dRibsLOCoasting > GEO.EPS_SMALL then nCoasting = EgtCopyGlob( nCrvRef, nCrvLO or nCrv, GDB_IN.AFTER) EgtTrimCurveStartAtLen( nCoasting, dRibsLOLen) EgtTrimCurveEndAtLen( nCoasting, dRibsLOCoasting) EgtModifyCurveExtrusion( nCoasting, vtSlicing, GDB_RT.GLOB) EgtSetName( nCoasting, COASTING_CRV) EgtSetInfo( nCoasting, KEY_TYPE, TYPE.COASTING) EgtSetColor( nCoasting, EgtStdColor('ORANGE')) EgtSetInfo( nCoasting, KEY_CRV_STRAND, dStrand) -- aggiorno ptE e vtE ptE = EgtEP( nCoasting, GDB_ID.ROOT) vtE = EgtEV( nCoasting, GDB_ID.ROOT) end EgtErase( nCrvRef) -- terzo tratto ( diretto verso esterno con ugello chiuso) if dRibsLOWipe > GEO.EPS_SMALL then local dAng = dRibsLOWipeAng + s_nDefaultWipeAng local nType = EgtGetInfo( nCrv, KEY_RIBS_TYPE, 'i') if nType == RIB_TYPE.EXTERNAL then dAng = - dAng end vtE:rotate( vtSlicing, EgtIf( bInvert, - dAng, dAng)) local ptFinal = ptE + vtE * dRibsLOWipe nWipe = EgtCurveCompoFromPoints( EgtGetParent( nCrv), { ptE, ptFinal}, GDB_RT.GLOB) if nWipe then EgtModifyCurveExtrusion( nWipe, vtSlicing, GDB_RT.GLOB) EgtRelocateGlob( nWipe, nCoasting or nCrvLO or nCrv, GDB_IN.AFTER) EgtSetName( nWipe, WIPE_CRV) EgtSetInfo( nWipe, KEY_TYPE, TYPE.WIPE) EgtSetInfo( nWipe, KEY_CRV_STRAND, dStrand) EgtSetColor( nWipe, EgtStdColor('AQUA')) end end return end end end -- se non ho trovato curva sul bordo su cui fare il lead out aggiungo coasting e wipe come sulle shell normali AddRetraction( nCrv, dRibsLOCoasting, dRibsLOWipe, dRibsLOWipeAng) end --------------------------------------------------------------------- local function CalcRibsToolPath( vEntIds, nRibsGrp, nTpathGrpId, LayerParams) if not vEntIds or #vEntIds == 0 then return end -- gruppo temporaneo con sistema di riferimento locale per conti local frLoc = Frame3d( ORIG(), LayerParams.vtSlicing) local nGrpTmp = EgtGroup( nRibsGrp, frLoc, GDB_RT.GLOB) -- aggiungo le costolature nel toolpath local nLastEnt = EgtGetLastInGroup( nTpathGrpId) or GDB_ID.NULL for i = 1, #vEntIds do -- copio entità nel gruppo toolpath local nNewEntId = EgtCopyGlob( vEntIds[i], nTpathGrpId, GDB_IN.LAST_SON) -- mi sposto dell'altezza layer EgtMove( nNewEntId, LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) -- approssimo la curva e ne risetto punto iniziale (se chiusa) local ptS = EgtSP( nNewEntId, GDB_ID.ROOT) EgtApproxCurve( nNewEntId, GDB_CA.ARCS, s_dApproxTol) if EgtCurveIsClosed( nNewEntId) then EgtChangeClosedCurveStartPoint( nNewEntId, ptS, GDB_RT.GLOB) end EgtModifyCurveExtrusion( nNewEntId, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetColor( nNewEntId, EgtStdColor('MAROON')) local dStrand = EgtGetInfo( vEntIds[i], KEY_RIBS_STRAND, 'd') EgtSetInfo( nNewEntId, KEY_CRV_STRAND, dStrand) EgtSetInfo( nNewEntId, KEY_ASSOCIATED_P_CRV, vEntIds[i]) EgtSetInfo( vEntIds[i], KEY_ASSOCIATED_TP_CRV, nNewEntId) end -- recupero i gruppi delle costolature local tabRibs = {} local nFirst = EgtGetNext( nLastEnt) or EgtGetFirstInGroup( nTpathGrpId) while nFirst do local sName = EgtGetName( nFirst) local vIds = EgtGetNameInGroup( nTpathGrpId, sName) table.insert( tabRibs, vIds) nFirst = EgtGetNextName( vIds[#vIds], RIBS_CRV .. '*') end local bSpecialCase = EgtGetInfo( nRibsGrp, KEY_RIBS_SPECIAL_CASE, 'b') or false -- Link local nLoopGrp = EgtGetFirstGroupInGroup( nRibsGrp) -- collego le passate di una stessa costolatura for i = 1, #tabRibs do if EgtCurveIsClosed( tabRibs[i][1]) then AddLink( tabRibs[i], nTpathGrpId, LINK_TYPE.NONE, LayerParams.dLinkParam, LayerParams.dSPOffs, LayerParams.vtSlicing) else local bLoopRib = EgtGetInfo( tabRibs[i][1], KEY_LOOP_RIB, 'b') or false for j = 1, #tabRibs[i] - 1 do local bUserLink = ( EgtGetInfo( tabRibs[i][j], KEY_RIBS_USER_LINK, 'b') or false) and ( EgtGetInfo( tabRibs[i][j+1], KEY_RIBS_USER_LINK, 'b') or false) local bSplitAfterTrim = ( EgtGetInfo( tabRibs[i][j], KEY_SPLIT_AFTER_TRIM, 'b') or false) and ( EgtGetInfo( tabRibs[i][j+1], KEY_SPLIT_AFTER_TRIM, 'b') or false) local nOrig1 = EgtGetInfo( tabRibs[i][j], KEY_ORIGINAL_RIB, 'i') or 0 local nOrig2 = EgtGetInfo( tabRibs[i][j + 1], KEY_ORIGINAL_RIB, 'i') or 0 local nSplitId1 = EgtGetInfo( tabRibs[i][j], KEY_SPLIT_ID, 'i') or 0 local nSplitId2 = EgtGetInfo( tabRibs[i][j + 1], KEY_SPLIT_ID, 'i') or 0 local bForceLink = ( nOrig1 == nOrig2 and nSplitId1 == nSplitId2) -- creo collegamento se userlink, passate dello stesso setto o passate divise dopo trim if ( nOrig1 ~= nOrig2 and bUserLink) or ( nSplitId1 == nSplitId2 and nOrig1 == nOrig2) or ( nOrig1 == nOrig2 and bSplitAfterTrim) then if not bLoopRib then CalcRibsLink( tabRibs[i][j], tabRibs[i][j + 1], nLoopGrp, bForceLink, LayerParams.vtSlicing, nGrpTmp) else local nLinkId = CalcLoopRibLink( tabRibs[i][j], tabRibs[i][j + 1], nLoopGrp, LayerParams.vtSlicing, nGrpTmp, bForceLink) -- se collegamento congiungo i setti in unico percorso if nLinkId then EgtAddCurveCompoCurve( tabRibs[i][j+1], nLinkId, true, false) EgtAddCurveCompoCurve( tabRibs[i][j+1], tabRibs[i][j], true, false) -- aggiorno id nel vettore dei setti per gestire correttamente le curve negli step successivi for k = 0, j do if tabRibs[i][k] == tabRibs[i][j] then tabRibs[i][k] = tabRibs[i][j+1] end end end end end end -- se LoopRib aggiungo collegamento tra primo e ultimo setto del gruppo if bLoopRib then local nTotCrv = #tabRibs[i] local nLinkId = CalcLoopRibLink( tabRibs[i][nTotCrv], tabRibs[i][1], nLoopGrp, LayerParams.vtSlicing, nGrpTmp, false) if nLinkId then -- se curva unica if tabRibs[i][nTotCrv] == tabRibs[i][1] then EgtAddCurveCompoCurve( tabRibs[i][1], nLinkId) -- setto info di curva chiusa per gestire correttamente il wipe EgtSetInfo( tabRibs[i][1], KEY_CLOSED_CRV, 1) -- modifica dello start point usando lo stesso delle shell local nCrvGrp = EgtGetParent( nTpathGrpId) local nPathGrp = EgtGetFirstNameInGroup( nCrvGrp, PATH_GRP) local nFirstShell = EgtGetFirstNameInGroup( nPathGrp, SHELL_CRV .. '*') if nFirstShell then -- verifico se già realizzato toolpath corrispondente local nRefCrv = EgtGetInfo( nFirstShell, KEY_ASSOCIATED_TP_CRV, 'i') or nFirstShell local ptStart = EgtSP( nFirstShell) EgtChangeClosedCurveStartPoint( tabRibs[i][1], ptStart) end else EgtAddCurveCompoCurve( tabRibs[i][1], nLinkId, true, false) EgtAddCurveCompoCurve( tabRibs[i][1], tabRibs[i][nTotCrv], true, false) tabRibs[i][nTotCrv] = tabRibs[i][1] end end end end end -- se necessario collego le diverse costolature for i = 1, #tabRibs - 1 do local bLink1 = EgtGetInfo( tabRibs[i][1], KEY_RIBS_LINK, 'b') local bLink2 = EgtGetInfo( tabRibs[i + 1][1], KEY_RIBS_LINK, 'b') local bLoop1 = EgtGetInfo( tabRibs[i][1], KEY_LOOP_RIB, 'b') or false local bLoop2 = EgtGetInfo( tabRibs[i + 1][1], KEY_LOOP_RIB, 'b') or false if bLink1 and bLink2 and not bLoop1 and not bLoop2 then local nCnt = #tabRibs[i] CalcRibsLink( tabRibs[i][nCnt], tabRibs[i + 1][1], nLoopGrp, false, LayerParams.vtSlicing, nGrpTmp) end end -- leadin/leadout local bForceNoSolidBorder = false local nType = EgtGetInfo( vEntIds[1], KEY_RIBS_TYPE, 'i') if nType == RIB_TYPE.UNBOUNDED then bForceNoSolidBorder = true end local nCrvRib = EgtGetNext( nLastEnt) while nCrvRib do -- verifico se necessario lead in local nPrev = EgtGetPrev( nCrvRib) if not nPrev or EgtGetName( nPrev) ~= LINK_CRV then AddRibsLeadIn( nCrvRib, nLoopGrp, LayerParams.vtSlicing, nGrpTmp, bForceNoSolidBorder, bSpecialCase) end -- verifico se necessario lead out local nNext = EgtGetNext( nCrvRib) if not nNext or EgtGetName( nNext) ~= LINK_CRV then AddRibsLeadOut( nCrvRib, nLoopGrp, LayerParams.vtSlicing, nGrpTmp, bForceNoSolidBorder, bSpecialCase) end nCrvRib = EgtGetNextName( nCrvRib, RIBS_CRV .. '*') end EgtErase( nGrpTmp) end -------------------------------------------------------------------- ------------------------- SPIRAL VASE ------------------------------ -------------------------------------------------------------------- local function AddSpiralVaseLeadOut( nOldId, LayerParams) if LayerParams.nLeadOutType ~= LEAD_TYPE.NONE then EgtTrimCurveEndAtLen( nOldId, EgtCurveLength( nOldId) - LayerParams.dOffsetLP) local nLeadOut = AddLeadOut( nOldId, LayerParams, EgtGetParent( nOldId)) if nLeadOut then if LayerParams.bLinearApprox then EgtApproxCurve( nLeadOut, GDB_CA.LINES, LayerParams.dLinearApproxTol) end local dDelta = LayerParams.dLayHeight / EgtCurveLength( nOldId) * EgtCurveLength( nLeadOut) EgtSpiralizeCurveAlongExtrusion( nLeadOut, dDelta) end AddRetractionOnLastCrv( nOldId, EgtGetParent( nOldId), LayerParams, LayerParams.dCoastingLen, LayerParams.dWipeLen, LayerParams.dWipeDir) else AddRetraction( nOldId, LayerParams.dCoastingLen, LayerParams.dWipeLen, LayerParams.dWipeDir) 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 local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') if nSlicingType == SLICING_TYPE.MULTIPLANAR or nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 or nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR then return SpiralVaseFullMultiPlanar( vLayIds, LayerParams) end local nOldId, nOldPathId local nRealLayer = 1 -- copio ultimo layer 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 local nSliceNbr = EgtGetInfo( nNewLay, KEY_SLICE_NBR, 'i') + 1 EgtSetName( nNewLay, SLICE_LAYER .. EgtNumToString( nSliceNbr)) EgtSetInfo( nNewLay, KEY_SLICE_NBR, nSliceNbr) -- porto alla nuova quota EgtMove( nNewLay, LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) local ptSlice = EgtGetInfo( nNewLay, KEY_SLICE_POS, 'p') ptSlice = ptSlice + LayerParams.dLayHeight * LayerParams.vtSlicing EgtSetInfo( nNewLay, KEY_SLICE_POS, ptSlice) end -- ciclo sui layer for nIdx = 1, #vLayIds do -- cerco i gruppi di contorni local vCrvGrpIds = EgtGetNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") if #vCrvGrpIds > 1 then -- se più di un gruppo di curve warning 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 local vtMove = V_NULL() -- eventuale spostamento dell'altezza layer if nSlicingType == SLICING_TYPE.DEG45_X or nSlicingType == SLICING_TYPE.DEG45_Y then vtMove = LayerParams.dLayHeight * LayerParams.vtSlicing EgtMove( nNewEntId, vtMove, GDB_RT.GLOB) end EgtModifyCurveExtrusion( nNewEntId, LayerParams.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 * LayerParams.vtSlicing, GDB_RT.GLOB) -- modifico altezza ultimo tratto local dTrimPar = EgtCurveParamAtLength( nNewEntId, EgtCurveLength( nNewEntId) - s_dSpralVaseFirstDelta) local nNewPart = EgtSplitCurveAtParam( nNewEntId, dTrimPar) EgtSpiralizeCurveAlongExtrusion( nNewPart, 0.5 * LayerParams.dLayHeight) if LayerParams.bLinearApprox then EgtApproxCurve( nNewEntId, GDB_CA.LINES, LayerParams.dLinearApproxTol) EgtApproxCurve( nNewPart, GDB_CA.LINES, LayerParams.dLinearApproxTol) end -- 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 -- a) garantisco continuità con layer precedente local ptOld = EgtEP( nOldId, GDB_ID.ROOT) if nRealLayer == 2 then -- aggiusto la quota per confronto sensato ptOld = ptOld - 0.5 * LayerParams.dLayHeight * LayerParams.vtSlicing end local ptNew = EgtSP( nNewEntId, GDB_ID.ROOT) -- se il punto di inizio non coincide con quello finale del percorso calcolato fino ad ora, modifico la curva per avere una transizione più uniforme tra i due layers if not AreSamePointApprox( ptOld, ptNew) then -- recupero la curva da usare come guida local nGuideId = EgtCopyGlob( nOldPathId, nPathGrpId) -- la rendo coerente con il toolpath EgtMove( nGuideId, vtMove + LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) if LayerParams.bInvert then EgtInvertCurve( nGuideId) end -- approssimo con tratti lineari imponendo lunghezza massima per migliorare spiralize EgtApproxCurve( nGuideId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) EgtApproxCurve( nNewEntId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) -- modifico i punti iniziali affinchè coincidano con il punto finale del percorso precedente EgtChangeClosedCurveStartPoint( nGuideId, ptOld, GDB_RT.GLOB) EgtChangeClosedCurveStartPoint( nNewEntId, ptOld, GDB_RT.GLOB) -- distribuisco la differenza sulla curva local dLen = EgtCurveLength( nNewEntId) if LayerParams.dSpiralVaseInterpLen < GEO.EPS_SMALL or LayerParams.dSpiralVaseInterpLen > dLen - GEO.EPS_SMALL then -- la differenza deve essere distribuita su tutta la curva EgtSpiralizeCurveAlongGuide( nNewEntId, nGuideId) -- forzo il punto di inizio a coincidere con il layer precedente ( non è garantito dallo spiralize con il path a causa dell'approx -- con gli archi che potrebbe modificare il punto finale del tpath rispetto a quello del path associato) EgtModifyCurveStartPoint( nNewEntId, ptOld, GDB_RT.GLOB) else -- la differenza deve essere distribuita solo su un sottotratto di lunghezza LayerParams.dSpiralVaseAdjLen local dParSplit = EgtCurveParamAtLength( nNewEntId, LayerParams.dSpiralVaseInterpLen) local nNewEndId2 = EgtSplitCurveAtParam( nNewEntId, dParSplit) -- trim della curva guida local _, _, dParMinDist = EgtPointCurveDist( EgtEP( nNewEntId, GDB_ID.ROOT), nGuideId, GDB_RT.GLOB) local nGuideId2 = EgtSplitCurveAtParam( nGuideId, dParMinDist) EgtErase( nGuideId2) -- spiralize solo del primo pezzo EgtSpiralizeCurveAlongGuide( nNewEntId, nGuideId) EgtModifyCurveStartPoint( nNewEntId, ptOld, GDB_RT.GLOB) EgtModifyCurveEndPoint( nNewEntId, EgtSP( nNewEndId2, GDB_ID.ROOT), GDB_RT.GLOB) -- riassemblo la curva EgtAddCurveCompoCurve( nNewEntId, nNewEndId2) end EgtErase( nGuideId) end -- b) 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 -- c) modifica graduale dell'altezza if nRealLayer == 2 then -- se seconda passata la prima metà deve essere a quota costante 0.5 * dLayHeight, la seconda metà deve salire gradualmente di 0.5 * dLayHeight EgtMove( nNewEntId, 0.5 * LayerParams.dLayHeight * LayerParams.vtSlicing, GDB_RT.GLOB) local nNewId = EgtSplitCurve( nNewEntId, 2) EgtSpiralizeCurveAlongExtrusion( nNewId + 1, 0.5 * LayerParams.dLayHeight) else EgtSpiralizeCurveAlongExtrusion( nNewEntId, LayerParams.dLayHeight) end end local vTPathsCrvs = EgtGetAllInGroup( nTpathGrpId) nOldPathId = vEntIds[1] nOldId = vTPathsCrvs[#vTPathsCrvs] -- moltiplicatore per feed if nRealLayer == 2 then -- il primo tratto si trova a metà altezza rispetto allo strato precedente, quindi il coefficiente moltiplicativo è due EgtSetInfo( vTPathsCrvs[1], KEY_FEED_COEFF, 2) -- nel secondo tratto l'altezza è variabile quindi devo calcolare il coefficiente per ogni sottotratto local dLenTot = EgtCurveLength( vTPathsCrvs[1]) + EgtCurveLength( vTPathsCrvs[2]) local dLen = EgtCurveLength( vTPathsCrvs[1]) local nFirst, nCnt = EgtExplodeCurveCompo( vTPathsCrvs[2]) for nId = nFirst, nFirst + nCnt - 1 do -- calcolo l'altezza effettiva basandomi sulla lunghezza parziale ( viene mimato il conto fatto in EgtSpiralizeCurveAlongExtrusion) dLen = dLen + EgtCurveLength( nId) local dHEff = LayerParams.dLayHeight * dLen / dLenTot local dFeedCoeff = LayerParams.dLayHeight / dHEff EgtSetInfo( nId, KEY_FEED_COEFF, dFeedCoeff) end nOldId = nFirst + nCnt - 1 elseif nRealLayer == 3 then -- solo la prima metà si trova ad un'altezza variabile rispetto allo strato precedente local dLenTot = EgtCurveLength( vTPathsCrvs[1]) local dLen = 0 local nNewId = EgtSplitCurve( vTPathsCrvs[1], 2) local nFirst, nCnt = EgtExplodeCurveCompo( nNewId) for nId = nFirst, nFirst + nCnt - 1 do dLen = dLen + EgtCurveLength( nId) local dHeff = LayerParams.dLayHeight * ( dLen / dLenTot + 0.5) local dFeedCoeff = LayerParams.dLayHeight / dHeff EgtSetInfo( nId, KEY_FEED_COEFF, dFeedCoeff) end nOldId = nNewId + 1 end nRealLayer = nRealLayer + 1 end if EgtProcessEvents( EgtIf( PRINT, 300, 0) + nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return false end end return true end --------------------------------------------------------------------- local function SpiralVasePartialMultiPlanar( vLayIds, LayerParams) -- la differenza in altezza tra due layers viene distribuita solo lungo il tratto finale di lunghezza dSpiralVaseLen -- la continuità tra i layers viene risolta sul tratto finale del layer percedente local bFirst = true -- individuo l'ultimo layer ( alcuni potrebbero essere vuoti) local nLastLay = 1 for nIdx = #vLayIds, 1, -1 do local nCrvGrp = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrp, PATH_GRP) or GDB_ID_NULL if EgtGetGroupObjs( nPathGrpId) > 0 then nLastLay = nIdx break end end -- ciclo sui layer local nOldId for nIdx = 1, #vLayIds do -- 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 false 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) if LayerParams.bInvert then EgtInvertCurve( nNewEntId) EgtSetInfo( nNewEntId, KEY_INVERTED_CRV, 1) end EgtSetColor( nNewEntId, EgtStdColor('GRAY')) -- sistemo il tratto finale del percorso precedente if not bFirst then local ptSOld = EgtSP( nOldId, GDB_ID.ROOT) local ptEOld = EgtEP( nOldId, GDB_ID.ROOT) -- proiezione ortogonale dei punti sul piano di slicing corrente 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) 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) local nProjCrv = EgtCopyGlob( vEntIds[1], nPathGrpId) if LayerParams.bInvert then EgtInvertCurve( nProjCrv) end -- conservo solo il sottotratto corrispondente a nOldId local _, _, dStartGuide = EgtPointCurveDist( ptSProj, nProjCrv, GDB_ID.ROOT) local _, _, dEndGuide = EgtPointCurveDist( ptEProj, nProjCrv, GDB_ID.ROOT) EgtTrimCurveStartEndAtParam( nProjCrv, dStartGuide, dEndGuide) -- proiezione sul piano precedente ( ptSlicingPrev, vtSlicingPrev) lungo vtSlicing local vtSlicingPrev = EgtGetInfo( vLayIds[nIdx-1], KEY_SLICE_DIR, 'v') local ptSlicingPrev = EgtGetInfo( vLayIds[nIdx-1], KEY_SLICE_POS, 'p') + LayerParams.dLayHeight * vtSlicingPrev local _, dE = EgtCurveDomain( nProjCrv) for dU = 0, dE do local pt = EgtUP( nProjCrv, dU, GDB_ID.ROOT) 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 -- delta che va applicato ( è la distanza ortogonale del punto finale di nOldId dal piano del toolpath corrente) local dDist = ( EgtEP( nOldId, GDB_ID.ROOT) - ( ptSlicing + LayerParams.dLayHeight * vtSlicing)) * vtSlicing EgtApproxCurve( nOldId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) local _, dE = EgtCurveDomain( nOldId) local vDelta = {} local dLen = EgtCurveLength( nOldId) for dU = 0, dE do local dCurrLen = EgtCurveLengthAtParam( nOldId, dU) vDelta[dU] = abs( dDist) * dCurrLen / dLen end for dU = 0, dE do local ptCurr = EgtUP( nOldId, dU, GDB_ID.ROOT) EgtModifyCurveCompoJoint( nOldId, dU, ptCurr + vDelta[dU] * vtSlicing, GDB_RT.GLOB) end -- c) approssimazione della curva EgtApproxCurve( nOldId, GDB_CA.ARCS, s_dApproxTol) if LayerParams.bLinearApprox then EgtApproxCurve( nOldId, GDB_CA.LINES, LayerParams.dLinearApproxTol) end -- forzo punti per garantire continuità EgtModifyCurveStartPoint( nOldId, ptSOld, GDB_RT.GLOB) EgtModifyCurveEndPoint( nOldId, ptCurrStart + LayerParams.dLayHeight * vtSlicing, GDB_RT.GLOB) end -- spostamento dell'altezza layer local vtMove = LayerParams.dLayHeight * vtSlicing EgtMove( nNewEntId, vtMove, GDB_RT.GLOB) EgtCopyGlob( nNewEntId, nPathGrpId) -- approssimazione if LayerParams.bLinearApprox then local ptS = EgtSP( nNewEntId, GDB_ID.ROOT) EgtApproxCurve( nNewEntId, GDB_CA.LINES, LayerParams.dLinearApproxTol) if EgtCurveIsClosed( nNewEntId) then EgtChangeClosedCurveStartPoint( nNewEntId, ptS, GDB_RT.GLOB) end end -- eventuale lead in if bFirst then bFirst = false 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 end -- separo l'ultimo tratto che farà da collegamento con il layer successivo if nIdx ~= nLastLay then local dTrimLen = EgtCurveLength( nNewEntId) - LayerParams.dSpiralVaseLen if dTrimLen < GEO.EPS_SMALL then -- se lunghezza di trim maggiore delle dimensioni forzo un valore accettabile dTrimLen = 0.5 * EgtCurveLength( nNewEntId) end local dTrimPar = EgtCurveParamAtLength( nNewEntId, dTrimLen) nOldId = EgtSplitCurveAtParam( nNewEntId, dTrimPar) end end if EgtProcessEvents( EgtIf( PRINT, 300, 0) + nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return false end end return true end --------------------------------------------------------------------- local function SpiralVasePartial( vLayIds, LayerParams) -- la differenza in altezza tra due layers viene distribuita solo lungo il tratto finale di lunghezza dSpiralVaseLen -- la continuità tra i layers viene risolta sul tratto finale del layer percedente local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') if nSlicingType == SLICING_TYPE.MULTIPLANAR or nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 or nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR then return SpiralVasePartialMultiPlanar( vLayIds, LayerParams) end local bFirst = true -- individuo l'ultimo layer ( alcuni potrebbero essere vuoti) local nLastLay = 1 for nIdx = #vLayIds, 1, -1 do local nCrvGrp = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrp, PATH_GRP) or GDB_ID_NULL if EgtGetGroupObjs( nPathGrpId) > 0 then nLastLay = nIdx break end end -- ciclo sui layer local nOldId for nIdx = 1, #vLayIds do -- 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 false 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, LayerParams.vtSlicing, GDB_RT.GLOB) EgtSetInfo( nNewEntId, KEY_CRV_STRAND, LayerParams.dStrand) if LayerParams.bInvert then EgtInvertCurve( nNewEntId) EgtSetInfo( nNewEntId, KEY_INVERTED_CRV, 1) end EgtSetColor( nNewEntId, EgtStdColor('GRAY')) -- sistemo il tratto finale del percorso precedente if not bFirst then local ptSOld = EgtSP( nOldId, GDB_ID.ROOT) local ptEOld = EgtEP( nOldId, GDB_ID.ROOT) -- modifico il punto iniziale corrente per avvicinarmi il più possibile alla fine del percorso precedente EgtChangeClosedCurveStartPoint( nNewEntId, ptEOld, GDB_RT.GLOB) local ptNew = EgtSP( nNewEntId, GDB_ID.ROOT) -- a) verifico continuità tra i layers if not AreSamePointApprox( ptEOld, ptNew) then -- se il punto finale del percorso precedente non coincide con quello iniziale del percorso corrente modifico il tratto finale del percorso precedente che va alzato sin modo -- che termini esattamente sull'inizio del percorso corrente local _, _, dStartGuide = EgtPointCurveDist( ptSOld, nNewEntId, GDB_ID.ROOT) local _, dEndGuide = EgtCurveDomain( nNewEntId) local nGuideId = EgtCopyParamRange( nNewEntId, dStartGuide, dEndGuide, nTpathGrpId) EgtModifyCurveExtrusion( nGuideId, LayerParams.vtSlicing, GDB_RT.GLOB) -- approssimo con tratti lineari imponendo lunghezza massima per migliorare spiralize EgtApproxCurve( nGuideId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) EgtApproxCurve( nOldId, GDB_CA.SPECIAL_LINES, 0.01, s_dSpiralVaseMaxLen) -- SpiralizeAlongGuide effettua una transizione dalla guida alla curva corrente, qui serve in contrario ( la curva deve arrivare sulla guida non partire da essa) -- quindi bisogna lavorare con le curve invertite EgtInvertCurve( nGuideId) EgtInvertCurve( nOldId) EgtSpiralizeCurveAlongGuide( nOldId, nGuideId) EgtInvertCurve( nOldId) EgtErase( nGuideId) -- approssimo la curva EgtApproxCurve( nOldId, GDB_CA.ARCS, s_dApproxTol) if LayerParams.bLinearApprox then EgtApproxCurve( nOldId, GDB_CA.LINES, LayerParams.dLinearApproxTol) end -- forzo punti per garantire continuità EgtModifyCurveStartPoint( nOldId, ptSOld, GDB_RT.GLOB) EgtModifyCurveEndPoint( nOldId, ptNew, GDB_RT.GLOB) end -- b) modifica graduale dell'altezza EgtSpiralizeCurveAlongExtrusion( nOldId, LayerParams.dLayHeight) end -- spostamento dell'altezza layer local vtMove = LayerParams.dLayHeight * LayerParams.vtSlicing EgtMove( nNewEntId, vtMove, GDB_RT.GLOB) -- approssimazione if LayerParams.bLinearApprox then local ptS = EgtSP( nNewEntId, GDB_ID.ROOT) EgtApproxCurve( nNewEntId, GDB_CA.LINES, LayerParams.dLinearApproxTol) if EgtCurveIsClosed( nNewEntId) then EgtChangeClosedCurveStartPoint( nNewEntId, ptS, GDB_RT.GLOB) end end -- eventuale lead in if bFirst then bFirst = false 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 end -- separo l'ultimo tratto che farà da collegamento con il layer successivo if nIdx ~= nLastLay then local dTrimLen = EgtCurveLength( nNewEntId) - LayerParams.dSpiralVaseLen if dTrimLen < GEO.EPS_SMALL then -- se lunghezza di trim maggiore delle dimensioni forzo un valore accettabile dTrimLen = 0.5 * EgtCurveLength( nNewEntId) end local dTrimPar = EgtCurveParamAtLength( nNewEntId, dTrimLen) nOldId = EgtSplitCurveAtParam( nNewEntId, dTrimPar) end end if EgtProcessEvents( EgtIf( PRINT, 300, 0) + nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return false end end return true end --------------------------------------------------------------------- local function SpiralVase( vLayIds, LayerParams) -- verifico quale modalità di spiral vase applicare : -- 1) dSpiralVaseLen = 0 : la differenza in altezza tra due layers ( dLayHeight) viene distribuita uniformemente sull'intero percorso -- 2) dSpiralVaseLen > 0 : la differenza in altezza tra due layers viene distribuita solo lungo il tratto finale di lunghezza dSpiralVaseLen if abs( LayerParams.dSpiralVaseLen) < GEO.EPS_SMALL then if not SpiralVaseFull( vLayIds, LayerParams) then return false end else if not SpiralVasePartial( vLayIds, LayerParams) then return false end 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( LayerParams) return true end --------------------------------------------------------------------- function CalcToolPath.Exec( nPartId) s_nPartId = nPartId -- Recupero i layer da processare local vLayIds = EgtGetNameInGroup( s_nPartId, SLICE_LAYER.."*") if not vLayIds or #vLayIds == 0 then EgtOutBox( 'Error missing slices', 'ToolPathCalc') return true end -- recupero i parametri per calcolo dei toolpath local LayerParams = GetLayerParamsForToolPathCalc() local nSlicingType = EgtGetInfo( s_nPartId, KEY_SLICING_TYPE, 'i') local bFirst = true -- caso spiral vase if LayerParams.bSpiralVase then return SpiralVase( vLayIds, LayerParams) end local nLayCnt = 1 -- Ciclo sui layer for nIdx = 1, #vLayIds do s_nCurrIdx = nIdx if nSlicingType == SLICING_TYPE.MULTIPLANAR or nSlicingType == SLICING_TYPE.MULTIPLANAR_DEG45 or nSlicingType == SLICING_TYPE.MULTIPLANAR_HOR then LayerParams.vtSlicing = EgtGetInfo( vLayIds[nIdx], KEY_SLICE_DIR, 'v') end -- scorro tutti i gruppi di contorni local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") while nCrvGrpId do -- recupero il gruppo dei percorsi local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, 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( nCrvGrpId, TOOLPATH_GRP) if not nTpathGrpId then nTpathGrpId = EgtGroup( nCrvGrpId) EgtSetName( nTpathGrpId, TOOLPATH_GRP) else EgtEmptyGroup( nTpathGrpId) end -- recupero gli elementi da stampare local vShellIds = EgtGetNameInGroup( nPathGrpId, SHELL_CRV .. '*') local vExtraShellIds = EgtGetNameInGroup( nPathGrpId, EXTRA_SHELL_CRV .. '*') local nInfillGrp = EgtGetFirstNameInGroup( nCrvGrpId, INFILL_GRP) or GDB_ID.NULL local nAuxSolidsGrp = EgtGetFirstNameInGroup( vLayIds[nIdx], AUX_SOLIDS_GRP) local nAuxSolidsPathGrp = EgtGetFirstNameInGroup( nCrvGrpId, AUX_SOLIDS_GRP) local nRibsGrp = EgtGetFirstNameInGroup( nCrvGrpId, RIBS_GRP) -- suddivido i ribs per tipologia local tRibs = {{}, {}, {}, {}} local vRibsIds = EgtGetNameInGroup( nRibsGrp, RIBS_CRV .. '*') or {} for i = 1, #vRibsIds do local nType = EgtGetInfo( vRibsIds[i], KEY_RIBS_TYPE, 'i') or RIB_TYPE.INTERNAL table.insert( tRibs[nType], vRibsIds[i]) end -- eventuale unione delle shell e dei SolidFills JoinShellsAndSolidFills( nInfillGrp, vShellIds, vExtraShellIds, LayerParams, tRibs) -- realizzo le diverse tipologie in base all'ordine selezionato for j = 1, #LayerParams.vPrintOrder do -- shell if LayerParams.vPrintOrder[j] == PRINT_ELEMENT.SHELL then CalcShellsToolPath( vShellIds, nTpathGrpId, bFirst, LayerParams) -- extra shell elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.EXTRA_SHELL then CalcExtraShellToolPath( vExtraShellIds, nTpathGrpId, LayerParams) -- infill elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.INFILL then local nFillType = EgtGetInfo( nInfillGrp, KEY_FILL_TYPE, 'i') or FILL_TYPE.NONE if nFillType & FILL_CATEGORY.SOLID_FILL ~= 0 then CalcSolidFillToolPath( nInfillGrp, nTpathGrpId, LayerParams) else CalcInfillToolPath( nInfillGrp, nTpathGrpId, LayerParams) end -- solidi ausiliari elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.AUX_SOLID then CalcAuxSolidsToolPath( nAuxSolidsGrp, nAuxSolidsPathGrp, nTpathGrpId, LayerParams) -- costolature elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.RIB_UNBOUNDED then CalcRibsToolPath( tRibs[RIB_TYPE.UNBOUNDED], nRibsGrp, nTpathGrpId, LayerParams) elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.RIB_INTERNAL then CalcRibsToolPath( tRibs[RIB_TYPE.INTERNAL], nRibsGrp, nTpathGrpId, LayerParams) elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.RIB_SUPPORT then CalcRibsToolPath( tRibs[RIB_TYPE.SUPPORT], nRibsGrp, nTpathGrpId, LayerParams) elseif LayerParams.vPrintOrder[j] == PRINT_ELEMENT.RIB_EXTERNAL then CalcRibsToolPath( tRibs[RIB_TYPE.EXTERNAL], nRibsGrp, nTpathGrpId, LayerParams) end end -- verifico non sia vuoto per aggiornare il numero di layers if EgtGetFirstInGroup( nTpathGrpId) then nLayCnt = nIdx end -- eventuale approssimazione delle curve if LayerParams.bLinearApprox then local nCrvId = EgtGetFirstInGroup( nTpathGrpId) while nCrvId do EgtApproxCurve( nCrvId, GDB_CA.LINES, LayerParams.dLinearApproxTol) nCrvId = EgtGetNext( nCrvId) end end if bFirst and EgtGetGroupObjs( nTpathGrpId) > 0 then bFirst = false end -- passo al gruppo di contorni successivo nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") end if EgtProcessEvents( EgtIf( PRINT, 300, 0) + nIdx / #vLayIds * 100, 0) == 1 then EgtDraw() return end end -- correzione in z AddZCorrection( LayerParams) -- setto info con numero di layers effettivi EgtSetInfo( nPartId, KEY_LAYER_CNT, nLayCnt) return true end --------------------------------------------------------------------- return CalcToolPath